| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160 |
- <?php
- /**
- * Zend Framework (http://framework.zend.com/)
- *
- * @see http://github.com/zendframework/zend-diactoros for the canonical source repository
- * @copyright Copyright (c) 2015-2016 Zend Technologies USA Inc. (http://www.zend.com)
- * @license https://github.com/zendframework/zend-diactoros/blob/master/LICENSE.md New BSD License
- */
- namespace Zend\Diactoros;
- use Psr\Http\Message\StreamInterface;
- use UnexpectedValueException;
- use function array_pop;
- use function implode;
- use function ltrim;
- use function preg_match;
- use function sprintf;
- use function str_replace;
- use function ucwords;
- /**
- * Provides base functionality for request and response de/serialization
- * strategies, including functionality for retrieving a line at a time from
- * the message, splitting headers from the body, and serializing headers.
- */
- abstract class AbstractSerializer
- {
- const CR = "\r";
- const EOL = "\r\n";
- const LF = "\n";
- /**
- * Retrieve a single line from the stream.
- *
- * Retrieves a line from the stream; a line is defined as a sequence of
- * characters ending in a CRLF sequence.
- *
- * @param StreamInterface $stream
- * @return string
- * @throws UnexpectedValueException if the sequence contains a CR or LF in
- * isolation, or ends in a CR.
- */
- protected static function getLine(StreamInterface $stream)
- {
- $line = '';
- $crFound = false;
- while (! $stream->eof()) {
- $char = $stream->read(1);
- if ($crFound && $char === self::LF) {
- $crFound = false;
- break;
- }
- // CR NOT followed by LF
- if ($crFound && $char !== self::LF) {
- throw new UnexpectedValueException('Unexpected carriage return detected');
- }
- // LF in isolation
- if (! $crFound && $char === self::LF) {
- throw new UnexpectedValueException('Unexpected line feed detected');
- }
- // CR found; do not append
- if ($char === self::CR) {
- $crFound = true;
- continue;
- }
- // Any other character: append
- $line .= $char;
- }
- // CR found at end of stream
- if ($crFound) {
- throw new UnexpectedValueException("Unexpected end of headers");
- }
- return $line;
- }
- /**
- * Split the stream into headers and body content.
- *
- * Returns an array containing two elements
- *
- * - The first is an array of headers
- * - The second is a StreamInterface containing the body content
- *
- * @param StreamInterface $stream
- * @return array
- * @throws UnexpectedValueException For invalid headers.
- */
- protected static function splitStream(StreamInterface $stream)
- {
- $headers = [];
- $currentHeader = false;
- while ($line = self::getLine($stream)) {
- if (preg_match(';^(?P<name>[!#$%&\'*+.^_`\|~0-9a-zA-Z-]+):(?P<value>.*)$;', $line, $matches)) {
- $currentHeader = $matches['name'];
- if (! isset($headers[$currentHeader])) {
- $headers[$currentHeader] = [];
- }
- $headers[$currentHeader][] = ltrim($matches['value']);
- continue;
- }
- if (! $currentHeader) {
- throw new UnexpectedValueException('Invalid header detected');
- }
- if (! preg_match('#^[ \t]#', $line)) {
- throw new UnexpectedValueException('Invalid header continuation');
- }
- // Append continuation to last header value found
- $value = array_pop($headers[$currentHeader]);
- $headers[$currentHeader][] = $value . ltrim($line);
- }
- // use RelativeStream to avoid copying initial stream into memory
- return [$headers, new RelativeStream($stream, $stream->tell())];
- }
- /**
- * Serialize headers to string values.
- *
- * @param array $headers
- * @return string
- */
- protected static function serializeHeaders(array $headers)
- {
- $lines = [];
- foreach ($headers as $header => $values) {
- $normalized = self::filterHeader($header);
- foreach ($values as $value) {
- $lines[] = sprintf('%s: %s', $normalized, $value);
- }
- }
- return implode("\r\n", $lines);
- }
- /**
- * Filter a header name to wordcase
- *
- * @param string $header
- * @return string
- */
- protected static function filterHeader($header)
- {
- $filtered = str_replace('-', ' ', $header);
- $filtered = ucwords($filtered);
- return str_replace(' ', '-', $filtered);
- }
- }
|