PlainHTTPFetcher.php 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. <?php
  2. /**
  3. * This module contains the plain non-curl HTTP fetcher
  4. * implementation.
  5. *
  6. * PHP versions 4 and 5
  7. *
  8. * LICENSE: See the COPYING file included in this distribution.
  9. *
  10. * @package OpenID
  11. * @author JanRain, Inc. <openid@janrain.com>
  12. * @copyright 2005-2008 Janrain, Inc.
  13. * @license http://www.apache.org/licenses/LICENSE-2.0 Apache
  14. */
  15. /**
  16. * Interface import
  17. */
  18. require_once "Auth/Yadis/HTTPFetcher.php";
  19. /**
  20. * This class implements a plain, hand-built socket-based fetcher
  21. * which will be used in the event that CURL is unavailable.
  22. *
  23. * @package OpenID
  24. */
  25. class Auth_Yadis_PlainHTTPFetcher extends Auth_Yadis_HTTPFetcher {
  26. /**
  27. * Does this fetcher support SSL URLs?
  28. */
  29. function supportsSSL()
  30. {
  31. return function_exists('openssl_open');
  32. }
  33. function get($url, $extra_headers = null)
  34. {
  35. if (!$this->canFetchURL($url)) {
  36. return null;
  37. }
  38. $redir = true;
  39. $stop = time() + $this->timeout;
  40. $off = $this->timeout;
  41. while ($redir && ($off > 0)) {
  42. $parts = parse_url($url);
  43. $specify_port = true;
  44. // Set a default port.
  45. if (!array_key_exists('port', $parts)) {
  46. $specify_port = false;
  47. if ($parts['scheme'] == 'http') {
  48. $parts['port'] = 80;
  49. } elseif ($parts['scheme'] == 'https') {
  50. $parts['port'] = 443;
  51. } else {
  52. return null;
  53. }
  54. }
  55. if (!array_key_exists('path', $parts)) {
  56. $parts['path'] = '/';
  57. }
  58. $host = $parts['host'];
  59. if ($parts['scheme'] == 'https') {
  60. $host = 'ssl://' . $host;
  61. }
  62. $user_agent = Auth_OpenID_USER_AGENT;
  63. $headers = array(
  64. "GET ".$parts['path'].
  65. (array_key_exists('query', $parts) ?
  66. "?".$parts['query'] : "").
  67. " HTTP/1.0",
  68. "User-Agent: $user_agent",
  69. "Host: ".$parts['host'].
  70. ($specify_port ? ":".$parts['port'] : ""),
  71. "Port: ".$parts['port']);
  72. $errno = 0;
  73. $errstr = '';
  74. if ($extra_headers) {
  75. foreach ($extra_headers as $h) {
  76. $headers[] = $h;
  77. }
  78. }
  79. @$sock = fsockopen($host, $parts['port'], $errno, $errstr,
  80. $this->timeout);
  81. if ($sock === false) {
  82. return false;
  83. }
  84. stream_set_timeout($sock, $this->timeout);
  85. fputs($sock, implode("\r\n", $headers) . "\r\n\r\n");
  86. $data = "";
  87. $kilobytes = 0;
  88. while (!feof($sock) &&
  89. $kilobytes < Auth_OpenID_FETCHER_MAX_RESPONSE_KB ) {
  90. $data .= fgets($sock, 1024);
  91. $kilobytes += 1;
  92. }
  93. fclose($sock);
  94. // Split response into header and body sections
  95. list($headers, $body) = explode("\r\n\r\n", $data, 2);
  96. $headers = explode("\r\n", $headers);
  97. $http_code = explode(" ", $headers[0]);
  98. $code = $http_code[1];
  99. if (in_array($code, array('301', '302'))) {
  100. $url = $this->_findRedirect($headers, $url);
  101. $redir = true;
  102. } else {
  103. $redir = false;
  104. }
  105. $off = $stop - time();
  106. }
  107. $new_headers = array();
  108. foreach ($headers as $header) {
  109. if (preg_match("/:/", $header)) {
  110. $parts = explode(": ", $header, 2);
  111. if (count($parts) == 2) {
  112. list($name, $value) = $parts;
  113. $new_headers[$name] = $value;
  114. }
  115. }
  116. }
  117. return new Auth_Yadis_HTTPResponse($url, $code, $new_headers, $body);
  118. }
  119. function post($url, $body, $extra_headers = null)
  120. {
  121. if (!$this->canFetchURL($url)) {
  122. return null;
  123. }
  124. $parts = parse_url($url);
  125. $headers = array();
  126. $post_path = $parts['path'];
  127. if (isset($parts['query'])) {
  128. $post_path .= '?' . $parts['query'];
  129. }
  130. $headers[] = "POST ".$post_path." HTTP/1.0";
  131. $headers[] = "Host: " . $parts['host'];
  132. $headers[] = "Content-type: application/x-www-form-urlencoded";
  133. $headers[] = "Content-length: " . strval(strlen($body));
  134. if ($extra_headers &&
  135. is_array($extra_headers)) {
  136. $headers = array_merge($headers, $extra_headers);
  137. }
  138. // Join all headers together.
  139. $all_headers = implode("\r\n", $headers);
  140. // Add headers, two newlines, and request body.
  141. $request = $all_headers . "\r\n\r\n" . $body;
  142. // Set a default port.
  143. if (!array_key_exists('port', $parts)) {
  144. if ($parts['scheme'] == 'http') {
  145. $parts['port'] = 80;
  146. } elseif ($parts['scheme'] == 'https') {
  147. $parts['port'] = 443;
  148. } else {
  149. return null;
  150. }
  151. }
  152. if ($parts['scheme'] == 'https') {
  153. $parts['host'] = sprintf("ssl://%s", $parts['host']);
  154. }
  155. // Connect to the remote server.
  156. $errno = 0;
  157. $errstr = '';
  158. $sock = fsockopen($parts['host'], $parts['port'], $errno, $errstr,
  159. $this->timeout);
  160. if ($sock === false) {
  161. return null;
  162. }
  163. stream_set_timeout($sock, $this->timeout);
  164. // Write the POST request.
  165. fputs($sock, $request);
  166. // Get the response from the server.
  167. $response = "";
  168. while (!feof($sock)) {
  169. if ($data = fgets($sock, 128)) {
  170. $response .= $data;
  171. } else {
  172. break;
  173. }
  174. }
  175. // Split the request into headers and body.
  176. list($headers, $response_body) = explode("\r\n\r\n", $response, 2);
  177. $headers = explode("\r\n", $headers);
  178. // Expect the first line of the headers data to be something
  179. // like HTTP/1.1 200 OK. Split the line on spaces and take
  180. // the second token, which should be the return code.
  181. $http_code = explode(" ", $headers[0]);
  182. $code = $http_code[1];
  183. $new_headers = array();
  184. foreach ($headers as $header) {
  185. if (preg_match("/:/", $header)) {
  186. list($name, $value) = explode(": ", $header, 2);
  187. $new_headers[$name] = $value;
  188. }
  189. }
  190. return new Auth_Yadis_HTTPResponse($url, $code,
  191. $new_headers, $response_body);
  192. }
  193. }