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

StreamHandler.php

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


001  <?php
002  namespace GuzzleHttp\Ring\Client;
003   
004  use GuzzleHttp\Ring\Core;
005  use GuzzleHttp\Ring\Exception\ConnectException;
006  use GuzzleHttp\Ring\Exception\RingException;
007  use GuzzleHttp\Ring\Future\CompletedFutureArray;
008  use GuzzleHttp\Stream\InflateStream;
009  use GuzzleHttp\Stream\StreamInterface;
010  use GuzzleHttp\Stream\Stream;
011  use GuzzleHttp\Stream\Utils;
012   
013  /**
014   * RingPHP client handler that uses PHP's HTTP stream wrapper.
015   */
016  class StreamHandler
017  {
018      private $options;
019      private $lastHeaders;
020   
021      public function __construct(array $options = [])
022      {
023          $this->options = $options;
024      }
025   
026      public function __invoke(array $request)
027      {
028          $url = Core::url($request);
029          Core::doSleep($request);
030   
031          try {
032              // Does not support the expect header.
033              $request = Core::removeHeader($request, 'Expect');
034              $stream = $this->createStream($url, $request);
035              return $this->createResponse($request, $url, $stream);
036          } catch (RingException $e) {
037              return $this->createErrorResponse($url, $e);
038          }
039      }
040   
041      private function createResponse(array $request, $url, $stream)
042      {
043          $hdrs = $this->lastHeaders;
044          $this->lastHeaders = null;
045          $parts = explode(' ', array_shift($hdrs), 3);
046          $response = [
047              'version'        => substr($parts[0], 5),
048              'status'         => $parts[1],
049              'reason'         => isset($parts[2]) ? $parts[2] : null,
050              'headers'        => Core::headersFromLines($hdrs),
051              'effective_url'  => $url,
052          ];
053   
054          $stream = $this->checkDecode($request, $response, $stream);
055   
056          // If not streaming, then drain the response into a stream.
057          if (empty($request['client']['stream'])) {
058              $dest = isset($request['client']['save_to'])
059                  ? $request['client']['save_to']
060                  : fopen('php://temp', 'r+');
061              $stream = $this->drain($stream, $dest);
062          }
063   
064          $response['body'] = $stream;
065   
066          return new CompletedFutureArray($response);
067      }
068   
069      private function checkDecode(array $request, array $response, $stream)
070      {
071          // Automatically decode responses when instructed.
072          if (!empty($request['client']['decode_content'])) {
073              switch (Core::firstHeader($response, 'Content-Encoding', true)) {
074                  case 'gzip':
075                  case 'deflate':
076                      $stream = new InflateStream(Stream::factory($stream));
077                      break;
078              }
079          }
080   
081          return $stream;
082      }
083   
084      /**
085       * Drains the stream into the "save_to" client option.
086       *
087       * @param resource                        $stream
088       * @param string|resource|StreamInterface $dest
089       *
090       * @return Stream
091       * @throws \RuntimeException when the save_to option is invalid.
092       */
093      private function drain($stream, $dest)
094      {
095          if (is_resource($stream)) {
096              if (!is_resource($dest)) {
097                  $stream = Stream::factory($stream);
098              } else {
099                  stream_copy_to_stream($stream, $dest);
100                  fclose($stream);
101                  rewind($dest);
102                  return $dest;
103              }
104          }
105   
106          // Stream the response into the destination stream
107          $dest = is_string($dest)
108              ? new Stream(Utils::open($dest, 'r+'))
109              : Stream::factory($dest);
110   
111          Utils::copyToStream($stream, $dest);
112          $dest->seek(0);
113          $stream->close();
114   
115          return $dest;
116      }
117   
118      /**
119       * Creates an error response for the given stream.
120       *
121       * @param string        $url
122       * @param RingException $e
123       *
124       * @return array
125       */
126      private function createErrorResponse($url, RingException $e)
127      {
128          // Determine if the error was a networking error.
129          $message = $e->getMessage();
130   
131          // This list can probably get more comprehensive.
132          if (strpos($message, 'getaddrinfo') // DNS lookup failed
133              || strpos($message, 'Connection refused')
134          ) {
135              $e = new ConnectException($e->getMessage(), 0, $e);
136          }
137   
138          return new CompletedFutureArray([
139              'status'        => null,
140              'body'          => null,
141              'headers'       => [],
142              'effective_url' => $url,
143              'error'         => $e
144          ]);
145      }
146   
147      /**
148       * Create a resource and check to ensure it was created successfully
149       *
150       * @param callable $callback Callable that returns stream resource
151       *
152       * @return resource
153       * @throws \RuntimeException on error
154       */
155      private function createResource(callable $callback)
156      {
157          $errors = null;
158          set_error_handler(function ($_, $msg, $file, $line) use (&$errors) {
159              $errors[] = [
160                  'message' => $msg,
161                  'file'    => $file,
162                  'line'    => $line
163              ];
164              return true;
165          });
166   
167          $resource = $callback();
168          restore_error_handler();
169   
170          if (!$resource) {
171              $message = 'Error creating resource: ';
172              foreach ($errors as $err) {
173                  foreach ($err as $key => $value) {
174                      $message .= "[$key$value" . PHP_EOL;
175                  }
176              }
177              throw new RingException(trim($message));
178          }
179   
180          return $resource;
181      }
182   
183      private function createStream($url, array $request)
184      {
185          static $methods;
186          if (!$methods) {
187              $methods = array_flip(get_class_methods(__CLASS__));
188          }
189   
190          // HTTP/1.1 streams using the PHP stream wrapper require a
191          // Connection: close header
192          if ((!isset($request['version']) || $request['version'] == '1.1')
193              && !Core::hasHeader($request, 'Connection')
194          ) {
195              $request['headers']['Connection'] = ['close'];
196          }
197   
198          // Ensure SSL is verified by default
199          if (!isset($request['client']['verify'])) {
200              $request['client']['verify'] = true;
201          }
202   
203          $params = [];
204          $options = $this->getDefaultOptions($request);
205   
206          if (isset($request['client'])) {
207              foreach ($request['client'] as $key => $value) {
208                  $method = "add_{$key}";
209                  if (isset($methods[$method])) {
210                      $this->{$method}($request, $options, $value, $params);
211                  }
212              }
213          }
214   
215          return $this->createStreamResource(
216              $url,
217              $request,
218              $options,
219              $this->createContext($request, $options, $params)
220          );
221      }
222   
223      private function getDefaultOptions(array $request)
224      {
225          $headers = "";
226          foreach ($request['headers'] as $name => $value) {
227              foreach ((array) $value as $val) {
228                  $headers .= "$name$val\r\n";
229              }
230          }
231   
232          $context = [
233              'http' => [
234                  'method'           => $request['http_method'],
235                  'header'           => $headers,
236                  'protocol_version' => isset($request['version']) ? $request['version'] : 1.1,
237                  'ignore_errors'    => true,
238                  'follow_location'  => 0,
239              ],
240          ];
241   
242          $body = Core::body($request);
243          if (isset($body)) {
244              $context['http']['content'] = $body;
245              // Prevent the HTTP handler from adding a Content-Type header.
246              if (!Core::hasHeader($request, 'Content-Type')) {
247                  $context['http']['header'] .= "Content-Type:\r\n";
248              }
249          }
250   
251          $context['http']['header'] = rtrim($context['http']['header']);
252   
253          return $context;
254      }
255   
256      private function add_proxy(array $request, &$options, $value, &$params)
257      {
258          if (!is_array($value)) {
259              $options['http']['proxy'] = $value;
260          } else {
261              $scheme = isset($request['scheme']) ? $request['scheme'] : 'http';
262              if (isset($value[$scheme])) {
263                  $options['http']['proxy'] = $value[$scheme];
264              }
265          }
266      }
267   
268      private function add_timeout(array $request, &$options, $value, &$params)
269      {
270          $options['http']['timeout'] = $value;
271      }
272   
273      private function add_verify(array $request, &$options, $value, &$params)
274      {
275          if ($value === true) {
276              // PHP 5.6 or greater will find the system cert by default. When
277              // < 5.6, use the Guzzle bundled cacert.
278              if (PHP_VERSION_ID < 50600) {
279                  $options['ssl']['cafile'] = ClientUtils::getDefaultCaBundle();
280              }
281          } elseif (is_string($value)) {
282              $options['ssl']['cafile'] = $value;
283              if (!file_exists($value)) {
284                  throw new RingException("SSL CA bundle not found: $value");
285              }
286          } elseif ($value === false) {
287              $options['ssl']['verify_peer'] = false;
288              $options['ssl']['allow_self_signed'] = true;
289              return;
290          } else {
291              throw new RingException('Invalid verify request option');
292          }
293   
294          $options['ssl']['verify_peer'] = true;
295          $options['ssl']['allow_self_signed'] = false;
296      }
297   
298      private function add_cert(array $request, &$options, $value, &$params)
299      {
300          if (is_array($value)) {
301              $options['ssl']['passphrase'] = $value[1];
302              $value = $value[0];
303          }
304   
305          if (!file_exists($value)) {
306              throw new RingException("SSL certificate not found: {$value}");
307          }
308   
309          $options['ssl']['local_cert'] = $value;
310      }
311   
312      private function add_progress(array $request, &$options, $value, &$params)
313      {
314          $fn = function ($code, $_1, $_2, $_3, $transferred, $total) use ($value) {
315              if ($code == STREAM_NOTIFY_PROGRESS) {
316                  $value($total, $transferred, null, null);
317              }
318          };
319   
320          // Wrap the existing function if needed.
321          $params['notification'] = isset($params['notification'])
322              ? Core::callArray([$params['notification'], $fn])
323              : $fn;
324      }
325   
326      private function add_debug(array $request, &$options, $value, &$params)
327      {
328          if ($value === false) {
329              return;
330          }
331   
332          static $map = [
333              STREAM_NOTIFY_CONNECT       => 'CONNECT',
334              STREAM_NOTIFY_AUTH_REQUIRED => 'AUTH_REQUIRED',
335              STREAM_NOTIFY_AUTH_RESULT   => 'AUTH_RESULT',
336              STREAM_NOTIFY_MIME_TYPE_IS  => 'MIME_TYPE_IS',
337              STREAM_NOTIFY_FILE_SIZE_IS  => 'FILE_SIZE_IS',
338              STREAM_NOTIFY_REDIRECTED    => 'REDIRECTED',
339              STREAM_NOTIFY_PROGRESS      => 'PROGRESS',
340              STREAM_NOTIFY_FAILURE       => 'FAILURE',
341              STREAM_NOTIFY_COMPLETED     => 'COMPLETED',
342              STREAM_NOTIFY_RESOLVE       => 'RESOLVE',
343          ];
344   
345          static $args = ['severity', 'message', 'message_code',
346              'bytes_transferred', 'bytes_max'];
347   
348          $value = Core::getDebugResource($value);
349          $ident = $request['http_method'] . ' ' . Core::url($request);
350          $fn = function () use ($ident, $value, $map, $args) {
351              $passed = func_get_args();
352              $code = array_shift($passed);
353              fprintf($value, '<%s> [%s] ', $ident, $map[$code]);
354              foreach (array_filter($passed) as $i => $v) {
355                  fwrite($value, $args[$i] . ': "' . $v . '" ');
356              }
357              fwrite($value, "\n");
358          };
359   
360          // Wrap the existing function if needed.
361          $params['notification'] = isset($params['notification'])
362              ? Core::callArray([$params['notification'], $fn])
363              : $fn;
364      }
365   
366      private function applyCustomOptions(array $request, array &$options)
367      {
368          if (!isset($request['client']['stream_context'])) {
369              return;
370          }
371   
372          if (!is_array($request['client']['stream_context'])) {
373              throw new RingException('stream_context must be an array');
374          }
375   
376          $options = array_replace_recursive(
377              $options,
378              $request['client']['stream_context']
379          );
380      }
381   
382      private function createContext(array $request, array $options, array $params)
383      {
384          $this->applyCustomOptions($request, $options);
385          return $this->createResource(
386              function () use ($request, $options, $params) {
387                  return stream_context_create($options, $params);
388              },
389              $request,
390              $options
391          );
392      }
393   
394      private function createStreamResource(
395          $url,
396          array $request,
397          array $options,
398          $context
399      ) {
400          return $this->createResource(
401              function () use ($url, $context) {
402                  if (false === strpos($url, 'http')) {
403                      trigger_error("URL is invalid: {$url}", E_USER_WARNING);
404                      return null;
405                  }
406                  $resource = fopen($url, 'r', null, $context);
407                  $this->lastHeaders = $http_response_header;
408                  return $resource;
409              },
410              $request,
411              $options
412          );
413      }
414  }
415