annotate vendor/zendframework/zend-diactoros/src/AbstractSerializer.php @ 0:c75dbcec494b

Initial commit from drush-created site
author Chris Cannam
date Thu, 05 Jul 2018 14:24:15 +0000
parents
children 5311817fb629
rev   line source
Chris@0 1 <?php
Chris@0 2 /**
Chris@0 3 * Zend Framework (http://framework.zend.com/)
Chris@0 4 *
Chris@0 5 * @see http://github.com/zendframework/zend-diactoros for the canonical source repository
Chris@0 6 * @copyright Copyright (c) 2015-2016 Zend Technologies USA Inc. (http://www.zend.com)
Chris@0 7 * @license https://github.com/zendframework/zend-diactoros/blob/master/LICENSE.md New BSD License
Chris@0 8 */
Chris@0 9
Chris@0 10 namespace Zend\Diactoros;
Chris@0 11
Chris@0 12 use Psr\Http\Message\StreamInterface;
Chris@0 13 use UnexpectedValueException;
Chris@0 14
Chris@0 15 /**
Chris@0 16 * Provides base functionality for request and response de/serialization
Chris@0 17 * strategies, including functionality for retrieving a line at a time from
Chris@0 18 * the message, splitting headers from the body, and serializing headers.
Chris@0 19 */
Chris@0 20 abstract class AbstractSerializer
Chris@0 21 {
Chris@0 22 const CR = "\r";
Chris@0 23 const EOL = "\r\n";
Chris@0 24 const LF = "\n";
Chris@0 25
Chris@0 26 /**
Chris@0 27 * Retrieve a single line from the stream.
Chris@0 28 *
Chris@0 29 * Retrieves a line from the stream; a line is defined as a sequence of
Chris@0 30 * characters ending in a CRLF sequence.
Chris@0 31 *
Chris@0 32 * @param StreamInterface $stream
Chris@0 33 * @return string
Chris@0 34 * @throws UnexpectedValueException if the sequence contains a CR or LF in
Chris@0 35 * isolation, or ends in a CR.
Chris@0 36 */
Chris@0 37 protected static function getLine(StreamInterface $stream)
Chris@0 38 {
Chris@0 39 $line = '';
Chris@0 40 $crFound = false;
Chris@0 41 while (! $stream->eof()) {
Chris@0 42 $char = $stream->read(1);
Chris@0 43
Chris@0 44 if ($crFound && $char === self::LF) {
Chris@0 45 $crFound = false;
Chris@0 46 break;
Chris@0 47 }
Chris@0 48
Chris@0 49 // CR NOT followed by LF
Chris@0 50 if ($crFound && $char !== self::LF) {
Chris@0 51 throw new UnexpectedValueException('Unexpected carriage return detected');
Chris@0 52 }
Chris@0 53
Chris@0 54 // LF in isolation
Chris@0 55 if (! $crFound && $char === self::LF) {
Chris@0 56 throw new UnexpectedValueException('Unexpected line feed detected');
Chris@0 57 }
Chris@0 58
Chris@0 59 // CR found; do not append
Chris@0 60 if ($char === self::CR) {
Chris@0 61 $crFound = true;
Chris@0 62 continue;
Chris@0 63 }
Chris@0 64
Chris@0 65 // Any other character: append
Chris@0 66 $line .= $char;
Chris@0 67 }
Chris@0 68
Chris@0 69 // CR found at end of stream
Chris@0 70 if ($crFound) {
Chris@0 71 throw new UnexpectedValueException("Unexpected end of headers");
Chris@0 72 }
Chris@0 73
Chris@0 74 return $line;
Chris@0 75 }
Chris@0 76
Chris@0 77 /**
Chris@0 78 * Split the stream into headers and body content.
Chris@0 79 *
Chris@0 80 * Returns an array containing two elements
Chris@0 81 *
Chris@0 82 * - The first is an array of headers
Chris@0 83 * - The second is a StreamInterface containing the body content
Chris@0 84 *
Chris@0 85 * @param StreamInterface $stream
Chris@0 86 * @return array
Chris@0 87 * @throws UnexpectedValueException For invalid headers.
Chris@0 88 */
Chris@0 89 protected static function splitStream(StreamInterface $stream)
Chris@0 90 {
Chris@0 91 $headers = [];
Chris@0 92 $currentHeader = false;
Chris@0 93
Chris@0 94 while ($line = self::getLine($stream)) {
Chris@0 95 if (preg_match(';^(?P<name>[!#$%&\'*+.^_`\|~0-9a-zA-Z-]+):(?P<value>.*)$;', $line, $matches)) {
Chris@0 96 $currentHeader = $matches['name'];
Chris@0 97 if (! isset($headers[$currentHeader])) {
Chris@0 98 $headers[$currentHeader] = [];
Chris@0 99 }
Chris@0 100 $headers[$currentHeader][] = ltrim($matches['value']);
Chris@0 101 continue;
Chris@0 102 }
Chris@0 103
Chris@0 104 if (! $currentHeader) {
Chris@0 105 throw new UnexpectedValueException('Invalid header detected');
Chris@0 106 }
Chris@0 107
Chris@0 108 if (! preg_match('#^[ \t]#', $line)) {
Chris@0 109 throw new UnexpectedValueException('Invalid header continuation');
Chris@0 110 }
Chris@0 111
Chris@0 112 // Append continuation to last header value found
Chris@0 113 $value = array_pop($headers[$currentHeader]);
Chris@0 114 $headers[$currentHeader][] = $value . ltrim($line);
Chris@0 115 }
Chris@0 116
Chris@0 117 // use RelativeStream to avoid copying initial stream into memory
Chris@0 118 return [$headers, new RelativeStream($stream, $stream->tell())];
Chris@0 119 }
Chris@0 120
Chris@0 121 /**
Chris@0 122 * Serialize headers to string values.
Chris@0 123 *
Chris@0 124 * @param array $headers
Chris@0 125 * @return string
Chris@0 126 */
Chris@0 127 protected static function serializeHeaders(array $headers)
Chris@0 128 {
Chris@0 129 $lines = [];
Chris@0 130 foreach ($headers as $header => $values) {
Chris@0 131 $normalized = self::filterHeader($header);
Chris@0 132 foreach ($values as $value) {
Chris@0 133 $lines[] = sprintf('%s: %s', $normalized, $value);
Chris@0 134 }
Chris@0 135 }
Chris@0 136
Chris@0 137 return implode("\r\n", $lines);
Chris@0 138 }
Chris@0 139
Chris@0 140 /**
Chris@0 141 * Filter a header name to wordcase
Chris@0 142 *
Chris@0 143 * @param string $header
Chris@0 144 * @return string
Chris@0 145 */
Chris@0 146 protected static function filterHeader($header)
Chris@0 147 {
Chris@0 148 $filtered = str_replace('-', ' ', $header);
Chris@0 149 $filtered = ucwords($filtered);
Chris@0 150 return str_replace(' ', '-', $filtered);
Chris@0 151 }
Chris@0 152 }