ILIAS  release_8 Revision v8.19
All Data Structures Namespaces Files Functions Variables Modules Pages
class.ilVirusScannerICapRemote.php
Go to the documentation of this file.
1 <?php
2 
19 declare(strict_types=1);
20 
22 {
23  private string $host;
24  private int $port;
26  private $socket;
27  public string $userAgent = 'PHP-CLIENT/0.1.0';
28 
29  public function __construct(string $scan_command, string $clean_command)
30  {
31  parent::__construct($scan_command, $clean_command);
32  $this->host = IL_ICAP_HOST;
33  $this->port = (int) IL_ICAP_PORT;
34  }
35 
36  public function options(string $service): array
37  {
38  $request = $this->getRequest('OPTIONS', $service);
39  $response = $this->send($request);
40  if ($response !== '') {
41  return $this->parseResponse($response);
42  }
43  return [];
44  }
45 
46  public function getRequest(string $method, string $service, array $body = [], array $headers = []): string
47  {
48  if (!array_key_exists('Host', $headers)) {
49  $headers['Host'] = $this->host;
50  }
51  if (!array_key_exists('User-Agent', $headers)) {
52  $headers['User-Agent'] = $this->userAgent;
53  }
54  if (!array_key_exists('Connection', $headers)) {
55  $headers['Connection'] = 'close';
56  }
57  $bodyData = '';
58  $hasBody = false;
59  $encapsulated = [];
60  foreach ($body as $type => $data) {
61  switch ($type) {
62  case 'req-hdr':
63  case 'res-hdr':
64  $encapsulated[$type] = strlen($bodyData);
65  $bodyData .= $data;
66  break;
67  case 'req-body':
68  case 'res-body':
69  $encapsulated[$type] = strlen($bodyData);
70  $bodyData .= dechex(strlen($data)) . "\r\n";
71  $bodyData .= $data;
72  $bodyData .= "\r\n";
73  $hasBody = true;
74  break;
75  }
76  }
77  if ($hasBody) {
78  $bodyData .= "0\r\n\r\n";
79  } elseif (count($encapsulated) > 0) {
80  $encapsulated['null-body'] = strlen($bodyData);
81  }
82  if (count($encapsulated) > 0) {
83  $headers['Encapsulated'] = '';
84  foreach ($encapsulated as $section => $offset) {
85  $headers['Encapsulated'] .= $headers['Encapsulated'] === '' ? '' : ', ';
86  $headers['Encapsulated'] .= "{$section}={$offset}";
87  }
88  }
89  $request = "{$method} icap://{$this->host}/{$service} ICAP/1.0\r\n";
90  foreach ($headers as $header => $value) {
91  $request .= "{$header}: {$value}\r\n";
92  }
93  $request .= "\r\n";
94  $request .= $bodyData;
95  return $request;
96  }
97 
98  public function send(string $request): string
99  {
100  $response = '';
101  try {
102  $this->connect();
103  socket_write($this->socket, $request);
104  while ($buffer = socket_read($this->socket, 2048)) {
105  $response .= $buffer;
106  }
107  $this->disconnect();
108  } catch (ErrorException $e) {
109  $this->log->warning("Cannot connect to icap://{$this->host}:{$this->port} (Socket error: " . $this->getLastSocketError() . ")");
110  }
111  return $response;
112  }
113 
114  private function connect(): bool
115  {
116  $this->socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
117  try {
118  if (!socket_connect($this->socket, $this->host, $this->port)) {
119  return false;
120  }
121  } catch (ErrorException $e) {
122  throw $e;
123  }
124 
125  return true;
126  }
127 
128  public function getLastSocketError(): int
129  {
130  return socket_last_error($this->socket);
131  }
132 
133  private function disconnect(): void
134  {
135  socket_shutdown($this->socket);
136  socket_close($this->socket);
137  }
138 
142  private function parseResponse(string $string): array
143  {
144  $response = [
145  'protocol' => [],
146  'headers' => [],
147  'body' => [],
148  'rawBody' => ''
149  ];
150  foreach (preg_split('/\r?\n/', $string) as $line) {
151  if ([] === $response['protocol']) {
152  if (0 !== strpos($line, 'ICAP/')) {
153  throw new RuntimeException('Unknown ICAP response');
154  }
155  $parts = preg_split('/ +/', $line, 3);
156  $response['protocol'] = [
157  'icap' => $parts[0] ?? '',
158  'code' => $parts[1] ?? '',
159  'message' => $parts[2] ?? '',
160  ];
161  continue;
162  }
163  if ('' === $line) {
164  break;
165  }
166  $parts = explode(": ", $line, 2);
167  if (isset($parts[0])) {
168  $response['headers'][$parts[0]] = $parts[1] ?? '';
169  }
170  }
171  $body = preg_split('/\r?\n\r?\n/', $string, 2);
172  if (isset($body[1])) {
173  $response['rawBody'] = $body[1];
174  if (array_key_exists('Encapsulated', $response['headers'])) {
175  $encapsulated = [];
176  $params = explode(", ", $response['headers']['Encapsulated']);
177  if (count($params) > 0) {
178  foreach ($params as $param) {
179  $parts = explode("=", $param);
180  if (count($parts) !== 2) {
181  continue;
182  }
183  $encapsulated[$parts[0]] = $parts[1];
184  }
185  }
186  foreach ($encapsulated as $section => $offset) {
187  $data = substr($body[1], $offset);
188  switch ($section) {
189  case 'req-hdr':
190  case 'res-hdr':
191  $response['body'][$section] = preg_split('/\r?\n\r?\n/', $data, 2)[0];
192  break;
193  case 'req-body':
194  case 'res-body':
195  $parts = preg_split('/\r?\n/', $data, 2);
196  if (count($parts) === 2) {
197  $response['body'][$section] = substr($parts[1], 0, hexdec($parts[0]));
198  }
199  break;
200  }
201  }
202  }
203  }
204  return $response;
205  }
206 
210  public function respMod(string $service, array $body = [], array $headers = []): array
211  {
212  $request = $this->getRequest('RESPMOD', $service, $body, $headers);
213  $response = $this->send($request);
214  return $this->parseResponse($response);
215  }
216 
220  public function reqMod(string $service, array $body = [], array $headers = []): array
221  {
222  $request = $this->getRequest('REQMOD', $service, $body, $headers);
223  $response = $this->send($request);
224  return $this->parseResponse($response);
225  }
226 }
227 //hsuhh-patch: end
getRequest(string $method, string $service, array $body=[], array $headers=[])
if($clientAssertionType !='urn:ietf:params:oauth:client-assertion-type:jwt-bearer'|| $grantType !='client_credentials') $parts
Definition: ltitoken.php:64
if(! $DIC->user() ->getId()||!ilLTIConsumerAccess::hasCustomProviderCreationAccess()) $params
Definition: ltiregstart.php:33
__construct(string $scan_command, string $clean_command)
$param
Definition: xapitoken.php:46
respMod(string $service, array $body=[], array $headers=[])
reqMod(string $service, array $body=[], array $headers=[])
__construct(Container $dic, ilPlugin $plugin)
$response
$service
Definition: ltiservices.php:43