Location: PHPKode > scripts > Fleck HTTP > dhorrigan-fleck-http-35d4dd5/src/Fleck/Http/Response.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 RuntimeException;
use InvalidArgumentException;
use OutOfBoundsException;

/**
 * The Response class allows you to easily create an HTTP response which you
 * can then send to the browser, or use however you like.
 */
class Response
{
    /**
     * @var array All valid HTTP response codes.
     * @static
     */
    protected static $statusCodes = [
        100 => 'Continue',
        101 => 'Switching Protocols',
        102 => 'Processing',
        200 => 'OK',
        201 => 'Created',
        202 => 'Accepted',
        203 => 'Non-Authoritative Information',
        204 => 'No Content',
        205 => 'Reset Content',
        206 => 'Partial Content',
        207 => 'Multi-Status',
        208 => 'Already Reported',
        226 => 'IM Used',
        300 => 'Multiple Choices',
        301 => 'Moved Permanently',
        302 => 'Found',
        303 => 'See Other',
        304 => 'Not Modified',
        305 => 'Use Proxy',
        306 => 'Reserved',
        307 => 'Temporary Redirect',
        308 => 'Permanent Redirect',
        400 => 'Bad Request',
        401 => 'Unauthorized',
        402 => 'Payment Required',
        403 => 'Forbidden',
        404 => 'Not Found',
        405 => 'Method Not Allowed',
        406 => 'Not Acceptable',
        407 => 'Proxy Authentication Required',
        408 => 'Request Timeout',
        409 => 'Conflict',
        410 => 'Gone',
        411 => 'Length Required',
        412 => 'Precondition Failed',
        413 => 'Request Entity Too Large',
        414 => 'Request-URI Too Long',
        415 => 'Unsupported Media Type',
        416 => 'Requested Range Not Satisfiable',
        417 => 'Expectation Failed',
        418 => 'I\'m a celestial teapot',
        422 => 'Unprocessable Entity',
        423 => 'Locked',
        424 => 'Failed Dependency',
        425 => 'Reserved for WebDAV advanced collections expired proposal',
        426 => 'Upgrade Required',
        428 => 'Precondition Required',
        429 => 'Too Many Requests',
        431 => 'Request Header Fields Too Large',
        500 => 'Internal Server Error',
        501 => 'Not Implemented',
        502 => 'Bad Gateway',
        503 => 'Service Unavailable',
        504 => 'Gateway Timeout',
        505 => 'HTTP Version Not Supported',
        506 => 'Variant Also Negotiates (Experimental)',
        507 => 'Insufficient Storage',
        508 => 'Loop Detected',
        510 => 'Not Extended',
        511 => 'Network Authentication Required',
    ];

    /**
     * @var Headers The Response headers.
     */
    public $headers = null;

    /**
     * @var string The content of the Response.
     */
    protected $content = '';

    /**
     * @var int The HTTP status code of the Response.
     */
    protected $status = 200;

    /**
     * @var string The Content-Type (mime-type) of the Response.
     */
    protected $contentType = null;

    /**
     * @var string The charset that the Response is using.
     */
    protected $charset = 'utf-8';
    
    /**
     * @var bool Whether the headers have been sent.
     */
    protected $headersSent = false;

    /**
     * @var bool Whether to treat this Response as an attachment.
     */
    protected $isAttachment = false;

    /**
     * @var string The attachment source file.
     */
    protected $attachmentSourceFile = null;

    /**
     * @var string The attachment filename to send to the browser.
     */
    protected $attachmentFilename = null;

    /**
     * Constructs the Response object based on the given argument.  The $arg
     * argument can either be an array of configuration options or a string
     * containing the Responses content.
     *
     * When sending a config array, the only valid options are options that
     * have a set*() method.
     *
     * @param string|array Either the content string or an options array.
     * @return void
     * @throws OutOfBoundsException
     * @throws InvalidArgumentException
     */
    public function __construct($arg = null)
    {
        if (is_array($arg)) {
            foreach ($arg as $key => $value) {
                $setterName = 'set'.ucfirst($key);
                if (method_exists($this, $setterName)) {
                    $this->$setterName($value);
                } else {
                    throw new OutOfBoundsException(sprintf('"%s" is not a valid property.', $key));
                }
            }
        } elseif (is_string($arg)) {
            $this->content = $arg;
        } elseif ($arg !== null) {
            throw new InvalidArgumentException('Array or String expected.');
        }

        if ($this->headers === null) {
            $this->setHeaders(new Headers());
        }
    }

    /**
     * Sets the headers.
     *
     * @param array $headers The headers to set.
     * @param bool $replaceExisting Whether to replace individual headers, or append.
     * @return Fleck\Http\Response The Response object.
     * @throws InvalidArgumentException
     */
    public function setHeaders($headers)
    {
        if (is_array($headers)) {
            $this->headers = new Headers($headers);
        } elseif ($headers instanceof Headers) {
            $this->headers = $headers;
        } else {
            throw new InvalidArgumentException('setHeaders must be sent an array or an instance of Fleck\Http\Headers.');
        }

        return $this;
    }

