ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
XapiProxy.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20namespace XapiProxy;
21
22use GuzzleHttp\Psr7\Request;
23use GuzzleHttp\Psr7\Response;
24
26{
29
30 public function __construct(string $client, string $token, ?bool $plugin = false)
31 {
33 $this->log()->debug($this->msg('proxy initialized'));
34 }
35
36 public function setRequestParams(Request $request): void
37 {
38 preg_match(self::PARTS_REG, (string) $request->getUri(), $this->cmdParts);
39 }
40
41 public function token(): string
42 {
43 return $this->token;
44 }
45
46 public function client(): string
47 {
48 return $this->client;
49 }
50
51 public function lrsType(): ?\ilCmiXapiLrsType
52 {
53 return $this->lrsType;
54 }
55
56 public function replacedValues(): ?array
57 {
58 return $this->replacedValues;
59 }
60
61 public function specificAllowedStatements(): ?array
62 {
63 return $this->specificAllowedStatements;
64 }
65
66 public function blockSubStatements(): bool
67 {
68 return $this->blockSubStatements;
69 }
70
74 public function cmdParts(): array
75 {
76 return $this->cmdParts;
77 }
78
79 public function method(): string
80 {
81 return $this->method;
82 }
83
84 public function getDefaultLrsEndpoint(): string
85 {
86 return $this->defaultLrsEndpoint;
87 }
88
89 public function getDefaultLrsKey(): string
90 {
91 return $this->defaultLrsKey;
92 }
93
94 public function getDefaultLrsSecret(): string
95 {
96 return $this->defaultLrsSecret;
97 }
98
99 public function getFallbackLrsEndpoint(): string
100 {
101 return $this->fallbackLrsEndpoint;
102 }
103
104 public function getFallbackLrsKey(): string
105 {
106 return $this->fallbackLrsKey;
107 }
108
109 public function getFallbackLrsSecret(): string
110 {
111 return $this->fallbackLrsSecret;
112 }
113
114 public function setXapiProxyRequest(XapiProxyRequest $xapiProxyRequest): void
115 {
116 $this->xapiProxyRequest = $xapiProxyRequest;
117 }
118
120 {
121 return $this->xapiProxyRequest;
122 }
123
124 public function setXapiProxyResponse(XapiProxyResponse $xapiProxyResponse): void
125 {
126 $this->xapiProxyResponse = $xapiProxyResponse;
127 }
128
130 {
131 return $this->xapiProxyResponse;
132 }
133
134 public function processStatements(\Psr\Http\Message\RequestInterface $request, $body): ?array
135 {
136 // everything is allowed
137 if (!is_array($this->specificAllowedStatements) && !$this->blockSubStatements) {
138 $this->log()->debug($this->msg("all statement are allowed"));
139 return null;
140 }
141 $obj = json_decode($body, false);
142 // single statement object
143 if (is_object($obj) && isset($obj->verb)) {
144 $this->log()->debug($this->msg("json is object and statement"));
145 $isSubStatement = $this->isSubStatementCheck($obj);
146 $verb = $obj->verb->id;
147 if ($this->blockSubStatements && $isSubStatement) {
148 $this->log()->debug($this->msg("sub-statement is NOT allowed, fake response - " . $verb));
149 $this->xapiProxyResponse->fakeResponseBlocked(null);
150 }
151 // $specificAllowedStatements
152 if (!is_array($this->specificAllowedStatements)) {
153 return null;
154 }
155 if (in_array($verb, $this->specificAllowedStatements)) {
156 $this->log()->debug($this->msg("statement is allowed, do nothing - " . $verb));
157 return null;
158 } else {
159 $this->log()->debug($this->msg("statement is NOT allowed, fake response - " . $verb));
160 $this->xapiProxyResponse->fakeResponseBlocked(null);
161 }
162 }
163 // array of statement objects
164 if (is_array($obj) && count($obj) > 0 && isset($obj[0]->verb)) {
165 $this->log()->debug($this->msg("json is array of statements"));
166 $ret = array();
167 $up = array();
168 foreach ($obj as $i => $singleObj) {
169 $ret[] = $singleObj->id;
170 // push every statementid for fakePostResponse
171 $isSubStatement = $this->isSubStatementCheck($singleObj);
172 $verb = $singleObj->verb->id;
173 if ($this->blockSubStatements && $isSubStatement) {
174 $this->log()->debug($this->msg("sub-statement is NOT allowed - " . $verb));
175 } else {
176 if (!is_array($this->specificAllowedStatements) || (is_array($this->specificAllowedStatements) && in_array($verb, $this->specificAllowedStatements))) {
177 $this->log()->debug($this->msg("statement is allowed - " . $verb));
178 $up[] = $singleObj;
179 }
180 }
181 }
182 if ($up === []) { // nothing allowed
183 $this->log()->debug($this->msg("no allowed statements in array - fake response..."));
184 $this->xapiProxyResponse->fakeResponseBlocked("");
185 // $this->xapiProxyResponse->fakeResponseBlocked($ret);
186 } elseif (count($up) !== count($ret)) { // mixed request with allowed and not allowed statements
187 $this->log()->debug($this->msg("mixed with allowed and unallowed statements"));
188 return array($up,$ret);
189 } else {
190 // just return nothing
191 return null;
192 }
193 }
194 return null;
195 }
196
197 public function modifyBody(string $body): string
198 {
199 $obj = json_decode($body, false);
200
201 if (json_last_error() != JSON_ERROR_NONE) {
202 // JSON is not valid
203 $this->log()->error($this->msg(json_last_error_msg()));
204 return $body;
205 }
206
207 // $log->debug(json_encode($obj, JSON_PRETTY_PRINT)); // only in DEBUG mode for better performance
208 if (is_object($obj)) {
209 if (is_array($this->replacedValues)) {
210 foreach ($this->replacedValues as $key => $value) {
211 $this->setValue($obj, (string) $key, (string) $value);
212 }
213 }
214 $this->handleStatementEvaluation($obj); // ToDo
215 }
216
217 if (is_array($obj)) {
218 for ($i = 0; $i < count($obj); $i++) {
219 if (is_array($this->replacedValues)) {
220 foreach ($this->replacedValues as $key => $value) {
221 $this->setValue($obj[$i], (string) $key, (string) $value);
222 }
223 }
224 $this->handleStatementEvaluation($obj[$i]); // ToDo
225 }
226 }
227 return json_encode($obj);
228 }
229
230 private function handleStatementEvaluation(object $xapiStatement): void
231 {
232 global $DIC;
233 if ($this->plugin) {
234 // ToDo: handle terminate -> delete session
235 $this->setStatus($xapiStatement);
236 } else {
237 /* @var $object */
238 $object = \ilObjectFactory::getInstanceByObjId($this->authToken->getObjId());
239 if ((string) $object->getLaunchMode() === (string) \ilObjCmiXapi::LAUNCH_MODE_NORMAL) {
240 // ToDo: check function hasContextActivitiesParentNotEqualToObject!
241 $statementEvaluation = new \ilXapiStatementEvaluation($this->log(), $object);
242 $statementEvaluation->evaluateStatement($xapiStatement, $this->authToken->getUsrId());
243
244 if ($this->authToken->getUsrId() != ANONYMOUS_USER_ID) {
246 $this->authToken->getObjId(),
247 $this->authToken->getUsrId()
248 );
249 }
250 }
251 if ($xapiStatement->verb->id == self::TERMINATED_VERB) {
252 // ToDo : only cmi5 or also xapi? authToken object still used after that?
253 $this->authToken->delete();
254 }
255 }
256 }
257
258 private function setValue(object &$obj, string $path, string $value): void
259 {
260 $path_components = explode('.', $path);
261 if (count($path_components) == 1) {
262 if (property_exists($obj, $path_components[0])) {
263 $obj->{$path_components[0]} = $value;
264 }
265 } else {
266 if (property_exists($obj, $path_components[0])) {
267 $this->setValue($obj->{array_shift($path_components)}, implode('.', $path_components), $value);
268 }
269 }
270 }
271
272 private function setStatus(object $obj): void
273 {
274 // if (isset($obj->verb) && isset($obj->actor) && isset($obj->object)) {
275 // $verb = $obj->verb->id;
276 // $score = 'NOT_SET';
277 // if (array_key_exists($verb, $this->sniffVerbs)) {
278 // // check context
279 // if ($this->isSubStatementCheck($obj)) {
280 // $this->log()->debug($this->msg("statement is sub-statement, ignore status verb " . $verb));
281 // return;
282 // }
283 // if (isset($obj->result) && isset($obj->result->score) && isset($obj->result->score->scaled)) {
284 // $score = $obj->result->score->scaled;
285 // }
286 // $this->log()->debug($this->msg("handleLPStatus: " . $this->sniffVerbs[$verb] . " : " . $score));
287 // \ilObjXapiCmi5::handleLPStatusFromProxy($this->client, $this->token, $this->sniffVerbs[$verb], $score);//UK check
288 // }
289 // }
290 }
291
292
293 private function isSubStatementCheck(object $obj): bool
294 {
295 $object = \ilObjectFactory::getInstanceByObjId($this->authToken->getObjId()); // get ActivityId in Constructor for better performance, is also used in handleEvaluationStatement
296 $objActivityId = $object->getActivityId();
297 $statementActivityId = $obj->object->id;
298 if ($statementActivityId != $objActivityId) {
299 $this->log()->debug($this->msg("statement object id " . $statementActivityId . " != activityId " . $objActivityId));
300 $this->log()->debug($this->msg("is Substatement"));
301 return true;
302 } else {
303 $this->log()->debug($this->msg("is not Substatement"));
304 return false;
305 }
306 }
307}
isSubStatementCheck(object $obj)
Definition: XapiProxy.php:293
handleStatementEvaluation(object $xapiStatement)
Definition: XapiProxy.php:230
setStatus(object $obj)
Definition: XapiProxy.php:272
setXapiProxyResponse(XapiProxyResponse $xapiProxyResponse)
Definition: XapiProxy.php:124
processStatements(\Psr\Http\Message\RequestInterface $request, $body)
Definition: XapiProxy.php:134
XapiProxyRequest $xapiProxyRequest
Definition: XapiProxy.php:27
modifyBody(string $body)
Definition: XapiProxy.php:197
setValue(object &$obj, string $path, string $value)
Definition: XapiProxy.php:258
XapiProxyResponse $xapiProxyResponse
Definition: XapiProxy.php:28
setXapiProxyRequest(XapiProxyRequest $xapiProxyRequest)
Definition: XapiProxy.php:114
setRequestParams(Request $request)
Definition: XapiProxy.php:36
__construct(string $client, string $token, ?bool $plugin=false)
Definition: XapiProxy.php:30
static _updateStatus(int $a_obj_id, int $a_usr_id, ?object $a_obj=null, bool $a_percentage=false, bool $a_force_raise=false)
static getInstanceByObjId(?int $obj_id, bool $stop_on_error=true)
get an instance of an Ilias object by object id
const ANONYMOUS_USER_ID
Definition: constants.php:27
$client
$path
Definition: ltiservices.php:30
__construct(Container $dic, ilPlugin $plugin)
@inheritDoc
global $DIC
Definition: shib_login.php:26
$token
Definition: xapitoken.php:70