ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
class.ilECSConnector.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
26{
27 public const HTTP_CODE_CREATED = 201;
28 public const HTTP_CODE_OK = 200;
29 public const HTTP_CODE_NOT_FOUND = 404;
30
31 public const HEADER_MEMBERSHIPS = 'X-EcsReceiverMemberships';
32 public const HEADER_COMMUNITIES = 'X-EcsReceiverCommunities';
33
34
35 protected string $path_postfix = '';
36
37 protected ?ilECSSetting $settings = null;
38 protected ?ilCurlConnection $curl = null;
39
40 protected array $header_strings = [];
41
42 protected ilLogger $logger;
43
44 public function __construct(?ilECSSetting $settings = null)
45 {
46 global $DIC;
47
48 $this->logger = $DIC->logger()->wsrv();
49 if ($settings) {
50 $this->settings = $settings;
51 } else {
52 $this->logger->warning('Using deprecated call.');
53 $this->logger->logStack(ilLogLevel::WARNING);
54 }
55 }
56
57 // Header methods
63 public function addHeader(string $a_name, string $a_value): void
64 {
65 $this->header_strings[] = ($a_name . ': ' . $a_value);
66 }
67
68 public function getHeader(): array
69 {
71 }
72
73 public function setHeader(array $a_header_strings): void
74 {
75 $this->header_strings = $a_header_strings;
76 }
77
81 public function getServer(): ilECSSetting
82 {
83 return $this->settings;
84 }
85
86
88 // auths methods
90
100 public function addAuth(string $a_post, int $a_target_mid): string
101 {
102 $this->logger->info(__METHOD__ . ': Add new Auth resource...');
103
104 $this->path_postfix = '/sys/auths';
105
106 try {
107 $this->prepareConnection();
108
109 $this->addHeader('Content-Type', 'application/json');
110 $this->addHeader('Accept', 'application/json');
111 $this->addHeader(self::HEADER_MEMBERSHIPS, (string) $a_target_mid);
112
113 $this->curl->setOpt(CURLOPT_HTTPHEADER, $this->getHeader());
114 $this->curl->setOpt(CURLOPT_POST, true);
115 $this->curl->setOpt(CURLOPT_POSTFIELDS, $a_post);
116 $ret = $this->call();
117
118 $info = $this->curl->getInfo(CURLINFO_HTTP_CODE);
119
120 $this->logger->info(__METHOD__ . ': Checking HTTP status...');
121 if ($info !== self::HTTP_CODE_CREATED) {
122 $this->logger->info(__METHOD__ . ': Cannot create auth resource, did not receive HTTP 201. ');
123 $this->logger->info(__METHOD__ . ': POST was: ' . $a_post);
124 $this->logger->info(__METHOD__ . ': HTTP code: ' . $info);
125 throw new ilECSConnectorException('Received HTTP status code: ' . $info);
126 }
127 $this->logger->info(__METHOD__ . ': ... got HTTP 201 (created)');
128 $this->logger->info(__METHOD__ . ': POST was: ' . $a_post);
129
130 $result = new ilECSResult($ret);
131 $auth = $result->getResult();
132
133 $this->logger->info(__METHOD__ . ': ... got hash: ' . $auth->hash);
134
135 return $auth->hash;
136 } catch (ilCurlConnectionException $exc) {
137 throw new ilECSConnectorException('Error calling ECS service: ' . $exc->getMessage());
138 }
139 }
140
147 public function getAuth(string $a_hash, bool $a_details_only = false)
148 {
149 if ($a_hash === '') {
150 $this->logger->error(__METHOD__ . ': No auth hash given. Aborting.');
151 throw new ilECSConnectorException('No auth hash given.');
152 }
153
154 $this->path_postfix = '/sys/auths/' . $a_hash;
155
156 if ($a_details_only) {
157 $this->path_postfix .= ('/details');
158 }
159
160
161 try {
162 $this->prepareConnection();
163 $res = $this->call();
164 $info = $this->curl->getInfo(CURLINFO_HTTP_CODE);
165
166 $this->logger->info(__METHOD__ . ': Checking HTTP status...');
167 if ($info !== self::HTTP_CODE_OK) {
168 $this->logger->info(__METHOD__ . ': Cannot get auth resource, did not receive HTTP 200. ');
169 throw new ilECSConnectorException('Received HTTP status code: ' . $info);
170 }
171 $this->logger->info(__METHOD__ . ': ... got HTTP 200 (ok)');
172
173 $ecs_result = new ilECSResult($res);
174 // Return ECSEContentDetails for details switch
175 if ($a_details_only) {
176 $details = new ilECSEContentDetails();
177 $details->loadFromJson($ecs_result->getResult());
178 return $details;
179 }
180 return $ecs_result;
181 } catch (ilCurlConnectionException $exc) {
182 throw new ilECSConnectorException('Error calling ECS service: ' . $exc->getMessage());
183 }
184 }
185
186 #######################################################
187 # event fifo methods
188 #####################################################
195 public function readEventFifo(bool $a_delete = false): ilECSResult
196 {
197 $this->path_postfix = '/sys/events/fifo';
198
199 try {
200 $this->prepareConnection();
201 $this->addHeader('Content-Type', 'application/json');
202 $this->addHeader('Accept', 'application/json');
203
204 if ($a_delete) {
205 $this->curl->setOpt(CURLOPT_POST, true);
206 $this->curl->setOpt(CURLOPT_POSTFIELDS, '');
207 }
208 $res = $this->call();
209
210 // Checking status code
211 $info = $this->curl->getInfo(CURLINFO_HTTP_CODE);
212 if ($info !== self::HTTP_CODE_OK) {
213 $this->logger->info(__METHOD__ . ': Cannot read event fifo, did not receive HTTP 200. ');
214 throw new ilECSConnectorException('Received HTTP status code: ' . $info);
215 }
216 //TODO check if this return needs to be moved after the finally
217 return new ilECSResult($res);
218 } catch (ilCurlConnectionException $exc) {
219 throw new ilECSConnectorException('Error calling ECS service: ' . $exc->getMessage());
220 } finally {
221 $this->curl->close();
222 }
223 }
224
226 // econtents methods
228
229 public function getResourceList(string $a_path): ilECSResult
230 {
231 $this->path_postfix = $a_path;
232
233 try {
234 $this->prepareConnection();
235 $this->curl->setOpt(CURLOPT_HTTPHEADER, $this->getHeader());
236 $res = $this->call();
237
238 // Checking status code
239 $info = $this->curl->getInfo(CURLINFO_HTTP_CODE);
240 $this->logger->debug(__METHOD__ . ': Checking HTTP status...');
241 if ($info !== self::HTTP_CODE_OK) {
242 $this->logger->debug(__METHOD__ . ': Cannot get ressource list, did not receive HTTP 200. ');
243 throw new ilECSConnectorException('Received HTTP status code: ' . $info);
244 }
245 $this->logger->debug(__METHOD__ . ': ... got HTTP 200 (ok)');
246
248 } catch (ilCurlConnectionException $exc) {
249 throw new ilECSConnectorException('Error calling ECS service: ' . $exc->getMessage());
250 }
251 }
252
253
259 public function getResource(string $a_path, int $a_econtent_id, bool $a_details_only = false): ilECSResult
260 {
261 // TODO make handling of a_econtent_id explict like setting it to null
262 if ($a_econtent_id) {
263 $this->logger->debug(__METHOD__ . ': Get resource with ID: ' . $a_econtent_id);
264 } else {
265 $this->logger->debug(__METHOD__ . ': Get all resources ...');
266 }
267
268 $this->path_postfix = $a_path;
269 if ($a_econtent_id) {
270 $this->path_postfix .= ('/' . $a_econtent_id);
271 }
272 if ($a_details_only) {
273 $this->path_postfix .= ('/details');
274 }
275
276 try {
277 $this->prepareConnection();
278 $res = $this->call();
279
280 // Checking status code
281 $info = (int) $this->curl->getInfo(CURLINFO_HTTP_CODE);
282 $this->logger->debug(__METHOD__ . ': Checking HTTP status...');
283 if ($info !== self::HTTP_CODE_OK) {
284 $this->logger->debug(__METHOD__ . ': Cannot get ressource, did not receive HTTP 200. ');
285 throw new ilECSConnectorException('Received HTTP status code: ' . $info);
286 }
287 $this->logger->debug(__METHOD__ . ': ... got HTTP 200 (ok)');
288
289 $result = new ilECSResult($res);
290 $result->setHeaders($this->curl->getResponseHeaderArray());
291 $result->setHTTPCode($info);
292
293 return $result;
294 } catch (ilCurlConnectionException $exc) {
295 throw new ilECSConnectorException('Error calling ECS service: ' . $exc->getMessage());
296 }
297 }
298
309 public function addResource(string $a_path, $a_post): int
310 {
311 $this->logger->info(__METHOD__ . ': Add new EContent...');
312
313 $this->path_postfix = $a_path;
314
315 try {
316 $this->prepareConnection();
317
318 $this->addHeader('Content-Type', 'application/json');
319
320 $this->curl->setOpt(CURLOPT_HTTPHEADER, $this->getHeader());
321 $this->curl->setOpt(CURLOPT_HEADER, true);
322 $this->curl->setOpt(CURLOPT_POST, true);
323 $this->curl->setOpt(CURLOPT_POSTFIELDS, $a_post);
324 $this->call();
325
326 $info = $this->curl->getInfo(CURLINFO_HTTP_CODE);
327
328 $this->logger->debug(__METHOD__ . ': Checking HTTP status...');
329 if ($info !== self::HTTP_CODE_CREATED) {
330 $this->logger->debug(__METHOD__ . ': Cannot create econtent, did not receive HTTP 201. ');
331 throw new ilECSConnectorException('Received HTTP status code: ' . $info);
332 }
333 $this->logger->debug(__METHOD__ . ': ... got HTTP 201 (created)');
334
335 return $this->_fetchEContentIdFromHeader($this->curl->getResponseHeaderArray());
336 } catch (ilCurlConnectionException $exc) {
337 throw new ilECSConnectorException('Error calling ECS service: ' . $exc->getMessage());
338 }
339 }
340
349 public function updateResource(string $a_path, int $a_econtent_id, string $a_post_string): void
350 {
351 $this->logger->debug(__METHOD__ . ': Update resource with id ' . $a_econtent_id);
352
353 $this->path_postfix = $a_path;
354
355 if ($a_econtent_id) {
356 $this->path_postfix .= ('/' . $a_econtent_id);
357 } else {
358 throw new ilECSConnectorException('Error calling updateResource: No content id given.');
359 }
360 try {
361 $this->prepareConnection();
362 $this->addHeader('Content-Type', 'application/json');
363 $this->addHeader('Accept', 'application/json');
364 $this->addHeader('Expect', '');
365 $this->curl->setOpt(CURLOPT_HTTPHEADER, $this->getHeader());
366 $this->curl->setOpt(CURLOPT_HEADER, true);
367 $this->curl->setOpt(CURLOPT_PUT, true);
368 //TODO migrate to filesystem->tempfile
369 $tempfile = ilFileUtils::ilTempnam();
370 $this->logger->info(__METHOD__ . ': Created new tempfile: ' . $tempfile);
371
372 $fp = fopen($tempfile, 'wb');
373 fwrite($fp, $a_post_string);
374 fclose($fp);
375
376 $this->curl->setOpt(CURLOPT_UPLOAD, true);
377 $this->curl->setOpt(CURLOPT_INFILESIZE, filesize($tempfile));
378 $fp = fopen($tempfile, 'rb');
379 $this->curl->setOpt(CURLOPT_INFILE, $fp);
380
381 $res = $this->call();
382
383 fclose($fp);
384 unlink($tempfile);
385
386 $info = $this->curl->getInfo(CURLINFO_HTTP_CODE);
387 $this->logger->debug(__METHOD__ . ': Checking HTTP status...');
388 if ($info !== self::HTTP_CODE_OK) {
389 $this->logger->debug(__METHOD__ . ': Cannot update resource. ', $a_path, $a_econtent_id);
390 throw new ilECSConnectorException('Received HTTP status code: ' . $info);
391 }
392 } catch (ilCurlConnectionException $exc) {
393 throw new ilECSConnectorException('Error calling ECS service: ' . $exc->getMessage());
394 }
395 }
396
404 public function deleteResource(string $a_path, int $a_econtent_id): ?ilECSResult
405 {
406 $this->logger->debug(__METHOD__ . ': Delete resource with id ' . $a_econtent_id);
407
408 $this->path_postfix = $a_path;
409
410 if ($a_econtent_id) {
411 $this->path_postfix .= ('/' . $a_econtent_id);
412 } else {
413 throw new ilECSConnectorException('Error calling deleteResource: No content id given.');
414 }
415
416 try {
417 $this->prepareConnection();
418 $this->curl->setOpt(CURLOPT_CUSTOMREQUEST, 'DELETE');
419 $res = $this->call();
420 $info = $this->curl->getInfo(CURLINFO_HTTP_CODE);
421 if (200 === $info) {
422 return new ilECSResult($res);
423 }
424 return null;
425 } catch (ilCurlConnectionException $exc) {
426 throw new ilECSConnectorException('Error calling ECS service: ' . $exc->getMessage());
427 }
428 }
429
431 // membership methods
433
438 public function getMemberships(int $a_mid = 0): ilECSResult
439 {
440 $this->logger->debug(__METHOD__ . ': Get existing memberships');
441
442 $this->path_postfix = '/sys/memberships';
443 if ($a_mid) {
444 $this->logger->debug(__METHOD__ . ': Read membership with id: ' . $a_mid);
445 $this->path_postfix .= ('/' . $a_mid);
446 }
447 try {
448 $this->prepareConnection();
449 $res = $this->call();
450
451 $this->curl->setOpt(CURLOPT_HTTPHEADER, array(0 => 'X-EcsQueryStrings: sender=true'));
452
453 // Checking status code
454 $info = $this->curl->getInfo(CURLINFO_HTTP_CODE);
455 if ($info !== self::HTTP_CODE_OK) {
456 $this->logger->debug(__METHOD__ . ': Cannot get memberships, did not receive HTTP 200. ');
457 throw new ilECSConnectorException('Received HTTP status code: ' . $info);
458 }
459
460 return new ilECSResult($res);
461 } catch (ilCurlConnectionException $exc) {
462 throw new ilECSConnectorException('Error calling ECS service: ' . $exc->getMessage() . $exc->getTraceAsString(), 0, $exc);
463 }
464 }
465
471 protected function prepareConnection(): void
472 {
473 try {
474 $this->curl = new ilCurlConnection($this->settings->getServerURI() . $this->path_postfix);
475 $this->curl->init(true);
476 $this->curl->setOpt(CURLOPT_HTTPHEADER, array(0 => 'Accept: application/json'));
477 $this->curl->setOpt(CURLOPT_RETURNTRANSFER, 1);
478 $this->curl->setOpt(CURLOPT_TIMEOUT_MS, 90000);
479 $this->curl->setOpt(CURLOPT_FORBID_REUSE, true);
480 $this->curl->setOpt(CURLOPT_FRESH_CONNECT, true);
481
482 if ($this->logger->isHandling(ilLogLevel::DEBUG)) {
483 $this->curl->setOpt(CURLOPT_VERBOSE, 1);
484 }
485
486 switch ($this->getServer()->getAuthType()) {
488 $this->curl->setOpt(CURLOPT_SSL_VERIFYPEER, 1);
489 #$this->curl->setOpt(CURLOPT_SSL_VERIFYHOST,0);
490 $this->curl->setOpt(CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
491 $this->curl->setOpt(
492 CURLOPT_USERPWD,
493 $this->getServer()->getAuthUser() . ':' . $this->getServer()->getAuthPass()
494 );
495 break;
496
498 $this->curl->setOpt(CURLOPT_SSL_VERIFYPEER, 1);
499 // use default 2 for libcurl 7.28.1 support
500 $this->curl->setOpt(CURLOPT_SSL_VERIFYHOST, 2);
501 $this->curl->setOpt(CURLOPT_CAINFO, $this->settings->getCACertPath());
502 $this->curl->setOpt(CURLOPT_SSLCERT, $this->settings->getClientCertPath());
503 $this->curl->setOpt(CURLOPT_SSLKEY, $this->settings->getKeyPath());
504 $this->curl->setOpt(CURLOPT_SSLKEYPASSWD, $this->settings->getKeyPassword());
505 break;
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}
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
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
__construct(?ilECSSetting $settings=null)
updateResource(string $a_path, int $a_econtent_id, string $a_post_string)
update resource
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.
$info
Definition: entry_point.php:21
$res
Definition: ltiservices.php:69
global $DIC
Definition: shib_login.php:26