    /**
     * Sends all of the registered headers to the browser.  Builds any missing, but
     * necessary, headers (e.g. Content-Type) prior to sending them.
     *
     * @return Fleck\Http\Response The Response object.
     * @throws RuntimeException
     */
    public function sendHeaders()
    {
        if ($this->headersSent or headers_sent()) {
            throw new RuntimeException('The HTTP headers have already been sent.');
        }

        http_response_code($this->getStatus());

        if ($this->contentType === null and ! $this->isAttachment) {
            $this->contentType = 'text/html';
        } elseif ($this->isAttachment) {
            if ($this->attachmentSourceFile === null) {
                throw new RuntimeException('You must set the attachment Source File when the Request is set as an Attachment.');
            }

            $finfo = finfo_open(FILEINFO_MIME);
            $mimeType = finfo_file($finfo, $this->attachmentSourceFile);
            finfo_close($finfo);

            if ($mimeType === false) {
                $mimeType = 'application/octet-stream';
            }
            $this->headers->set('Content-Type', $mimeType);

            if ($this->attachmentFilename === null) {
                $this->attachmentFilename = basename($this->attachmentSourceFile);
            }

            $this->headers->set('Content-Disposition', 'attachment; filename="'.$this->attachmentFilename.'"');
        }

        if (! $this->headers->has('Content-Type')) {
            $this->headers->set('Content-Type', $this->contentType.'; charset='.$this->charset);
        }

        foreach ($this->headers as $name => $values) {
            foreach ($values as $value) {
                header(sprintf('%s: %s', $name, $value));
            }
        }

        $this->headersSent = true;

        return $this;
    }

     /**
     * Gets the Response's content.
     *
     * @return string The Response content.
     */
    public function getContent()
    {
        return $this->content;
    }

    /**
     * Sets the Response's content.
     *
     * @param string The content of the Response.
     * @return Fleck\Http\Response The Fleck\Http\Response object.
     */
    public function setContent($content = '')
    {
        $this->content = $content;

        return $this;
    }

    /**
     * Sends the Response content to the browser either via echo or readfile()
     * depending on if the response is an attachment.
     *
     * @return Fleck\Http\Response The Fleck\Http\Response object.
     */
    public function sendContent()
    {
        if ($this->isAttachment) {
            if ( ! $this->headersSent) {
                throw new RuntimeException('You must send the headers before sending the content when the Response is an attachment.');
            }
            readfile($this->attachmentSourceFile);
        } else {
            echo $this->getContent();
        }

        return $this;
    }
    /**
     * Gets the Response's Status code.  You can optionally have it returned
     * as the full status string (e.g. "200 OK").
     *
     * @param bool Whether to return the full status string.
     * @return string|int
     */
    public function getStatus($asString = false)
    {
        if ($asString) {
            return $this->status.' '.self::$statusCodes[$this->status];
        }

        return $this->status;
    }

    /**
     * Sets the Response's status code to the given code.
     *
     * @param int The status code to set.
     * @return Fleck\Http\Response The Fleck\Http\Response object.
     * @throws OutOfBoundsException
     */
    public function setStatus($status)
    {
        if (! array_key_exists($status, self::$statusCodes)) {
            throw new OutOfBoundsException(sprintf('%d is not a valid HTTP status code.', $status));
        }
        $this->status = $status;

        return $this;
    }

    /**
     * Sets whether to treat this Response as an attachment (i.e. download it
     * as a file).
     *
     * @param bool Whether to treat the Response as an attachment.
     * @return Fleck\Http\Response The Fleck\Http\Response object.
     */
    public function setAttachment($isAttachment = true)
    {
        $this->isAttachment = $isAttachment;

        return $this;
    }

    /**
     * Sets the attachment source file name.  This is the file that is to be
     * streamed to the browser.
     *
     * @param string The attachment source file name.
     * @return Fleck\Http\Response The Fleck\Http\Response object.
     * @throws InvalidArgumentException
     */
    public function setAttachmentSourceFile($file)
    {
        if (! is_file($file) or ! is_readable($file)) {
            throw new InvalidArgumentException(sprintf('"%s" is not a readable file.', $file));
        } 
        $this->attachmentSourceFile = $file;

        return $this;
    }

    /**
     * Set the attachement file name that will be sent to the browser.
     *
     * @param string The attachment file name.
     * @return Fleck\Http\Response The Fleck\Http\Response object.
     */
    public function setAttachmentFilename($filename)
    {
        $this->attachmentFilename = $filename;

        return $this;
    }

    /**
     * A shortcut for sending the headers then the content.
     * This is the same as calling $r->sendHeaders()->sendContent();
     *
     * @return Fleck\Http\Response The Fleck\Http\Response object.
     */
    public function send()
    {
        return $this->sendHeaders()->sendContent();
    }

    /**
     * Magic method for when the Response is cast as a string.
     *
     * @return string The Response content.
     */
    public function __toString()
    {
        return $this->getContent();
    }
}
Return current item: Fleck HTTP