ILIAS  release_7 Revision v7.30-3-g800a261c036
class.ilVirusScannerICapRemote.php
Go to the documentation of this file.
1<?php
2//hsuhh-patch: begin
3/* Copyright (c) 1998-2009 ILIAS open source, Extended GPL, see docs/LICENSE */
4
13require_once "./Services/VirusScanner/classes/class.ilVirusScanner.php";
14
16{
18 private $host;
20 private $port;
22 private $socket;
24 public $userAgent = 'PHP-CLIENT/0.1.0';
25
31 public function __construct($a_scancommand, $a_cleancommand)
32 {
33 parent::__construct($a_scancommand, $a_cleancommand);
34 $this->host = IL_ICAP_HOST;
35 $this->port = IL_ICAP_PORT;
36 }
37
42 public function options($service)
43 {
44 $request = $this->getRequest('OPTIONS', $service);
45 $response = $this->send($request);
46 if(strlen($response) > 0) {
47 return $this->parseResponse($response);
48 }
49 return [];
50 }
51
59 public function getRequest($method, $service, $body = [], $headers = [])
60 {
61 if (!array_key_exists('Host', $headers)) {
62 $headers['Host'] = $this->host;
63 }
64 if (!array_key_exists('User-Agent', $headers)) {
65 $headers['User-Agent'] = $this->userAgent;
66 }
67 if (!array_key_exists('Connection', $headers)) {
68 $headers['Connection'] = 'close';
69 }
70 $bodyData = '';
71 $hasBody = false;
72 $encapsulated = [];
73 foreach ($body as $type => $data) {
74 switch ($type) {
75 case 'req-hdr':
76 case 'res-hdr':
77 $encapsulated[$type] = strlen($bodyData);
78 $bodyData .= $data;
79 break;
80 case 'req-body':
81 case 'res-body':
82 $encapsulated[$type] = strlen($bodyData);
83 $bodyData .= dechex(strlen($data)) . "\r\n";
84 $bodyData .= $data;
85 $bodyData .= "\r\n";
86 $hasBody = true;
87 break;
88 }
89 }
90 if ($hasBody) {
91 $bodyData .= "0\r\n\r\n";
92 } elseif (count($encapsulated) > 0) {
93 $encapsulated['null-body'] = strlen($bodyData);
94 }
95 if (count($encapsulated) > 0) {
96 $headers['Encapsulated'] = '';
97 foreach ($encapsulated as $section => $offset) {
98 $headers['Encapsulated'] .= $headers['Encapsulated'] === '' ? '' : ', ';
99 $headers['Encapsulated'] .= "{$section}={$offset}";
100 }
101 }
102 $request = "{$method} icap://{$this->host}/{$service} ICAP/1.0\r\n";
103 foreach ($headers as $header => $value) {
104 $request .= "{$header}: {$value}\r\n";
105 }
106 $request .= "\r\n";
107 $request .= $bodyData;
108 return $request;
109 }
110
115 public function send($request)
116 {
117 $response = '';
118 try{
119 $this->connect();
120 socket_write($this->socket, $request);
121 while ($buffer = socket_read($this->socket, 2048)) {
122 $response .= $buffer;
123 }
124 $this->disconnect();
125 } catch(ErrorException $e){
126 $this->log->warning("Cannot connect to icap://{$this->host}:{$this->port} (Socket error: " . $this->getLastSocketError() . ")");
127 }
128 return $response;
129 }
130
135 private function connect()
136 {
137 $this->socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
138 try{
139 if (!socket_connect($this->socket, $this->host, $this->port)) {
140 return false;
141 }
142 } catch(ErrorException $e){
143 throw $e;
144 }
145
146 return true;
147 }
148
153 public function getLastSocketError()
154 {
155 return socket_last_error($this->socket);
156 }
157
161 private function disconnect()
162 {
163 socket_shutdown($this->socket);
164 socket_close($this->socket);
165 }
166
171 private function parseResponse($string)
172 {
173 $response = [
174 'protocol' => [],
175 'headers' => [],
176 'body' => [],
177 'rawBody' => ''
178 ];
179 foreach (preg_split('/\r?\n/', $string) as $line) {
180 if ([] === $response['protocol']) {
181 if (0 !== strpos($line, 'ICAP/')) {
182 throw new RuntimeException('Unknown ICAP response');
183 }
184 $parts = preg_split('/ +/', $line, 3);
185 $response['protocol'] = [
186 'icap' => isset($parts[0]) ? $parts[0] : '',
187 'code' => isset($parts[1]) ? $parts[1] : '',
188 'message' => isset($parts[2]) ? $parts[2] : '',
189 ];
190 continue;
191 }
192 if ('' === $line) {
193 break;
194 }
195 $parts = preg_split('/: /', $line, 2);
196 if (isset($parts[0])) {
197 $response['headers'][$parts[0]] = isset($parts[1]) ? $parts[1] : '';
198 }
199 }
200 $body = preg_split('/\r?\n\r?\n/', $string, 2);
201 if (isset($body[1])) {
202 $response['rawBody'] = $body[1];
203 if (array_key_exists('Encapsulated', $response['headers'])) {
204 $encapsulated = [];
205 $params = preg_split('/, /', $response['headers']['Encapsulated']);
206 if (count($params) > 0) {
207 foreach ($params as $param) {
208 $parts = preg_split('/=/', $param);
209 if (count($parts) !== 2) {
210 continue;
211 }
212 $encapsulated[$parts[0]] = $parts[1];
213 }
214 }
215 foreach ($encapsulated as $section => $offset) {
216 $data = substr($body[1], $offset);
217 switch ($section) {
218 case 'req-hdr':
219 case 'res-hdr':
220 $response['body'][$section] = preg_split('/\r?\n\r?\n/', $data, 2)[0];
221 break;
222 case 'req-body':
223 case 'res-body':
224 $parts = preg_split('/\r?\n/', $data, 2);
225 if (count($parts) === 2) {
226 $response['body'][$section] = substr($parts[1], 0, hexdec($parts[0]));
227 }
228 break;
229 }
230 }
231 }
232 }
233 return $response;
234 }
235
242 public function respMod($service, $body = [], $headers = [])
243 {
244 $request = $this->getRequest('RESPMOD', $service, $body, $headers);
245 $response = $this->send($request);
246 return $this->parseResponse($response);
247 }
248
255 public function reqMod($service, $body = [], $headers = [])
256 {
257 $request = $this->getRequest('REQMOD', $service, $body, $headers);
258 $response = $this->send($request);
259 return $this->parseResponse($response);
260 }
261}
262//hsuhh-patch: end
$section
Definition: Utf8Test.php:83
An exception for terminatinating execution or to throw for unit testing.
Interface to the ClamAV virus protector.
getRequest($method, $service, $body=[], $headers=[])
getLastSocketError()
Get last error code from socket object.
reqMod($service, $body=[], $headers=[])
respMod($service, $body=[], $headers=[])
__construct($a_scancommand, $a_cleancommand)
ilVirusScannerICap constructor.
Base class for the interface to an external virus scanner This class is abstract and needs to be exte...
__construct(Container $dic, ilPlugin $plugin)
@inheritDoc
$response
$service
Definition: result.php:17
$data
Definition: storeScorm.php:23
$param
Definition: xapitoken.php:29