ILIAS  release_5-1 Revision 5.0.0-5477-g43f3e3fab5f
Request.php
Go to the documentation of this file.
1<?php
50require_once 'PEAR.php';
54require_once 'Net/Socket.php';
58require_once 'Net/URL.php';
59
63define('HTTP_REQUEST_METHOD_GET', 'GET', true);
64define('HTTP_REQUEST_METHOD_HEAD', 'HEAD', true);
65define('HTTP_REQUEST_METHOD_POST', 'POST', true);
66define('HTTP_REQUEST_METHOD_PUT', 'PUT', true);
67define('HTTP_REQUEST_METHOD_DELETE', 'DELETE', true);
68define('HTTP_REQUEST_METHOD_OPTIONS', 'OPTIONS', true);
69define('HTTP_REQUEST_METHOD_TRACE', 'TRACE', true);
75define('HTTP_REQUEST_ERROR_FILE', 1);
76define('HTTP_REQUEST_ERROR_URL', 2);
77define('HTTP_REQUEST_ERROR_PROXY', 4);
78define('HTTP_REQUEST_ERROR_REDIRECTS', 8);
79define('HTTP_REQUEST_ERROR_RESPONSE', 16);
80define('HTTP_REQUEST_ERROR_GZIP_METHOD', 32);
81define('HTTP_REQUEST_ERROR_GZIP_READ', 64);
82define('HTTP_REQUEST_ERROR_GZIP_DATA', 128);
83define('HTTP_REQUEST_ERROR_GZIP_CRC', 256);
89define('HTTP_REQUEST_HTTP_VER_1_0', '1.0', true);
90define('HTTP_REQUEST_HTTP_VER_1_1', '1.1', true);
93if (extension_loaded('mbstring') && (2 & ini_get('mbstring.func_overload'))) {
97 define('HTTP_REQUEST_MBSTRING', true);
98} else {
102 define('HTTP_REQUEST_MBSTRING', false);
103}
104
122{
130 var $_url;
131
137
143
149
155
161
167
173
179
185
191
197
203
208 var $_bodyDisallowed = array('TRACE');
209
218 var $_bodyRequired = array('POST', 'PUT');
219
224 var $_postFiles = array();
225
231
237
243
249
255
260 var $_useBrackets = true;
261
266 var $_listeners = array();
267
272 var $_saveBody = true;
273
278 var $_readTimeout = null;
279
284 var $_socketOptions = null;
312 function HTTP_Request($url = '', $params = array())
313 {
314 $this->_method = HTTP_REQUEST_METHOD_GET;
315 $this->_http = HTTP_REQUEST_HTTP_VER_1_1;
316 $this->_requestHeaders = array();
317 $this->_postData = array();
318 $this->_body = null;
319
320 $this->_user = null;
321 $this->_pass = null;
322
323 $this->_proxy_host = null;
324 $this->_proxy_port = null;
325 $this->_proxy_user = null;
326 $this->_proxy_pass = null;
327
328 $this->_allowRedirects = false;
329 $this->_maxRedirects = 3;
330 $this->_redirects = 0;
331
332 $this->_timeout = null;
333 $this->_response = null;
334
335 foreach ($params as $key => $value) {
336 $this->{'_' . $key} = $value;
337 }
338
339 if (!empty($url)) {
340 $this->setURL($url);
341 }
342
343 // Default useragent
344 $this->addHeader('User-Agent', 'PEAR HTTP_Request class ( http://pear.php.net/ )');
345
346 // We don't do keep-alives by default
347 $this->addHeader('Connection', 'close');
348
349 // Basic authentication
350 if (!empty($this->_user)) {
351 $this->addHeader('Authorization', 'Basic ' . base64_encode($this->_user . ':' . $this->_pass));
352 }
353
354 // Proxy authentication (see bug #5913)
355 if (!empty($this->_proxy_user)) {
356 $this->addHeader('Proxy-Authorization', 'Basic ' . base64_encode($this->_proxy_user . ':' . $this->_proxy_pass));
357 }
358
359 // Use gzip encoding if possible
360 if (HTTP_REQUEST_HTTP_VER_1_1 == $this->_http && extension_loaded('zlib')) {
361 $this->addHeader('Accept-Encoding', 'gzip');
362 }
363 }
364
372 {
373 if ($this->_url->port != 80 AND strcasecmp($this->_url->protocol, 'http') == 0) {
374 $host = $this->_url->host . ':' . $this->_url->port;
375
376 } elseif ($this->_url->port != 443 AND strcasecmp($this->_url->protocol, 'https') == 0) {
377 $host = $this->_url->host . ':' . $this->_url->port;
378
379 } elseif ($this->_url->port == 443 AND strcasecmp($this->_url->protocol, 'https') == 0 AND strpos($this->_url->url, ':443') !== false) {
380 $host = $this->_url->host . ':' . $this->_url->port;
381
382 } else {
383 $host = $this->_url->host;
384 }
385
386 return $host;
387 }
388
399 function reset($url, $params = array())
400 {
401 $this->HTTP_Request($url, $params);
402 }
403
410 function setURL($url)
411 {
412 $this->_url = &new Net_URL($url, $this->_useBrackets);
413
414 if (!empty($this->_url->user) || !empty($this->_url->pass)) {
415 $this->setBasicAuth($this->_url->user, $this->_url->pass);
416 }
417
418 if (HTTP_REQUEST_HTTP_VER_1_1 == $this->_http) {
419 $this->addHeader('Host', $this->_generateHostHeader());
420 }
421
422 // set '/' instead of empty path rather than check later (see bug #8662)
423 if (empty($this->_url->path)) {
424 $this->_url->path = '/';
425 }
426 }
427
434 function getUrl()
435 {
436 return empty($this->_url)? '': $this->_url->getUrl();
437 }
438
448 function setProxy($host, $port = 8080, $user = null, $pass = null)
449 {
450 $this->_proxy_host = $host;
451 $this->_proxy_port = $port;
452 $this->_proxy_user = $user;
453 $this->_proxy_pass = $pass;
454
455 if (!empty($user)) {
456 $this->addHeader('Proxy-Authorization', 'Basic ' . base64_encode($user . ':' . $pass));
457 }
458 }
459
466 function setBasicAuth($user, $pass)
467 {
468 $this->_user = $user;
469 $this->_pass = $pass;
470
471 $this->addHeader('Authorization', 'Basic ' . base64_encode($user . ':' . $pass));
472 }
473
480 function setMethod($method)
481 {
482 $this->_method = $method;
483 }
484
491 function setHttpVer($http)
492 {
493 $this->_http = $http;
494 }
495
503 function addHeader($name, $value)
504 {
505 $this->_requestHeaders[strtolower($name)] = $value;
506 }
507
514 function removeHeader($name)
515 {
516 if (isset($this->_requestHeaders[strtolower($name)])) {
517 unset($this->_requestHeaders[strtolower($name)]);
518 }
519 }
520
529 function addQueryString($name, $value, $preencoded = false)
530 {
531 $this->_url->addQueryString($name, $value, $preencoded);
532 }
533
541 function addRawQueryString($querystring, $preencoded = true)
542 {
543 $this->_url->addRawQueryString($querystring, $preencoded);
544 }
545
554 function addPostData($name, $value, $preencoded = false)
555 {
556 if ($preencoded) {
557 $this->_postData[$name] = $value;
558 } else {
559 $this->_postData[$name] = $this->_arrayMapRecursive('urlencode', $value);
560 }
561 }
562
571 function _arrayMapRecursive($callback, $value)
572 {
573 if (!is_array($value)) {
574 return call_user_func($callback, $value);
575 } else {
576 $map = array();
577 foreach ($value as $k => $v) {
578 $map[$k] = $this->_arrayMapRecursive($callback, $v);
579 }
580 return $map;
581 }
582 }
583
600 function addFile($inputName, $fileName, $contentType = 'application/octet-stream')
601 {
602 if (!is_array($fileName) && !is_readable($fileName)) {
603 return PEAR::raiseError("File '{$fileName}' is not readable", HTTP_REQUEST_ERROR_FILE);
604 } elseif (is_array($fileName)) {
605 foreach ($fileName as $name) {
606 if (!is_readable($name)) {
607 return PEAR::raiseError("File '{$name}' is not readable", HTTP_REQUEST_ERROR_FILE);
608 }
609 }
610 }
611 $this->addHeader('Content-Type', 'multipart/form-data');
612 $this->_postFiles[$inputName] = array(
613 'name' => $fileName,
614 'type' => $contentType
615 );
616 return true;
617 }
618
627 function addRawPostData($postdata, $preencoded = true)
628 {
629 $this->_body = $preencoded ? $postdata : urlencode($postdata);
630 }
631
638 function setBody($body)
639 {
640 $this->_body = $body;
641 }
642
651 function clearPostData()
652 {
653 $this->_postData = null;
654 }
655
663 function addCookie($name, $value)
664 {
665 $cookies = isset($this->_requestHeaders['cookie']) ? $this->_requestHeaders['cookie']. '; ' : '';
666 $this->addHeader('Cookie', $cookies . $name . '=' . $value);
667 }
668
677 function clearCookies()
678 {
679 $this->removeHeader('Cookie');
680 }
681
690 function sendRequest($saveBody = true)
691 {
692 if (!is_a($this->_url, 'Net_URL')) {
693 return PEAR::raiseError('No URL given', HTTP_REQUEST_ERROR_URL);
694 }
695
696 $host = isset($this->_proxy_host) ? $this->_proxy_host : $this->_url->host;
697 $port = isset($this->_proxy_port) ? $this->_proxy_port : $this->_url->port;
698
699 if (strcasecmp($this->_url->protocol, 'https') == 0) {
700 // Bug #14127, don't try connecting to HTTPS sites without OpenSSL
701 if (version_compare(PHP_VERSION, '4.3.0', '<') || !extension_loaded('openssl')) {
702 return PEAR::raiseError('Need PHP 4.3.0 or later with OpenSSL support for https:// requests',
704 } elseif (isset($this->_proxy_host)) {
705 return PEAR::raiseError('HTTPS proxies are not supported', HTTP_REQUEST_ERROR_PROXY);
706 }
707 $host = 'ssl://' . $host;
708 }
709
710 // magic quotes may fuck up file uploads and chunked response processing
711 $magicQuotes = ini_get('magic_quotes_runtime');
712 ini_set('magic_quotes_runtime', false);
713
714 // RFC 2068, section 19.7.1: A client MUST NOT send the Keep-Alive
715 // connection token to a proxy server...
716 if (isset($this->_proxy_host) && !empty($this->_requestHeaders['connection']) &&
717 'Keep-Alive' == $this->_requestHeaders['connection'])
718 {
719 $this->removeHeader('connection');
720 }
721
722 $keepAlive = (HTTP_REQUEST_HTTP_VER_1_1 == $this->_http && empty($this->_requestHeaders['connection'])) ||
723 (!empty($this->_requestHeaders['connection']) && 'Keep-Alive' == $this->_requestHeaders['connection']);
724 $sockets = &PEAR::getStaticProperty('HTTP_Request', 'sockets');
725 $sockKey = $host . ':' . $port;
726 unset($this->_sock);
727
728 // There is a connected socket in the "static" property?
729 if ($keepAlive && !empty($sockets[$sockKey]) &&
730 !empty($sockets[$sockKey]->fp))
731 {
732 $this->_sock =& $sockets[$sockKey];
733 $err = null;
734 } else {
735 $this->_notify('connect');
736 $this->_sock =& new Net_Socket();
737 $err = $this->_sock->connect($host, $port, null, $this->_timeout, $this->_socketOptions);
738 }
739 PEAR::isError($err) or $err = $this->_sock->write($this->_buildRequest());
740
741 if (!PEAR::isError($err)) {
742 if (!empty($this->_readTimeout)) {
743 $this->_sock->setTimeout($this->_readTimeout[0], $this->_readTimeout[1]);
744 }
745
746 $this->_notify('sentRequest');
747
748 // Read the response
749 $this->_response = &new HTTP_Response($this->_sock, $this->_listeners);
750 $err = $this->_response->process(
751 $this->_saveBody && $saveBody,
752 HTTP_REQUEST_METHOD_HEAD != $this->_method
753 );
754
755 if ($keepAlive) {
756 $keepAlive = (isset($this->_response->_headers['content-length'])
757 || (isset($this->_response->_headers['transfer-encoding'])
758 && strtolower($this->_response->_headers['transfer-encoding']) == 'chunked'));
759 if ($keepAlive) {
760 if (isset($this->_response->_headers['connection'])) {
761 $keepAlive = strtolower($this->_response->_headers['connection']) == 'keep-alive';
762 } else {
763 $keepAlive = 'HTTP/'.HTTP_REQUEST_HTTP_VER_1_1 == $this->_response->_protocol;
764 }
765 }
766 }
767 }
768
769 ini_set('magic_quotes_runtime', $magicQuotes);
770
771 if (PEAR::isError($err)) {
772 return $err;
773 }
774
775 if (!$keepAlive) {
776 $this->disconnect();
777 // Store the connected socket in "static" property
778 } elseif (empty($sockets[$sockKey]) || empty($sockets[$sockKey]->fp)) {
779 $sockets[$sockKey] =& $this->_sock;
780 }
781
782 // Check for redirection
783 if ( $this->_allowRedirects
784 AND $this->_redirects <= $this->_maxRedirects
785 AND $this->getResponseCode() > 300
786 AND $this->getResponseCode() < 399
787 AND !empty($this->_response->_headers['location'])) {
788
789
790 $redirect = $this->_response->_headers['location'];
791
792 // Absolute URL
793 if (preg_match('/^https?:\/\//i', $redirect)) {
794 $this->_url = &new Net_URL($redirect);
795 $this->addHeader('Host', $this->_generateHostHeader());
796 // Absolute path
797 } elseif ($redirect{0} == '/') {
798 $this->_url->path = $redirect;
799
800 // Relative path
801 } elseif (substr($redirect, 0, 3) == '../' OR substr($redirect, 0, 2) == './') {
802 if (substr($this->_url->path, -1) == '/') {
803 $redirect = $this->_url->path . $redirect;
804 } else {
805 $redirect = dirname($this->_url->path) . '/' . $redirect;
806 }
808 $this->_url->path = $redirect;
809
810 // Filename, no path
811 } else {
812 if (substr($this->_url->path, -1) == '/') {
813 $redirect = $this->_url->path . $redirect;
814 } else {
815 $redirect = dirname($this->_url->path) . '/' . $redirect;
816 }
817 $this->_url->path = $redirect;
818 }
819
820 $this->_redirects++;
821 return $this->sendRequest($saveBody);
822
823 // Too many redirects
824 } elseif ($this->_allowRedirects AND $this->_redirects > $this->_maxRedirects) {
825 return PEAR::raiseError('Too many redirects', HTTP_REQUEST_ERROR_REDIRECTS);
826 }
827
828 return true;
829 }
830
836 function disconnect()
837 {
838 if (!empty($this->_sock) && !empty($this->_sock->fp)) {
839 $this->_notify('disconnect');
840 $this->_sock->disconnect();
841 }
842 }
843
851 {
852 return isset($this->_response->_code) ? $this->_response->_code : false;
853 }
854
862 {
863 return isset($this->_response->_reason) ? $this->_response->_reason : false;
864 }
865
874 function getResponseHeader($headername = null)
875 {
876 if (!isset($headername)) {
877 return isset($this->_response->_headers)? $this->_response->_headers: array();
878 } else {
879 $headername = strtolower($headername);
880 return isset($this->_response->_headers[$headername]) ? $this->_response->_headers[$headername] : false;
881 }
882 }
883
891 {
892 return isset($this->_response->_body) ? $this->_response->_body : false;
893 }
894
902 {
903 return isset($this->_response->_cookies) ? $this->_response->_cookies : false;
904 }
905
912 function _buildRequest()
913 {
914 $separator = ini_get('arg_separator.output');
915 ini_set('arg_separator.output', '&');
916 $querystring = ($querystring = $this->_url->getQueryString()) ? '?' . $querystring : '';
917 ini_set('arg_separator.output', $separator);
918
919 $host = isset($this->_proxy_host) ? $this->_url->protocol . '://' . $this->_url->host : '';
920 $port = (isset($this->_proxy_host) AND $this->_url->port != 80) ? ':' . $this->_url->port : '';
921 $path = $this->_url->path . $querystring;
922 $url = $host . $port . $path;
923
924 if (!strlen($url)) {
925 $url = '/';
926 }
927
928 $request = $this->_method . ' ' . $url . ' HTTP/' . $this->_http . "\r\n";
929
930 if (in_array($this->_method, $this->_bodyDisallowed) ||
931 (0 == strlen($this->_body) && (HTTP_REQUEST_METHOD_POST != $this->_method ||
932 (empty($this->_postData) && empty($this->_postFiles)))))
933 {
934 $this->removeHeader('Content-Type');
935 } else {
936 if (empty($this->_requestHeaders['content-type'])) {
937 // Add default content-type
938 $this->addHeader('Content-Type', 'application/x-www-form-urlencoded');
939 } elseif ('multipart/form-data' == $this->_requestHeaders['content-type']) {
940 $boundary = 'HTTP_Request_' . md5(uniqid('request') . microtime());
941 $this->addHeader('Content-Type', 'multipart/form-data; boundary=' . $boundary);
942 }
943 }
944
945 // Request Headers
946 if (!empty($this->_requestHeaders)) {
947 foreach ($this->_requestHeaders as $name => $value) {
948 $canonicalName = implode('-', array_map('ucfirst', explode('-', $name)));
949 $request .= $canonicalName . ': ' . $value . "\r\n";
950 }
951 }
952
953 // Method does not allow a body, simply add a final CRLF
954 if (in_array($this->_method, $this->_bodyDisallowed)) {
955
956 $request .= "\r\n";
957
958 // Post data if it's an array
959 } elseif (HTTP_REQUEST_METHOD_POST == $this->_method &&
960 (!empty($this->_postData) || !empty($this->_postFiles))) {
961
962 // "normal" POST request
963 if (!isset($boundary)) {
964 $postdata = implode('&', array_map(
965 create_function('$a', 'return $a[0] . \'=\' . $a[1];'),
966 $this->_flattenArray('', $this->_postData)
967 ));
968
969 // multipart request, probably with file uploads
970 } else {
971 $postdata = '';
972 if (!empty($this->_postData)) {
973 $flatData = $this->_flattenArray('', $this->_postData);
974 foreach ($flatData as $item) {
975 $postdata .= '--' . $boundary . "\r\n";
976 $postdata .= 'Content-Disposition: form-data; name="' . $item[0] . '"';
977 $postdata .= "\r\n\r\n" . urldecode($item[1]) . "\r\n";
978 }
979 }
980 foreach ($this->_postFiles as $name => $value) {
981 if (is_array($value['name'])) {
982 $varname = $name . ($this->_useBrackets? '[]': '');
983 } else {
984 $varname = $name;
985 $value['name'] = array($value['name']);
986 }
987 foreach ($value['name'] as $key => $filename) {
988 $fp = fopen($filename, 'r');
989 $basename = basename($filename);
990 $type = is_array($value['type'])? @$value['type'][$key]: $value['type'];
991
992 $postdata .= '--' . $boundary . "\r\n";
993 $postdata .= 'Content-Disposition: form-data; name="' . $varname . '"; filename="' . $basename . '"';
994 $postdata .= "\r\nContent-Type: " . $type;
995 $postdata .= "\r\n\r\n" . fread($fp, filesize($filename)) . "\r\n";
996 fclose($fp);
997 }
998 }
999 $postdata .= '--' . $boundary . "--\r\n";
1000 }
1001 $request .= 'Content-Length: ' .
1002 (HTTP_REQUEST_MBSTRING? mb_strlen($postdata, 'iso-8859-1'): strlen($postdata)) .
1003 "\r\n\r\n";
1004 $request .= $postdata;
1005
1006 // Explicitly set request body
1007 } elseif (0 < strlen($this->_body)) {
1008
1009 $request .= 'Content-Length: ' .
1010 (HTTP_REQUEST_MBSTRING? mb_strlen($this->_body, 'iso-8859-1'): strlen($this->_body)) .
1011 "\r\n\r\n";
1012 $request .= $this->_body;
1013
1014 // No body: send a Content-Length header nonetheless (request #12900),
1015 // but do that only for methods that require a body (bug #14740)
1016 } else {
1017
1018 if (in_array($this->_method, $this->_bodyRequired)) {
1019 $request .= "Content-Length: 0\r\n";
1020 }
1021 $request .= "\r\n";
1022 }
1023
1024 return $request;
1025 }
1026
1036 function _flattenArray($name, $values)
1037 {
1038 if (!is_array($values)) {
1039 return array(array($name, $values));
1040 } else {
1041 $ret = array();
1042 foreach ($values as $k => $v) {
1043 if (empty($name)) {
1044 $newName = $k;
1045 } elseif ($this->_useBrackets) {
1046 $newName = $name . '[' . $k . ']';
1047 } else {
1048 $newName = $name;
1049 }
1050 $ret = array_merge($ret, $this->_flattenArray($newName, $v));
1051 }
1052 return $ret;
1053 }
1054 }
1055
1056
1076 function attach(&$listener)
1077 {
1078 if (!is_a($listener, 'HTTP_Request_Listener')) {
1079 return false;
1080 }
1081 $this->_listeners[$listener->getId()] =& $listener;
1082 return true;
1083 }
1084
1085
1093 function detach(&$listener)
1094 {
1095 if (!is_a($listener, 'HTTP_Request_Listener') ||
1096 !isset($this->_listeners[$listener->getId()])) {
1097 return false;
1098 }
1099 unset($this->_listeners[$listener->getId()]);
1100 return true;
1101 }
1102
1103
1112 function _notify($event, $data = null)
1113 {
1114 foreach (array_keys($this->_listeners) as $id) {
1115 $this->_listeners[$id]->update($this, $event, $data);
1116 }
1117 }
1118}
1119
1120
1131{
1137
1143
1149
1155
1161
1167
1172 var $_body = '';
1173
1179
1184 var $_listeners = array();
1185
1191
1198 function HTTP_Response(&$sock, &$listeners)
1199 {
1200 $this->_sock =& $sock;
1201 $this->_listeners =& $listeners;
1202 }
1203
1204
1220 function process($saveBody = true, $canHaveBody = true)
1221 {
1222 do {
1223 $line = $this->_sock->readLine();
1224 if (!preg_match('!^(HTTP/\d\.\d) (\d{3})(?: (.+))?!', $line, $s)) {
1225 return PEAR::raiseError('Malformed response', HTTP_REQUEST_ERROR_RESPONSE);
1226 } else {
1227 $this->_protocol = $s[1];
1228 $this->_code = intval($s[2]);
1229 $this->_reason = empty($s[3])? null: $s[3];
1230 }
1231 while ('' !== ($header = $this->_sock->readLine())) {
1232 $this->_processHeader($header);
1233 }
1234 } while (100 == $this->_code);
1235
1236 $this->_notify('gotHeaders', $this->_headers);
1237
1238 // RFC 2616, section 4.4:
1239 // 1. Any response message which "MUST NOT" include a message-body ...
1240 // is always terminated by the first empty line after the header fields
1241 // 3. ... If a message is received with both a
1242 // Transfer-Encoding header field and a Content-Length header field,
1243 // the latter MUST be ignored.
1244 $canHaveBody = $canHaveBody && $this->_code >= 200 &&
1245 $this->_code != 204 && $this->_code != 304;
1246
1247 // If response body is present, read it and decode
1248 $chunked = isset($this->_headers['transfer-encoding']) && ('chunked' == $this->_headers['transfer-encoding']);
1249 $gzipped = isset($this->_headers['content-encoding']) && ('gzip' == $this->_headers['content-encoding']);
1250 $hasBody = false;
1251 if ($canHaveBody && ($chunked || !isset($this->_headers['content-length']) ||
1252 0 != $this->_headers['content-length']))
1253 {
1254 if ($chunked || !isset($this->_headers['content-length'])) {
1255 $this->_toRead = null;
1256 } else {
1257 $this->_toRead = $this->_headers['content-length'];
1258 }
1259 while (!$this->_sock->eof() && (is_null($this->_toRead) || 0 < $this->_toRead)) {
1260 if ($chunked) {
1261 $data = $this->_readChunked();
1262 } elseif (is_null($this->_toRead)) {
1263 $data = $this->_sock->read(4096);
1264 } else {
1265 $data = $this->_sock->read(min(4096, $this->_toRead));
1266 $this->_toRead -= HTTP_REQUEST_MBSTRING? mb_strlen($data, 'iso-8859-1'): strlen($data);
1267 }
1268 if ('' == $data && (!$this->_chunkLength || $this->_sock->eof())) {
1269 break;
1270 } else {
1271 $hasBody = true;
1272 if ($saveBody || $gzipped) {
1273 $this->_body .= $data;
1274 }
1275 $this->_notify($gzipped? 'gzTick': 'tick', $data);
1276 }
1277 }
1278 }
1279
1280 if ($hasBody) {
1281 // Uncompress the body if needed
1282 if ($gzipped) {
1283 $body = $this->_decodeGzip($this->_body);
1284 if (PEAR::isError($body)) {
1285 return $body;
1286 }
1287 $this->_body = $body;
1288 $this->_notify('gotBody', $this->_body);
1289 } else {
1290 $this->_notify('gotBody');
1291 }
1292 }
1293 return true;
1294 }
1295
1296
1304 {
1305 if (false === strpos($header, ':')) {
1306 return;
1307 }
1308 list($headername, $headervalue) = explode(':', $header, 2);
1309 $headername = strtolower($headername);
1310 $headervalue = ltrim($headervalue);
1311
1312 if ('set-cookie' != $headername) {
1313 if (isset($this->_headers[$headername])) {
1314 $this->_headers[$headername] .= ',' . $headervalue;
1315 } else {
1316 $this->_headers[$headername] = $headervalue;
1317 }
1318 } else {
1319 $this->_parseCookie($headervalue);
1320 }
1321 }
1322
1323
1330 function _parseCookie($headervalue)
1331 {
1332 $cookie = array(
1333 'expires' => null,
1334 'domain' => null,
1335 'path' => null,
1336 'secure' => false
1337 );
1338
1339 // Only a name=value pair
1340 if (!strpos($headervalue, ';')) {
1341 $pos = strpos($headervalue, '=');
1342 $cookie['name'] = trim(substr($headervalue, 0, $pos));
1343 $cookie['value'] = trim(substr($headervalue, $pos + 1));
1344
1345 // Some optional parameters are supplied
1346 } else {
1347 $elements = explode(';', $headervalue);
1348 $pos = strpos($elements[0], '=');
1349 $cookie['name'] = trim(substr($elements[0], 0, $pos));
1350 $cookie['value'] = trim(substr($elements[0], $pos + 1));
1351
1352 for ($i = 1; $i < count($elements); $i++) {
1353 if (false === strpos($elements[$i], '=')) {
1354 $elName = trim($elements[$i]);
1355 $elValue = null;
1356 } else {
1357 list ($elName, $elValue) = array_map('trim', explode('=', $elements[$i]));
1358 }
1359 $elName = strtolower($elName);
1360 if ('secure' == $elName) {
1361 $cookie['secure'] = true;
1362 } elseif ('expires' == $elName) {
1363 $cookie['expires'] = str_replace('"', '', $elValue);
1364 } elseif ('path' == $elName || 'domain' == $elName) {
1365 $cookie[$elName] = urldecode($elValue);
1366 } else {
1367 $cookie[$elName] = $elValue;
1368 }
1369 }
1370 }
1371 $this->_cookies[] = $cookie;
1372 }
1373
1374
1381 function _readChunked()
1382 {
1383 // at start of the next chunk?
1384 if (0 == $this->_chunkLength) {
1385 $line = $this->_sock->readLine();
1386 if (preg_match('/^([0-9a-f]+)/i', $line, $matches)) {
1387 $this->_chunkLength = hexdec($matches[1]);
1388 // Chunk with zero length indicates the end
1389 if (0 == $this->_chunkLength) {
1390 $this->_sock->readLine(); // make this an eof()
1391 return '';
1392 }
1393 } else {
1394 return '';
1395 }
1396 }
1397 $data = $this->_sock->read($this->_chunkLength);
1398 $this->_chunkLength -= HTTP_REQUEST_MBSTRING? mb_strlen($data, 'iso-8859-1'): strlen($data);
1399 if (0 == $this->_chunkLength) {
1400 $this->_sock->readLine(); // Trailing CRLF
1401 }
1402 return $data;
1403 }
1404
1405
1414 function _notify($event, $data = null)
1415 {
1416 foreach (array_keys($this->_listeners) as $id) {
1417 $this->_listeners[$id]->update($this, $event, $data);
1418 }
1419 }
1420
1421
1434 {
1435 if (HTTP_REQUEST_MBSTRING) {
1436 $oldEncoding = mb_internal_encoding();
1437 mb_internal_encoding('iso-8859-1');
1438 }
1439 $length = strlen($data);
1440 // If it doesn't look like gzip-encoded data, don't bother
1441 if (18 > $length || strcmp(substr($data, 0, 2), "\x1f\x8b")) {
1442 return $data;
1443 }
1444 $method = ord(substr($data, 2, 1));
1445 if (8 != $method) {
1446 return PEAR::raiseError('_decodeGzip(): unknown compression method', HTTP_REQUEST_ERROR_GZIP_METHOD);
1447 }
1448 $flags = ord(substr($data, 3, 1));
1449 if ($flags & 224) {
1450 return PEAR::raiseError('_decodeGzip(): reserved bits are set', HTTP_REQUEST_ERROR_GZIP_DATA);
1451 }
1452
1453 // header is 10 bytes minimum. may be longer, though.
1454 $headerLength = 10;
1455 // extra fields, need to skip 'em
1456 if ($flags & 4) {
1457 if ($length - $headerLength - 2 < 8) {
1458 return PEAR::raiseError('_decodeGzip(): data too short', HTTP_REQUEST_ERROR_GZIP_DATA);
1459 }
1460 $extraLength = unpack('v', substr($data, 10, 2));
1461 if ($length - $headerLength - 2 - $extraLength[1] < 8) {
1462 return PEAR::raiseError('_decodeGzip(): data too short', HTTP_REQUEST_ERROR_GZIP_DATA);
1463 }
1464 $headerLength += $extraLength[1] + 2;
1465 }
1466 // file name, need to skip that
1467 if ($flags & 8) {
1468 if ($length - $headerLength - 1 < 8) {
1469 return PEAR::raiseError('_decodeGzip(): data too short', HTTP_REQUEST_ERROR_GZIP_DATA);
1470 }
1471 $filenameLength = strpos(substr($data, $headerLength), chr(0));
1472 if (false === $filenameLength || $length - $headerLength - $filenameLength - 1 < 8) {
1473 return PEAR::raiseError('_decodeGzip(): data too short', HTTP_REQUEST_ERROR_GZIP_DATA);
1474 }
1475 $headerLength += $filenameLength + 1;
1476 }
1477 // comment, need to skip that also
1478 if ($flags & 16) {
1479 if ($length - $headerLength - 1 < 8) {
1480 return PEAR::raiseError('_decodeGzip(): data too short', HTTP_REQUEST_ERROR_GZIP_DATA);
1481 }
1482 $commentLength = strpos(substr($data, $headerLength), chr(0));
1483 if (false === $commentLength || $length - $headerLength - $commentLength - 1 < 8) {
1484 return PEAR::raiseError('_decodeGzip(): data too short', HTTP_REQUEST_ERROR_GZIP_DATA);
1485 }
1486 $headerLength += $commentLength + 1;
1487 }
1488 // have a CRC for header. let's check
1489 if ($flags & 1) {
1490 if ($length - $headerLength - 2 < 8) {
1491 return PEAR::raiseError('_decodeGzip(): data too short', HTTP_REQUEST_ERROR_GZIP_DATA);
1492 }
1493 $crcReal = 0xffff & crc32(substr($data, 0, $headerLength));
1494 $crcStored = unpack('v', substr($data, $headerLength, 2));
1495 if ($crcReal != $crcStored[1]) {
1496 return PEAR::raiseError('_decodeGzip(): header CRC check failed', HTTP_REQUEST_ERROR_GZIP_CRC);
1497 }
1498 $headerLength += 2;
1499 }
1500 // unpacked data CRC and size at the end of encoded data
1501 $tmp = unpack('V2', substr($data, -8));
1502 $dataCrc = $tmp[1];
1503 $dataSize = $tmp[2];
1504
1505 // finally, call the gzinflate() function
1506 // don't pass $dataSize to gzinflate, see bugs #13135, #14370
1507 $unpacked = gzinflate(substr($data, $headerLength, -8));
1508 if (false === $unpacked) {
1509 return PEAR::raiseError('_decodeGzip(): gzinflate() call failed', HTTP_REQUEST_ERROR_GZIP_READ);
1510 } elseif ($dataSize != strlen($unpacked)) {
1511 return PEAR::raiseError('_decodeGzip(): data size check failed', HTTP_REQUEST_ERROR_GZIP_READ);
1512 } elseif ((0xffffffff & $dataCrc) != (0xffffffff & crc32($unpacked))) {
1513 return PEAR::raiseError('_decodeGzip(): data CRC check failed', HTTP_REQUEST_ERROR_GZIP_CRC);
1514 }
1515 if (HTTP_REQUEST_MBSTRING) {
1516 mb_internal_encoding($oldEncoding);
1517 }
1518 return $unpacked;
1519 }
1520} // End class HTTP_Response
1521?>
const HTTP_REQUEST_ERROR_PROXY
Definition: Request.php:77
const HTTP_REQUEST_ERROR_GZIP_CRC
Definition: Request.php:83
const HTTP_REQUEST_HTTP_VER_1_1
Definition: Request.php:90
const HTTP_REQUEST_ERROR_FILE
#-
Definition: Request.php:75
const HTTP_REQUEST_ERROR_RESPONSE
Definition: Request.php:79
const HTTP_REQUEST_ERROR_REDIRECTS
Definition: Request.php:78
const HTTP_REQUEST_METHOD_GET
PEAR and PEAR_Error classes (for error handling)
Definition: Request.php:63
const HTTP_REQUEST_ERROR_URL
Definition: Request.php:76
const HTTP_REQUEST_ERROR_GZIP_METHOD
Definition: Request.php:80
const HTTP_REQUEST_METHOD_HEAD
Definition: Request.php:64
const HTTP_REQUEST_METHOD_POST
Definition: Request.php:65
const HTTP_REQUEST_ERROR_GZIP_DATA
Definition: Request.php:82
const HTTP_REQUEST_ERROR_GZIP_READ
Definition: Request.php:81
$filename
Definition: buildRTE.php:89
setURL($url)
Sets the URL to be requested.
Definition: Request.php:410
_buildRequest()
Builds the request string.
Definition: Request.php:912
HTTP_Request($url='', $params=array())
#-
Definition: Request.php:312
detach(&$listener)
Removes a Listener from the list of listeners.
Definition: Request.php:1093
clearPostData()
Clears any postdata that has been added (DEPRECATED).
Definition: Request.php:651
addRawQueryString($querystring, $preencoded=true)
Sets the querystring to literally what you supply.
Definition: Request.php:541
addFile($inputName, $fileName, $contentType='application/octet-stream')
Adds a file to form-based file upload.
Definition: Request.php:600
getResponseReason()
Returns the response reason phrase.
Definition: Request.php:861
addCookie($name, $value)
Appends a cookie to "Cookie:" header.
Definition: Request.php:663
addPostData($name, $value, $preencoded=false)
Adds postdata items.
Definition: Request.php:554
getResponseHeader($headername=null)
Returns either the named header or all if no name given.
Definition: Request.php:874
removeHeader($name)
Removes a request header.
Definition: Request.php:514
_flattenArray($name, $values)
Helper function to change the (probably multidimensional) associative array into the simple one.
Definition: Request.php:1036
getResponseCookies()
Returns cookies set in response.
Definition: Request.php:901
setProxy($host, $port=8080, $user=null, $pass=null)
Sets a proxy to be used.
Definition: Request.php:448
clearCookies()
Clears any cookies that have been added (DEPRECATED).
Definition: Request.php:677
addQueryString($name, $value, $preencoded=false)
Adds a querystring parameter.
Definition: Request.php:529
attach(&$listener)
Adds a Listener to the list of listeners that are notified of the object's events.
Definition: Request.php:1076
setHttpVer($http)
Sets the HTTP version to use, 1.0 or 1.1.
Definition: Request.php:491
_generateHostHeader()
Generates a Host header for HTTP/1.1 requests.
Definition: Request.php:371
getResponseBody()
Returns the body of the response.
Definition: Request.php:890
disconnect()
Disconnect the socket, if connected.
Definition: Request.php:836
_notify($event, $data=null)
Notifies all registered listeners of an event.
Definition: Request.php:1112
addRawPostData($postdata, $preencoded=true)
Adds raw postdata (DEPRECATED)
Definition: Request.php:627
_arrayMapRecursive($callback, $value)
Recursively applies the callback function to the value.
Definition: Request.php:571
setBody($body)
Sets the request body (for POST, PUT and similar requests)
Definition: Request.php:638
addHeader($name, $value)
Adds a request header.
Definition: Request.php:503
getResponseCode()
Returns the response code.
Definition: Request.php:850
reset($url, $params=array())
Resets the object to its initial state (DEPRECATED).
Definition: Request.php:399
setBasicAuth($user, $pass)
Sets basic authentication parameters.
Definition: Request.php:466
setMethod($method)
Sets the method to be used, GET, POST etc.
Definition: Request.php:480
getUrl()
Returns the current request URL.
Definition: Request.php:434
sendRequest($saveBody=true)
Sends the request.
Definition: Request.php:690
_processHeader($header)
Processes the response header.
Definition: Request.php:1303
_notify($event, $data=null)
Notifies all registered listeners of an event.
Definition: Request.php:1414
process($saveBody=true, $canHaveBody=true)
Processes a HTTP response.
Definition: Request.php:1220
_parseCookie($headervalue)
Parse a Set-Cookie header to fill $_cookies array.
Definition: Request.php:1330
_decodeGzip($data)
Decodes the message-body encoded by gzip.
Definition: Request.php:1433
HTTP_Response(&$sock, &$listeners)
Constructor.
Definition: Request.php:1198
_readChunked()
Read a part of response body encoded with chunked Transfer-Encoding.
Definition: Request.php:1381
Generalized Socket class.
Definition: Socket.php:35
Definition: URL.php:41
resolvePath($path)
Resolves //, ../ and .
Definition: URL.php:381
isError($data, $code=null)
Tell whether a value is a PEAR error.
Definition: PEAR.php:279
& getStaticProperty($class, $var)
If you have a class that's mostly/entirely static, and you need static properties,...
Definition: PEAR.php:230
& raiseError($message=null, $code=null, $mode=null, $options=null, $userinfo=null, $error_class=null, $skipmsg=false)
This method is a wrapper that returns an instance of the configured error class with this object's de...
Definition: PEAR.php:524
if(!file_exists(getcwd().'/ilias.ini.php')) if(isset( $_GET["client_id"]))
registration confirmation script for ilias
Definition: confirmReg.php:20
$header
$data
$params
Definition: example_049.php:96
$separator
$url
Definition: shib_logout.php:72
$path
Definition: index.php:22
$redirect
Definition: index.php:18