diff options
Diffstat (limited to 'inc/3rdparty/humble-http-agent/RollingCurl.php')
-rw-r--r-- | inc/3rdparty/humble-http-agent/RollingCurl.php | 402 |
1 files changed, 402 insertions, 0 deletions
diff --git a/inc/3rdparty/humble-http-agent/RollingCurl.php b/inc/3rdparty/humble-http-agent/RollingCurl.php new file mode 100644 index 00000000..fdd021af --- /dev/null +++ b/inc/3rdparty/humble-http-agent/RollingCurl.php | |||
@@ -0,0 +1,402 @@ | |||
1 | <?php | ||
2 | /* | ||
3 | Authored by Josh Fraser (www.joshfraser.com) | ||
4 | Released under Apache License 2.0 | ||
5 | |||
6 | Maintained by Alexander Makarov, http://rmcreative.ru/ | ||
7 | |||
8 | Modified by Keyvan Minoukadeh for the Five Filters project: http://fivefilters.org | ||
9 | */ | ||
10 | |||
11 | /** | ||
12 | * Class that represent a single curl request | ||
13 | */ | ||
14 | class RollingCurlRequest { | ||
15 | public $url = false; | ||
16 | public $url_original = false; // used for tracking redirects | ||
17 | public $method = 'GET'; | ||
18 | public $post_data = null; | ||
19 | public $headers = null; | ||
20 | public $options = null; | ||
21 | |||
22 | /** | ||
23 | * @param string $url | ||
24 | * @param string $method | ||
25 | * @param $post_data | ||
26 | * @param $headers | ||
27 | * @param $options | ||
28 | * @return void | ||
29 | */ | ||
30 | function __construct($url, $method = "GET", $post_data = null, $headers = null, $options = null) { | ||
31 | $this->url = $url; | ||
32 | $this->url_original = $url; | ||
33 | $this->method = $method; | ||
34 | $this->post_data = $post_data; | ||
35 | $this->headers = $headers; | ||
36 | $this->options = $options; | ||
37 | } | ||
38 | |||
39 | /** | ||
40 | * @param string $url | ||
41 | * @return void | ||
42 | */ | ||
43 | public function set_original_url($url) { | ||
44 | $this->url_original = $url; | ||
45 | } | ||
46 | /** | ||
47 | * @return void | ||
48 | */ | ||
49 | public function __destruct() { | ||
50 | unset($this->url, $this->url_original, $this->method, $this->post_data, $this->headers, $this->options); | ||
51 | } | ||
52 | } | ||
53 | |||
54 | /** | ||
55 | * RollingCurl custom exception | ||
56 | */ | ||
57 | class RollingCurlException extends Exception { | ||
58 | } | ||
59 | |||
60 | /** | ||
61 | * Class that holds a rolling queue of curl requests. | ||
62 | * | ||
63 | * @throws RollingCurlException | ||
64 | */ | ||
65 | class RollingCurl implements Countable { | ||
66 | /** | ||
67 | * @var int | ||
68 | * | ||
69 | * Window size is the max number of simultaneous connections allowed. | ||
70 | * | ||
71 | * REMEMBER TO RESPECT THE SERVERS: | ||
72 | * Sending too many requests at one time can easily be perceived | ||
73 | * as a DOS attack. Increase this window_size if you are making requests | ||
74 | * to multiple servers or have permission from the receving server admins. | ||
75 | */ | ||
76 | private $window_size = 5; | ||
77 | |||
78 | /** | ||
79 | * @var float | ||
80 | * | ||
81 | * Timeout is the timeout used for curl_multi_select. | ||
82 | */ | ||
83 | private $timeout = 10; | ||
84 | |||
85 | /** | ||
86 | * @var string|array | ||
87 | * | ||
88 | * Callback function to be applied to each result. | ||
89 | */ | ||
90 | private $callback; | ||
91 | |||
92 | /** | ||
93 | * @var array | ||
94 | * | ||
95 | * Set your base options that you want to be used with EVERY request. | ||
96 | */ | ||
97 | protected $options = array( | ||
98 | CURLOPT_SSL_VERIFYPEER => 0, | ||
99 | CURLOPT_RETURNTRANSFER => 1, | ||
100 | CURLOPT_CONNECTTIMEOUT => 30, | ||
101 | CURLOPT_TIMEOUT => 30 | ||
102 | ); | ||
103 | |||
104 | /** | ||
105 | * @var array | ||
106 | */ | ||
107 | private $headers = array(); | ||
108 | |||
109 | /** | ||
110 | * @var Request[] | ||
111 | * | ||
112 | * The request queue | ||
113 | */ | ||
114 | private $requests = array(); | ||
115 | |||
116 | /** | ||
117 | * @var RequestMap[] | ||
118 | * | ||
119 | * Maps handles to request indexes | ||
120 | */ | ||
121 | private $requestMap = array(); | ||
122 | |||
123 | /** | ||
124 | * @param $callback | ||
125 | * Callback function to be applied to each result. | ||
126 | * | ||
127 | * Can be specified as 'my_callback_function' | ||
128 | * or array($object, 'my_callback_method'). | ||
129 | * | ||
130 | * Function should take three parameters: $response, $info, $request. | ||
131 | * $response is response body, $info is additional curl info. | ||
132 | * $request is the original request | ||
133 | * | ||
134 | * @return void | ||
135 | */ | ||
136 | function __construct($callback = null) { | ||
137 | $this->callback = $callback; | ||
138 | } | ||
139 | |||
140 | /** | ||
141 | * @param string $name | ||
142 | * @return mixed | ||
143 | */ | ||
144 | public function __get($name) { | ||
145 | return (isset($this->{$name})) ? $this->{$name} : null; | ||
146 | } | ||
147 | |||
148 | /** | ||
149 | * @param string $name | ||
150 | * @param mixed $value | ||
151 | * @return bool | ||
152 | */ | ||
153 | public function __set($name, $value) { | ||
154 | // append the base options & headers | ||
155 | if ($name == "options" || $name == "headers") { | ||
156 | $this->{$name} = $value + $this->{$name}; | ||
157 | } else { | ||
158 | $this->{$name} = $value; | ||
159 | } | ||
160 | return true; | ||
161 | } | ||
162 | |||
163 | /** | ||
164 | * Count number of requests added (Countable interface) | ||
165 | * | ||
166 | * @return int | ||
167 | */ | ||
168 | public function count() { | ||
169 | return count($this->requests); | ||
170 | } | ||
171 | |||
172 | /** | ||
173 | * Add a request to the request queue | ||
174 | * | ||
175 | * @param Request $request | ||
176 | * @return bool | ||
177 | */ | ||
178 | public function add($request) { | ||
179 | $this->requests[] = $request; | ||
180 | return true; | ||
181 | } | ||
182 | |||
183 | /** | ||
184 | * Create new Request and add it to the request queue | ||
185 | * | ||
186 | * @param string $url | ||
187 | * @param string $method | ||
188 | * @param $post_data | ||
189 | * @param $headers | ||
190 | * @param $options | ||
191 | * @return bool | ||
192 | */ | ||
193 | public function request($url, $method = "GET", $post_data = null, $headers = null, $options = null) { | ||
194 | $this->requests[] = new RollingCurlRequest($url, $method, $post_data, $headers, $options); | ||
195 | return true; | ||
196 | } | ||
197 | |||
198 | /** | ||
199 | * Perform GET request | ||
200 | * | ||
201 | * @param string $url | ||
202 | * @param $headers | ||
203 | * @param $options | ||
204 | * @return bool | ||
205 | */ | ||
206 | public function get($url, $headers = null, $options = null) { | ||
207 | return $this->request($url, "GET", null, $headers, $options); | ||
208 | } | ||
209 | |||
210 | /** | ||
211 | * Perform POST request | ||
212 | * | ||
213 | * @param string $url | ||
214 | * @param $post_data | ||
215 | * @param $headers | ||
216 | * @param $options | ||
217 | * @return bool | ||
218 | */ | ||
219 | public function post($url, $post_data = null, $headers = null, $options = null) { | ||
220 | return $this->request($url, "POST", $post_data, $headers, $options); | ||
221 | } | ||
222 | |||
223 | /** | ||
224 | * Execute processing | ||
225 | * | ||
226 | * @param int $window_size Max number of simultaneous connections | ||
227 | * @return string|bool | ||
228 | */ | ||
229 | public function execute($window_size = null) { | ||
230 | // rolling curl window must always be greater than 1 | ||
231 | if (sizeof($this->requests) == 1) { | ||
232 | return $this->single_curl(); | ||
233 | } else { | ||
234 | // start the rolling curl. window_size is the max number of simultaneous connections | ||
235 | return $this->rolling_curl($window_size); | ||
236 | } | ||
237 | } | ||
238 | |||
239 | /** | ||
240 | * Performs a single curl request | ||
241 | * | ||
242 | * @access private | ||
243 | * @return string | ||
244 | */ | ||
245 | private function single_curl() { | ||
246 | $ch = curl_init(); | ||
247 | $request = array_shift($this->requests); | ||
248 | $options = $this->get_options($request); | ||
249 | curl_setopt_array($ch, $options); | ||
250 | $output = curl_exec($ch); | ||
251 | $info = curl_getinfo($ch); | ||
252 | |||
253 | // it's not neccesary to set a callback for one-off requests | ||
254 | if ($this->callback) { | ||
255 | $callback = $this->callback; | ||
256 | if (is_callable($this->callback)) { | ||
257 | call_user_func($callback, $output, $info, $request); | ||
258 | } | ||
259 | } | ||
260 | else | ||
261 | return $output; | ||
262 | return true; | ||
263 | } | ||
264 | |||
265 | /** | ||
266 | * Performs multiple curl requests | ||
267 | * | ||
268 | * @access private | ||
269 | * @throws RollingCurlException | ||
270 | * @param int $window_size Max number of simultaneous connections | ||
271 | * @return bool | ||
272 | */ | ||
273 | private function rolling_curl($window_size = null) { | ||
274 | if ($window_size) | ||
275 | $this->window_size = $window_size; | ||
276 | |||
277 | // make sure the rolling window isn't greater than the # of urls | ||
278 | if (sizeof($this->requests) < $this->window_size) | ||
279 | $this->window_size = sizeof($this->requests); | ||
280 | |||
281 | if ($this->window_size < 2) { | ||
282 | throw new RollingCurlException("Window size must be greater than 1"); | ||
283 | } | ||
284 | |||
285 | $master = curl_multi_init(); | ||
286 | |||
287 | // start the first batch of requests | ||
288 | for ($i = 0; $i < $this->window_size; $i++) { | ||
289 | $ch = curl_init(); | ||
290 | |||
291 | $options = $this->get_options($this->requests[$i]); | ||
292 | |||
293 | curl_setopt_array($ch, $options); | ||
294 | curl_multi_add_handle($master, $ch); | ||
295 | |||
296 | // Add to our request Maps | ||
297 | $key = (string) $ch; | ||
298 | $this->requestMap[$key] = $i; | ||
299 | } | ||
300 | |||
301 | do { | ||
302 | while (($execrun = curl_multi_exec($master, $running)) == CURLM_CALL_MULTI_PERFORM) ; | ||
303 | if ($execrun != CURLM_OK) | ||
304 | break; | ||
305 | // a request was just completed -- find out which one | ||
306 | while ($done = curl_multi_info_read($master)) { | ||
307 | |||
308 | // get the info and content returned on the request | ||
309 | $info = curl_getinfo($done['handle']); | ||
310 | $output = curl_multi_getcontent($done['handle']); | ||
311 | |||
312 | // send the return values to the callback function. | ||
313 | $callback = $this->callback; | ||
314 | if (is_callable($callback)) { | ||
315 | $key = (string) $done['handle']; | ||
316 | $request = $this->requests[$this->requestMap[$key]]; | ||
317 | unset($this->requestMap[$key]); | ||
318 | call_user_func($callback, $output, $info, $request); | ||
319 | } | ||
320 | |||
321 | // start a new request (it's important to do this before removing the old one) | ||
322 | if ($i < sizeof($this->requests) && isset($this->requests[$i]) && $i < count($this->requests)) { | ||
323 | $ch = curl_init(); | ||
324 | $options = $this->get_options($this->requests[$i]); | ||
325 | curl_setopt_array($ch, $options); | ||
326 | curl_multi_add_handle($master, $ch); | ||
327 | |||
328 | // Add to our request Maps | ||
329 | $key = (string) $ch; | ||
330 | $this->requestMap[$key] = $i; | ||
331 | $i++; | ||
332 | } | ||
333 | |||
334 | // remove the curl handle that just completed | ||
335 | curl_multi_remove_handle($master, $done['handle']); | ||
336 | |||
337 | } | ||
338 | |||
339 | // Block for data in / output; error handling is done by curl_multi_exec | ||
340 | //if ($running) curl_multi_select($master, $this->timeout); | ||
341 | // removing timeout as it causes problems on Windows with PHP 5.3.5 and Curl 7.20.0 | ||
342 | if ($running) curl_multi_select($master); | ||
343 | |||
344 | } while ($running); | ||
345 | curl_multi_close($master); | ||
346 | return true; | ||
347 | } | ||
348 | |||
349 | |||
350 | /** | ||
351 | * Helper function to set up a new request by setting the appropriate options | ||
352 | * | ||
353 | * @access private | ||
354 | * @param Request $request | ||
355 | * @return array | ||
356 | */ | ||
357 | private function get_options($request) { | ||
358 | // options for this entire curl object | ||
359 | $options = $this->__get('options'); | ||
360 | // We're managing reirects in PHP - allows us to intervene and rewrite/block URLs | ||
361 | // before the next request goes out. | ||
362 | $options[CURLOPT_FOLLOWLOCATION] = 0; | ||
363 | $options[CURLOPT_MAXREDIRS] = 0; | ||
364 | //if (ini_get('safe_mode') == 'Off' || !ini_get('safe_mode')) { | ||
365 | // $options[CURLOPT_FOLLOWLOCATION] = 1; | ||
366 | // $options[CURLOPT_MAXREDIRS] = 5; | ||
367 | //} | ||
368 | $headers = $this->__get('headers'); | ||
369 | // append custom headers for this specific request | ||
370 | if ($request->headers) { | ||
371 | $headers = $headers + $request->headers; | ||
372 | } | ||
373 | |||
374 | // append custom options for this specific request | ||
375 | if ($request->options) { | ||
376 | $options = $request->options + $options; | ||
377 | } | ||
378 | |||
379 | // set the request URL | ||
380 | $options[CURLOPT_URL] = $request->url; | ||
381 | |||
382 | if ($headers) { | ||
383 | $options[CURLOPT_HTTPHEADER] = $headers; | ||
384 | } | ||
385 | // return response headers | ||
386 | $options[CURLOPT_HEADER] = 1; | ||
387 | |||
388 | // send HEAD request? | ||
389 | if ($request->method == 'HEAD') { | ||
390 | $options[CURLOPT_NOBODY] = 1; | ||
391 | } | ||
392 | |||
393 | return $options; | ||
394 | } | ||
395 | |||
396 | /** | ||
397 | * @return void | ||
398 | */ | ||
399 | public function __destruct() { | ||
400 | unset($this->window_size, $this->callback, $this->options, $this->headers, $this->requests); | ||
401 | } | ||
402 | } \ No newline at end of file | ||