ILIAS  release_8 Revision v8.24
class.ilECSConnector.php
Go to the documentation of this file.
1<?php
2
18declare(strict_types=1);
19
25{
26 public const HTTP_CODE_CREATED = 201;
27 public const HTTP_CODE_OK = 200;
28 public const HTTP_CODE_NOT_FOUND = 404;
29
30 public const HEADER_MEMBERSHIPS = 'X-EcsReceiverMemberships';
31 public const HEADER_COMMUNITIES = 'X-EcsReceiverCommunities';
32
33
34 protected string $path_postfix = '';
35
36 protected ?ilECSSetting $settings = null;
37 protected ?ilCurlConnection $curl = null;
38
39 protected array $header_strings = [];
40
41 protected ilLogger $logger;
42
43 public function __construct(ilECSSetting $settings = null)
44 {
45 global $DIC;
46
47 $this->logger = $DIC->logger()->wsrv();
48 if ($settings) {
49 $this->settings = $settings;
50 } else {
51 $this->logger->warning('Using deprecated call.');
52 $this->logger->logStack(ilLogLevel::WARNING);
53 }
54 }
55
56 // Header methods
62 public function addHeader(string $a_name, string $a_value): void
63 {
64 $this->header_strings[] = ($a_name . ': ' . $a_value);
65 }
66
67 public function getHeader(): array
68 {
70 }
71
72 public function setHeader(array $a_header_strings): void
73 {
74 $this->header_strings = $a_header_strings;
75 }
76
80 public function getServer(): ilECSSetting
81 {
82 return $this->settings;
83 }
84
85
87 // auths methods
89
99 public function addAuth(string $a_post, int $a_target_mid): string
100 {
101 $this->logger->info(__METHOD__ . ': Add new Auth resource...');
102
103 $this->path_postfix = '/sys/auths';
104
105 try {
106 $this->prepareConnection();
107
108 $this->addHeader('Content-Type', 'application/json');
109 $this->addHeader('Accept', 'application/json');
110 $this->addHeader(self::HEADER_MEMBERSHIPS, (string) $a_target_mid);
111
112 $this->curl->setOpt(CURLOPT_HTTPHEADER, $this->getHeader());
113 $this->curl->setOpt(CURLOPT_POST, true);
114 $this->curl->setOpt(CURLOPT_POSTFIELDS, $a_post);
115 $ret = $this->call();
116
117 $info = $this->curl->getInfo(CURLINFO_HTTP_CODE);
118
119 $this->logger->info(__METHOD__ . ': Checking HTTP status...');
120 if ($info !== self::HTTP_CODE_CREATED) {
121 $this->logger->info(__METHOD__ . ': Cannot create auth resource, did not receive HTTP 201. ');
122 $this->logger->info(__METHOD__ . ': POST was: ' . $a_post);
123 $this->logger->info(__METHOD__ . ': HTTP code: ' . $info);
124 throw new ilECSConnectorException('Received HTTP status code: ' . $info);
125 }
126 $this->logger->info(__METHOD__ . ': ... got HTTP 201 (created)');
127 $this->logger->info(__METHOD__ . ': POST was: ' . $a_post);
128
129 $result = new ilECSResult($ret);
130 $auth = $result->getResult();
131
132 $this->logger->info(__METHOD__ . ': ... got hash: ' . $auth->hash);
133
134 return $auth->hash;
135 } catch (ilCurlConnectionException $exc) {
136 throw new ilECSConnectorException('Error calling ECS service: ' . $exc->getMessage());
137 }
138 }
139
146 public function getAuth(string $a_hash, bool $a_details_only = false)
147 {
148 if ($a_hash === '') {
149 $this->logger->error(__METHOD__ . ': No auth hash given. Aborting.');
150 throw new ilECSConnectorException('No auth hash given.');
151 }
152
153 $this->path_postfix = '/sys/auths/' . $a_hash;
154
155 if ($a_details_only) {
156 $this->path_postfix .= ('/details');
157 }
158
159
160 try {
161 $this->prepareConnection();
162 $res = $this->call();
163 $info = $this->curl->getInfo(CURLINFO_HTTP_CODE);
164
165 $this->logger->info(__METHOD__ . ': Checking HTTP status...');
166 if ($info !== self::HTTP_CODE_OK) {
167 $this->logger->info(__METHOD__ . ': Cannot get auth resource, did not receive HTTP 200. ');
168 throw new ilECSConnectorException('Received HTTP status code: ' . $info);
169 }
170 $this->logger->info(__METHOD__ . ': ... got HTTP 200 (ok)');
171
172 $ecs_result = new ilECSResult($res);
173 // Return ECSEContentDetails for details switch
174 if ($a_details_only) {
176 $details->loadFromJson($ecs_result->getResult());
177 return $details;
178 }
179 return $ecs_result;
180 } catch (ilCurlConnectionException $exc) {
181 throw new ilECSConnectorException('Error calling ECS service: ' . $exc->getMessage());
182 }
183 }
184
185 #######################################################
186 # event fifo methods
187 #####################################################
194 public function readEventFifo(bool $a_delete = false): ilECSResult
195 {
196 $this->path_postfix = '/sys/events/fifo';
197
198 try {
199 $this->prepareConnection();
200 $this->addHeader('Content-Type', 'application/json');
201 $this->addHeader('Accept', 'application/json');
202
203 if ($a_delete) {
204 $this->curl->setOpt(CURLOPT_POST, true);
205 $this->curl->setOpt(CURLOPT_POSTFIELDS, '');
206 }
207 $res = $this->call();
208
209 // Checking status code
210 $info = $this->curl->getInfo(CURLINFO_HTTP_CODE);
211 if ($info !== self::HTTP_CODE_OK) {
212 $this->logger->info(__METHOD__ . ': Cannot read event fifo, did not receive HTTP 200. ');
213 throw new ilECSConnectorException('Received HTTP status code: ' . $info);
214 }
215 //TODO check if this return needs to be moved after the finally
216 return new ilECSResult($res);
217 } catch (ilCurlConnectionException $exc) {
218 throw new ilECSConnectorException('Error calling ECS service: ' . $exc->getMessage());
219 } finally {
220 $this->curl->close();
221 }
222 }
223
225 // econtents methods
227
228 public function getResourceList(string $a_path): ilECSResult
229 {
230 $this->path_postfix = $a_path;
231
232 try {
233 $this->prepareConnection();
234 $this->curl->setOpt(CURLOPT_HTTPHEADER, $this->getHeader());
235 $res = $this->call();
236
237 // Checking status code
238 $info = $this->curl->getInfo(CURLINFO_HTTP_CODE);
239 $this->logger->debug(__METHOD__ . ': Checking HTTP status...');
240 if ($info !== self::HTTP_CODE_OK) {
241 $this->logger->debug(__METHOD__ . ': Cannot get ressource list, did not receive HTTP 200. ');
242 throw new ilECSConnectorException('Received HTTP status code: ' . $info);
243 }
244 $this->logger->debug(__METHOD__ . ': ... got HTTP 200 (ok)');
245
247 } catch (ilCurlConnectionException $exc) {
248 throw new ilECSConnectorException('Error calling ECS service: ' . $exc->getMessage());
249 }
250 }
251
252
258 public function getResource(string $a_path, int $a_econtent_id, bool $a_details_only = false): ilECSResult
259 {
260 // TODO make handling of a_econtent_id explict like setting it to null
261 if ($a_econtent_id) {
262 $this->logger->debug(__METHOD__ . ': Get resource with ID: ' . $a_econtent_id);
263 } else {
264 $this->logger->debug(__METHOD__ . ': Get all resources ...');
265 }
266
267 $this->path_postfix = $a_path;
268 if ($a_econtent_id) {
269 $this->path_postfix .= ('/' . $a_econtent_id);
270 }
271 if ($a_details_only) {
272 $this->path_postfix .= ('/details');
273 }
274
275 try {
276 $this->prepareConnection();
277 $res = $this->call();
278
279 // Checking status code
280 $info = (int) $this->curl->getInfo(CURLINFO_HTTP_CODE);
281 $this->logger->debug(__METHOD__ . ': Checking HTTP status...');
282 if ($info !== self::HTTP_CODE_OK) {
283 $this->logger->debug(__METHOD__ . ': Cannot get ressource, did not receive HTTP 200. ');
284 throw new ilECSConnectorException('Received HTTP status code: ' . $info);
285 }
286 $this->logger->debug(__METHOD__ . ': ... got HTTP 200 (ok)');
287
288 $result = new ilECSResult($res);
289 $result->setHeaders($this->curl->getResponseHeaderArray());
290 $result->setHTTPCode($info);
291
292 return $result;
293 } catch (ilCurlConnectionException $exc) {
294 throw new ilECSConnectorException('Error calling ECS service: ' . $exc->getMessage());
295 }
296 }
297
308 public function addResource(string $a_path, $a_post): int
309 {
310 $this->logger->info(__METHOD__ . ': Add new EContent...');
311
312 $this->path_postfix = $a_path;
313
314 try {
315 $this->prepareConnection();
316
317 $this->addHeader('Content-Type', 'application/json');
318
319 $this->curl->setOpt(CURLOPT_HTTPHEADER, $this->getHeader());
320 $this->curl->setOpt(CURLOPT_HEADER, true);
321 $this->curl->setOpt(CURLOPT_POST, true);
322 $this->curl->setOpt(CURLOPT_POSTFIELDS, $a_post);
323 $this->call();
324
325 $info = $this->curl->getInfo(CURLINFO_HTTP_CODE);
326
327 $this->logger->debug(__METHOD__ . ': Checking HTTP status...');
328 if ($info !== self::HTTP_CODE_CREATED) {
329 $this->logger->debug(__METHOD__ . ': Cannot create econtent, did not receive HTTP 201. ');
330 throw new ilECSConnectorException('Received HTTP status code: ' . $info);
331 }
332 $this->logger->debug(__METHOD__ . ': ... got HTTP 201 (created)');
333
334 return $this->_fetchEContentIdFromHeader($this->curl->getResponseHeaderArray());
335 } catch (ilCurlConnectionException $exc) {
336 throw new ilECSConnectorException('Error calling ECS service: ' . $exc->getMessage());
337 }
338 }
339
348 public function updateResource(string $a_path, int $a_econtent_id, string $a_post_string): void
349 {
350 $this->logger->debug(__METHOD__ . ': Update resource with id ' . $a_econtent_id);
351
352 $this->path_postfix = $a_path;
353
354 if ($a_econtent_id) {
355 $this->path_postfix .= ('/' . $a_econtent_id);
356 } else {
357 throw new ilECSConnectorException('Error calling updateResource: No content id given.');
358 }
359 try {
360 $this->prepareConnection();
361 $this->addHeader('Content-Type', 'application/json');
362 $this->addHeader('Accept', 'application/json');
363 $this->addHeader('Expect', '');
364 $this->curl->setOpt(CURLOPT_HTTPHEADER, $this->getHeader());
365 $this->curl->setOpt(CURLOPT_HEADER, true);
366 $this->curl->setOpt(CURLOPT_PUT, true);
367 //TODO migrate to filesystem->tempfile
368 $tempfile = ilFileUtils::ilTempnam();
369 $this->logger->info(__METHOD__ . ': Created new tempfile: ' . $tempfile);
370
371 $fp = fopen($tempfile, 'wb');
372 fwrite($fp, $a_post_string);
373 fclose($fp);
374
375 $this->curl->setOpt(CURLOPT_UPLOAD, true);
376 $this->curl->setOpt(CURLOPT_INFILESIZE, filesize($tempfile));
377 $fp = fopen($tempfile, 'rb');
378 $this->curl->setOpt(CURLOPT_INFILE, $fp);
379
380 $res = $this->call();
381
382 fclose($fp);
383 unlink($tempfile);
384
385 $info = $this->curl->getInfo(CURLINFO_HTTP_CODE);
386 $this->logger->debug(__METHOD__ . ': Checking HTTP status...');
387 if ($info !== self::HTTP_CODE_OK) {
388 $this->logger->debug(__METHOD__ . ': Cannot update resource. ', $a_path, $a_econtent_id);
389 throw new ilECSConnectorException('Received HTTP status code: ' . $info);
390 }
391 } catch (ilCurlConnectionException $exc) {
392 throw new ilECSConnectorException('Error calling ECS service: ' . $exc->getMessage());
393 }
394 }
395
403 public function deleteResource(string $a_path, int $a_econtent_id): ?ilECSResult
404 {
405 $this->logger->debug(__METHOD__ . ': Delete resource with id ' . $a_econtent_id);
406
407 $this->path_postfix = $a_path;
408
409 if ($a_econtent_id) {
410 $this->path_postfix .= ('/' . $a_econtent_id);
411 } else {
412 throw new ilECSConnectorException('Error calling deleteResource: No content id given.');
413 }
414
415 try {
416 $this->prepareConnection();
417 $this->curl->setOpt(CURLOPT_CUSTOMREQUEST, 'DELETE');
418 $res = $this->call();
419 $info = $this->curl->getInfo(CURLINFO_HTTP_CODE);
420 if (200 === $info) {
421 return new ilECSResult($res);
422 }
423 return null;
424 } catch (ilCurlConnectionException $exc) {
425 throw new ilECSConnectorException('Error calling ECS service: ' . $exc->getMessage());
426 }
427 }
428
430 // membership methods
432
437 public function getMemberships(int $a_mid = 0): ilECSResult
438 {
439 $this->logger->debug(__METHOD__ . ': Get existing memberships');
440
441 $this->path_postfix = '/sys/memberships';
442 if ($a_mid) {
443 $this->logger->debug(__METHOD__ . ': Read membership with id: ' . $a_mid);
444 $this->path_postfix .= ('/' . $a_mid);
445 }
446 try {
447 $this->prepareConnection();
448 $res = $this->call();
449
450 $this->curl->setOpt(CURLOPT_HTTPHEADER, array(0 => 'X-EcsQueryStrings: sender=true'));
451
452 // Checking status code
453 $info = $this->curl->getInfo(CURLINFO_HTTP_CODE);
454 if ($info !== self::HTTP_CODE_OK) {
455 $this->logger->debug(__METHOD__ . ': Cannot get memberships, did not receive HTTP 200. ');
456 throw new ilECSConnectorException('Received HTTP status code: ' . $info);
457 }
458
459 return new ilECSResult($res);
460 } catch (ilCurlConnectionException $exc) {
461 throw new ilECSConnectorException('Error calling ECS service: ' . $exc->getMessage() . $exc->getTraceAsString(), 0, $exc);
462 }
463 }
464
470 protected function prepareConnection(): void
471 {
472 try {
473 $this->curl = new ilCurlConnection($this->settings->getServerURI() . $this->path_postfix);
474 $this->curl->init(true);
475 $this->curl->setOpt(CURLOPT_HTTPHEADER, array(0 => 'Accept: application/json'));
476 $this->curl->setOpt(CURLOPT_RETURNTRANSFER, 1);
477 $this->curl->setOpt(CURLOPT_TIMEOUT_MS, 2000);
478 $this->curl->setOpt(CURLOPT_FORBID_REUSE, true);
479 $this->curl->setOpt(CURLOPT_FRESH_CONNECT, true);
480
481 if ($this->logger->isHandling(ilLogLevel::DEBUG)) {
482 $this->curl->setOpt(CURLOPT_VERBOSE, 1);
483 }
484
485 switch ($this->getServer()->getAuthType()) {
487 $this->curl->setOpt(CURLOPT_SSL_VERIFYPEER, 1);
488 #$this->curl->setOpt(CURLOPT_SSL_VERIFYHOST,0);
489 $this->curl->setOpt(CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
490 $this->curl->setOpt(
491 CURLOPT_USERPWD,
492 $this->getServer()->getAuthUser() . ':' . $this->getServer()->getAuthPass()
493 );
494 break;
495
497 $this->curl->setOpt(CURLOPT_SSL_VERIFYPEER, 1);
498 // use default 2 for libcurl 7.28.1 support
499 $this->curl->setOpt(CURLOPT_SSL_VERIFYHOST, 2);
500 $this->curl->setOpt(CURLOPT_CAINFO, $this->settings->getCACertPath());
501 $this->curl->setOpt(CURLOPT_SSLCERT, $this->settings->getClientCertPath());
502 $this->curl->setOpt(CURLOPT_SSLKEY, $this->settings->getKeyPath());
503 $this->curl->setOpt(CURLOPT_SSLKEYPASSWD, $this->settings->getKeyPassword());
504 break;
505
506 }
507 } catch (ilCurlConnectionException $exc) {
508 throw($exc);
509 }
510 }
511
519 protected function call()
520 {
521 try {
522 return $this->curl->exec();
523 } catch (ilCurlConnectionException $exc) {
524 $this->logger->error($exc->getMessage());
525 throw($exc);
526 }
527 }
528
534 private function _fetchEContentIdFromHeader(array $a_header): int
535 {
536 $location_parts = [];
537 foreach ($a_header as $header => $value) {
538 if (strcasecmp('Location', $header) === 0) {
539 $location_parts = explode('/', $value);
540 break;
541 }
542 }
543 if (!$location_parts) {
544 $this->logger->error(__METHOD__ . ': Cannot find location headers.');
545 throw new ilECSConnectorException("Cannot find location header in response");
546 }
547 if (count($location_parts) === 1) {
548 $this->logger->warning(__METHOD__ . ': Cannot find path seperator.');
549 throw new ilECSConnectorException("Location header has wrong format: " . $location_parts[0]);
550 }
551 $econtent_id = end($location_parts);
552 $this->logger->info(__METHOD__ . ': Received EContentId ' . $econtent_id);
553 return (int) $econtent_id;
554 }
555}
ilECSSetting $settings
addResource(string $a_path, $a_post)
Add resource.
readEventFifo(bool $a_delete=false)
Read event fifo.
deleteResource(string $a_path, int $a_econtent_id)
Delete resource.
_fetchEContentIdFromHeader(array $a_header)
fetch new econtent id from location header
addAuth(string $a_post, int $a_target_mid)
Add auth resource.
getResourceList(string $a_path)
getResource(string $a_path, int $a_econtent_id, bool $a_details_only=false)
Get resources from ECS server.
addHeader(string $a_name, string $a_value)
Add Header.
getMemberships(int $a_mid=0)
ilCurlConnection $curl
updateResource(string $a_path, int $a_econtent_id, string $a_post_string)
update resource
__construct(ilECSSetting $settings=null)
prepareConnection()
prepare connection
getAuth(string $a_hash, bool $a_details_only=false)
get auth resource
getServer()
Get current server setting.
setHeader(array $a_header_strings)
Presentation of ecs content details (http://...campusconnect/courselinks/id/details)
const RESULT_TYPE_URL_LIST
static ilTempnam(?string $a_temp_path=null)
Returns a unique and non existing Path for e temporary file or directory.
Component logger with individual log levels by component id.
global $DIC
Definition: feed.php:28
$res
Definition: ltiservices.php:69
$auth
Definition: metadata.php:76
array $details
Details for error message relating to last request processed.
Definition: System.php:109