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  Request
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  * $request = new Flooer_Http_Request();
0021  * $request->addUriMapRule(
0022  *     '^tags/(.+)/(.*)',
0023  *     'key=$1&params=$2',
0024  *     'params'
0025  * );
0026  * $request->addUriMapRule(
0027  *     array('^TAGS/(.+)/(.*)', '#', 'i'),
0028  *     'key=$1&params=$2',
0029  *     array('params', '/')
0030  * );
0031  * $request->mapUri();
0032  * $value = $request->key;
0033  */
0034 
0035 /**
0036  * HTTP request class
0037  *
0038  * @category    Flooer
0039  * @package     Flooer_Http
0040  * @subpackage  Request
0041  * @author      Akira Ohgaki <akiraohgaki@gmail.com>
0042  */
0043 class Flooer_Http_Request
0044 {
0045 
0046     /**
0047      * Configuration options
0048      *
0049      * @var     array
0050      */
0051     protected $_config = array(
0052         'importPredefinedVars' => true,
0053         'mapUri' => false,
0054         'uriMapRules' => array()
0055     );
0056 
0057     /**
0058      * Overloaded properties
0059      *
0060      * @var     array
0061      */
0062     protected $_properties = array();
0063 
0064     /**
0065      * Constructor
0066      *
0067      * @param   array $config
0068      * @return  void
0069      */
0070     public function __construct(array $config = null)
0071     {
0072         if ($config) {
0073             $this->_config = $config + $this->_config;
0074         }
0075         if ($this->_config['importPredefinedVars']) {
0076             $this->importPredefinedVars();
0077         }
0078         if ($this->_config['mapUri']) {
0079             $this->mapUri();
0080         }
0081     }
0082 
0083     /**
0084      * Magic method to set a property
0085      *
0086      * @param   string $key
0087      * @param   mixed $value
0088      * @return  void
0089      */
0090     public function __set($key, $value)
0091     {
0092         $this->_properties[$key] = $value;
0093     }
0094 
0095     /**
0096      * Magic method to get a property
0097      *
0098      * @param   string $key
0099      * @return  mixed
0100      */
0101     public function __get($key)
0102     {
0103         if (isset($this->_properties[$key])) {
0104             return $this->_properties[$key];
0105         }
0106         return null;
0107     }
0108 
0109     /**
0110      * Magic method to check a property
0111      *
0112      * @param   string $key
0113      * @return  bool
0114      */
0115     public function __isset($key)
0116     {
0117         return isset($this->_properties[$key]);
0118     }
0119 
0120     /**
0121      * Magic method to unset a property
0122      *
0123      * @param   string $key
0124      * @return  void
0125      */
0126     public function __unset($key)
0127     {
0128         unset($this->_properties[$key]);
0129     }
0130 
0131     /**
0132      * Import a predefined variables
0133      *
0134      * @return  void
0135      */
0136     public function importPredefinedVars()
0137     {
0138         switch ($_SERVER['REQUEST_METHOD']) {
0139             case 'GET':
0140                 if (!empty($_GET)) {
0141                     $this->_properties += $_GET;
0142                 }
0143                 break;
0144             case 'POST':
0145                 if (!empty($_POST)) {
0146                     $this->_properties += $_POST;
0147                 }
0148                 break;
0149             case 'PUT':
0150                 $contentType = $this->getHeader('Content-Type');
0151                 if (!empty($contentType)
0152                     && strpos(strtolower($contentType), 'application/x-www-form-urlencoded') !== false
0153                 ) {
0154                     parse_str($this->getRawBody(), $put);
0155                     if (!empty($put)) {
0156                         $this->_properties += $put;
0157                     }
0158                 }
0159                 break;
0160             case 'DELETE':
0161                 // Continue to default
0162             default:
0163                 if (!empty($_SERVER['QUERY_STRING'])) {
0164                     parse_str($_SERVER['QUERY_STRING'], $params);
0165                     if (!empty($params)) {
0166                         $this->_properties += $params;
0167                     }
0168                 }
0169                 break;
0170         }
0171     }
0172 
0173     /**
0174      * URI mapping
0175      *
0176      * @return  void
0177      */
0178     public function mapUri()
0179     {
0180         $uri = $this->getUri();
0181         if (strpos($uri, $_SERVER['SCRIPT_NAME']) === 0) {
0182             $uri = substr($uri, strlen($_SERVER['SCRIPT_NAME']));
0183         }
0184         else if (strpos($uri, dirname($_SERVER['SCRIPT_NAME'])) === 0) {
0185             $uri = substr($uri, strlen(dirname($_SERVER['SCRIPT_NAME'])));
0186         }
0187         $uri = trim(preg_replace("/^([^\?]*).*/", "$1", $uri), '/');
0188         if ($uri !== '' && $this->_config['uriMapRules']) {
0189             foreach ($this->_config['uriMapRules'] as $rule) {
0190                 $pattern = null;
0191                 $patternDelimiter = '#';
0192                 $patternModifiers = null;
0193                 $replacement = null;
0194                 $addition = null;
0195                 $additionDelimiter = '/';
0196                 if (!empty($rule[0])) {
0197                     if (is_array($rule[0])) {
0198                         if (!empty($rule[0][0])) {
0199                             $pattern = $rule[0][0];
0200                         }
0201                         if (!empty($rule[0][1])) {
0202                             $patternDelimiter = $rule[0][1];
0203                         }
0204                         if (!empty($rule[0][2])) {
0205                             $patternModifiers = $rule[0][2];
0206                         }
0207                     }
0208                     else {
0209                         $pattern = $rule[0];
0210                     }
0211                     $pattern = $patternDelimiter
0212                         . $pattern
0213                         . $patternDelimiter
0214                         . $patternModifiers;
0215                 }
0216                 if (!empty($rule[1])) {
0217                     $replacement = $rule[1];
0218                 }
0219                 if (!empty($rule[2])) {
0220                     if (is_array($rule[2])) {
0221                         if (!empty($rule[2][0])) {
0222                             $addition = $rule[2][0];
0223                         }
0224                         if (!empty($rule[2][1])) {
0225                             $additionDelimiter = $rule[2][1];
0226                         }
0227                     }
0228                     else {
0229                         $addition = $rule[2];
0230                     }
0231                 }
0232                 if ($pattern && $replacement && preg_match($pattern, $uri)) {
0233                     $query = preg_replace($pattern, $replacement, $uri);
0234                     parse_str($query, $params);
0235                     if ($addition && !empty($params[$addition])) {
0236                         $kvPairs = explode(
0237                             $additionDelimiter,
0238                             trim($params[$addition], $additionDelimiter)
0239                         );
0240                         for ($i = 0; $i < count($kvPairs); $i++) {
0241                             $n = $i + 1;
0242                             if (isset($kvPairs[$n])) {
0243                                 $params[$kvPairs[$i]] = $kvPairs[$n];
0244                                 $i = $n;
0245                             }
0246                             else {
0247                                 $params[$kvPairs[$i]] = null;
0248                             }
0249                         }
0250                     }
0251                     $this->_properties = $params + $this->_properties;
0252                     break;
0253                 }
0254             }
0255         }
0256     }
0257 
0258     /**
0259      * Set a URI mapping rules
0260      *
0261      * @param   array $uriMapRules
0262      * @return  void
0263      */
0264     public function setUriMapRules(array $uriMapRules)
0265     {
0266         $this->_config['uriMapRules'] = $uriMapRules;
0267     }
0268 
0269     /**
0270      * Get a URI mapping rules
0271      *
0272      * @return  array
0273      */
0274     public function getUriMapRules()
0275     {
0276         return $this->_config['uriMapRules'];
0277     }
0278 
0279     /**
0280      * Add a URI mapping rule
0281      *
0282      * @param   array|string $pattern Regex
0283      * @param   string $replacement Query string
0284      * @param   array|string $addition Needle to parse as a key-value pairs
0285      * @return  void
0286      */
0287     public function addUriMapRule($pattern, $replacement, $addition = null)
0288     {
0289         $this->_config['uriMapRules'][] = array($pattern, $replacement, $addition);
0290     }
0291 
0292     /**
0293      * Check for a secure connection
0294      *
0295      * @return  bool
0296      */
0297     public function isSecure()
0298     {
0299         if (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') {
0300             return true;
0301         }
0302         return false;
0303     }
0304 
0305     /**
0306      * Check for a XML HTTP request
0307      *
0308      * @return  bool
0309      */
0310     public function isXmlHttpRequest()
0311     {
0312         if (!empty($_SERVER['HTTP_X_REQUESTED_WITH'])
0313             && strtolower($_SERVER['HTTP_X_REQUESTED_WITH'])  == 'xmlhttprequest'
0314         ) {
0315             return true;
0316         }
0317         return false;
0318     }
0319 
0320     /**
0321      * Get a request method
0322      *
0323      * @param   bool $override
0324      * @return  string
0325      */
0326     public function getMethod($override = false)
0327     {
0328         $method = $_SERVER['REQUEST_METHOD'];
0329         if ($override
0330             && !empty($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'])
0331         ) {
0332             $method = strtoupper($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE']);
0333         }
0334         return $method;
0335     }
0336 
0337     /**
0338      * Get a request URI
0339      *
0340      * @return  string|null
0341      */
0342     public function getUri()
0343     {
0344         $uri = null;
0345         // IIS Mod-Rewrite module
0346         if (!empty($_SERVER['HTTP_X_ORIGINAL_URL'])) {
0347             $uri = $_SERVER['HTTP_X_ORIGINAL_URL'];
0348         }
0349         // IIS Isapi_Rewrite module
0350         else if (!empty($_SERVER['HTTP_X_REWRITE_URL'])) {
0351             $uri = $_SERVER['HTTP_X_REWRITE_URL'];
0352         }
0353         // Common
0354         else if (!empty($_SERVER['REQUEST_URI'])) {
0355             $uri = $_SERVER['REQUEST_URI'];
0356         }
0357         // IIS and PHP-CGI
0358         else if (!empty($_SERVER['PATH_INFO'])) {
0359             if ($_SERVER['PATH_INFO'] == $_SERVER['SCRIPT_NAME']) {
0360                 $uri = $_SERVER['PATH_INFO'];
0361             }
0362             else {
0363                 $uri = $_SERVER['SCRIPT_NAME'] . $_SERVER['PATH_INFO'];
0364             }
0365             if (!empty($_SERVER['QUERY_STRING'])) {
0366                 $uri .= '?' . $_SERVER['QUERY_STRING'];
0367             }
0368         }
0369         else if (!empty($_SERVER['ORIG_PATH_INFO'])) {
0370             if ($_SERVER['ORIG_PATH_INFO'] == $_SERVER['SCRIPT_NAME']) {
0371                 $uri = $_SERVER['ORIG_PATH_INFO'];
0372             }
0373             else {
0374                 $uri = $_SERVER['SCRIPT_NAME'] . $_SERVER['ORIG_PATH_INFO'];
0375             }
0376             if (!empty($_SERVER['QUERY_STRING'])) {
0377                 $uri .= '?' . $_SERVER['QUERY_STRING'];
0378             }
0379         }
0380         return $uri;
0381     }
0382 
0383     /**
0384      * Get a request header
0385      *
0386      * @param   string $name
0387      * @return  string|null
0388      */
0389     public function getHeader($name)
0390     {
0391         $header = null;
0392         $key = 'HTTP_' . str_replace('-', '_', strtoupper($name));
0393         if (!empty($_SERVER[$key])) {
0394             $header = $_SERVER[$key];
0395         }
0396         else if (function_exists('apache_request_headers')) {
0397             $headers = array_change_key_case(apache_request_headers(), CASE_LOWER);
0398             $key = strtolower($name);
0399             if (!empty($headers[$key])) {
0400                 $header = $headers[$key];
0401             }
0402         }
0403         return $header;
0404     }
0405 
0406     /**
0407      * Get an accept language
0408      *
0409      * @param   bool $subset
0410      * @return  string|null
0411      */
0412     public function getAcceptLanguage($subset = true)
0413     {
0414         $language = null;
0415         if (!empty($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
0416             preg_match(
0417                 "/^([a-z]{2})(\-|\_)?([a-z]{2})?\,?/i",
0418                 $_SERVER['HTTP_ACCEPT_LANGUAGE'],
0419                 $matches
0420             );
0421             if ($subset && !empty($matches[1]) && !empty($matches[3])) {
0422                 $language = strtolower($matches[1]) . '-' . strtoupper($matches[3]);
0423             }
0424             else if (!empty($matches[1])) {
0425                 $language = strtolower($matches[1]);
0426             }
0427         }
0428         return $language;
0429     }
0430 
0431     /**
0432      * Get a raw body data
0433      *
0434      * @return  mixed
0435      */
0436     public function getRawBody()
0437     {
0438         return file_get_contents('php://input');
0439     }
0440 
0441 }