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