Skip to content

Commit 522fe31

Browse files
authored
Merge pull request php-curl-class#387 from zachborboa/updates
Implement a more efficient handling of requests in parallel
2 parents 1d786ca + 3789e20 commit 522fe31

File tree

4 files changed

+54
-39
lines changed

4 files changed

+54
-39
lines changed

examples/flickr_photo_search.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
use \Curl\Curl;
55

6-
const FLICKR_API_KEY = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX');
6+
const FLICKR_API_KEY = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
77

88
$data = array(
99
'method' => 'flickr.photos.search',

src/Curl/Curl.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ public function __construct($base_url = null)
100100
}
101101

102102
$this->curl = curl_init();
103-
$this->id = 1;
103+
$this->id = uniqid('', true);
104104
$this->setDefaultUserAgent();
105105
$this->setDefaultJsonDecoder();
106106
$this->setDefaultXmlDecoder();
@@ -385,6 +385,11 @@ public function exec($ch = null)
385385

386386
$this->call($this->completeFunction);
387387

388+
// Close open file handles and reset the curl instance.
389+
if (!($this->fileHandle === null)) {
390+
$this->downloadComplete($this->fileHandle);
391+
}
392+
388393
return $this->response;
389394
}
390395

src/Curl/MultiCurl.php

Lines changed: 41 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@ class MultiCurl
66
{
77
public $baseUrl = null;
88
public $multiCurl;
9-
public $curls = array();
10-
private $nextCurlId = 1;
9+
public $windowSize = 25;
10+
11+
private $curls = array();
12+
private $activeCurls = array();
1113
private $isStarted = false;
1214

1315
private $beforeSendFunction = null;
@@ -56,7 +58,7 @@ public function addDelete($url, $query_parameters = array(), $data = array())
5658
$curl->setURL($url, $query_parameters);
5759
$curl->setOpt(CURLOPT_CUSTOMREQUEST, 'DELETE');
5860
$curl->setOpt(CURLOPT_POSTFIELDS, $curl->buildPostData($data));
59-
$this->addHandle($curl);
61+
$this->queueHandle($curl);
6062
return $curl;
6163
}
6264

@@ -90,7 +92,7 @@ public function addDownload($url, $mixed_filename)
9092
$curl->setOpt(CURLOPT_FILE, $curl->fileHandle);
9193
$curl->setOpt(CURLOPT_CUSTOMREQUEST, 'GET');
9294
$curl->setOpt(CURLOPT_HTTPGET, true);
93-
$this->addHandle($curl);
95+
$this->queueHandle($curl);
9496
return $curl;
9597
}
9698

@@ -113,7 +115,7 @@ public function addGet($url, $data = array())
113115
$curl->setURL($url, $data);
114116
$curl->setOpt(CURLOPT_CUSTOMREQUEST, 'GET');
115117
$curl->setOpt(CURLOPT_HTTPGET, true);
116-
$this->addHandle($curl);
118+
$this->queueHandle($curl);
117119
return $curl;
118120
}
119121

@@ -136,7 +138,7 @@ public function addHead($url, $data = array())
136138
$curl->setURL($url, $data);
137139
$curl->setOpt(CURLOPT_CUSTOMREQUEST, 'HEAD');
138140
$curl->setOpt(CURLOPT_NOBODY, true);
139-
$this->addHandle($curl);
141+
$this->queueHandle($curl);
140142
return $curl;
141143
}
142144

@@ -159,7 +161,7 @@ public function addOptions($url, $data = array())
159161
$curl->setURL($url, $data);
160162
$curl->unsetHeader('Content-Length');
161163
$curl->setOpt(CURLOPT_CUSTOMREQUEST, 'OPTIONS');
162-
$this->addHandle($curl);
164+
$this->queueHandle($curl);
163165
return $curl;
164166
}
165167

@@ -183,7 +185,7 @@ public function addPatch($url, $data = array())
183185
$curl->unsetHeader('Content-Length');
184186
$curl->setOpt(CURLOPT_CUSTOMREQUEST, 'PATCH');
185187
$curl->setOpt(CURLOPT_POSTFIELDS, $data);
186-
$this->addHandle($curl);
188+
$this->queueHandle($curl);
187189
return $curl;
188190
}
189191

@@ -225,7 +227,7 @@ public function addPost($url, $data = array(), $follow_303_with_post = false)
225227

226228
$curl->setOpt(CURLOPT_POST, true);
227229
$curl->setOpt(CURLOPT_POSTFIELDS, $curl->buildPostData($data));
228-
$this->addHandle($curl);
230+
$this->queueHandle($curl);
229231
return $curl;
230232
}
231233

@@ -252,7 +254,7 @@ public function addPut($url, $data = array())
252254
$curl->setHeader('Content-Length', strlen($put_data));
253255
}
254256
$curl->setOpt(CURLOPT_POSTFIELDS, $put_data);
255-
$this->addHandle($curl);
257+
$this->queueHandle($curl);
256258
return $curl;
257259
}
258260

