Location: PHPKode > scripts > Fleck HTTP > dhorrigan-fleck-http-35d4dd5/src/Fleck/Http/Headers.php
<?php
/**
 * Part of the Fleck HTTP Component
 *
 * @author     Dan Horrigan <hide@address.com>
 * @copyright  2012 Dan Horrigan
 * @license    http://opensource.org/licenses/mit-license.php  MIT License
 * @version    1.0-dev
 */

namespace Fleck\Http;

use OutOfBoundsException;
use RuntimeException;
use ArrayIterator;
use IteratorAggregate;
use Countable;
use ArrayAccess;

/**
 * Encapsulates any Response or Request headers.
 */
class Headers implements IteratorAggregate, Countable, ArrayAccess
{
    /**
     * @var array Holds all the headers
     */
    protected $headers = [];

    /**
     * Takes a string of properly formatted HTTP headers and parses it
     * out and returns a valid Headers object.  This can be used to parse
     * raw response headers and the resulting object be sent to the
     * Response or Request classes.
     *
     * @static
     * @param string The headers string
     * @return Headers The new Headers object
     * @throws RuntimeException
     */
    public static function fromString($string)
    {
        $headers = new static();
        $currentHeader = [];

        foreach (explode("\r\n", $string) as $line) {

            // Parse a valid header line.
            if (preg_match('/^(?P<label>[a-zA-Z0-9_-]+):\s*(?P<value>.*)$/', $line, $match)) {
                if ( ! empty($currentHeader)) {
                    $headers->set($currentHeader['label'], $currentHeader['value'], false);
                }
                $currentHeader = ['label' => $match['label'], 'value' => $match['value']];
            }

            // If we are in a header, but there it doesn't match a new header line,
            // then it must be a continuation of the current header.
            elseif ( ! empty($currentHeader) and preg_match('/^\s+.*$/', $line, $match)) {
                $currentHeader['value'] .= trim($line);
            }

            // A blank line indicates the end of the headers.
            elseif (preg_match('/^\s*$/', $line)) {
                break;
            } else {
                throw new RuntimeException(sprintf('"%s" is not a valid header.', $line));
            }
        }

        // Finish up by writing the open header if there is one.
        if ( ! empty($currentHeader)) {
            $headers->set($currentHeader['label'], $currentHeader['value'], false);
        }

        return $headers;
    }

    /**
     * Sets up with Headers object with the given headers.
     *
     * @param array Headers to initialize with.
     */
    public function __construct(array $headers = [])
    {
        if ( ! empty($headers)) {
            $this->add($headers);
        }
    }

    /**
     * Returns all of the headers.
     *
     * @return array The headers.
     */
    public function all()
    {
        return $this->headers;
    }

    /**
     * Sets an array of headers.
     *
     * @param array The headers to add.
     * @return Headers
     */
    public function add(array $headers)
    {
        foreach ($headers as $label => $values) {
            $this->set($label, $values);
        }

        return $this;
    }

    /**
     * Sets the given header to the given value.  It optionally accepts an array
     * of values, which will send multiple headers of the same name with the
     * given values when the headers are sent.
     *
     * @param string $label The name of the header.
     * @param mixed $value The value(s) of the header.
     * @param bool $replaceExisting Whether to replace the given header, or append.
     * @return Headers The Headers object.
     */
    public function set($label, $value = null, $replaceExisting = true)
    {
        $label = $this->cleanLabel($label);
        $value = $this->cleanValue($value);
        if ($replaceExisting or ! array_key_exists($label, $this->headers)) {
            $this->headers[$label] = is_array($value) ? $value : [$value];
        } else {
            array_push($this->headers[$label], $value);
        }

        return $this;
    }

    /**
     * Gets the given header if it exists.
     *
     * @param mixed The Header label.
     * @param bool Get only the first header value.
     * @return mixeed The header value.
     * @throws OutOfBoundsException
     */
    public function get($label, $firstOnly = true)
    {
        $label = $this->cleanLabel($label);
        if ( ! array_key_exists($label, $this->headers)) {
            throw new OutOfBoundsException(sprintf('%s is not a valid offset.', $label));
        }

        return $firstOnly ? $this->headers[$label][0] : $this->headers[$label];
    }

    /**
     * Checks if the given header exists.
     *
     * @param mixed The Header label.
     * @return bool Whether it exists.
     */
    public function has($label)
    {
        $label = $this->cleanLabel($label);

        return array_key_exists($label, $this->headers);
    }

    /**
     * Removes the given header.
     *
     * @param mixed The header to remove.
     * @return Headers
     */
    public function remove($label)
    {
        $label = $this->cleanLabel($label);
        unset($this->headers[$label]);

        return $this;
    }

    /**
     * Returns all of the headers in string form.
     *
     * @return string The header string.
     */
    public function __toString()
    {
        if (count($this->headers) === 0) {
            return '';
        }
        
        $string = '';

        foreach ($this->headers as $label => $values) {
            foreach ($values as $value) {
                $string .= $label.': '.$value."\r\n";
            }
        }

        return $string;
    }

    /**
     * Returns an ArrayIterator for the headers.
     *
     * @return ArrayIterator An ArrayIterator instance.
     */
    public function getIterator()
    {
        return new ArrayIterator($this->headers);
    }

    /**
     * Gets the number of headers.
     *
     * @return int The number of headers.
     */
    public function count()
    {
        return count($this->headers);
    }

    /**
     * Checks if the given header exists.
     *
     * @param mixed The Header label.
     * @return bool Whether it exists.
     */
    public function offsetExists($label)
    {
        return $this->has($label);
    }

    /**
     * Gets the given header if it exists.
     *
     * @param mixed The Header label.
     * @return mixeed The header value.
     * @throws OutOfBoundsException
     */
    public function offsetGet($label)
    {
        return $this->get($label);
    }

    /**
     * Sets the given header.
     *
     * @param string The header label.
     * @param mixed The header value.
     * @return void
     */
    public function offsetSet($label, $value)
    {
        $this->set($label, $value);
    }

    /**
     * Removes the given header.
     *
     * @param mixed The header to remove.
     * @return void
     */
    public function offsetUnset($label)
    {
        $this->remove($label);
    }

    /**
     * Sanitizes, then Normalizes the given header label.
     *
     * @param string The header label.
     * @return string The clean label.
     */
    protected function cleanLabel($label)
    {
        // Sanitize the label
        $label = preg_replace('/[^a-zA-Z0-9_-]/', '', $label);

        // Normalize the label
        $label = ucwords(strtolower(str_replace(['_', '-'], ' ', $label)));
        return str_replace(' ', '-', $label);
    }

    /**
     * Removes all line breaks from the header value.
     *
     * @param string The header value.
     * @return string The clean value.
     */
    protected function cleanValue($value)
    {
        return str_replace(["\r", "\n"], '', $value);
    }
}
Return current item: Fleck HTTP