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