You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
			
				
					894 lines
				
				29 KiB
			
		
		
			
		
	
	
					894 lines
				
				29 KiB
			|   
											8 months ago
										 | <?php | ||
|  | 
 | ||
|  | /** | ||
|  |  * Handle all HTTP requests using cURL and manages the responses. | ||
|  |  * | ||
|  |  * @version 2011.06.07 | ||
|  |  * @copyright 2006-2011 Ryan Parman | ||
|  |  * @copyright 2006-2010 Foleeo Inc. | ||
|  |  * @copyright 2010-2011 Amazon.com, Inc. or its affiliates. | ||
|  |  * @copyright 2008-2011 Contributors | ||
|  |  * @license http://opensource.org/licenses/bsd-license.php Simplified BSD License | ||
|  |  */ | ||
|  | class RequestCore | ||
|  | { | ||
|  |     /** | ||
|  |      * The URL being requested. | ||
|  |      */ | ||
|  |     public $request_url; | ||
|  | 
 | ||
|  |     /** | ||
|  |      * The headers being sent in the request. | ||
|  |      */ | ||
|  |     public $request_headers; | ||
|  | 
 | ||
|  |     /** | ||
|  |      * The raw response callback headers | ||
|  |      */ | ||
|  |     public $response_raw_headers; | ||
|  | 
 | ||
|  |     /** | ||
|  |      * Response body when error occurs | ||
|  |      */ | ||
|  |     public $response_error_body; | ||
|  | 
 | ||
|  |     /** | ||
|  |      *The hander of write file | ||
|  |      */ | ||
|  |     public $write_file_handle; | ||
|  | 
 | ||
|  |     /** | ||
|  |      * The body being sent in the request. | ||
|  |      */ | ||
|  |     public $request_body; | ||
|  | 
 | ||
|  |     /** | ||
|  |      * The response returned by the request. | ||
|  |      */ | ||
|  |     public $response; | ||
|  | 
 | ||
|  |     /** | ||
|  |      * The headers returned by the request. | ||
|  |      */ | ||
|  |     public $response_headers; | ||
|  | 
 | ||
|  |     /** | ||
|  |      * The body returned by the request. | ||
|  |      */ | ||
|  |     public $response_body; | ||
|  | 
 | ||
|  |     /** | ||
|  |      * The HTTP status code returned by the request. | ||
|  |      */ | ||
|  |     public $response_code; | ||
|  | 
 | ||
|  |     /** | ||
|  |      * Additional response data. | ||
|  |      */ | ||
|  |     public $response_info; | ||
|  | 
 | ||
|  |     /** | ||
|  |      * The method by which the request is being made. | ||
|  |      */ | ||
|  |     public $method; | ||
|  | 
 | ||
|  |     /** | ||
|  |      * Store the proxy settings to use for the request. | ||
|  |      */ | ||
|  |     public $proxy = null; | ||
|  | 
 | ||
|  |     /** | ||
|  |      * The username to use for the request. | ||
|  |      */ | ||
|  |     public $username = null; | ||
|  | 
 | ||
|  |     /** | ||
|  |      * The password to use for the request. | ||
|  |      */ | ||
|  |     public $password = null; | ||
|  | 
 | ||
|  |     /** | ||
|  |      * Custom CURLOPT settings. | ||
|  |      */ | ||
|  |     public $curlopts = null; | ||
|  | 
 | ||
|  |     /** | ||
|  |      * The state of debug mode. | ||
|  |      */ | ||
|  |     public $debug_mode = false; | ||
|  | 
 | ||
|  |     /** | ||
|  |      * The default class to use for HTTP Requests (defaults to <RequestCore>). | ||
|  |      */ | ||
|  |     public $request_class = 'OSS\Http\RequestCore'; | ||
|  | 
 | ||
|  |     /** | ||
|  |      * The default class to use for HTTP Responses (defaults to <ResponseCore>). | ||
|  |      */ | ||
|  |     public $response_class = 'OSS\Http\ResponseCore'; | ||
|  | 
 | ||
|  |     /** | ||
|  |      * Default useragent string to use. | ||
|  |      */ | ||
|  |     public $useragent = 'RequestCore/1.4.3'; | ||
|  | 
 | ||
|  |     /** | ||
|  |      * File to read from while streaming up. | ||
|  |      */ | ||
|  |     public $read_file = null; | ||
|  | 
 | ||
|  |     /** | ||
|  |      * The resource to read from while streaming up. | ||
|  |      */ | ||
|  |     public $read_stream = null; | ||
|  | 
 | ||
|  |     /** | ||
|  |      * The size of the stream to read from. | ||
|  |      */ | ||
|  |     public $read_stream_size = null; | ||
|  | 
 | ||
|  |     /** | ||
|  |      * The length already read from the stream. | ||
|  |      */ | ||
|  |     public $read_stream_read = 0; | ||
|  | 
 | ||
|  |     /** | ||
|  |      * File to write to while streaming down. | ||
|  |      */ | ||
|  |     public $write_file = null; | ||
|  | 
 | ||
|  |     /** | ||
|  |      * The resource to write to while streaming down. | ||
|  |      */ | ||
|  |     public $write_stream = null; | ||
|  | 
 | ||
|  |     /** | ||
|  |      * Stores the intended starting seek position. | ||
|  |      */ | ||
|  |     public $seek_position = null; | ||
|  | 
 | ||
|  |     /** | ||
|  |      * The location of the cacert.pem file to use. | ||
|  |      */ | ||
|  |     public $cacert_location = false; | ||
|  | 
 | ||
|  |     /** | ||
|  |      * The state of SSL certificate verification. | ||
|  |      */ | ||
|  |     public $ssl_verification = true; | ||
|  | 
 | ||
|  |     /** | ||
|  |      * The user-defined callback function to call when a stream is read from. | ||
|  |      */ | ||
|  |     public $registered_streaming_read_callback = null; | ||
|  | 
 | ||
|  |     /** | ||
|  |      * The user-defined callback function to call when a stream is written to. | ||
|  |      */ | ||
|  |     public $registered_streaming_write_callback = null; | ||
|  | 
 | ||
|  |     /** | ||
|  |      * The request timeout time, which is 5,184,000 seconds,that is, 6 days by default | ||
|  |      * | ||
|  |      * @var int | ||
|  |      */ | ||
|  |     public $timeout = 5184000; | ||
|  | 
 | ||
|  |     /** | ||
|  |      * The connection timeout time, which is 10 seconds by default | ||
|  |      * | ||
|  |      * @var int | ||
|  |      */ | ||
|  |     public $connect_timeout = 10; | ||
|  | 
 | ||
|  |     /*%******************************************************************************************%*/ | ||
|  |     // CONSTANTS | ||
|  | 
 | ||
|  |     /** | ||
|  |      * GET HTTP Method | ||
|  |      */ | ||
|  |     const HTTP_GET = 'GET'; | ||
|  | 
 | ||
|  |     /** | ||
|  |      * POST HTTP Method | ||
|  |      */ | ||
|  |     const HTTP_POST = 'POST'; | ||
|  | 
 | ||
|  |     /** | ||
|  |      * PUT HTTP Method | ||
|  |      */ | ||
|  |     const HTTP_PUT = 'PUT'; | ||
|  | 
 | ||
|  |     /** | ||
|  |      * DELETE HTTP Method | ||
|  |      */ | ||
|  |     const HTTP_DELETE = 'DELETE'; | ||
|  | 
 | ||
|  |     /** | ||
|  |      * HEAD HTTP Method | ||
|  |      */ | ||
|  |     const HTTP_HEAD = 'HEAD'; | ||
|  | 
 | ||
|  | 
 | ||
|  |     /*%******************************************************************************************%*/ | ||
|  |     // CONSTRUCTOR/DESTRUCTOR | ||
|  | 
 | ||
|  |     /** | ||
|  |      * Construct a new instance of this class. | ||
|  |      * | ||
|  |      * @param string $url (Optional) The URL to request or service endpoint to query. | ||
|  |      * @param string $proxy (Optional) The faux-url to use for proxy settings. Takes the following format: `proxy://user:pass@hostname:port` | ||
|  |      * @param array $helpers (Optional) An associative array of classnames to use for request, and response functionality. Gets passed in automatically by the calling class. | ||
|  |      * @return $this A reference to the current instance. | ||
|  |      */ | ||
|  |     public function __construct($url = null, $proxy = null, $helpers = null) | ||
|  |     { | ||
|  |         // Set some default values. | ||
|  |         $this->request_url = $url; | ||
|  |         $this->method = self::HTTP_GET; | ||
|  |         $this->request_headers = array(); | ||
|  |         $this->request_body = ''; | ||
|  | 
 | ||
|  |         // Set a new Request class if one was set. | ||
|  |         if (isset($helpers['request']) && !empty($helpers['request'])) { | ||
|  |             $this->request_class = $helpers['request']; | ||
|  |         } | ||
|  | 
 | ||
|  |         // Set a new Request class if one was set. | ||
|  |         if (isset($helpers['response']) && !empty($helpers['response'])) { | ||
|  |             $this->response_class = $helpers['response']; | ||
|  |         } | ||
|  | 
 | ||
|  |         if ($proxy) { | ||
|  |             $this->set_proxy($proxy); | ||
|  |         } | ||
|  | 
 | ||
|  |         return $this; | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * Destruct the instance. Closes opened file handles. | ||
|  |      * | ||
|  |      * @return $this A reference to the current instance. | ||
|  |      */ | ||
|  |     public function __destruct() | ||
|  |     { | ||
|  |         if (isset($this->read_file) && isset($this->read_stream)) { | ||
|  |             fclose($this->read_stream); | ||
|  |         } | ||
|  | 
 | ||
|  |         if (isset($this->write_file) && isset($this->write_stream)) { | ||
|  |             fclose($this->write_stream); | ||
|  |         } | ||
|  | 
 | ||
|  |         return $this; | ||
|  |     } | ||
|  | 
 | ||
|  | 
 | ||
|  |     /*%******************************************************************************************%*/ | ||
|  |     // REQUEST METHODS | ||
|  | 
 | ||
|  |     /** | ||
|  |      * Set the credentials to use for authentication. | ||
|  |      * | ||
|  |      * @param string $user (Required) The username to authenticate with. | ||
|  |      * @param string $pass (Required) The password to authenticate with. | ||
|  |      * @return $this A reference to the current instance. | ||
|  |      */ | ||
|  |     public function set_credentials($user, $pass) | ||
|  |     { | ||
|  |         $this->username = $user; | ||
|  |         $this->password = $pass; | ||
|  |         return $this; | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * Add a custom HTTP header to the cURL request. | ||
|  |      * | ||
|  |      * @param string $key (Required) The custom HTTP header to set. | ||
|  |      * @param mixed $value (Required) The value to assign to the custom HTTP header. | ||
|  |      * @return $this A reference to the current instance. | ||
|  |      */ | ||
|  |     public function add_header($key, $value) | ||
|  |     { | ||
|  |         $this->request_headers[$key] = $value; | ||
|  |         return $this; | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * Remove an HTTP header from the cURL request. | ||
|  |      * | ||
|  |      * @param string $key (Required) The custom HTTP header to set. | ||
|  |      * @return $this A reference to the current instance. | ||
|  |      */ | ||
|  |     public function remove_header($key) | ||
|  |     { | ||
|  |         if (isset($this->request_headers[$key])) { | ||
|  |             unset($this->request_headers[$key]); | ||
|  |         } | ||
|  |         return $this; | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * Set the method type for the request. | ||
|  |      * | ||
|  |      * @param string $method (Required) One of the following constants: <HTTP_GET>, <HTTP_POST>, <HTTP_PUT>, <HTTP_HEAD>, <HTTP_DELETE>. | ||
|  |      * @return $this A reference to the current instance. | ||
|  |      */ | ||
|  |     public function set_method($method) | ||
|  |     { | ||
|  |         $this->method = strtoupper($method); | ||
|  |         return $this; | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * Set a custom useragent string for the class. | ||
|  |      * | ||
|  |      * @param string $ua (Required) The useragent string to use. | ||
|  |      * @return $this A reference to the current instance. | ||
|  |      */ | ||
|  |     public function set_useragent($ua) | ||
|  |     { | ||
|  |         $this->useragent = $ua; | ||
|  |         return $this; | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * Set the body to send in the request. | ||
|  |      * | ||
|  |      * @param string $body (Required) The textual content to send along in the body of the request. | ||
|  |      * @return $this A reference to the current instance. | ||
|  |      */ | ||
|  |     public function set_body($body) | ||
|  |     { | ||
|  |         $this->request_body = $body; | ||
|  |         return $this; | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * Set the URL to make the request to. | ||
|  |      * | ||
|  |      * @param string $url (Required) The URL to make the request to. | ||
|  |      * @return $this A reference to the current instance. | ||
|  |      */ | ||
|  |     public function set_request_url($url) | ||
|  |     { | ||
|  |         $this->request_url = $url; | ||
|  |         return $this; | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * Set additional CURLOPT settings. These will merge with the default settings, and override if | ||
|  |      * there is a duplicate. | ||
|  |      * | ||
|  |      * @param array $curlopts (Optional) A set of key-value pairs that set `CURLOPT` options. These will merge with the existing CURLOPTs, and ones passed here will override the defaults. Keys should be the `CURLOPT_*` constants, not strings. | ||
|  |      * @return $this A reference to the current instance. | ||
|  |      */ | ||
|  |     public function set_curlopts($curlopts) | ||
|  |     { | ||
|  |         $this->curlopts = $curlopts; | ||
|  |         return $this; | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * Set the length in bytes to read from the stream while streaming up. | ||
|  |      * | ||
|  |      * @param integer $size (Required) The length in bytes to read from the stream. | ||
|  |      * @return $this A reference to the current instance. | ||
|  |      */ | ||
|  |     public function set_read_stream_size($size) | ||
|  |     { | ||
|  |         $this->read_stream_size = $size; | ||
|  | 
 | ||
|  |         return $this; | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * Set the resource to read from while streaming up. Reads the stream from its current position until | ||
|  |      * EOF or `$size` bytes have been read. If `$size` is not given it will be determined by <php:fstat()> and | ||
|  |      * <php:ftell()>. | ||
|  |      * | ||
|  |      * @param resource $resource (Required) The readable resource to read from. | ||
|  |      * @param integer $size (Optional) The size of the stream to read. | ||
|  |      * @return $this A reference to the current instance. | ||
|  |      */ | ||
|  |     public function set_read_stream($resource, $size = null) | ||
|  |     { | ||
|  |         if (!isset($size) || $size < 0) { | ||
|  |             $stats = fstat($resource); | ||
|  | 
 | ||
|  |             if ($stats && $stats['size'] >= 0) { | ||
|  |                 $position = ftell($resource); | ||
|  | 
 | ||
|  |                 if ($position !== false && $position >= 0) { | ||
|  |                     $size = $stats['size'] - $position; | ||
|  |                 } | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         $this->read_stream = $resource; | ||
|  | 
 | ||
|  |         return $this->set_read_stream_size($size); | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * Set the file to read from while streaming up. | ||
|  |      * | ||
|  |      * @param string $location (Required) The readable location to read from. | ||
|  |      * @return $this A reference to the current instance. | ||
|  |      */ | ||
|  |     public function set_read_file($location) | ||
|  |     { | ||
|  |         $this->read_file = $location; | ||
|  |         $read_file_handle = fopen($location, 'r'); | ||
|  | 
 | ||
|  |         return $this->set_read_stream($read_file_handle); | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * Set the resource to write to while streaming down. | ||
|  |      * | ||
|  |      * @param resource $resource (Required) The writeable resource to write to. | ||
|  |      * @return $this A reference to the current instance. | ||
|  |      */ | ||
|  |     public function set_write_stream($resource) | ||
|  |     { | ||
|  |         $this->write_stream = $resource; | ||
|  | 
 | ||
|  |         return $this; | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * Set the file to write to while streaming down. | ||
|  |      * | ||
|  |      * @param string $location (Required) The writeable location to write to. | ||
|  |      * @return $this A reference to the current instance. | ||
|  |      */ | ||
|  |     public function set_write_file($location) | ||
|  |     { | ||
|  |         $this->write_file = $location; | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * Set the proxy to use for making requests. | ||
|  |      * | ||
|  |      * @param string $proxy (Required) The faux-url to use for proxy settings. Takes the following format: `proxy://user:pass@hostname:port` | ||
|  |      * @return $this A reference to the current instance. | ||
|  |      */ | ||
|  |     public function set_proxy($proxy) | ||
|  |     { | ||
|  |         $proxy = parse_url($proxy); | ||
|  |         $proxy['user'] = isset($proxy['user']) ? $proxy['user'] : null; | ||
|  |         $proxy['pass'] = isset($proxy['pass']) ? $proxy['pass'] : null; | ||
|  |         $proxy['port'] = isset($proxy['port']) ? $proxy['port'] : null; | ||
|  |         $this->proxy = $proxy; | ||
|  |         return $this; | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * Set the intended starting seek position. | ||
|  |      * | ||
|  |      * @param integer $position (Required) The byte-position of the stream to begin reading from. | ||
|  |      * @return $this A reference to the current instance. | ||
|  |      */ | ||
|  |     public function set_seek_position($position) | ||
|  |     { | ||
|  |         $this->seek_position = isset($position) ? (integer)$position : null; | ||
|  | 
 | ||
|  |         return $this; | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * A callback function that is invoked by cURL for streaming up. | ||
|  |      * | ||
|  |      * @param resource $curl_handle (Required) The cURL handle for the request. | ||
|  |      * @param resource $header_content (Required) The header callback result. | ||
|  |      * @return headers from a stream. | ||
|  |      */ | ||
|  |    public function streaming_header_callback($curl_handle, $header_content) | ||
|  |    { | ||
|  |         $code = curl_getinfo($curl_handle, CURLINFO_HTTP_CODE); | ||
|  | 
 | ||
|  |         if (isset($this->write_file) && intval($code) / 100 == 2 && !isset($this->write_file_handle)) | ||
|  |         { | ||
|  |             $this->write_file_handle = fopen($this->write_file, 'w'); | ||
|  |             $this->set_write_stream($this->write_file_handle); | ||
|  |         } | ||
|  | 
 | ||
|  |         $this->response_raw_headers .= $header_content; | ||
|  |         return strlen($header_content); | ||
|  |     } | ||
|  | 
 | ||
|  | 
 | ||
|  |     /** | ||
|  |      * Register a callback function to execute whenever a data stream is read from using | ||
|  |      * <CFRequest::streaming_read_callback()>. | ||
|  |      * | ||
|  |      * The user-defined callback function should accept three arguments: | ||
|  |      * | ||
|  |      * <ul> | ||
|  |      *    <li><code>$curl_handle</code> - <code>resource</code> - Required - The cURL handle resource that represents the in-progress transfer.</li> | ||
|  |      *    <li><code>$file_handle</code> - <code>resource</code> - Required - The file handle resource that represents the file on the local file system.</li> | ||
|  |      *    <li><code>$length</code> - <code>integer</code> - Required - The length in kilobytes of the data chunk that was transferred.</li> | ||
|  |      * </ul> | ||
|  |      * | ||
|  |      * @param string|array|function $callback (Required) The callback function is called by <php:call_user_func()>, so you can pass the following values: <ul> | ||
|  |      *    <li>The name of a global function to execute, passed as a string.</li> | ||
|  |      *    <li>A method to execute, passed as <code>array('ClassName', 'MethodName')</code>.</li> | ||
|  |      *    <li>An anonymous function (PHP 5.3+).</li></ul> | ||
|  |      * @return $this A reference to the current instance. | ||
|  |      */ | ||
|  |     public function register_streaming_read_callback($callback) | ||
|  |     { | ||
|  |         $this->registered_streaming_read_callback = $callback; | ||
|  | 
 | ||
|  |         return $this; | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * Register a callback function to execute whenever a data stream is written to using | ||
|  |      * <CFRequest::streaming_write_callback()>. | ||
|  |      * | ||
|  |      * The user-defined callback function should accept two arguments: | ||
|  |      * | ||
|  |      * <ul> | ||
|  |      *    <li><code>$curl_handle</code> - <code>resource</code> - Required - The cURL handle resource that represents the in-progress transfer.</li> | ||
|  |      *    <li><code>$length</code> - <code>integer</code> - Required - The length in kilobytes of the data chunk that was transferred.</li> | ||
|  |      * </ul> | ||
|  |      * | ||
|  |      * @param string|array|function $callback (Required) The callback function is called by <php:call_user_func()>, so you can pass the following values: <ul> | ||
|  |      *    <li>The name of a global function to execute, passed as a string.</li> | ||
|  |      *    <li>A method to execute, passed as <code>array('ClassName', 'MethodName')</code>.</li> | ||
|  |      *    <li>An anonymous function (PHP 5.3+).</li></ul> | ||
|  |      * @return $this A reference to the current instance. | ||
|  |      */ | ||
|  |     public function register_streaming_write_callback($callback) | ||
|  |     { | ||
|  |         $this->registered_streaming_write_callback = $callback; | ||
|  | 
 | ||
|  |         return $this; | ||
|  |     } | ||
|  | 
 | ||
|  | 
 | ||
|  |     /*%******************************************************************************************%*/ | ||
|  |     // PREPARE, SEND, AND PROCESS REQUEST | ||
|  | 
 | ||
|  |     /** | ||
|  |      * A callback function that is invoked by cURL for streaming up. | ||
|  |      * | ||
|  |      * @param resource $curl_handle (Required) The cURL handle for the request. | ||
|  |      * @param resource $file_handle (Required) The open file handle resource. | ||
|  |      * @param integer $length (Required) The maximum number of bytes to read. | ||
|  |      * @return binary Binary data from a stream. | ||
|  |      */ | ||
|  |     public function streaming_read_callback($curl_handle, $file_handle, $length) | ||
|  |     { | ||
|  |         // Once we've sent as much as we're supposed to send... | ||
|  |         if ($this->read_stream_read >= $this->read_stream_size) { | ||
|  |             // Send EOF | ||
|  |             return ''; | ||
|  |         } | ||
|  | 
 | ||
|  |         // If we're at the beginning of an upload and need to seek... | ||
|  |         if ($this->read_stream_read == 0 && isset($this->seek_position) && $this->seek_position !== ftell($this->read_stream)) { | ||
|  |             if (fseek($this->read_stream, $this->seek_position) !== 0) { | ||
|  |                 throw new RequestCore_Exception('The stream does not support seeking and is either not at the requested position or the position is unknown.'); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         $read = fread($this->read_stream, min($this->read_stream_size - $this->read_stream_read, $length)); // Remaining upload data or cURL's requested chunk size | ||
|  |         $this->read_stream_read += strlen($read); | ||
|  | 
 | ||
|  |         $out = $read === false ? '' : $read; | ||
|  | 
 | ||
|  |         // Execute callback function | ||
|  |         if ($this->registered_streaming_read_callback) { | ||
|  |             call_user_func($this->registered_streaming_read_callback, $curl_handle, $file_handle, $out); | ||
|  |         } | ||
|  | 
 | ||
|  |         return $out; | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * A callback function that is invoked by cURL for streaming down. | ||
|  |      * | ||
|  |      * @param resource $curl_handle (Required) The cURL handle for the request. | ||
|  |      * @param binary $data (Required) The data to write. | ||
|  |      * @return integer The number of bytes written. | ||
|  |      */ | ||
|  |     public function streaming_write_callback($curl_handle, $data) | ||
|  |     { | ||
|  |         $code = curl_getinfo($curl_handle, CURLINFO_HTTP_CODE); | ||
|  | 
 | ||
|  |         if (intval($code) / 100 != 2) | ||
|  |         { | ||
|  |             $this->response_error_body .= $data; | ||
|  |             return strlen($data); | ||
|  |         } | ||
|  | 
 | ||
|  |         $length = strlen($data); | ||
|  |         $written_total = 0; | ||
|  |         $written_last = 0; | ||
|  | 
 | ||
|  |         while ($written_total < $length) { | ||
|  |             $written_last = fwrite($this->write_stream, substr($data, $written_total)); | ||
|  | 
 | ||
|  |             if ($written_last === false) { | ||
|  |                 return $written_total; | ||
|  |             } | ||
|  | 
 | ||
|  |             $written_total += $written_last; | ||
|  |         } | ||
|  | 
 | ||
|  |         // Execute callback function | ||
|  |         if ($this->registered_streaming_write_callback) { | ||
|  |             call_user_func($this->registered_streaming_write_callback, $curl_handle, $written_total); | ||
|  |         } | ||
|  | 
 | ||
|  |         return $written_total; | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * Prepare and adds the details of the cURL request. This can be passed along to a <php:curl_multi_exec()> | ||
|  |      * function. | ||
|  |      * | ||
|  |      * @return resource The handle for the cURL object. | ||
|  |      * | ||
|  |      */ | ||
|  |     public function prep_request() | ||
|  |     { | ||
|  |         $curl_handle = curl_init(); | ||
|  | 
 | ||
|  |         // Set default options. | ||
|  |         curl_setopt($curl_handle, CURLOPT_URL, $this->request_url); | ||
|  |         curl_setopt($curl_handle, CURLOPT_FILETIME, true); | ||
|  |         curl_setopt($curl_handle, CURLOPT_FRESH_CONNECT, false); | ||
|  | //		curl_setopt($curl_handle, CURLOPT_CLOSEPOLICY, CURLCLOSEPOLICY_LEAST_RECENTLY_USED); | ||
|  |         curl_setopt($curl_handle, CURLOPT_MAXREDIRS, 5); | ||
|  |         curl_setopt($curl_handle, CURLOPT_HEADER, true); | ||
|  |         curl_setopt($curl_handle, CURLOPT_RETURNTRANSFER, true); | ||
|  |         curl_setopt($curl_handle, CURLOPT_TIMEOUT, $this->timeout); | ||
|  |         curl_setopt($curl_handle, CURLOPT_CONNECTTIMEOUT, $this->connect_timeout); | ||
|  |         curl_setopt($curl_handle, CURLOPT_NOSIGNAL, true); | ||
|  |         curl_setopt($curl_handle, CURLOPT_REFERER, $this->request_url); | ||
|  |         curl_setopt($curl_handle, CURLOPT_USERAGENT, $this->useragent); | ||
|  |         curl_setopt($curl_handle, CURLOPT_HEADERFUNCTION, array($this, 'streaming_header_callback')); | ||
|  |         curl_setopt($curl_handle, CURLOPT_READFUNCTION, array($this, 'streaming_read_callback')); | ||
|  | 
 | ||
|  |         // Verification of the SSL cert | ||
|  |         if ($this->ssl_verification) { | ||
|  |             curl_setopt($curl_handle, CURLOPT_SSL_VERIFYPEER, true); | ||
|  |             curl_setopt($curl_handle, CURLOPT_SSL_VERIFYHOST, 2); | ||
|  |         } else { | ||
|  |             curl_setopt($curl_handle, CURLOPT_SSL_VERIFYPEER, false); | ||
|  |             curl_setopt($curl_handle, CURLOPT_SSL_VERIFYHOST, false); | ||
|  |         } | ||
|  | 
 | ||
|  |         // chmod the file as 0755 | ||
|  |         if ($this->cacert_location === true) { | ||
|  |             curl_setopt($curl_handle, CURLOPT_CAINFO, dirname(__FILE__) . '/cacert.pem'); | ||
|  |         } elseif (is_string($this->cacert_location)) { | ||
|  |             curl_setopt($curl_handle, CURLOPT_CAINFO, $this->cacert_location); | ||
|  |         } | ||
|  | 
 | ||
|  |         // Debug mode | ||
|  |         if ($this->debug_mode) { | ||
|  |             curl_setopt($curl_handle, CURLOPT_VERBOSE, true); | ||
|  |         } | ||
|  | 
 | ||
|  |         // Handle open_basedir & safe mode | ||
|  |         if (!ini_get('safe_mode') && !ini_get('open_basedir')) { | ||
|  |             curl_setopt($curl_handle, CURLOPT_FOLLOWLOCATION, true); | ||
|  |         } | ||
|  | 
 | ||
|  |         // Enable a proxy connection if requested. | ||
|  |         if ($this->proxy) { | ||
|  |             $host = $this->proxy['host']; | ||
|  |             $host .= ($this->proxy['port']) ? ':' . $this->proxy['port'] : ''; | ||
|  |             curl_setopt($curl_handle, CURLOPT_PROXY, $host); | ||
|  | 
 | ||
|  |             if (isset($this->proxy['user']) && isset($this->proxy['pass'])) { | ||
|  |                 curl_setopt($curl_handle, CURLOPT_PROXYUSERPWD, $this->proxy['user'] . ':' . $this->proxy['pass']); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         // Set credentials for HTTP Basic/Digest Authentication. | ||
|  |         if ($this->username && $this->password) { | ||
|  |             curl_setopt($curl_handle, CURLOPT_HTTPAUTH, CURLAUTH_ANY); | ||
|  |             curl_setopt($curl_handle, CURLOPT_USERPWD, $this->username . ':' . $this->password); | ||
|  |         } | ||
|  | 
 | ||
|  |         // Handle the encoding if we can. | ||
|  |         if (extension_loaded('zlib')) { | ||
|  |             curl_setopt($curl_handle, CURLOPT_ENCODING, ''); | ||
|  |         } | ||
|  | 
 | ||
|  |         // Process custom headers | ||
|  |         if (isset($this->request_headers) && count($this->request_headers)) { | ||
|  |             $temp_headers = array(); | ||
|  | 
 | ||
|  |             foreach ($this->request_headers as $k => $v) { | ||
|  |                 $temp_headers[] = $k . ': ' . $v; | ||
|  |             } | ||
|  | 
 | ||
|  |             curl_setopt($curl_handle, CURLOPT_HTTPHEADER, $temp_headers); | ||
|  |         } | ||
|  | 
 | ||
|  |         switch ($this->method) { | ||
|  |             case self::HTTP_PUT: | ||
|  |                 //unset($this->read_stream); | ||
|  |                 curl_setopt($curl_handle, CURLOPT_CUSTOMREQUEST, 'PUT'); | ||
|  |                 if (isset($this->read_stream)) { | ||
|  |                     if (!isset($this->read_stream_size) || $this->read_stream_size < 0) { | ||
|  |                         throw new RequestCore_Exception('The stream size for the streaming upload cannot be determined.'); | ||
|  |                     } | ||
|  |                     curl_setopt($curl_handle, CURLOPT_INFILESIZE, $this->read_stream_size); | ||
|  |                     curl_setopt($curl_handle, CURLOPT_UPLOAD, true); | ||
|  |                 } else { | ||
|  |                     curl_setopt($curl_handle, CURLOPT_POSTFIELDS, $this->request_body); | ||
|  |                 } | ||
|  |                 break; | ||
|  | 
 | ||
|  |             case self::HTTP_POST: | ||
|  |                 curl_setopt($curl_handle, CURLOPT_CUSTOMREQUEST, 'POST'); | ||
|  |                 if (isset($this->read_stream)) { | ||
|  |                     if (!isset($this->read_stream_size) || $this->read_stream_size < 0) { | ||
|  |                         throw new RequestCore_Exception('The stream size for the streaming upload cannot be determined.'); | ||
|  |                     } | ||
|  |                     curl_setopt($curl_handle, CURLOPT_INFILESIZE, $this->read_stream_size); | ||
|  |                     curl_setopt($curl_handle, CURLOPT_UPLOAD, true); | ||
|  |                 } else { | ||
|  |                     curl_setopt($curl_handle, CURLOPT_POSTFIELDS, $this->request_body); | ||
|  |                 } | ||
|  |                 break; | ||
|  | 
 | ||
|  |             case self::HTTP_HEAD: | ||
|  |                 curl_setopt($curl_handle, CURLOPT_CUSTOMREQUEST, self::HTTP_HEAD); | ||
|  |                 curl_setopt($curl_handle, CURLOPT_NOBODY, 1); | ||
|  |                 break; | ||
|  | 
 | ||
|  |             default: // Assumed GET | ||
|  |                 curl_setopt($curl_handle, CURLOPT_CUSTOMREQUEST, $this->method); | ||
|  |                 if (isset($this->write_stream) || isset($this->write_file)) { | ||
|  |                     curl_setopt($curl_handle, CURLOPT_WRITEFUNCTION, array($this, 'streaming_write_callback')); | ||
|  |                     curl_setopt($curl_handle, CURLOPT_HEADER, false); | ||
|  |                 } else { | ||
|  |                     curl_setopt($curl_handle, CURLOPT_POSTFIELDS, $this->request_body); | ||
|  |                 } | ||
|  |                 break; | ||
|  |         } | ||
|  | 
 | ||
|  |         // Merge in the CURLOPTs | ||
|  |         if (isset($this->curlopts) && sizeof($this->curlopts) > 0) { | ||
|  |             foreach ($this->curlopts as $k => $v) { | ||
|  |                 curl_setopt($curl_handle, $k, $v); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         return $curl_handle; | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * Take the post-processed cURL data and break it down into useful header/body/info chunks. Uses the | ||
|  |      * data stored in the `curl_handle` and `response` properties unless replacement data is passed in via | ||
|  |      * parameters. | ||
|  |      * | ||
|  |      * @param resource $curl_handle (Optional) The reference to the already executed cURL request. | ||
|  |      * @param string $response (Optional) The actual response content itself that needs to be parsed. | ||
|  |      * @return ResponseCore A <ResponseCore> object containing a parsed HTTP response. | ||
|  |      */ | ||
|  |     public function process_response($curl_handle = null, $response = null) | ||
|  |     { | ||
|  |         // Accept a custom one if it's passed. | ||
|  |         if ($curl_handle && $response) { | ||
|  |             $this->response = $response; | ||
|  |         } | ||
|  | 
 | ||
|  |         // As long as this came back as a valid resource... | ||
|  |         if (is_resource($curl_handle)) { | ||
|  |             // Determine what's what. | ||
|  |             $header_size = curl_getinfo($curl_handle, CURLINFO_HEADER_SIZE); | ||
|  |             $this->response_headers = substr($this->response, 0, $header_size); | ||
|  |             $this->response_body = substr($this->response, $header_size); | ||
|  |             $this->response_code = curl_getinfo($curl_handle, CURLINFO_HTTP_CODE); | ||
|  |             $this->response_info = curl_getinfo($curl_handle); | ||
|  | 
 | ||
|  |             if (intval($this->response_code) / 100 != 2 && isset($this->write_file)) | ||
|  |             { | ||
|  |                 $this->response_headers = $this->response_raw_headers; | ||
|  |                 $this->response_body = $this->response_error_body; | ||
|  |             } | ||
|  | 
 | ||
|  |             // Parse out the headers | ||
|  |             $this->response_headers = explode("\r\n\r\n", trim($this->response_headers)); | ||
|  |             $this->response_headers = array_pop($this->response_headers); | ||
|  |             $this->response_headers = explode("\r\n", $this->response_headers); | ||
|  |             array_shift($this->response_headers); | ||
|  | 
 | ||
|  |             // Loop through and split up the headers. | ||
|  |             $header_assoc = array(); | ||
|  |             foreach ($this->response_headers as $header) { | ||
|  |                 $kv = explode(': ', $header); | ||
|  |                 $header_assoc[strtolower($kv[0])] = isset($kv[1]) ? $kv[1] : ''; | ||
|  |             } | ||
|  | 
 | ||
|  |             // Reset the headers to the appropriate property. | ||
|  |             $this->response_headers = $header_assoc; | ||
|  |             $this->response_headers['info'] = $this->response_info; | ||
|  |             $this->response_headers['info']['method'] = $this->method; | ||
|  | 
 | ||
|  |             if ($curl_handle && $response) { | ||
|  |                 return new ResponseCore($this->response_headers, $this->response_body, $this->response_code); | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         // Return false | ||
|  |         return false; | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * Send the request, calling necessary utility functions to update built-in properties. | ||
|  |      * | ||
|  |      * @param boolean $parse (Optional) Whether to parse the response with ResponseCore or not. | ||
|  |      * @return string The resulting unparsed data from the request. | ||
|  |      */ | ||
|  |     public function send_request($parse = false) | ||
|  |     { | ||
|  |         set_time_limit(0); | ||
|  | 
 | ||
|  |         $curl_handle = $this->prep_request(); | ||
|  |         $this->response = curl_exec($curl_handle); | ||
|  | 
 | ||
|  |         if ($this->response === false) { | ||
|  |             throw new RequestCore_Exception('cURL resource: ' . (string)$curl_handle . '; cURL error: ' . curl_error($curl_handle) . ' (' . curl_errno($curl_handle) . ')'); | ||
|  |         } | ||
|  | 
 | ||
|  |         $parsed_response = $this->process_response($curl_handle, $this->response); | ||
|  | 
 | ||
|  |         curl_close($curl_handle); | ||
|  | 
 | ||
|  |         if ($parse) { | ||
|  |             return $parsed_response; | ||
|  |         } | ||
|  | 
 | ||
|  |         return $this->response; | ||
|  |     } | ||
|  | 
 | ||
|  |     /*%******************************************************************************************%*/ | ||
|  |     // RESPONSE METHODS | ||
|  | 
 | ||
|  |     /** | ||
|  |      * Get the HTTP response headers from the request. | ||
|  |      * | ||
|  |      * @param string $header (Optional) A specific header value to return. Defaults to all headers. | ||
|  |      * @return string|array All or selected header values. | ||
|  |      */ | ||
|  |     public function get_response_header($header = null) | ||
|  |     { | ||
|  |         if ($header) { | ||
|  |             return $this->response_headers[strtolower($header)]; | ||
|  |         } | ||
|  |         return $this->response_headers; | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * Get the HTTP response body from the request. | ||
|  |      * | ||
|  |      * @return string The response body. | ||
|  |      */ | ||
|  |     public function get_response_body() | ||
|  |     { | ||
|  |         return $this->response_body; | ||
|  |     } | ||
|  | 
 | ||
|  |     /** | ||
|  |      * Get the HTTP response code from the request. | ||
|  |      * | ||
|  |      * @return string The HTTP response code. | ||
|  |      */ | ||
|  |     public function get_response_code() | ||
|  |     { | ||
|  |         return $this->response_code; | ||
|  |     } | ||
|  | } |