1 : <?php
2 : class EpiCurl
3 : {
4 : const timeout = 3;
5 : static $inst = null;
6 : static $singleton = 0;
7 : private $mc;
8 : private $msgs;
9 : private $running;
10 : private $execStatus;
11 : private $selectStatus;
12 : private $sleepIncrement = 1.1;
13 : private $requests = array();
14 : private $responses = array();
15 : private $properties = array();
16 :
17 : function __construct()
18 : {
19 1 : if(self::$singleton == 0)
20 1 : {
21 0 : throw new Exception('This class cannot be instantiated by the new keyword. You must instantiate it using: $obj = EpiCurl::getInstance();');
22 : }
23 :
24 1 : $this->mc = curl_multi_init();
25 0 : $this->properties = array(
26 1 : 'code' => CURLINFO_HTTP_CODE,
27 1 : 'time' => CURLINFO_TOTAL_TIME,
28 1 : 'length'=> CURLINFO_CONTENT_LENGTH_DOWNLOAD,
29 : 'type' => CURLINFO_CONTENT_TYPE
30 1 : );
31 1 : }
32 :
33 : public function addCurl($ch)
34 : {
35 24 : $key = (string)$ch;
36 24 : $this->requests[$key] = $ch;
37 :
38 24 : $code = curl_multi_add_handle($this->mc, $ch);
39 :
40 : // (1)
41 24 : if($code === CURLM_OK || $code === CURLM_CALL_MULTI_PERFORM)
42 24 : {
43 : do {
44 24 : $code = $this->execStatus = curl_multi_exec($this->mc, $this->running);
45 24 : } while ($this->execStatus === CURLM_CALL_MULTI_PERFORM);
46 :
47 24 : return new EpiCurlManager($key);
48 : }
49 : else
50 : {
51 0 : return $code;
52 : }
53 : }
54 :
55 : public function getResult($key = null)
56 : {
57 24 : if($key != null)
58 24 : {
59 24 : if(isset($this->responses[$key]))
60 24 : {
61 24 : return $this->responses[$key];
62 : }
63 :
64 24 : $innerSleepInt = $outerSleepInt = 1;
65 24 : while($this->running && ($this->execStatus == CURLM_OK || $this->execStatus == CURLM_CALL_MULTI_PERFORM))
66 : {
67 24 : usleep($outerSleepInt);
68 24 : $outerSleepInt *= $this->sleepIncrement;
69 24 : $ms=curl_multi_select($this->mc, 0);
70 24 : if($ms > 0)
71 24 : {
72 : do{
73 24 : $this->execStatus = curl_multi_exec($this->mc, $this->running);
74 24 : usleep($innerSleepInt);
75 24 : $innerSleepInt *= $this->sleepIncrement;
76 24 : usleep($innerSleepInt);
77 24 : }while($this->execStatus==CURLM_CALL_MULTI_PERFORM);
78 24 : $innerSleepInt = 0;
79 24 : }
80 24 : $this->storeResponses();
81 24 : if(isset($this->responses[$key]))
82 24 : {
83 24 : return $this->responses[$key];
84 : }
85 24 : $runningCurrent = $this->running;
86 24 : }
87 0 : return null;
88 : }
89 0 : return false;
90 : }
91 :
92 : private function storeResponses()
93 : {
94 24 : while($done = curl_multi_info_read($this->mc))
95 : {
96 24 : $key = (string)$done['handle'];
97 24 : $this->responses[$key]['data'] = curl_multi_getcontent($done['handle']);
98 24 : foreach($this->properties as $name => $const)
99 : {
100 24 : $this->responses[$key][$name] = curl_getinfo($done['handle'], $const);
101 24 : }
102 24 : curl_multi_remove_handle($this->mc, $done['handle']);
103 24 : curl_close($done['handle']);
104 24 : }
105 24 : }
106 :
107 : static function getInstance()
108 : {
109 29 : if(self::$inst == null)
110 29 : {
111 1 : self::$singleton = 1;
112 1 : self::$inst = new EpiCurl();
113 1 : }
114 :
115 29 : return self::$inst;
116 : }
117 : }
118 :
119 : class EpiCurlManager
120 : {
121 : private $key;
122 : private $epiCurl;
123 :
124 : function __construct($key)
125 : {
126 24 : $this->key = $key;
127 24 : $this->epiCurl = EpiCurl::getInstance();
128 24 : }
129 :
130 : function __get($name)
131 : {
132 24 : $responses = $this->epiCurl->getResult($this->key);
133 24 : return $responses[$name];
134 : }
135 :
136 : function __isset($name)
137 : {
138 0 : $val = self::__get($name);
139 0 : return empty($val);
140 : }
141 : }
142 :
143 : /*
144 : * Credits:
145 : * - (1) Alistair pointed out that curl_multi_add_handle can return CURLM_CALL_MULTI_PERFORM on success.
146 : */
147 : ?>
|