File indexing completed on 2024-04-28 17:09:58

0001 <?php
0002 
0003 /**
0004  * Flooer Framework
0005  *
0006  * LICENSE: BSD License (2 Clause)
0007  *
0008  * @category    Flooer
0009  * @package     Flooer_Http
0010  * @subpackage  Response
0011  * @author      Akira Ohgaki <akiraohgaki@gmail.com>
0012  * @copyright   Akira Ohgaki
0013  * @license     https://opensource.org/licenses/BSD-2-Clause  BSD License (2 Clause)
0014  * @link        https://github.com/akiraohgaki/flooer
0015  */
0016 
0017 /**
0018  * Usage
0019  *
0020  * $response = new Flooer_Http_Response();
0021  * $response->setStatus(201);
0022  * $response->setHeader('Content-Type', 'text/html');
0023  * $response->setBody($data);
0024  * $response->send();
0025  */
0026 
0027 /**
0028  * HTTP response class
0029  *
0030  * @category    Flooer
0031  * @package     Flooer_Http
0032  * @subpackage  Response
0033  * @author      Akira Ohgaki <akiraohgaki@gmail.com>
0034  */
0035 class Flooer_Http_Response
0036 {
0037 
0038     /**
0039      * Configuration options
0040      *
0041      * @var     array
0042      */
0043     protected $_config = array(
0044         'status' => null,
0045         'redirect' => null,
0046         'headers' => array(),
0047         'body' => null,
0048         'replace' => true
0049     );
0050 
0051     /**
0052      * Status codes
0053      *
0054      * @var     array
0055      * @link    http://www.iana.org/assignments/http-status-codes
0056      */
0057     protected $_statusCodes = array(
0058         100 => '100 Continue',
0059         101 => '101 Switching Protocols',
0060         102 => '102 Processing',
0061         // 103-199 Unassigned
0062         200 => '200 OK',
0063         201 => '201 Created',
0064         202 => '202 Accepted',
0065         203 => '203 Non-Authoritative Information',
0066         204 => '204 No Content',
0067         205 => '205 Reset Content',
0068         206 => '206 Partial Content',
0069         207 => '207 Multi-Status',
0070         208 => '208 Already Reported',
0071         // 209-225 Unassigned
0072         226 => '226 IM Used',
0073         // 227-299 Unassigned
0074         300 => '300 Multiple Choices',
0075         301 => '301 Moved Permanently',
0076         302 => '302 Found',
0077         303 => '303 See Other',
0078         304 => '304 Not Modified',
0079         305 => '305 Use Proxy',
0080         // 306 Unused
0081         307 => '307 Temporary Redirect',
0082         308 => '308 Permanent Redirect',
0083         // 309-399 Unassigned
0084         400 => '400 Bad Request',
0085         401 => '401 Unauthorized',
0086         402 => '402 Payment Required',
0087         403 => '403 Forbidden',
0088         404 => '404 Not Found',
0089         405 => '405 Method Not Allowed',
0090         406 => '406 Not Acceptable',
0091         407 => '407 Proxy Authentication Required',
0092         408 => '408 Request Timeout',
0093         409 => '409 Conflict',
0094         410 => '410 Gone',
0095         411 => '411 Length Required',
0096         412 => '412 Precondition Failed',
0097         413 => '413 Payload Too Large',
0098         414 => '414 URI Too Long',
0099         415 => '415 Unsupported Media Type',
0100         416 => '416 Range Not Satisfiable',
0101         417 => '417 Expectation Failed',
0102         // 418-420 Unassigned
0103         421 => '421 Misdirected Request',
0104         422 => '422 Unprocessable Entity',
0105         423 => '423 Locked',
0106         424 => '424 Failed Dependency',
0107         // 425 Unassigned
0108         426 => '426 Upgrade Required',
0109         // 427 Unassigned
0110         428 => '428 Precondition Required',
0111         429 => '429 Too Many Requests',
0112         // 430 Unassigned
0113         431 => '431 Request Header Fields Too Large',
0114         // 432-450 Unassigned
0115         451 => '451 Unavailable for Legal Reasons',
0116         // 452-499 Unassigned
0117         500 => '500 Internal Server Error',
0118         501 => '501 Not Implemented',
0119         502 => '502 Bad Gateway',
0120         503 => '503 Service Unavailable',
0121         504 => '504 Gateway Timeout',
0122         505 => '505 HTTP Version Not Supported',
0123         506 => '506 Variant Also Negotiates',
0124         507 => '507 Insufficient Storage',
0125         508 => '508 Loop Detected',
0126         // 509 Unassigned
0127         510 => '510 Not Extended',
0128         511 => '511 Network Authentication Required'
0129         // 512-599 Unassigned
0130     );
0131 
0132     /**
0133      * Content types
0134      *
0135      * @var     array
0136      */
0137     protected $_contentTypes = array(
0138         'xml' => 'application/xml',
0139         'rdf' => 'application/rdf+xml',
0140         'atom' => 'application/atom+xml',
0141         'rss' => 'application/rss+xml',
0142         'xhtml' => 'application/xhtml+xml',
0143         'json' => 'application/json',
0144         'php' => 'text/html',
0145         'phtml' => 'text/html',
0146         'html' => 'text/html',
0147         'txt' => 'text/plain',
0148         'csv' => 'text/csv',
0149         'tsv' => 'text/tab-separated-values',
0150         'vcf' => 'text/x-vcard',
0151         'ics' => 'text/calendar',
0152         'js' => 'text/javascript',
0153         'css' => 'text/css'
0154     );
0155 
0156     /**
0157      * Constructor
0158      *
0159      * @param   array $config
0160      * @return  void
0161      */
0162     public function __construct(array $config = null)
0163     {
0164         if ($config) {
0165             $this->_config = $config + $this->_config;
0166         }
0167     }
0168 
0169     /**
0170      * Send a response
0171      *
0172      * @return  void
0173      */
0174     public function send()
0175     {
0176         if ($this->_config['status']) {
0177             $this->sendStatus($this->_config['status']);
0178         }
0179         if ($this->_config['redirect']) {
0180             $this->redirect($this->_config['redirect']);
0181         }
0182         if ($this->_config['headers']) {
0183             foreach ($this->_config['headers'] as $name => $value) {
0184                 $this->sendHeader($name, $value);
0185             }
0186         }
0187         if ($this->_config['body']) {
0188             echo $this->_config['body'];
0189         }
0190     }
0191 
0192     /**
0193      * Send a status code
0194      *
0195      * @param   int $code
0196      * @return  void
0197      */
0198     public function sendStatus($code)
0199     {
0200         if (isset($this->_statusCodes[$code])) {
0201             header(
0202                 $_SERVER['SERVER_PROTOCOL'] . ' ' . $this->_statusCodes[$code],
0203                 $this->_config['replace']
0204             );
0205             header(
0206                 'Status: ' . $this->_statusCodes[$code],
0207                 $this->_config['replace'],
0208                 $code
0209             );
0210         }
0211     }
0212 
0213     /**
0214      * Redirection
0215      *
0216      * @param   string $location
0217      * @return  void
0218      */
0219     public function redirect($location)
0220     {
0221         header('Location: ' . $location, true);
0222         exit;
0223     }
0224 
0225     /**
0226      * Send a response header
0227      *
0228      * @param   string $name
0229      * @param   string $value
0230      * @return  void
0231      */
0232     public function sendHeader($name, $value)
0233     {
0234         header($name . ': ' . $value, $this->_config['replace']);
0235     }
0236 
0237     /**
0238      * Detect a content type
0239      *
0240      * @param   string $filename
0241      * @return  string|null
0242      */
0243     public function detectContentType($filename)
0244     {
0245         $type = null;
0246         if (preg_match("/.+\.([^\.]+)$/", strtolower($filename), $matches)
0247             && isset($this->_contentTypes[$matches[1]])
0248         ) {
0249             $type = $this->_contentTypes[$matches[1]];
0250             if (extension_loaded('mbstring') && mb_http_output() != 'pass') {
0251                 $type .= '; charset=' . mb_http_output();
0252             }
0253         }
0254         return $type;
0255     }
0256 
0257     /**
0258      * Set a status code
0259      *
0260      * @param   int $code
0261      * @return  void
0262      */
0263     public function setStatus($code)
0264     {
0265         $this->_config['status'] = $code;
0266     }
0267 
0268     /**
0269      * Get a status code
0270      *
0271      * @return  int
0272      */
0273     public function getStatus()
0274     {
0275         return $this->_config['status'];
0276     }
0277 
0278     /**
0279      * Set a redirect location
0280      *
0281      * @param   string $location
0282      * @return  void
0283      */
0284     public function setRedirect($location)
0285     {
0286         $this->_config['redirect'] = $location;
0287     }
0288 
0289     /**
0290      * Get a redirect location
0291      *
0292      * @return  string
0293      */
0294     public function getRedirect()
0295     {
0296         return $this->_config['redirect'];
0297     }
0298 
0299     /**
0300      * Set a response headers
0301      *
0302      * @param   array $headers
0303      * @return  void
0304      */
0305     public function setHeaders(array $headers)
0306     {
0307         $this->_config['headers'] = $headers;
0308     }
0309 
0310     /**
0311      * Get a response headers
0312      *
0313      * @return  array
0314      */
0315     public function getHeaders()
0316     {
0317         return $this->_config['headers'];
0318     }
0319 
0320     /**
0321      * Set a response header
0322      *
0323      * @param   string $name
0324      * @param   string $value
0325      * @return  void
0326      */
0327     public function setHeader($name, $value)
0328     {
0329         $this->_config['headers'][$name] = $value;
0330     }
0331 
0332     /**
0333      * Get a response header
0334      *
0335      * @param   string $name
0336      * @return  string|null
0337      */
0338     public function getHeader($name)
0339     {
0340         if (isset($this->_config['headers'][$name])) {
0341             return $this->_config['headers'][$name];
0342         }
0343         return null;
0344     }
0345 
0346     /**
0347      * Set a response body data
0348      *
0349      * @param   mixed $data
0350      * @return  void
0351      */
0352     public function setBody($data)
0353     {
0354         $this->_config['body'] = $data;
0355     }
0356 
0357     /**
0358      * Get a response body data
0359      *
0360      * @return  mixed
0361      */
0362     public function getBody()
0363     {
0364         return $this->_config['body'];
0365     }
0366 
0367     /**
0368      * Set a header replace option
0369      *
0370      * @param   bool $replace
0371      * @return  void
0372      */
0373     public function setReplace($replace)
0374     {
0375         $this->_config['replace'] = $replace;
0376     }
0377 
0378     /**
0379      * Get a header replace option
0380      *
0381      * @return  bool
0382      */
0383     public function getReplace()
0384     {
0385         return $this->_config['replace'];
0386     }
0387 
0388 }