Verzeichnisstruktur phpBB-3.2.0
- Veröffentlicht
- 06.01.2017
So funktioniert es
|
Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück |
Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis. |
|
(Beispiel Datei-Icons)
|
Auf das Icon klicken um den Quellcode anzuzeigen |
CurlMultiHandler.php
001 <?php
002 namespace GuzzleHttp\Ring\Client;
003
004 use GuzzleHttp\Ring\Future\FutureArray;
005 use React\Promise\Deferred;
006
007 /**
008 * Returns an asynchronous response using curl_multi_* functions.
009 *
010 * This handler supports future responses and the "delay" request client
011 * option that can be used to delay before sending a request.
012 *
013 * When using the CurlMultiHandler, custom curl options can be specified as an
014 * associative array of curl option constants mapping to values in the
015 * **curl** key of the "client" key of the request.
016 *
017 * @property resource $_mh Internal use only. Lazy loaded multi-handle.
018 */
019 class CurlMultiHandler
020 {
021 /** @var callable */
022 private $factory;
023 private $selectTimeout;
024 private $active;
025 private $handles = [];
026 private $delays = [];
027 private $maxHandles;
028
029 /**
030 * This handler accepts the following options:
031 *
032 * - mh: An optional curl_multi resource
033 * - handle_factory: An optional callable used to generate curl handle
034 * resources. the callable accepts a request hash and returns an array
035 * of the handle, headers file resource, and the body resource.
036 * - select_timeout: Optional timeout (in seconds) to block before timing
037 * out while selecting curl handles. Defaults to 1 second.
038 * - max_handles: Optional integer representing the maximum number of
039 * open requests. When this number is reached, the queued futures are
040 * flushed.
041 *
042 * @param array $options
043 */
044 public function __construct(array $options = [])
045 {
046 if (isset($options['mh'])) {
047 $this->_mh = $options['mh'];
048 }
049 $this->factory = isset($options['handle_factory'])
050 ? $options['handle_factory'] : new CurlFactory();
051 $this->selectTimeout = isset($options['select_timeout'])
052 ? $options['select_timeout'] : 1;
053 $this->maxHandles = isset($options['max_handles'])
054 ? $options['max_handles'] : 100;
055 }
056
057 public function __get($name)
058 {
059 if ($name === '_mh') {
060 return $this->_mh = curl_multi_init();
061 }
062
063 throw new \BadMethodCallException();
064 }
065
066 public function __destruct()
067 {
068 // Finish any open connections before terminating the script.
069 if ($this->handles) {
070 $this->execute();
071 }
072
073 if (isset($this->_mh)) {
074 curl_multi_close($this->_mh);
075 unset($this->_mh);
076 }
077 }
078
079 public function __invoke(array $request)
080 {
081 $factory = $this->factory;
082 $result = $factory($request);
083 $entry = [
084 'request' => $request,
085 'response' => [],
086 'handle' => $result[0],
087 'headers' => &$result[1],
088 'body' => $result[2],
089 'deferred' => new Deferred(),
090 ];
091
092 $id = (int) $result[0];
093
094 $future = new FutureArray(
095 $entry['deferred']->promise(),
096 [$this, 'execute'],
097 function () use ($id) {
098 return $this->cancel($id);
099 }
100 );
101
102 $this->addRequest($entry);
103
104 // Transfer outstanding requests if there are too many open handles.
105 if (count($this->handles) >= $this->maxHandles) {
106 $this->execute();
107 }
108
109 return $future;
110 }
111
112 /**
113 * Runs until all outstanding connections have completed.
114 */
115 public function execute()
116 {
117 do {
118
119 if ($this->active &&
120 curl_multi_select($this->_mh, $this->selectTimeout) === -1
121 ) {
122 // Perform a usleep if a select returns -1.
123 // See: https://bugs.php.net/bug.php?id=61141
124 usleep(250);
125 }
126
127 // Add any delayed futures if needed.
128 if ($this->delays) {
129 $this->addDelays();
130 }
131
132 do {
133 $mrc = curl_multi_exec($this->_mh, $this->active);
134 } while ($mrc === CURLM_CALL_MULTI_PERFORM);
135
136 $this->processMessages();
137
138 // If there are delays but no transfers, then sleep for a bit.
139 if (!$this->active && $this->delays) {
140 usleep(500);
141 }
142
143 } while ($this->active || $this->handles);
144 }
145
146 private function addRequest(array &$entry)
147 {
148 $id = (int) $entry['handle'];
149 $this->handles[$id] = $entry;
150
151 // If the request is a delay, then add the reques to the curl multi
152 // pool only after the specified delay.
153 if (isset($entry['request']['client']['delay'])) {
154 $this->delays[$id] = microtime(true) + ($entry['request']['client']['delay'] / 1000);
155 } elseif (empty($entry['request']['future'])) {
156 curl_multi_add_handle($this->_mh, $entry['handle']);
157 } else {
158 curl_multi_add_handle($this->_mh, $entry['handle']);
159 // "lazy" futures are only sent once the pool has many requests.
160 if ($entry['request']['future'] !== 'lazy') {
161 do {
162 $mrc = curl_multi_exec($this->_mh, $this->active);
163 } while ($mrc === CURLM_CALL_MULTI_PERFORM);
164 $this->processMessages();
165 }
166 }
167 }
168
169 private function removeProcessed($id)
170 {
171 if (isset($this->handles[$id])) {
172 curl_multi_remove_handle(
173 $this->_mh,
174 $this->handles[$id]['handle']
175 );
176 curl_close($this->handles[$id]['handle']);
177 unset($this->handles[$id], $this->delays[$id]);
178 }
179 }
180
181 /**
182 * Cancels a handle from sending and removes references to it.
183 *
184 * @param int $id Handle ID to cancel and remove.
185 *
186 * @return bool True on success, false on failure.
187 */
188 private function cancel($id)
189 {
190 // Cannot cancel if it has been processed.
191 if (!isset($this->handles[$id])) {
192 return false;
193 }
194
195 $handle = $this->handles[$id]['handle'];
196 unset($this->delays[$id], $this->handles[$id]);
197 curl_multi_remove_handle($this->_mh, $handle);
198 curl_close($handle);
199
200 return true;
201 }
202
203 private function addDelays()
204 {
205 $currentTime = microtime(true);
206
207 foreach ($this->delays as $id => $delay) {
208 if ($currentTime >= $delay) {
209 unset($this->delays[$id]);
210 curl_multi_add_handle(
211 $this->_mh,
212 $this->handles[$id]['handle']
213 );
214 }
215 }
216 }
217
218 private function processMessages()
219 {
220 while ($done = curl_multi_info_read($this->_mh)) {
221 $id = (int) $done['handle'];
222
223 if (!isset($this->handles[$id])) {
224 // Probably was cancelled.
225 continue;
226 }
227
228 $entry = $this->handles[$id];
229 $entry['response']['transfer_stats'] = curl_getinfo($done['handle']);
230
231 if ($done['result'] !== CURLM_OK) {
232 $entry['response']['curl']['errno'] = $done['result'];
233 if (function_exists('curl_strerror')) {
234 $entry['response']['curl']['error'] = curl_strerror($done['result']);
235 }
236 }
237
238 $result = CurlFactory::createResponse(
239 $this,
240 $entry['request'],
241 $entry['response'],
242 $entry['headers'],
243 $entry['body']
244 );
245
246 $this->removeProcessed($id);
247 $entry['deferred']->resolve($result);
248 }
249 }
250 }
251