<?php
class
RollingCurlRequest {
public
$url
= false;
public
$method
=
'GET'
;
public
$post_data
= null;
public
$headers
= null;
public
$options
= null;
public
$info
= null;
public
$callback
;
public
$recursion
= false;
function
__construct(
$url
,
$options
= null,
$info
= null,
$method
=
"GET"
,
$post_data
= null,
$headers
= null ) {
$this
->url =
$url
;
$this
->method =
$method
;
$this
->post_data =
$post_data
;
$this
->headers =
$headers
;
$this
->options =
$options
;
$this
->info =
$info
;
}
public
function
__destruct() {
unset(
$this
->url,
$this
->method,
$this
->post_data,
$this
->headers,
$this
->options);
}
}
class
RollingCurlException
extends
Exception {
}
class
RollingCurl {
private
$window_size
= 5;
public
$current_size
=0;
private
$timeout
= 10;
protected
$options
=
array
(
CURLOPT_SSL_VERIFYPEER => 0,
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_VERBOSE => 0,
CURLOPT_TIMEOUT => 20,
CURLOPT_DNS_CACHE_TIMEOUT => 3600,
CURLOPT_CONNECTTIMEOUT => 10,
CURLOPT_ENCODING =>
'gzip,deflate'
,
CURLOPT_FOLLOWLOCATION => 1,
CURLOPT_MAXREDIRS => 2,
CURLOPT_USERAGENT =>
'Mozilla/5.0 (Windows NT 6.3; WOW64; rv:31.0) Gecko/20100101 Firefox/31.0'
,
);
private
$headers
=
array
(
'Connection: Keep-Alive'
,
'Keep-Alive: 300'
,
'Expect:'
);
private
$requests
=
array
();
private
$requestMap
=
array
();
function
__construct(
$callback
= null) {
$this
->callback =
$callback
;
}
public
function
__get(
$name
) {
return
(isset(
$this
->{
$name
})) ?
$this
->{
$name
} : null;
}
public
function
__set(
$name
,
$value
) {
if
(
$name
==
"options"
||
$name
==
"headers"
) {
$this
->{
$name
} =
$value
+
$this
->{
$name
};
}
else
{
$this
->{
$name
} =
$value
;
}
return
true;
}
public
function
add(
$request
) {
$this
->requests[] =
$request
;
return
true;
}
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;
}
public
function
get(
$url
,
$headers
= null,
$options
= null) {
return
$this
->request(
$url
,
"GET"
, null,
$headers
,
$options
);
}
public
function
post(
$url
,
$post_data
= null,
$headers
= null,
$options
= null) {
return
$this
->request(
$url
,
"POST"
,
$post_data
,
$headers
,
$options
);
}
public
function
execute(
$window_size
= null) {
if
(sizeof(
$this
->requests) == 1) {
return
$this
->single_curl();
}
else
{
return
$this
->rolling_curl(
$window_size
);
}
}
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
);
if
(curl_error(
$ch
))
$info
[
'error'
] = curl_error(
$ch
);
if
(
$request
->callback) {
$callback
=
$request
->callback;
if
(
is_callable
(
$callback
)) {
call_user_func(
$callback
,
$output
,
$info
,
$request
);
}
}
else
return
$output
;
return
true;
}
private
function
rolling_curl(
$window_size
= null) {
if
(
$window_size
)
$this
->window_size =
$window_size
;
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();
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
);
$key
= (int)
$ch
;
$chs
[
$key
] =
$ch
;
$this
->requestMap[
$key
] =
$i
;
$this
->current_size++;
}
do
{
do
{
$execrun
= curl_multi_exec(
$master
,
$running
);
}
while
(
$execrun
== CURLM_CALL_MULTI_PERFORM);
if
(
$execrun
!= CURLM_OK)
echo
"ERROR!\n "
. curl_multi_strerror(
$execrun
);
if
(
$running
)
curl_multi_select(
$master
,
$this
->timeout);
while
(
$done
= curl_multi_info_read(
$master
)) {
$ch
=
$done
[
'handle'
];
$info
= curl_getinfo(
$ch
);
$output
= curl_multi_getcontent(
$ch
);
if
(
$done
[
'result'
] != CURLE_OK)
$info
[
'error'
] = curl_error(
$ch
);
$key
= (int)
$ch
;
$request
=
$this
->requests[
$this
->requestMap[
$key
]];
$callback
=
$request
->callback;
if
(
is_callable
(
$callback
)) {
unset(
$this
->requests[
$this
->requestMap[
$key
]]);
unset(
$this
->requestMap[
$key
]);
$this
->current_size--;
call_user_func(
$callback
,
$output
,
$info
,
$request
);
}
curl_multi_remove_handle(
$master
,
$done
[
'handle'
]);
if
(isset(
$this
->requests[
$i
])) {
$ch
=
$chs
[
$key
];
$options
=
$this
->get_options(
$this
->requests[
$i
]);
curl_setopt_array(
$ch
,
$options
);
curl_multi_add_handle(
$master
,
$ch
);
$key
= (int)
$ch
;
$this
->requestMap[
$key
] =
$i
;
$this
->current_size++;
$i
++;
}
}
}
while
(
$this
->current_size) ;
curl_multi_close(
$master
);
return
true;
}
public
function
state() {
return
curl_multi_select(
$this
->master,
$this
->timeout);
}
private
function
get_options(
$request
) {
$options
=
$this
->__get(
'options'
);
if
(
ini_get
(
'safe_mode'
) ==
'Off'
|| !
ini_get
(
'safe_mode'
)) {
$options
[CURLOPT_FOLLOWLOCATION] = 1;
$options
[CURLOPT_MAXREDIRS] = 5;
}
if
(
$request
->options) {
$options
=
$request
->options +
$options
;
}
$headers
=
$this
->__get(
'headers'
);
if
(
$request
->headers) {
$headers
=
$request
->headers +
$headers
;
}
$options
[CURLOPT_URL] =
$request
->url;
if
(
$request
->post_data) {
$options
[CURLOPT_POST] = 1;
$options
[CURLOPT_POSTFIELDS] =
$request
->post_data;
}
if
(
$headers
) {
$options
[CURLOPT_HEADER] = 0;
$options
[CURLOPT_HTTPHEADER] =
$headers
;
}
return
$options
;
}
public
function
__destruct() {
unset(
$this
->window_size,
$this
->callback,
$this
->options,
$this
->headers,
$this
->requests);
}
Function test() {
var_dump(
$this
->requests);
}
}