-<?php
-/*
-Authored by Josh Fraser (www.joshfraser.com)
-Released under Apache License 2.0
-
-Maintained by Alexander Makarov, http://rmcreative.ru/
-
-Modified by Keyvan Minoukadeh for the Five Filters project: http://fivefilters.org
-*/
-
-/**
- * Class that represent a single curl request
- */
-class RollingCurlRequest {
- public $url = false;
- public $url_original = false; // used for tracking redirects
- public $method = 'GET';
- public $post_data = null;
- public $headers = null;
- public $options = null;
-
- /**
- * @param string $url
- * @param string $method
- * @param $post_data
- * @param $headers
- * @param $options
- * @return void
- */
- function __construct($url, $method = "GET", $post_data = null, $headers = null, $options = null) {
- $this->url = $url;
- $this->url_original = $url;
- $this->method = $method;
- $this->post_data = $post_data;
- $this->headers = $headers;
- $this->options = $options;
- }
-
- /**
- * @param string $url
- * @return void
- */
- public function set_original_url($url) {
- $this->url_original = $url;
- }
- /**
- * @return void
- */
- public function __destruct() {
- unset($this->url, $this->url_original, $this->method, $this->post_data, $this->headers, $this->options);
- }
-}
-
-/**
- * RollingCurl custom exception
- */
-class RollingCurlException extends Exception {
-}
-
-/**
- * Class that holds a rolling queue of curl requests.
- *
- * @throws RollingCurlException
- */
-class RollingCurl implements Countable {
- /**
- * @var int
- *
- * Window size is the max number of simultaneous connections allowed.
- *
- * REMEMBER TO RESPECT THE SERVERS:
- * Sending too many requests at one time can easily be perceived
- * as a DOS attack. Increase this window_size if you are making requests
- * to multiple servers or have permission from the receving server admins.
- */
- private $window_size = 5;
-
- /**
- * @var float
- *
- * Timeout is the timeout used for curl_multi_select.
- */
- private $timeout = 10;
-
- /**
- * @var string|array
- *
- * Callback function to be applied to each result.
- */
- private $callback;
-
- /**
- * @var array
- *
- * Set your base options that you want to be used with EVERY request.
- */
- protected $options = array(
- CURLOPT_SSL_VERIFYPEER => 0,
- CURLOPT_RETURNTRANSFER => 1,
- CURLOPT_CONNECTTIMEOUT => 30,
- CURLOPT_TIMEOUT => 30
- );
-
- /**
- * @var array
- */
- private $headers = array();
-
- /**
- * @var Request[]
- *
- * The request queue
- */
- private $requests = array();
-
- /**
- * @var RequestMap[]
- *
- * Maps handles to request indexes
- */
- private $requestMap = array();
-
- /**
- * @param $callback
- * Callback function to be applied to each result.
- *
- * Can be specified as 'my_callback_function'
- * or array($object, 'my_callback_method').
- *
- * Function should take three parameters: $response, $info, $request.
- * $response is response body, $info is additional curl info.
- * $request is the original request
- *
- * @return void
- */
- function __construct($callback = null) {
- $this->callback = $callback;
- }
-
- /**
- * @param string $name
- * @return mixed
- */
- public function __get($name) {
- return (isset($this->{$name})) ? $this->{$name} : null;
- }
-
- /**
- * @param string $name
- * @param mixed $value
- * @return bool
- */
- public function __set($name, $value) {
- // append the base options & headers
- if ($name == "options" || $name == "headers") {
- $this->{$name} = $value + $this->{$name};
- } else {
- $this->{$name} = $value;
- }
- return true;
- }
-
- /**
- * Count number of requests added (Countable interface)
- *
- * @return int
- */
- public function count() {
- return count($this->requests);
- }
-
- /**
- * Add a request to the request queue
- *
- * @param Request $request
- * @return bool
- */
- public function add($request) {
- $this->requests[] = $request;
- return true;
- }
-
- /**
- * Create new Request and add it to the request queue
- *
- * @param string $url
- * @param string $method
- * @param $post_data
- * @param $headers
- * @param $options
- * @return bool
- */
- public function request($url, $method = "GET", $post_data = null, $headers = null, $options = null) {
- $this->requests[] = new RollingCurlRequest($url, $method, $post_data, $headers, $options);
- return true;
- }
-
- /**
- * Perform GET request
- *
- * @param string $url
- * @param $headers
- * @param $options
- * @return bool
- */
- public function get($url, $headers = null, $options = null) {
- return $this->request($url, "GET", null, $headers, $options);
- }
-
- /**
- * Perform POST request
- *
- * @param string $url
- * @param $post_data
- * @param $headers
- * @param $options
- * @return bool
- */
- public function post($url, $post_data = null, $headers = null, $options = null) {
- return $this->request($url, "POST", $post_data, $headers, $options);
- }
-
- /**
- * Execute processing
- *
- * @param int $window_size Max number of simultaneous connections
- * @return string|bool
- */
- public function execute($window_size = null) {
- // rolling curl window must always be greater than 1
- if (sizeof($this->requests) == 1) {
- return $this->single_curl();
- } else {
- // start the rolling curl. window_size is the max number of simultaneous connections
- return $this->rolling_curl($window_size);
- }
- }
-
- /**
- * Performs a single curl request
- *
- * @access private
- * @return string
- */
- private function single_curl() {
- $ch = curl_init();
- $request = array_shift($this->requests);
- $options = $this->get_options($request);
- curl_setopt_array($ch, $options);
- $output = curl_exec($ch);
- $info = curl_getinfo($ch);
-
- // it's not neccesary to set a callback for one-off requests
- if ($this->callback) {
- $callback = $this->callback;
- if (is_callable($this->callback)) {
- call_user_func($callback, $output, $info, $request);
- }
- }
- else
- return $output;
- return true;
- }
-
- /**
- * Performs multiple curl requests
- *
- * @access private
- * @throws RollingCurlException
- * @param int $window_size Max number of simultaneous connections
- * @return bool
- */
- private function rolling_curl($window_size = null) {
- if ($window_size)
- $this->window_size = $window_size;
-
- // make sure the rolling window isn't greater than the # of urls
- if (sizeof($this->requests) < $this->window_size)
- $this->window_size = sizeof($this->requests);
-
- if ($this->window_size < 2) {
- throw new RollingCurlException("Window size must be greater than 1");
- }
-
- $master = curl_multi_init();
-
- // start the first batch of requests
- for ($i = 0; $i < $this->window_size; $i++) {
- $ch = curl_init();
-
- $options = $this->get_options($this->requests[$i]);
-
- curl_setopt_array($ch, $options);
- curl_multi_add_handle($master, $ch);
-
- // Add to our request Maps
- $key = (string) $ch;
- $this->requestMap[$key] = $i;
- }
-
- do {
- while (($execrun = curl_multi_exec($master, $running)) == CURLM_CALL_MULTI_PERFORM) ;
- if ($execrun != CURLM_OK)
- break;
- // a request was just completed -- find out which one
- while ($done = curl_multi_info_read($master)) {
-
- // get the info and content returned on the request
- $info = curl_getinfo($done['handle']);
- $output = curl_multi_getcontent($done['handle']);
-
- // send the return values to the callback function.
- $callback = $this->callback;
- if (is_callable($callback)) {
- $key = (string) $done['handle'];
- $request = $this->requests[$this->requestMap[$key]];
- unset($this->requestMap[$key]);
- call_user_func($callback, $output, $info, $request);
- }
-
- // start a new request (it's important to do this before removing the old one)
- if ($i < sizeof($this->requests) && isset($this->requests[$i]) && $i < count($this->requests)) {
- $ch = curl_init();
- $options = $this->get_options($this->requests[$i]);
- curl_setopt_array($ch, $options);
- curl_multi_add_handle($master, $ch);
-
- // Add to our request Maps
- $key = (string) $ch;
- $this->requestMap[$key] = $i;
- $i++;
- }
-
- // remove the curl handle that just completed
- curl_multi_remove_handle($master, $done['handle']);
-
- }
-
- // Block for data in / output; error handling is done by curl_multi_exec
- //if ($running) curl_multi_select($master, $this->timeout);
- // removing timeout as it causes problems on Windows with PHP 5.3.5 and Curl 7.20.0
- if ($running) curl_multi_select($master);
-
- } while ($running);
- curl_multi_close($master);
- return true;
- }
-
-
- /**
- * Helper function to set up a new request by setting the appropriate options
- *
- * @access private
- * @param Request $request
- * @return array
- */
- private function get_options($request) {
- // options for this entire curl object
- $options = $this->__get('options');
- // We're managing reirects in PHP - allows us to intervene and rewrite/block URLs
- // before the next request goes out.
- $options[CURLOPT_FOLLOWLOCATION] = 0;
- $options[CURLOPT_MAXREDIRS] = 0;
- //if (ini_get('safe_mode') == 'Off' || !ini_get('safe_mode')) {
- // $options[CURLOPT_FOLLOWLOCATION] = 1;
- // $options[CURLOPT_MAXREDIRS] = 5;
- //}
- $headers = $this->__get('headers');
- // append custom headers for this specific request
- if ($request->headers) {
- $headers = $headers + $request->headers;
- }
-
- // append custom options for this specific request
- if ($request->options) {
- $options = $request->options + $options;
- }
-
- // set the request URL
- $options[CURLOPT_URL] = $request->url;
-
- if ($headers) {
- $options[CURLOPT_HTTPHEADER] = $headers;
- }
- // return response headers
- $options[CURLOPT_HEADER] = 1;
-
- // send HEAD request?
- if ($request->method == 'HEAD') {
- $options[CURLOPT_NOBODY] = 1;
- }
-
- return $options;
- }
-
- /**
- * @return void
- */
- public function __destruct() {
- unset($this->window_size, $this->callback, $this->options, $this->headers, $this->requests);
- }
+<?php\r
+/*\r
+Authored by Josh Fraser (www.joshfraser.com)\r
+Released under Apache License 2.0\r
+\r
+Maintained by Alexander Makarov, http://rmcreative.ru/\r
+\r
+Modified by Keyvan Minoukadeh for the Five Filters project: http://fivefilters.org\r
+*/\r
+\r
+/**\r
+ * Class that represent a single curl request\r
+ */\r
+class RollingCurlRequest {\r
+ public $url = false;\r
+ public $url_original = false; // used for tracking redirects\r
+ public $method = 'GET';\r
+ public $post_data = null;\r
+ public $headers = null;\r
+ public $options = null;\r
+\r
+ /**\r
+ * @param string $url\r
+ * @param string $method\r
+ * @param $post_data\r
+ * @param $headers\r
+ * @param $options\r
+ * @return void\r
+ */\r
+ function __construct($url, $method = "GET", $post_data = null, $headers = null, $options = null) {\r
+ $this->url = $url;\r
+ $this->url_original = $url;\r
+ $this->method = $method;\r
+ $this->post_data = $post_data;\r
+ $this->headers = $headers;\r
+ $this->options = $options;\r
+ }\r
+ \r
+ /**\r
+ * @param string $url\r
+ * @return void\r
+ */\r
+ public function set_original_url($url) {\r
+ $this->url_original = $url;\r
+ }\r
+ /**\r
+ * @return void\r
+ */\r
+ public function __destruct() {\r
+ unset($this->url, $this->url_original, $this->method, $this->post_data, $this->headers, $this->options);\r
+ }\r
+}\r
+\r
+/**\r
+ * RollingCurl custom exception\r
+ */\r
+class RollingCurlException extends Exception {\r
+}\r
+\r
+/**\r
+ * Class that holds a rolling queue of curl requests.\r
+ *\r
+ * @throws RollingCurlException\r
+ */\r
+class RollingCurl implements Countable {\r
+ /**\r
+ * @var int\r
+ *\r
+ * Window size is the max number of simultaneous connections allowed.\r
+ *\r
+ * REMEMBER TO RESPECT THE SERVERS:\r
+ * Sending too many requests at one time can easily be perceived\r
+ * as a DOS attack. Increase this window_size if you are making requests\r
+ * to multiple servers or have permission from the receving server admins.\r
+ */\r
+ private $window_size = 5;\r
+\r
+ /**\r
+ * @var float\r
+ *\r
+ * Timeout is the timeout used for curl_multi_select.\r
+ */\r
+ private $timeout = 10;\r
+\r
+ /**\r
+ * @var string|array\r
+ *\r
+ * Callback function to be applied to each result.\r
+ */\r
+ private $callback;\r
+\r
+ /**\r
+ * @var array\r
+ *\r
+ * Set your base options that you want to be used with EVERY request.\r
+ */\r
+ protected $options = array(\r
+ CURLOPT_SSL_VERIFYPEER => 0,\r
+ CURLOPT_RETURNTRANSFER => 1,\r
+ CURLOPT_CONNECTTIMEOUT => 30,\r
+ CURLOPT_TIMEOUT => 30\r
+ );\r
+\r
+ /**\r
+ * @var array\r
+ */\r
+ private $headers = array();\r
+\r
+ /**\r
+ * @var Request[]\r
+ *\r
+ * The request queue\r
+ */\r
+ private $requests = array();\r
+\r
+ /**\r
+ * @var RequestMap[]\r
+ *\r
+ * Maps handles to request indexes\r
+ */\r
+ private $requestMap = array();\r
+\r
+ /**\r
+ * @param $callback\r
+ * Callback function to be applied to each result.\r
+ *\r
+ * Can be specified as 'my_callback_function'\r
+ * or array($object, 'my_callback_method').\r
+ *\r
+ * Function should take three parameters: $response, $info, $request.\r
+ * $response is response body, $info is additional curl info.\r
+ * $request is the original request\r
+ *\r
+ * @return void\r
+ */\r
+ function __construct($callback = null) {\r
+ $this->callback = $callback;\r
+ }\r
+\r
+ /**\r
+ * @param string $name\r
+ * @return mixed\r
+ */\r
+ public function __get($name) {\r
+ return (isset($this->{$name})) ? $this->{$name} : null;\r
+ }\r
+\r
+ /**\r
+ * @param string $name\r
+ * @param mixed $value\r
+ * @return bool\r
+ */\r
+ public function __set($name, $value) {\r
+ // append the base options & headers\r
+ if ($name == "options" || $name == "headers") {\r
+ $this->{$name} = $value + $this->{$name};\r
+ } else {\r
+ $this->{$name} = $value;\r
+ }\r
+ return true;\r
+ }\r
+\r
+ /**\r
+ * Count number of requests added (Countable interface)\r
+ *\r
+ * @return int\r
+ */\r
+ public function count() {\r
+ return count($this->requests);\r
+ } \r
+ \r
+ /**\r
+ * Add a request to the request queue\r
+ *\r
+ * @param Request $request\r
+ * @return bool\r
+ */\r
+ public function add($request) {\r
+ $this->requests[] = $request;\r
+ return true;\r
+ }\r
+\r
+ /**\r
+ * Create new Request and add it to the request queue\r
+ *\r
+ * @param string $url\r
+ * @param string $method\r
+ * @param $post_data\r
+ * @param $headers\r
+ * @param $options\r
+ * @return bool\r
+ */\r
+ public function request($url, $method = "GET", $post_data = null, $headers = null, $options = null) {\r
+ $this->requests[] = new RollingCurlRequest($url, $method, $post_data, $headers, $options);\r
+ return true;\r
+ }\r
+\r
+ /**\r
+ * Perform GET request\r
+ *\r
+ * @param string $url\r
+ * @param $headers\r
+ * @param $options\r
+ * @return bool\r
+ */\r
+ public function get($url, $headers = null, $options = null) {\r
+ return $this->request($url, "GET", null, $headers, $options);\r
+ }\r
+\r
+ /**\r
+ * Perform POST request\r
+ *\r
+ * @param string $url\r
+ * @param $post_data\r
+ * @param $headers\r
+ * @param $options\r
+ * @return bool\r
+ */\r
+ public function post($url, $post_data = null, $headers = null, $options = null) {\r
+ return $this->request($url, "POST", $post_data, $headers, $options);\r
+ }\r
+\r
+ /**\r
+ * Execute processing\r
+ *\r
+ * @param int $window_size Max number of simultaneous connections\r
+ * @return string|bool\r
+ */\r
+ public function execute($window_size = null) {\r
+ // rolling curl window must always be greater than 1\r
+ if (sizeof($this->requests) == 1) {\r
+ return $this->single_curl();\r
+ } else {\r
+ // start the rolling curl. window_size is the max number of simultaneous connections\r
+ return $this->rolling_curl($window_size);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Performs a single curl request\r
+ *\r
+ * @access private\r
+ * @return string\r
+ */\r
+ private function single_curl() {\r
+ $ch = curl_init();\r
+ $request = array_shift($this->requests);\r
+ $options = $this->get_options($request);\r
+ curl_setopt_array($ch, $options);\r
+ $output = curl_exec($ch);\r
+ $info = curl_getinfo($ch);\r
+\r
+ // it's not neccesary to set a callback for one-off requests\r
+ if ($this->callback) {\r
+ $callback = $this->callback;\r
+ if (is_callable($this->callback)) {\r
+ call_user_func($callback, $output, $info, $request);\r
+ }\r
+ }\r
+ else\r
+ return $output;\r
+ return true;\r
+ }\r
+\r
+ /**\r
+ * Performs multiple curl requests\r
+ *\r
+ * @access private\r
+ * @throws RollingCurlException\r
+ * @param int $window_size Max number of simultaneous connections\r
+ * @return bool\r
+ */\r
+ private function rolling_curl($window_size = null) {\r
+ if ($window_size)\r
+ $this->window_size = $window_size;\r
+\r
+ // make sure the rolling window isn't greater than the # of urls\r
+ if (sizeof($this->requests) < $this->window_size)\r
+ $this->window_size = sizeof($this->requests);\r
+\r
+ if ($this->window_size < 2) {\r
+ throw new RollingCurlException("Window size must be greater than 1");\r
+ }\r
+\r
+ $master = curl_multi_init();\r
+\r
+ // start the first batch of requests\r
+ for ($i = 0; $i < $this->window_size; $i++) {\r
+ $ch = curl_init();\r
+\r
+ $options = $this->get_options($this->requests[$i]);\r
+\r
+ curl_setopt_array($ch, $options);\r
+ curl_multi_add_handle($master, $ch);\r
+\r
+ // Add to our request Maps\r
+ $key = (string) $ch;\r
+ $this->requestMap[$key] = $i;\r
+ }\r
+\r
+ do {\r
+ while (($execrun = curl_multi_exec($master, $running)) == CURLM_CALL_MULTI_PERFORM) ;\r
+ if ($execrun != CURLM_OK)\r
+ break;\r
+ // a request was just completed -- find out which one\r
+ while ($done = curl_multi_info_read($master)) {\r
+\r
+ // get the info and content returned on the request\r
+ $info = curl_getinfo($done['handle']);\r
+ $output = curl_multi_getcontent($done['handle']);\r
+\r
+ // send the return values to the callback function.\r
+ $callback = $this->callback;\r
+ if (is_callable($callback)) {\r
+ $key = (string) $done['handle'];\r
+ $request = $this->requests[$this->requestMap[$key]];\r
+ unset($this->requestMap[$key]);\r
+ call_user_func($callback, $output, $info, $request);\r
+ }\r
+\r
+ // start a new request (it's important to do this before removing the old one)\r
+ if ($i < sizeof($this->requests) && isset($this->requests[$i]) && $i < count($this->requests)) {\r
+ $ch = curl_init();\r
+ $options = $this->get_options($this->requests[$i]);\r
+ curl_setopt_array($ch, $options);\r
+ curl_multi_add_handle($master, $ch);\r
+\r
+ // Add to our request Maps\r
+ $key = (string) $ch;\r
+ $this->requestMap[$key] = $i;\r
+ $i++;\r
+ }\r
+\r
+ // remove the curl handle that just completed\r
+ curl_multi_remove_handle($master, $done['handle']);\r
+\r
+ }\r
+\r
+ // Block for data in / output; error handling is done by curl_multi_exec\r
+ //if ($running) curl_multi_select($master, $this->timeout);\r
+ // removing timeout as it causes problems on Windows with PHP 5.3.5 and Curl 7.20.0\r
+ if ($running) curl_multi_select($master);\r
+\r
+ } while ($running);\r
+ curl_multi_close($master);\r
+ return true;\r
+ }\r
+\r
+\r
+ /**\r
+ * Helper function to set up a new request by setting the appropriate options\r
+ *\r
+ * @access private\r
+ * @param Request $request\r
+ * @return array\r
+ */\r
+ private function get_options($request) {\r
+ // options for this entire curl object\r
+ $options = $this->__get('options');\r
+ // We're managing reirects in PHP - allows us to intervene and rewrite/block URLs\r
+ // before the next request goes out.\r
+ $options[CURLOPT_FOLLOWLOCATION] = 0;\r
+ $options[CURLOPT_MAXREDIRS] = 0;\r
+ //if (ini_get('safe_mode') == 'Off' || !ini_get('safe_mode')) {\r
+ // $options[CURLOPT_FOLLOWLOCATION] = 1;\r
+ // $options[CURLOPT_MAXREDIRS] = 5;\r
+ //}\r
+ $headers = $this->__get('headers');\r
+ // append custom headers for this specific request\r
+ if ($request->headers) {\r
+ $headers = $headers + $request->headers;\r
+ }\r
+\r
+ // append custom options for this specific request\r
+ if ($request->options) {\r
+ $options = $request->options + $options;\r
+ }\r
+\r
+ // set the request URL\r
+ $options[CURLOPT_URL] = $request->url;\r
+\r
+ if ($headers) {\r
+ $options[CURLOPT_HTTPHEADER] = $headers;\r
+ }\r
+ // return response headers\r
+ $options[CURLOPT_HEADER] = 1;\r
+ \r
+ // send HEAD request?\r
+ if ($request->method == 'HEAD') {\r
+ $options[CURLOPT_NOBODY] = 1;\r
+ }\r
+\r
+ return $options;\r
+ }\r
+\r
+ /**\r
+ * @return void\r
+ */\r
+ public function __destruct() {\r
+ unset($this->window_size, $this->callback, $this->options, $this->headers, $this->requests);\r
+ }\r
}
\ No newline at end of file