ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
class.ilVirusScannerICapRemote.php
Go to the documentation of this file.
1<?php
2
19declare(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 (!str_starts_with($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], (int) $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
205 return $response;
206 }
207
211 public function respMod(string $service, array $body = [], array $headers = []): array
212 {
213 $request = $this->getRequest('RESPMOD', $service, $body, $headers);
214 $response = $this->send($request);
215 return $this->parseResponse($response);
216 }
217
221 public function reqMod(string $service, array $body = [], array $headers = []): array
222 {
223 $request = $this->getRequest('REQMOD', $service, $body, $headers);
224 $response = $this->send($request);
225 return $this->parseResponse($response);
226 }
227}
reqMod(string $service, array $body=[], array $headers=[])
__construct(string $scan_command, string $clean_command)
getRequest(string $method, string $service, array $body=[], array $headers=[])
respMod(string $service, array $body=[], array $headers=[])
if(! $DIC->user() ->getId()||!ilLTIConsumerAccess::hasCustomProviderCreationAccess()) $params
Definition: ltiregstart.php:31
$service
Definition: ltiresult.php:36
if($clientAssertionType !='urn:ietf:params:oauth:client-assertion-type:jwt-bearer'|| $grantType !='client_credentials') $parts
Definition: ltitoken.php:61
__construct(Container $dic, ilPlugin $plugin)
@inheritDoc
$param
Definition: xapitoken.php:46
$response
Definition: xapitoken.php:93