@@ -279,7 +281,7 @@ public function addSearch($url, $data = array())
279281
$curl->setHeader('Content-Length', strlen($put_data));
280282
}
281283
$curl->setOpt(CURLOPT_POSTFIELDS, $put_data);
282-
$this->addHandle($curl);
284+
$this->queueHandle($curl);
283285
return $curl;
284286
}
285287

@@ -522,40 +524,47 @@ public function start()
522524
return;
523525
}
524526

525-
foreach ($this->curls as $ch) {
526-
$this->initHandle($ch);
527+
$this->isStarted = true;
528+
529+
$window_size = $this->windowSize;
530+
if ($window_size > count($this->curls)) {
531+
$window_size = count($this->curls);
527532
}
528533

529-
$this->isStarted = true;
534+
for ($i = 0; $i < $window_size; $i++) {
535+
$this->initHandle(array_pop($this->curls));
536+
}
530537

531538
do {
532539
curl_multi_select($this->multiCurl);
533540
curl_multi_exec($this->multiCurl, $active);
534541

535542
while (!($info_array = curl_multi_info_read($this->multiCurl)) === false) {
536543
if ($info_array['msg'] === CURLMSG_DONE) {
537-
foreach ($this->curls as $key => $ch) {
544+
foreach ($this->activeCurls as $key => $ch) {
538545
if ($ch->curl === $info_array['handle']) {
539546
// Set the error code for multi handles using the "result" key in the array returned by
540547
// curl_multi_info_read(). Using curl_errno() on a multi handle will incorrectly return 0
541548
// for errors.
542549
$ch->curlErrorCode = $info_array['result'];
543550
$ch->exec($ch->curl);
544-
curl_multi_remove_handle($this->multiCurl, $ch->curl);
545-
unset($this->curls[$key]);
546551

547-
// Close open file handles and reset the curl instance.
548-
if (!($ch->fileHandle === null)) {
549-
$ch->downloadComplete($ch->fileHandle);
552+
unset($this->activeCurls[$key]);
553+
554+
// Start a new request before removing the handle of the completed one.
555+
if (count($this->curls) >= 1) {
556+
$this->initHandle(array_pop($this->curls));
550557
}
558+
curl_multi_remove_handle($this->multiCurl, $ch->curl);
559+
551560
break;
552561
}
553562
}
554563
}
555564
}
556565

557566
if (!$active) {
558-
$active = count($this->curls);
567+
$active = count($this->activeCurls);
559568
}
560569
} while ($active > 0);
561570

@@ -614,31 +623,22 @@ public function __destruct()
614623
}
615624

616625
/**
617-
* Add Handle
626+
* Queue Handle
618627
*
619628
* @access private
620629
* @param $curl
621-
* @throws \ErrorException
622630
*/
623-
private function addHandle($curl)
631+
private function queueHandle($curl)
624632
{
625-
$curlm_error_code = curl_multi_add_handle($this->multiCurl, $curl->curl);
626-
if (!($curlm_error_code === CURLM_OK)) {
627-
throw new \ErrorException('cURL multi add handle error: ' . curl_multi_strerror($curlm_error_code));
628-
}
629-
$this->curls[] = $curl;
630-
$curl->id = $this->nextCurlId++;
631-
632-
if ($this->isStarted) {
633-
$this->initHandle($curl);
634-
}
633+
$this->curls[$curl->id] = $curl;
635634
}
636635

637636
/**
638637
* Init Handle
639638
*
640639
* @access private
641640
* @param $curl
641+
* @throws \ErrorException
642642
*/
643643
private function initHandle($curl)
644644
{
@@ -664,6 +664,13 @@ private function initHandle($curl)
664664
}
665665
$curl->setJsonDecoder($this->jsonDecoder);
666666
$curl->setXmlDecoder($this->xmlDecoder);
667+
668+
$curlm_error_code = curl_multi_add_handle($this->multiCurl, $curl->curl);
669+
if (!($curlm_error_code === CURLM_OK)) {
670+
throw new \ErrorException('cURL multi add handle error: ' . curl_multi_strerror($curlm_error_code));
671+
}
672+
673+
$this->activeCurls[$curl->id] = $curl;
667674
$curl->call($curl->beforeSendFunction);
668675
}
669676
}

tests/script.sh

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1-
# Check syntax in php files.
2-
find . -type "f" -iname "*.php" ! -path "*/vendor/*" -exec php -l {} \;
3-
41
errors=0
52

3+
# Check syntax in php files. Use `xargs' over `find -exec' as xargs exits with a value of 1 when any command errors.
4+
find . -type "f" -iname "*.php" ! -path "*/vendor/*" | xargs -L "1" php -l
5+
if [[ "${?}" -ne 0 ]]; then
6+
((errors++))
7+
fi
8+
69
# Run tests.
710
phpunit --configuration tests/phpunit.xml
811
if [[ "${?}" -ne 0 ]]; then

0 commit comments

Comments
 (0)