ILIAS  release_5-1 Revision 5.0.0-5477-g43f3e3fab5f
class.ilBMFTransport_HTTP.php
Go to the documentation of this file.
1<?php
32require_once dirname(__FILE__).'/../class.ilBMFBase.php';
33
42{
43
49 var $headers = array();
50
57
63 var $timeout = 4;
64
70 var $urlparts = null;
71
77 var $url = '';
78
85
92
99
106 var $result_encoding = 'UTF-8';
107
112
113 var $result_headers = array();
114
115 var $result_cookies = array();
116
126 {
127 parent::ilBMFBase('HTTP');
128 $this->urlparts = @parse_url($url);
129 $this->url = $url;
130 $this->encoding = $encoding;
131 }
132
142 function send($msg, $options = null)
143 {
144 if (!$this->_validateUrl()) {
145 return $this->fault;
146 }
147
148 if (isset($options['timeout'])) {
149 $this->timeout = (int)$options['timeout'];
150 }
151
152 if (strcasecmp($this->urlparts['scheme'], 'HTTP') == 0) {
153 return $this->_sendHTTP($msg, $options);
154 } elseif (strcasecmp($this->urlparts['scheme'], 'HTTPS') == 0) {
155 return $this->_sendHTTPS($msg, $options);
156 }
157
158 return $this->_raiseSoapFault('Invalid url scheme ' . $this->url);
159 }
160
169 function setCredentials($username, $password)
170 {
171 $this->headers['Authorization'] = 'Basic ' . base64_encode($username . ':' . $password);
172 }
173
181 function addCookie($name, $value)
182 {
183 $this->cookies[$name] = $value;
184 }
185
192 {
193 foreach ($this->cookies as $name=>$value) {
194 $cookies = (isset($cookies) ? $cookies. '; ' : '') .
195 urlencode($name) . '=' . urlencode($value);
196 }
197 return $cookies;
198 }
199
206 function _validateUrl()
207 {
208 if (!is_array($this->urlparts) ) {
209 $this->_raiseSoapFault('Unable to parse URL ' . $this->url);
210 return false;
211 }
212 if (!isset($this->urlparts['host'])) {
213 $this->_raiseSoapFault('No host in URL ' . $this->url);
214 return false;
215 }
216 if (!isset($this->urlparts['port'])) {
217 if (strcasecmp($this->urlparts['scheme'], 'HTTP') == 0) {
218 $this->urlparts['port'] = 80;
219 } elseif (strcasecmp($this->urlparts['scheme'], 'HTTPS') == 0) {
220 $this->urlparts['port'] = 443;
221 }
222
223 }
224 if (isset($this->urlparts['user'])) {
225 $this->setCredentials(urldecode($this->urlparts['user']),
226 urldecode($this->urlparts['pass']));
227 }
228 if (!isset($this->urlparts['path']) || !$this->urlparts['path']) {
229 $this->urlparts['path'] = '/';
230 }
231
232 return true;
233 }
234
243 {
244 $h = stristr($headers, 'Content-Type');
245 preg_match_all('/^Content-Type:\s*(.*)$/im', $h, $ct, PREG_SET_ORDER);
246 $n = count($ct);
247 $ct = $ct[$n - 1];
248
249 // Strip the string of \r.
250 $this->result_content_type = str_replace("\r", '', $ct[1]);
251
252 if (preg_match('/(.*?)(?:;\s?charset=)(.*)/i',
253 $this->result_content_type,
254 $m)) {
255 $this->result_content_type = $m[1];
256 if (count($m) > 2) {
257 $enc = strtoupper(str_replace('"', '', $m[2]));
258 if (in_array($enc, $this->_encodings)) {
259 $this->result_encoding = $enc;
260 }
261 }
262 }
263
264 // Deal with broken servers that don't set content type on faults.
265 if (!$this->result_content_type) {
266 $this->result_content_type = 'text/xml';
267 }
268 }
269
276 {
277 /* Largely borrowed from HTTP_Request. */
278 $this->result_headers = array();
279 $headers = split("\r?\n", $headers);
280 foreach ($headers as $value) {
281 if (strpos($value,':') === false) {
282 $this->result_headers[0] = $value;
283 continue;
284 }
285 list($name, $value) = split(':', $value);
286 $headername = strtolower($name);
287 $headervalue = trim($value);
288 $this->result_headers[$headername] = $headervalue;
289
290 if ($headername == 'set-cookie') {
291 // Parse a SetCookie header to fill _cookies array.
292 $cookie = array('expires' => null,
293 'domain' => $this->urlparts['host'],
294 'path' => null,
295 'secure' => false);
296
297 if (!strpos($headervalue, ';')) {
298 // Only a name=value pair.
299 list($cookie['name'], $cookie['value']) = array_map('trim', explode('=', $headervalue));
300 $cookie['name'] = urldecode($cookie['name']);
301 $cookie['value'] = urldecode($cookie['value']);
302
303 } else {
304 // Some optional parameters are supplied.
305 $elements = explode(';', $headervalue);
306 list($cookie['name'], $cookie['value']) = array_map('trim', explode('=', $elements[0]));
307 $cookie['name'] = urldecode($cookie['name']);
308 $cookie['value'] = urldecode($cookie['value']);
309
310 for ($i = 1; $i < count($elements);$i++) {
311 list($elName, $elValue) = array_map('trim', explode('=', $elements[$i]));
312 if ('secure' == $elName) {
313 $cookie['secure'] = true;
314 } elseif ('expires' == $elName) {
315 $cookie['expires'] = str_replace('"', '', $elValue);
316 } elseif ('path' == $elName OR 'domain' == $elName) {
317 $cookie[$elName] = urldecode($elValue);
318 } else {
319 $cookie[$elName] = $elValue;
320 }
321 }
322 }
323 $this->result_cookies[] = $cookie;
324 }
325 }
326 }
327
334 function _parseResponse()
335 {
336 if (preg_match("/^(.*?)\r?\n\r?\n(.*)/s",
337 $this->incoming_payload,
338 $match)) {
339 $this->response = $match[2];
340 // Find the response error, some servers response with 500 for
341 // SOAP faults.
342 $this->_parseHeaders($match[1]);
343
344 list($protocol, $code, $msg) = sscanf($this->result_headers[0],
345 '%s %s %s');
346 unset($this->result_headers[0]);
347
348 switch($code) {
349 case 100: // Continue
350 $this->incoming_payload = $match[2];
351 return $this->_parseResponse();
352 case 400:
353 $this->_raiseSoapFault("HTTP Response $code Bad Request");
354 return false;
355 break;
356 case 401:
357 $this->_raiseSoapFault("HTTP Response $code Authentication Failed");
358 return false;
359 break;
360 case 403:
361 $this->_raiseSoapFault("HTTP Response $code Forbidden");
362 return false;
363 break;
364 case 404:
365 $this->_raiseSoapFault("HTTP Response $code Not Found");
366 return false;
367 break;
368 case 407:
369 $this->_raiseSoapFault("HTTP Response $code Proxy Authentication Required");
370 return false;
371 break;
372 case 408:
373 $this->_raiseSoapFault("HTTP Response $code Request Timeout");
374 return false;
375 break;
376 case 410:
377 $this->_raiseSoapFault("HTTP Response $code Gone");
378 return false;
379 break;
380 default:
381 if ($code >= 400 && $code < 500) {
382 $this->_raiseSoapFault("HTTP Response $code Not Found, Server message: $msg");
383 return false;
384 }
385 }
386
387 $this->_parseEncoding($match[1]);
388
389 if ($this->result_content_type == 'application/dime') {
390 // XXX quick hack insertion of DIME
391 if (PEAR::isError($this->_decodeDIMEMessage($this->response,$this->headers,$this->attachments))) {
392 // _decodeDIMEMessage already raised $this->fault
393 return false;
394 }
395 $this->result_content_type = $this->headers['content-type'];
396 } elseif (stristr($this->result_content_type,'multipart/related')) {
397 $this->response = $this->incoming_payload;
398 if (PEAR::isError($this->_decodeMimeMessage($this->response,$this->headers,$this->attachments))) {
399 // _decodeMimeMessage already raised $this->fault
400 return false;
401 }
402 } elseif ($this->result_content_type != 'text/xml') {
403 $this->_raiseSoapFault($this->response);
404 return false;
405 }
406 // if no content, return false
407 return strlen($this->response) > 0;
408 }
409 $this->_raiseSoapFault('Invalid HTTP Response');
410 return false;
411 }
412
421 function _getRequest($msg, $options)
422 {
423 $this->headers = array();
424
425 $action = isset($options['soapaction']) ? $options['soapaction'] : '';
426 $fullpath = $this->urlparts['path'];
427 if (isset($this->urlparts['query'])) {
428 $fullpath .= '?' . $this->urlparts['query'];
429 }
430 if (isset($this->urlparts['fragment'])) {
431 $fullpath .= '#' . $this->urlparts['fragment'];
432 }
433
434 if (isset($options['proxy_host'])) {
435 $fullpath = 'http://' . $this->urlparts['host'] . ':' .
436 $this->urlparts['port'] . $fullpath;
437 }
438
439 if (isset($options['proxy_user'])) {
440 $this->headers['Proxy-Authorization'] = 'Basic ' .
441 base64_encode($options['proxy_user'] . ':' .
442 $options['proxy_pass']);
443 }
444
445 if (isset($options['user'])) {
446 $this->setCredentials($options['user'], $options['pass']);
447 }
448
449 $this->headers['User-Agent'] = $this->_userAgent;
450 $this->headers['Host'] = $this->urlparts['host'];
451 $this->headers['Content-Type'] = "text/xml; charset=$this->encoding";
452 $this->headers['Content-Length'] = strlen($msg);
453 $this->headers['SOAPAction'] = '"' . $action . '"';
454 if (isset($options['headers'])) {
455 $this->headers = array_merge($this->headers, $options['headers']);
456 }
457
458 $this->cookies = array();
459 if (!isset($options['nocookies']) || !$options['nocookies']) {
460 // Add the cookies we got from the last request.
461 if (isset($this->result_cookies)) {
462 foreach ($this->result_cookies as $cookie) {
463 if ($cookie['domain'] == $this->urlparts['host'])
464 $this->cookies[$cookie['name']] = $cookie['value'];
465 }
466 }
467 }
468 // Add cookies the user wants to set.
469 if (isset($options['cookies'])) {
470 foreach ($options['cookies'] as $cookie) {
471 if ($cookie['domain'] == $this->urlparts['host'])
472 $this->cookies[$cookie['name']] = $cookie['value'];
473 }
474 }
475 if (count($this->cookies)) {
476 $this->headers['Cookie'] = $this->_genCookieHeader();
477 }
478 $headers = '';
479 foreach ($this->headers as $k => $v) {
480 $headers .= "$k: $v\r\n";
481 }
482 $this->outgoing_payload = "POST $fullpath HTTP/1.0\r\n" . $headers .
483 "\r\n" . $msg;
484
485 return $this->outgoing_payload;
486 }
487
496 function _sendHTTP($msg, $options)
497 {
498 $this->incoming_payload = '';
499 $this->_getRequest($msg, $options);
500 $host = $this->urlparts['host'];
501 $port = $this->urlparts['port'];
502 if (isset($options['proxy_host'])) {
503 $host = $options['proxy_host'];
504 $port = isset($options['proxy_port']) ? $options['proxy_port'] : 8080;
505 }
506 // Send.
507 if ($this->timeout > 0) {
508 $fp = @fsockopen($host, $port, $this->errno, $this->errmsg, $this->timeout);
509 } else {
510 $fp = @fsockopen($host, $port, $this->errno, $this->errmsg);
511 }
512 if (!$fp) {
513 return $this->_raiseSoapFault("Connect Error to $host:$port");
514 }
515 if ($this->timeout > 0) {
516 // some builds of PHP do not support this, silence the warning
517 @socket_set_timeout($fp, $this->timeout);
518 }
519 if (!fputs($fp, $this->outgoing_payload, strlen($this->outgoing_payload))) {
520 return $this->_raiseSoapFault("Error POSTing Data to $host");
521 }
522
523 // get reponse
524 // XXX time consumer
525 do {
526 $data = fread($fp, 4096);
527 $_tmp_status = socket_get_status($fp);
528 if ($_tmp_status['timed_out']) {
529 return $this->_raiseSoapFault("Timed out read from $host");
530 } else {
531 $this->incoming_payload .= $data;
532 }
533 } while (!$_tmp_status['eof']);
534
535 fclose($fp);
536
537 if (!$this->_parseResponse()) {
538 return $this->fault;
539 }
540 return $this->response;
541 }
542
551 function _sendHTTPS($msg, $options)
552 {
553 /* NOTE This function uses the CURL functions
554 * Your php must be compiled with CURL
555 */
556 if (!extension_loaded('curl')) {
557 return $this->_raiseSoapFault('CURL Extension is required for HTTPS');
558 }
559
560/* Databay: Changes for BMF */
561 $this->_getRequest($msg, $options);
562
563 $ch = curl_init();
564
565 if (isset($options['proxy_host'])) {
566 // $options['http_proxy'] == 'hostname:port'
567 $host = $options['proxy_host'];
568 $port = isset($options['proxy_port']) ? $options['proxy_port'] : 8080;
569 curl_setopt($ch, CURLOPT_PROXY, $host . ":" . $port);
570 }
571
572 if (isset($options['proxy_user'])) {
573 // $options['http_proxy_userpw'] == 'username:password'
574 curl_setopt($ch, CURLOPT_PROXYUSERPWD, $options['proxy_user'] . ':' . $options['proxy_pass']);
575 }
576
577 if (isset($options['user'])) {
578 curl_setopt($ch, CURLOPT_USERPWD, $options['user'] . ':' . $options['pass']);
579 }
580
581 if (!isset($options['soapaction'])) {
582 $options['soapaction'] = '';
583 }
584 curl_setopt($ch, CURLOPT_HTTPHEADER , array('Content-Type: text/xml;charset=' . $this->encoding, 'SOAPAction: "'.$options['soapaction'].'"'));
585 curl_setopt($ch, CURLOPT_USERAGENT , $this->_userAgent);
586
587 if ($this->timeout) {
588 curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeout); //times out after 4s
589 }
590
591 curl_setopt($ch, CURLOPT_POSTFIELDS, $msg);
592 curl_setopt($ch, CURLOPT_URL, $this->url);
593 curl_setopt($ch, CURLOPT_POST, 1);
594/* Databay: Changes for BMF */
595# curl_setopt($ch, CURLOPT_FAILONERROR, 0);
596 curl_setopt($ch, CURLOPT_FAILONERROR, 1);
597 curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
598 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
599 curl_setopt($ch, CURLOPT_HEADER, 1);
600/* Databay: Changes for BMF */
601 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
602/* Databay: Changes for BMF */
603 curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
604/* Databay: Changes for BMF */
605 curl_setopt($ch, CURLOPT_VERBOSE, 1);
606 if (defined('CURLOPT_HTTP_VERSION')) {
607 curl_setopt($ch, CURLOPT_HTTP_VERSION, 1);
608 }
609
610 if (isset($options['curl'])) {
611 foreach ($options['curl'] as $key => $val) {
612 curl_setopt($ch, $key, $val);
613 }
614 }
615
616 // Save the outgoing XML. This doesn't quite match _sendHTTP as CURL
617 // generates the headers, but having the XML is usually the most
618 // important part for tracing/debugging.
619 $this->outgoing_payload = $msg;
620
621 $this->incoming_payload = curl_exec($ch);
622 if (!$this->incoming_payload) {
623 $m = 'curl_exec error ' . curl_errno($ch) . ' ' . curl_error($ch);
624 curl_close($ch);
625 return $this->_raiseSoapFault($m);
626 }
627 curl_close($ch);
628
629 if (!$this->_parseResponse()) {
630 return $this->fault;
631 }
632
633 return $this->response;
634 }
635
636}
$n
Definition: RandomTest.php:80
isError($data, $code=null)
Tell whether a value is a PEAR error.
Definition: PEAR.php:279
const SOAP_LIBRARY_NAME
const SOAP_DEFAULT_ENCODING
$fault
Recent PEAR_Error object.
& _raiseSoapFault($str, $detail='', $actorURI='', $code=null, $mode=null, $options=null, $skipmsg=false)
Raises a SOAP error.
_decodeDIMEMessage(&$data, &$headers, &$attachments)
_decodeMimeMessage(&$data, &$headers, &$attachments)
_parseResponse()
Removes HTTP headers from response.
addCookie($name, $value)
Adds a cookie.
$result_content_type
HTTP-Response Content-Type.
_genCookieHeader()
Generates the correct headers for the cookies.
ilBMFTransport_HTTP($url, $encoding=SOAP_DEFAULT_ENCODING)
ilBMFTransport_HTTP Constructor
setCredentials($username, $password)
Sets data for HTTP authentication, creates authorization header.
_sendHTTPS($msg, $options)
Sends outgoing request, and read/parse response, via HTTPS.
send($msg, $options=null)
Sends and receives SOAP data.
_parseHeaders($headers)
Parses the headers.
_getRequest($msg, $options)
Creates HTTP request, including headers, for outgoing request.
_sendHTTP($msg, $options)
Sends outgoing request, and read/parse response.
_validateUrl()
Validate url data passed to constructor.
_parseEncoding($headers)
Finds out what the encoding is.
$h
$data
$code
Definition: example_050.php:99
if(!is_array($argv)) $options