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.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

(Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

CurlMultiHandler.php

Zuletzt modifiziert: 09.10.2024, 12:57 - Dateigröße: 7.46 KiB


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