1<?php 2 3/** 4 * This module contains the CURL-based HTTP fetcher 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/** 17 * Interface import 18 */ 19require_once "Auth/Yadis/HTTPFetcher.php"; 20 21require_once "Auth/OpenID.php"; 22 23/** 24 * A paranoid {@link Auth_Yadis_HTTPFetcher} class which uses CURL 25 * for fetching. 26 * 27 * @package OpenID 28 */ 29class Auth_Yadis_ParanoidHTTPFetcher extends Auth_Yadis_HTTPFetcher { 30 function Auth_Yadis_ParanoidHTTPFetcher() 31 { 32 $this->reset(); 33 } 34 35 function reset() 36 { 37 $this->headers = array(); 38 $this->data = ""; 39 } 40 41 /** 42 * @access private 43 */ 44 function _writeHeader($ch, $header) 45 { 46 array_push($this->headers, rtrim($header)); 47 return strlen($header); 48 } 49 50 /** 51 * @access private 52 */ 53 function _writeData($ch, $data) 54 { 55 if (strlen($this->data) > 1024*Auth_OpenID_FETCHER_MAX_RESPONSE_KB) { 56 return 0; 57 } else { 58 $this->data .= $data; 59 return strlen($data); 60 } 61 } 62 63 /** 64 * Does this fetcher support SSL URLs? 65 */ 66 function supportsSSL() 67 { 68 $v = curl_version(); 69 if(is_array($v)) { 70 return in_array('https', $v['protocols']); 71 } elseif (is_string($v)) { 72 return preg_match('/OpenSSL/i', $v); 73 } else { 74 return 0; 75 } 76 } 77 78 function get($url, $extra_headers = null) 79 { 80 if (!$this->canFetchURL($url)) { 81 return null; 82 } 83 84 $stop = time() + $this->timeout; 85 $off = $this->timeout; 86 87 $redir = true; 88 89 while ($redir && ($off > 0)) { 90 $this->reset(); 91 92 $c = curl_init(); 93 94 if ($c === false) { 95 Auth_OpenID::log( 96 "curl_init returned false; could not " . 97 "initialize for URL '%s'", $url); 98 return null; 99 } 100 101 if (defined('CURLOPT_NOSIGNAL')) { 102 curl_setopt($c, CURLOPT_NOSIGNAL, true); 103 } 104 105 if (!$this->allowedURL($url)) { 106 Auth_OpenID::log("Fetching URL not allowed: %s", 107 $url); 108 return null; 109 } 110 111 curl_setopt($c, CURLOPT_WRITEFUNCTION, 112 array($this, "_writeData")); 113 curl_setopt($c, CURLOPT_HEADERFUNCTION, 114 array($this, "_writeHeader")); 115 116 if ($extra_headers) { 117 curl_setopt($c, CURLOPT_HTTPHEADER, $extra_headers); 118 } 119 120 $cv = curl_version(); 121 if(is_array($cv)) { 122 $curl_user_agent = 'curl/'.$cv['version']; 123 } else { 124 $curl_user_agent = $cv; 125 } 126 curl_setopt($c, CURLOPT_USERAGENT, 127 Auth_OpenID_USER_AGENT.' '.$curl_user_agent); 128 curl_setopt($c, CURLOPT_TIMEOUT, $off); 129 curl_setopt($c, CURLOPT_URL, $url); 130 131 if (defined('Auth_OpenID_VERIFY_HOST')) { 132 // set SSL verification options only if Auth_OpenID_VERIFY_HOST 133 // is explicitly set, otherwise use system default. 134 if (Auth_OpenID_VERIFY_HOST) { 135 curl_setopt($c, CURLOPT_SSL_VERIFYPEER, true); 136 curl_setopt($c, CURLOPT_SSL_VERIFYHOST, 2); 137 if (defined('Auth_OpenID_CAINFO')) { 138 curl_setopt($c, CURLOPT_CAINFO, Auth_OpenID_CAINFO); 139 } 140 } else { 141 curl_setopt($c, CURLOPT_SSL_VERIFYPEER, false); 142 } 143 } 144 145 curl_exec($c); 146 147 $code = curl_getinfo($c, CURLINFO_HTTP_CODE); 148 $body = $this->data; 149 $headers = $this->headers; 150 151 if (!$code) { 152 Auth_OpenID::log("Got no response code when fetching %s", $url); 153 Auth_OpenID::log("CURL error (%s): %s", 154 curl_errno($c), curl_error($c)); 155 return null; 156 } 157 158 if (in_array($code, array(301, 302, 303, 307))) { 159 $url = $this->_findRedirect($headers, $url); 160 $redir = true; 161 } else { 162 $redir = false; 163 curl_close($c); 164 165 if (defined('Auth_OpenID_VERIFY_HOST') && 166 Auth_OpenID_VERIFY_HOST == true && 167 $this->isHTTPS($url)) { 168 Auth_OpenID::log('OpenID: Verified SSL host %s using '. 169 'curl/get', $url); 170 } 171 $new_headers = array(); 172 173 foreach ($headers as $header) { 174 if (strpos($header, ': ')) { 175 list($name, $value) = explode(': ', $header, 2); 176 $new_headers[$name] = $value; 177 } 178 } 179 180 Auth_OpenID::log( 181 "Successfully fetched '%s': GET response code %s", 182 $url, $code); 183 184 return new Auth_Yadis_HTTPResponse($url, $code, 185 $new_headers, $body); 186 } 187 188 $off = $stop - time(); 189 } 190 191 return null; 192 } 193 194 function post($url, $body, $extra_headers = null) 195 { 196 if (!$this->canFetchURL($url)) { 197 return null; 198 } 199 200 $this->reset(); 201 202 $c = curl_init(); 203 204 if (defined('CURLOPT_NOSIGNAL')) { 205 curl_setopt($c, CURLOPT_NOSIGNAL, true); 206 } 207 208 curl_setopt($c, CURLOPT_POST, true); 209 curl_setopt($c, CURLOPT_POSTFIELDS, $body); 210 curl_setopt($c, CURLOPT_TIMEOUT, $this->timeout); 211 curl_setopt($c, CURLOPT_URL, $url); 212 curl_setopt($c, CURLOPT_WRITEFUNCTION, 213 array($this, "_writeData")); 214 215 if (defined('Auth_OpenID_VERIFY_HOST')) { 216 // set SSL verification options only if Auth_OpenID_VERIFY_HOST 217 // is explicitly set, otherwise use system default. 218 if (Auth_OpenID_VERIFY_HOST) { 219 curl_setopt($c, CURLOPT_SSL_VERIFYPEER, true); 220 curl_setopt($c, CURLOPT_SSL_VERIFYHOST, 2); 221 if (defined('Auth_OpenID_CAINFO')) { 222 curl_setopt($c, CURLOPT_CAINFO, Auth_OpenID_CAINFO); 223 } 224 } else { 225 curl_setopt($c, CURLOPT_SSL_VERIFYPEER, false); 226 } 227 } 228 229 curl_exec($c); 230 231 $code = curl_getinfo($c, CURLINFO_HTTP_CODE); 232 233 if (!$code) { 234 Auth_OpenID::log("Got no response code when fetching %s", $url); 235 Auth_OpenID::log("CURL error (%s): %s", 236 curl_errno($c), curl_error($c)); 237 return null; 238 } 239 240 if (defined('Auth_OpenID_VERIFY_HOST') && 241 Auth_OpenID_VERIFY_HOST == true && 242 $this->isHTTPS($url)) { 243 Auth_OpenID::log('OpenID: Verified SSL host %s using '. 244 'curl/post', $url); 245 } 246 $body = $this->data; 247 248 curl_close($c); 249 250 $new_headers = $extra_headers; 251 252 foreach ($this->headers as $header) { 253 if (strpos($header, ': ')) { 254 list($name, $value) = explode(': ', $header, 2); 255 $new_headers[$name] = $value; 256 } 257 258 } 259 260 Auth_OpenID::log("Successfully fetched '%s': POST response code %s", 261 $url, $code); 262 263 return new Auth_Yadis_HTTPResponse($url, $code, 264 $new_headers, $body); 265 } 266} 267 268