Merge pull request #419 from zachborboa/master

Process multicurl requests in ascending numerical order
This commit is contained in:
Zach Borboa
2016-12-25 02:05:52 -05:00
committed by GitHub
6 changed files with 153 additions and 172 deletions
-3
View File
@@ -242,9 +242,6 @@ Curl::setXmlDecoder($function)
Curl::success($callback)
Curl::unsetHeader($key)
Curl::verbose($on = true, $output = STDERR)
Curl::array_flatten_multidim($array, $prefix = false)
Curl::is_array_assoc($array)
Curl::is_array_multidim($array)
MultiCurl::__construct($base_url = null)
MultiCurl::__destruct()
MultiCurl::addCurl(Curl $curl)
+80
View File
@@ -0,0 +1,80 @@
<?php
namespace Curl;
class ArrayUtil
{
/**
* Is Array Assoc
*
* @access public
* @param $array
*
* @return boolean
*/
public static function is_array_assoc($array)
{
return (bool)count(array_filter(array_keys($array), 'is_string'));
}
/**
* Is Array Multidim
*
* @access public
* @param $array
*
* @return boolean
*/
public static function is_array_multidim($array)
{
if (!is_array($array)) {
return false;
}
return (bool)count(array_filter($array, 'is_array'));
}
/**
* Array Flatten Multidim
*
* @access public
* @param $array
* @param $prefix
*
* @return array
*/
public static function array_flatten_multidim($array, $prefix = false)
{
$return = array();
if (is_array($array) || is_object($array)) {
if (empty($array)) {
$return[$prefix] = '';
} else {
foreach ($array as $key => $value) {
if (is_scalar($value)) {
if ($prefix) {
$return[$prefix . '[' . $key . ']'] = $value;
} else {
$return[$key] = $value;
}
} else {
if ($value instanceof \CURLFile) {
$return[$key] = $value;
} else {
$return = array_merge(
$return,
self::array_flatten_multidim(
$value,
$prefix ? $prefix . '[' . $key . ']' : $key
)
);
}
}
}
}
} elseif ($array === null) {
$return[$prefix] = $array;
}
return $return;
}
}
+35 -109
View File
@@ -7,39 +7,6 @@ class Curl
const VERSION = '7.1.0';
const DEFAULT_TIMEOUT = 30;
public static $RFC2616 = array(
// RFC2616: "any CHAR except CTLs or separators".
// CHAR = <any US-ASCII character (octets 0 - 127)>
// CTL = <any US-ASCII control character
// (octets 0 - 31) and DEL (127)>
// separators = "(" | ")" | "<" | ">" | "@"
// | "," | ";" | ":" | "\" | <">
// | "/" | "[" | "]" | "?" | "="
// | "{" | "}" | SP | HT
// SP = <US-ASCII SP, space (32)>
// HT = <US-ASCII HT, horizontal-tab (9)>
// <"> = <US-ASCII double-quote mark (34)>
'!', '#', '$', '%', '&', "'", '*', '+', '-', '.', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B',
'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', '^', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '|', '~',
);
public static $RFC6265 = array(
// RFC6265: "US-ASCII characters excluding CTLs, whitespace DQUOTE, comma, semicolon, and backslash".
// %x21
'!',
// %x23-2B
'#', '$', '%', '&', "'", '(', ')', '*', '+',
// %x2D-3A
'-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':',
// %x3C-5B
'<', '=', '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q',
'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[',
// %x5D-7E
']', '^', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~',
);
public $curl;
public $id = null;
@@ -81,6 +48,39 @@ class Curl
private $xmlPattern = '~^(?:text/|application/(?:atom\+|rss\+)?)xml~i';
private $defaultDecoder = null;
public static $RFC2616 = array(
// RFC2616: "any CHAR except CTLs or separators".
// CHAR = <any US-ASCII character (octets 0 - 127)>
// CTL = <any US-ASCII control character
// (octets 0 - 31) and DEL (127)>
// separators = "(" | ")" | "<" | ">" | "@"
// | "," | ";" | ":" | "\" | <">
// | "/" | "[" | "]" | "?" | "="
// | "{" | "}" | SP | HT
// SP = <US-ASCII SP, space (32)>
// HT = <US-ASCII HT, horizontal-tab (9)>
// <"> = <US-ASCII double-quote mark (34)>
'!', '#', '$', '%', '&', "'", '*', '+', '-', '.', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B',
'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', '^', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '|', '~',
);
public static $RFC6265 = array(
// RFC6265: "US-ASCII characters excluding CTLs, whitespace DQUOTE, comma, semicolon, and backslash".
// %x21
'!',
// %x23-2B
'#', '$', '%', '&', "'", '(', ')', '*', '+',
// %x2D-3A
'-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':',
// %x3C-5B
'<', '=', '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q',
'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[',
// %x5D-7E
']', '^', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~',
);
private static $deferredProperties = array(
'effectiveUrl',
'rfc2616',
@@ -148,8 +148,8 @@ class Curl
// Manually build a single-dimensional array from a multi-dimensional array as using curl_setopt($ch,
// CURLOPT_POSTFIELDS, $data) doesn't correctly handle multi-dimensional arrays when files are
// referenced.
if (self::is_array_multidim($data)) {
$data = self::array_flatten_multidim($data);
if (\Curl\ArrayUtil::is_array_multidim($data)) {
$data = \Curl\ArrayUtil::array_flatten_multidim($data);
}
// Modify array values to ensure any referenced files are properly handled depending on the support of
@@ -1379,78 +1379,4 @@ class Curl
}
return $response_headers;
}
/**
* Is Array Assoc
*
* @access public
* @param $array
*
* @return boolean
*/
public static function is_array_assoc($array)
{
return (bool)count(array_filter(array_keys($array), 'is_string'));
}
/**
* Is Array Multidim
*
* @access public
* @param $array
*
* @return boolean
*/
public static function is_array_multidim($array)
{
if (!is_array($array)) {
return false;
}
return (bool)count(array_filter($array, 'is_array'));
}
/**
* Array Flatten Multidim
*
* @access public
* @param $array
* @param $prefix
*
* @return array
*/
public static function array_flatten_multidim($array, $prefix = false)
{
$return = array();
if (is_array($array) || is_object($array)) {
if (empty($array)) {
$return[$prefix] = '';
} else {
foreach ($array as $key => $value) {
if (is_scalar($value)) {
if ($prefix) {
$return[$prefix . '[' . $key . ']'] = $value;
} else {
$return[$key] = $value;
}
} else {
if ($value instanceof \CURLFile) {
$return[$key] = $value;
} else {
$return = array_merge(
$return,
self::array_flatten_multidim(
$value,
$prefix ? $prefix . '[' . $key . ']' : $key
)
);
}
}
}
}
} elseif ($array === null) {
$return[$prefix] = $array;
}
return $return;
}
}
+2 -2
View File
@@ -641,7 +641,7 @@ class MultiCurl
}
for ($i = 0; $i < $concurrency; $i++) {
$this->initHandle(array_pop($this->curls));
$this->initHandle(array_shift($this->curls));
}
do {
@@ -662,7 +662,7 @@ class MultiCurl
// Start a new request before removing the handle of the completed one.
if (count($this->curls) >= 1) {
$this->initHandle(array_pop($this->curls));
$this->initHandle(array_shift($this->curls));
}
curl_multi_remove_handle($this->multiCurl, $ch->curl);
+18 -58
View File
@@ -14,7 +14,7 @@ class CurlTest extends PHPUnit_Framework_TestCase
public function testArrayAssociative()
{
$this->assertTrue(Curl::is_array_assoc(array(
$this->assertTrue(\Curl\ArrayUtil::is_array_assoc(array(
'foo' => 'wibble',
'bar' => 'wubble',
'baz' => 'wobble',
@@ -23,7 +23,7 @@ class CurlTest extends PHPUnit_Framework_TestCase
public function testArrayIndexed()
{
$this->assertFalse(Curl::is_array_assoc(array(
$this->assertFalse(\Curl\ArrayUtil::is_array_assoc(array(
'wibble',
'wubble',
'wobble',
@@ -957,9 +957,8 @@ class CurlTest extends PHPUnit_Framework_TestCase
{
$test = new Test();
$test->curl->setCookie('mycookie', 'yum');
$this->assertEquals('yum', $test->server('cookie', 'GET', array(
'key' => 'mycookie',
)));
$test->server('setcookie', 'GET');
$this->assertEquals('yum', $test->curl->responseCookies['mycookie']);
}
public function testSetCookies()
@@ -971,21 +970,18 @@ class CurlTest extends PHPUnit_Framework_TestCase
);
$test = new Test();
$test->curl->setCookies($cookies);
$test->server('cookie', 'GET');
$test->server('setcookie', 'GET');
$this->assertEquals(http_build_query($cookies, '', '&'), $test->curl->response);
$this->assertEquals('yum', $test->curl->responseCookies['mycookie']);
$this->assertEquals('apple', $test->curl->responseCookies['fruit']);
$this->assertEquals('red', $test->curl->responseCookies['color']);
}
public function testSetCookieEncodingSpace()
{
$curl = new Curl();
$curl->setCookie('cookie', 'Om nom nom nom');
$reflectionClass = new ReflectionClass('\Curl\Curl');
$reflectionProperty = $reflectionClass->getProperty('options');
$reflectionProperty->setAccessible(true);
$options = $reflectionProperty->getValue($curl);
$this->assertEquals('cookie=Om%20nom%20nom%20nom', $options[CURLOPT_COOKIE]);
$this->assertEquals('cookie=Om%20nom%20nom%20nom', $curl->getOpt(CURLOPT_COOKIE));
}
public function testSetMultipleCookies()
@@ -993,24 +989,14 @@ class CurlTest extends PHPUnit_Framework_TestCase
$curl = new Curl();
$curl->setCookie('cookie', 'Om nom nom nom');
$curl->setCookie('foo', 'bar');
$reflectionClass = new ReflectionClass('\Curl\Curl');
$reflectionProperty = $reflectionClass->getProperty('options');
$reflectionProperty->setAccessible(true);
$options = $reflectionProperty->getValue($curl);
$this->assertEquals('cookie=Om%20nom%20nom%20nom; foo=bar', $options[CURLOPT_COOKIE]);
$this->assertEquals('cookie=Om%20nom%20nom%20nom; foo=bar', $curl->getOpt(CURLOPT_COOKIE));
}
public function testSetCookieEncodingColon()
{
$curl = new Curl();
$curl->setCookie('JSESSIONID', '0000wd-PcsB3bZ-KzYGAqm_rKlm:17925chrl');
$reflectionClass = new ReflectionClass('\Curl\Curl');
$reflectionProperty = $reflectionClass->getProperty('options');
$reflectionProperty->setAccessible(true);
$options = $reflectionProperty->getValue($curl);
$this->assertEquals('JSESSIONID=0000wd-PcsB3bZ-KzYGAqm_rKlm:17925chrl', $options[CURLOPT_COOKIE]);
$this->assertEquals('JSESSIONID=0000wd-PcsB3bZ-KzYGAqm_rKlm:17925chrl', $curl->getOpt(CURLOPT_COOKIE));
}
public function testSetCookieString()
@@ -1019,12 +1005,7 @@ class CurlTest extends PHPUnit_Framework_TestCase
$test = new Test();
$test->curl->setCookieString($cookie_string);
$reflectionClass = new ReflectionClass('\Curl\Curl');
$reflectionProperty = $reflectionClass->getProperty('options');
$reflectionProperty->setAccessible(true);
$options = $reflectionProperty->getValue($test->curl);
$this->assertEquals($cookie_string, $options[CURLOPT_COOKIE]);
$this->assertEquals($cookie_string, $test->curl->getOpt(CURLOPT_COOKIE));
$this->assertEquals('fruit=apple&color=red', $test->server('cookie', 'GET'));
}
@@ -3004,27 +2985,16 @@ class CurlTest extends PHPUnit_Framework_TestCase
$curl = new Curl();
$success = $curl->setOpt($option, $value);
$reflector = new ReflectionObject($curl);
$property = $reflector->getProperty('options');
$property->setAccessible(true);
$options = $property->getValue($curl);
$this->assertTrue($success);
$this->assertTrue(isset($options[$option]));
$this->assertEquals($value, $options[$option]);
$this->assertEquals($value, $curl->getOpt($option));
// Ensure the option is not stored when curl_setopt() fails. Make curl_setopt() return false and suppress
// errors. Triggers warning: "curl_setopt(): Curl option contains invalid characters (\0)".
$curl = new Curl();
$success = @$curl->setOpt($option, $null);
$reflector = new ReflectionObject($curl);
$property = $reflector->getProperty('options');
$property->setAccessible(true);
$options = $property->getValue($curl);
$this->assertFalse($success);
$this->assertFalse(isset($options[$option]));
$this->assertNull($curl->getOpt($option));
// Ensure options following a Curl::setOpt() failure are not set when using Curl::setOpts().
$options = array(
@@ -3034,13 +3004,8 @@ class CurlTest extends PHPUnit_Framework_TestCase
$curl = new Curl();
$success = @$curl->setOpts($options);
$reflector = new ReflectionObject($curl);
$property = $reflector->getProperty('options');
$property->setAccessible(true);
$options = $property->getValue($curl);
$this->assertFalse($success);
$this->assertFalse(isset($options[CURLOPT_COOKIE]));
$this->assertNull($curl->getOpt(CURLOPT_COOKIE));
// Ensure Curl::setOpts() returns true when all options are successfully set.
$options = array(
@@ -3051,15 +3016,10 @@ class CurlTest extends PHPUnit_Framework_TestCase
$curl = new Curl();
$success = $curl->setOpts($options);
$reflector = new ReflectionObject($curl);
$property = $reflector->getProperty('options');
$property->setAccessible(true);
$options = $property->getValue($curl);
$this->assertTrue($success);
$this->assertEquals('a=b', $options[CURLOPT_COOKIE]);
$this->assertTrue($options[CURLOPT_FOLLOWLOCATION]);
$this->assertTrue($options[CURLOPT_VERBOSE]);
$this->assertEquals('a=b', $curl->getOpt(CURLOPT_COOKIE));
$this->assertTrue($curl->getOpt(CURLOPT_FOLLOWLOCATION));
$this->assertTrue($curl->getOpt(CURLOPT_VERBOSE));
}
public function testBuildUrlArgSeparator()
@@ -2486,4 +2486,22 @@ class MultiCurlTest extends PHPUnit_Framework_TestCase
$this->assertEquals($sequential_id, $instance->id);
}
}
public function testAscendingNumericalOrder()
{
$counter = 0;
$multi_curl = new MultiCurl();
$multi_curl->setConcurrency(1);
$multi_curl->complete(function ($instance) use (&$counter) {
$sequential_id = $instance->getOpt(CURLOPT_POSTFIELDS);
PHPUnit_Framework_Assert::assertEquals($counter, $sequential_id);
$counter++;
});
for ($i = 0; $i < 100; $i++) {
$multi_curl->addPost(Test::TEST_URL, $i);
}
$multi_curl->start();
}
}