ILIAS  trunk Revision v11.0_alpha-1843-g9e1fad99175
All Data Structures Namespaces Files Functions Variables Enumerations Enumerator Modules Pages
XapiProxy.php
Go to the documentation of this file.
1 <?php
2 
19 declare(strict_types=1);
20 namespace XapiProxy;
21 
24 
26 {
29 
30  public function __construct(string $client, string $token, ?bool $plugin = false)
31  {
32  parent::__construct($client, $token, $plugin);
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 }
XapiProxyResponse $xapiProxyResponse
Definition: XapiProxy.php:28
setXapiProxyRequest(XapiProxyRequest $xapiProxyRequest)
Definition: XapiProxy.php:114
const ANONYMOUS_USER_ID
Definition: constants.php:27
__construct(string $client, string $token, ?bool $plugin=false)
Definition: XapiProxy.php:30
modifyBody(string $body)
Definition: XapiProxy.php:197
setXapiProxyResponse(XapiProxyResponse $xapiProxyResponse)
Definition: XapiProxy.php:124
setStatus(object $obj)
Definition: XapiProxy.php:272
$path
Definition: ltiservices.php:29
XapiProxyRequest $xapiProxyRequest
Definition: XapiProxy.php:27
while($session_entry=$r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) return null
$client
$token
Definition: xapitoken.php:70
global $DIC
Definition: shib_login.php:22
setValue(object &$obj, string $path, string $value)
Definition: XapiProxy.php:258
static getInstanceByObjId(?int $obj_id, bool $stop_on_error=true)
get an instance of an Ilias object by object id
handleStatementEvaluation(object $xapiStatement)
Definition: XapiProxy.php:230
__construct(Container $dic, ilPlugin $plugin)
processStatements(\Psr\Http\Message\RequestInterface $request, $body)
Definition: XapiProxy.php:134
static _updateStatus(int $a_obj_id, int $a_usr_id, ?object $a_obj=null, bool $a_percentage=false, bool $a_force_raise=false)
setRequestParams(Request $request)
Definition: XapiProxy.php:36
isSubStatementCheck(object $obj)
Definition: XapiProxy.php:293