Overview

Namespaces

  • MvcCore
    • Ext
      • Auth
        • Virtual
      • Debug
        • Tracy
      • Form
        • Core
        • Validators
      • Request
      • Router
        • Lang
      • View
        • Helpers
  • None

Classes

  • MvcCore
  • MvcCore\Config
  • MvcCore\Controller
  • MvcCore\Debug
  • MvcCore\Ext\Auth
  • MvcCore\Ext\Auth\Controller
  • MvcCore\Ext\Auth\SignInForm
  • MvcCore\Ext\Auth\SignOutForm
  • MvcCore\Ext\Auth\User
  • MvcCore\Ext\Auth\Virtual\Controller
  • MvcCore\Ext\Auth\Virtual\Form
  • MvcCore\Ext\Auth\Virtual\User
  • MvcCore\Ext\Debug\Tracy
  • MvcCore\Ext\Debug\Tracy\AuthPanel
  • MvcCore\Ext\Debug\Tracy\IncludePanel
  • MvcCore\Ext\Debug\Tracy\MvcCorePanel
  • MvcCore\Ext\Debug\Tracy\RoutingPanel
  • MvcCore\Ext\Debug\Tracy\SessionPanel
  • MvcCore\Ext\Form
  • MvcCore\Ext\Form\Button
  • MvcCore\Ext\Form\Checkbox
  • MvcCore\Ext\Form\CheckboxGroup
  • MvcCore\Ext\Form\Core\Base
  • MvcCore\Ext\Form\Core\Configuration
  • MvcCore\Ext\Form\Core\Field
  • MvcCore\Ext\Form\Core\FieldGroup
  • MvcCore\Ext\Form\Core\Helpers
  • MvcCore\Ext\Form\Core\Validator
  • MvcCore\Ext\Form\Core\View
  • MvcCore\Ext\Form\CountrySelect
  • MvcCore\Ext\Form\Date
  • MvcCore\Ext\Form\DateTime
  • MvcCore\Ext\Form\Email
  • MvcCore\Ext\Form\Hidden
  • MvcCore\Ext\Form\NoType
  • MvcCore\Ext\Form\Number
  • MvcCore\Ext\Form\Password
  • MvcCore\Ext\Form\RadioGroup
  • MvcCore\Ext\Form\Range
  • MvcCore\Ext\Form\ResetButton
  • MvcCore\Ext\Form\ResetInput
  • MvcCore\Ext\Form\Select
  • MvcCore\Ext\Form\SubmitButton
  • MvcCore\Ext\Form\SubmitInput
  • MvcCore\Ext\Form\Text
  • MvcCore\Ext\Form\Textarea
  • MvcCore\Ext\Form\Time
  • MvcCore\Ext\Form\Validators\CompanyId
  • MvcCore\Ext\Form\Validators\CompanyVatId
  • MvcCore\Ext\Form\Validators\Date
  • MvcCore\Ext\Form\Validators\Email
  • MvcCore\Ext\Form\Validators\FloatVal
  • MvcCore\Ext\Form\Validators\Integer
  • MvcCore\Ext\Form\Validators\Maxlength
  • MvcCore\Ext\Form\Validators\MaxSelectedOptions
  • MvcCore\Ext\Form\Validators\MinSelectedOptions
  • MvcCore\Ext\Form\Validators\NumberField
  • MvcCore\Ext\Form\Validators\Pattern
  • MvcCore\Ext\Form\Validators\Phone
  • MvcCore\Ext\Form\Validators\RangeField
  • MvcCore\Ext\Form\Validators\SafeString
  • MvcCore\Ext\Form\Validators\Time
  • MvcCore\Ext\Form\Validators\Url
  • MvcCore\Ext\Form\Validators\ValueInOptions
  • MvcCore\Ext\Form\Validators\ZipCode
  • MvcCore\Ext\Request\ApacheDpi
  • MvcCore\Ext\Request\Cli
  • MvcCore\Ext\Router\Lang
  • MvcCore\Ext\Router\Lang\Route
  • MvcCore\Ext\Router\Media
  • MvcCore\Ext\Router\MediaSiteKey
  • MvcCore\Ext\View\Helpers\Assets
  • MvcCore\Ext\View\Helpers\Css
  • MvcCore\Ext\View\Helpers\Js
  • MvcCore\Ext\View\Helpers\LineBreaks
  • MvcCore\Model
  • MvcCore\Request
  • MvcCore\Response
  • MvcCore\Route
  • MvcCore\Router
  • MvcCore\Session
  • MvcCore\Tool
  • MvcCore\View

Exceptions

  • MvcCore\Ext\Form\Core\Exception
  • Overview
  • Namespace
  • Class
  • Tree
  1:   2:   3:   4:   5:   6:   7:   8:   9:  10:  11:  12:  13:  14:  15:  16:  17:  18:  19:  20:  21:  22:  23:  24:  25:  26:  27:  28:  29:  30:  31:  32:  33:  34:  35:  36:  37:  38:  39:  40:  41:  42:  43:  44:  45:  46:  47:  48:  49:  50:  51:  52:  53:  54:  55:  56:  57:  58:  59:  60:  61:  62:  63:  64:  65:  66:  67:  68:  69:  70:  71:  72:  73:  74:  75:  76:  77:  78:  79:  80:  81:  82:  83:  84:  85:  86:  87:  88:  89:  90:  91:  92:  93:  94:  95:  96:  97:  98:  99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: 187: 188: 189: 190: 191: 192: 193: 194: 195: 196: 197: 198: 199: 200: 201: 202: 203: 204: 205: 206: 207: 208: 209: 210: 211: 212: 213: 214: 215: 216: 217: 218: 219: 220: 221: 222: 223: 224: 225: 226: 227: 228: 229: 230: 231: 232: 233: 234: 235: 236: 237: 238: 239: 240: 241: 242: 243: 244: 245: 246: 247: 248: 249: 250: 251: 252: 253: 254: 255: 256: 257: 258: 259: 260: 261: 262: 263: 264: 265: 266: 267: 268: 269: 270: 271: 272: 273: 274: 275: 276: 277: 278: 279: 280: 281: 282: 283: 284: 285: 286: 287: 288: 289: 290: 291: 292: 293: 294: 295: 296: 297: 298: 299: 300: 301: 302: 303: 304: 305: 306: 307: 308: 309: 310: 311: 312: 313: 314: 315: 316: 317: 318: 319: 320: 321: 322: 323: 324: 325: 326: 327: 328: 329: 330: 331: 332: 333: 334: 335: 336: 337: 338: 339: 340: 341: 342: 343: 344: 345: 346: 347: 348: 349: 350: 351: 352: 353: 354: 355: 356: 357: 358: 359: 360: 361: 362: 363: 364: 365: 366: 367: 368: 369: 370: 371: 372: 373: 374: 375: 376: 377: 378: 379: 380: 381: 382: 383: 384: 385: 386: 387: 388: 389: 390: 391: 392: 393: 394: 395: 396: 397: 398: 399: 400: 401: 402: 403: 404: 405: 406: 407: 408: 409: 410: 411: 412: 413: 414: 415: 416: 417: 418: 419: 420: 421: 422: 423: 424: 425: 426: 427: 428: 429: 430: 431: 432: 433: 434: 435: 436: 437: 438: 439: 440: 441: 442: 443: 444: 445: 446: 447: 448: 449: 450: 451: 452: 453: 454: 455: 456: 457: 458: 459: 460: 461: 462: 463: 464: 465: 466: 467: 468: 469: 470: 471: 472: 473: 474: 475: 476: 477: 478: 479: 480: 481: 482: 483: 484: 485: 486: 487: 488: 489: 490: 491: 492: 493: 494: 495: 496: 497: 498: 499: 500: 501: 502: 503: 504: 505: 
<?php

/**
 * MvcCore
 *
 * This source file is subject to the BSD 3 License
 * For the full copyright and license information, please view 
 * the LICENSE.md file that are distributed with this source code.
 *
 * @copyright   Copyright (c) 2016 Tom FlĂ­dr (https://github.com/mvccore/mvccore)
 * @license     https://mvccore.github.io/docs/mvccore/4.0.0/LICENCE.md
 */

namespace MvcCore;

require_once('Tool.php');
require_once(__DIR__.'/../MvcCore.php');

/**
 * Core request:
 * - linear request url parsing from $_SERVER into local properties describing url sections
 * - params reading from $_GET/$_POST or direct input (in JSON or in query string)
 * - params cleaning by developer rules
 */
class Request
{
    const PROTOCOL_HTTP = 'http:';
    const PROTOCOL_HTTPS = 'https:';

    const METHOD_GET = 'GET';
    const METHOD_POST = 'POST';

    /**
     * Language international code, lowercase, not used by default.
     * To use this variable - install \MvcCore\Router extension \MvcCoreExt\Router\Lang
     * Example: 'en'
     * @var string
     */
    public $Lang        = '';

    /**
     * Country/locale code, uppercase, not used by default.
     * To use this variable - install \MvcCore\Router extension \MvcCoreExt\Router\Locale
     * Example: 'US'
     * @var string
     */
    public $Locale      = '';
    
    /**
     * Http protocol: 'http:' | 'https:'
     * Example: 'http:'
     * @var string
     */
    public $Protocol        = '';

    /**
     * Application server name - domain without any port.
     * Example: 'localhost'
     * @var string
     */
    public $ServerName      = '';

    /**
     * Application host with port if there is any.
     * Example: 'localhost:88'
     * @var string
     */
    public $Host        = '';

    /**
     * Http port parsed by parse_url().
     * Example: '88'
     * @var string
     */
    public $Port        = '';

    /**
     * Requested path in from application root (if mod_rewrite enabled), never with query string.
     * Example: '/products/page/2'
     * @var string
     */
    public $Path        = '';

    /**
     * Uri query string without question mark.
     * Example: 'param-1=value-1&param-2=value-2&param-3[]=value-3-a&param-3[]=value-3-b'
     * @var string
     */
    public $Query       = '';

    /**
     * Uri fragment parsed by parse_url()
     * Example: '#any-sublink-path'
     * @var mixed
     */
    public $Fragment    = '';

    /**
     * Php requested script name path from application root.
     * Example: '/index.php'
     * @var string
     */
    public $ScriptName  = '';

    /**
     * Application root path in hard drive: C:/www/my/development/direcotry/www
     * @var string
     */
    public $AppRoot     = '';

    /**
     * Base app directory path after domain, if application is placed in domain subdirectory
     * Example:
     *  full url: 'http://localhost:88/my/development/direcotry/www/requested/path/after/domain?with=possible&query=string'
     *  base path: '/my/development/direcotry/www'
     * @var string
     */
    public $BasePath    = '';

    /**
     * Request path after domain with possible query string
     * Example: '/requested/path/after/app/root?with=possible&query=string'
     * @var string
     */
    public $RequestPath = '';

    /**
     * Url to requested domain and possible port.
     * Example: 'http://domain:88'
     * @var string
     */
    public $DomainUrl   = '';

    /**
     * Base url to application root.
     * Example: 'http://domain:88/my/development/direcotry/www'
     * @var string
     */
    public $BaseUrl     = '';

    /**
     * Request url including scheme, domain, port, path, without any query string
     * Example: ''http://localhost:88/my/development/direcotry/www/requested/path/after/domain'
     * @var string
     */
    public $RequestUrl  = '';

    /**
     * Request url including scheme, domain, port, path and with query string
     * Example: 'http://localhost:88/my/development/direcotry/www/requested/path/after/domain?with=possible&query=string'
     * @var string
     */
    public $FullUrl     = '';

    /**
     * Http method (uppercase) - GET, POST, PUT, HEAD...
     * Example: 'GET'
     * @var string
     */
    public $Method      = '';
    
    /**
     * Referer url if any, safely readed by: 
     * filter_var($_SERVER['HTTP_REFERER'], FILTER_SANITIZE_URL);
     * Example: 'GET'
     * @var string
     */
    public $Referer     = '';

    /**
     * Request params array, with keys defined in route or by query string, 
     * always with controller and action keys completed by router.
     * Example: array('controller' => 'default', 'action' => 'default', 'user' => "' OR 1=1;-- with raw danger value!");
     * To get safe param value - use: $request->GetParam('user', 'a-zA-Z0-9');
     * @var array
     */
    public $Params      = array();

    /**
     * Media site key - 'full' | 'tablet' | 'mobile'
     * To use this variable - install \MvcCore\Router extension \MvcCoreExt\Router\Media
     * Example: 'full'
     * @var string
     */
    public $MediaSiteKey = '';

    /**
     * Content of $_SERVER global variable
     * @var array
     */
    protected $serverGlobals = array();

    /**
     * Content of $_GET global variable
     * @var array
     */
    protected $getGlobals = array();

    /**
     * Content of $_POST global variable
     * @var array
     */
    protected $postGlobals = array();
    
    /**
     * Requested script name
     * @var array
     */
    protected $indexScriptName = '';

    /**
     * Request flag if request targets internal package asset or not,
     * - 0 - request is Controller:Asset call for internal package asset
     * - 1 - request is classic application request
     * @var mixed
     */
    protected $appRequest = -1;

    /**
     * Get everytime new instance of http request, 
     * global variables should be changed and injected here 
     * to get different request object from currently called real request.
     * @param array $server 
     * @param array $get 
     * @param array $post 
     * @return \MvcCore\Request
     */
    public static function GetInstance (array & $server, array & $get, array & $post) {
        $requestClass = \MvcCore::GetInstance()->GetRequestClass();
        return new $requestClass($server, $get, $post);
    }

    /**
     * Get everytime new instance of http request, 
     * global variables should be changed and injected here 
     * to get different request object from currently called real request.
     * 
     * @param array $server 
     * @param array $get 
     * @param array $post 
     */
    public function __construct (array & $server, array & $get, array & $post) { 
        $this->serverGlobals = $server;
        $this->getGlobals = $get;
        $this->postGlobals = $post;

        $this->initScriptName();
        $this->initAppRoot();
        $this->initMethod();
        $this->initBasePath();
        $this->initProtocol();
        $this->initParsedUrlSegments();
        $this->initHttpParams();
        $this->initPath();
        $this->initReferer();
        $this->initUrlCompositions();
        
        unset($this->serverGlobals, $this->getGlobals, $this->postGlobals);
    }

    /**
     * Sets any custom property ('PropertyName') by $request->SetPropertyName('value'),
     * which is not necessary to define previously or gets previously defined
     * property ('PropertyName') by $request->GetPropertyName(); Throws exception
     * if no property defined by get call or if virtual call begins with anything
     * different from 'set' or 'get'.
     * This method returns custom value for get and $request instance for set.
     * @param string $rawName
     * @param array  $arguments
     * @throws \Exception
     * @return mixed|\MvcCore\Request
     */
    public function __call ($rawName, $arguments = array()) {
        $nameBegin = strtolower(substr($rawName, 0, 3));
        $name = substr($rawName, 3);
        if ($nameBegin == 'get' && isset($this->$name)) {
            return $this->$name;
        } else if ($nameBegin == 'set') {
            $this->$name = isset($arguments[0]) ? $arguments[0] : NULL;
            return $this;
        } else {
            throw new \Exception('['.__CLASS__."] No property with name '$name' defined.");
        }
    }

    /**
     * Universal getter, if property not defined, NULL is returned.
     * @param string $name 
     * @return mixed
     */
    public function __get ($name) {
        return isset($this->$name) ? $this->$name : NULL ;
    }

    /**
     * Universal setter, if property not defined, it's automaticly declarated.
     * @param string    $name 
     * @param mixed     $value
     * @return void
     */
    public function __set ($name, $value) {
        $this->$name = $value;
    }

    /**
     * Set directly raw param value without any change
     * @param string $name 
     * @param string $value 
     * @return \MvcCore\Request
     */
    public function SetParam ($name = "", $value = "") {
        $this->Params[$name] = $value;
        return $this;
    }

    /**
     * Get param value, filtered for characters defined as second argument to use them in preg_replace().
     * @param string $name 
     * @param string $pregReplaceAllowedChars 
     * @return string
     */
    public function GetParam ($name = "", $pregReplaceAllowedChars = "a-zA-Z0-9_/\-\.\@") {
        $result = '';
        $params = $this->Params;
        if (isset($params[$name])) {
            $rawValue = trim($params[$name]);
            if (mb_strlen($rawValue) > 0) {
                if (!$pregReplaceAllowedChars || $pregReplaceAllowedChars == ".*") {
                    $result = $rawValue;
                } else {
                    $pattern = "#[^" . $pregReplaceAllowedChars . "]#";
                    $result = preg_replace($pattern, "", $rawValue);
                }
            }
        }
        return $result;
    }

    /**
     * Return boolean flag if request target 
     * is anything different than 'Controller:Asset'
     * @return bool
     */
    public function IsAppRequest () {
        if ($this->appRequest == -1) {
            $this->appRequest = 1;
            $ctrl = 'controller';
            $action = 'action';
            if (isset($this->Params[$ctrl]) && isset($this->Params[$action])) {
                if ($this->Params[$ctrl] == $ctrl && $this->Params[$action] == 'asset') {
                    $this->appRequest = 0;
                }
            }
        }
        return (bool) $this->appRequest;
    }

    /**
     * Initialize index.php script name.
     * @return void
     */
    protected function initScriptName () {
        $this->indexScriptName = str_replace('\\', '/', $this->serverGlobals['SCRIPT_NAME']);
        $this->ScriptName = '/' . substr($this->indexScriptName, strrpos($this->indexScriptName, '/') + 1);
    }

    /**
     * Initialize application root directory.
     * @return void
     */
    protected function initAppRoot () {
        // $appRootRelativePath = mb_substr($this->indexScriptName, 0, strrpos($this->indexScriptName, '/') + 1);
        // ucfirst - cause IIS has lower case drive name here - different from __DIR__ value
        $indexFilePath = ucfirst(str_replace('\\', '/', $this->serverGlobals['SCRIPT_FILENAME']));
        if (strpos(__FILE__, 'phar://') === 0) {
            $appRootFullPath = 'phar://' . $indexFilePath;
        } else {
            $appRootFullPath = substr($indexFilePath, 0, mb_strrpos($indexFilePath, '/'));
        }
        $this->AppRoot = str_replace(array('\\', '//'), '/', $appRootFullPath);
    }

    /**
     * Initialize http method.
     * @return void
     */
    protected function initMethod () {
        $this->Method = strtoupper($this->serverGlobals['REQUEST_METHOD']);
    }

    /**
     * Complete base application path like: /localhost/my/development/direcotry/www
     * @return void
     */
    protected function initBasePath () {
        $lastSlashPos = mb_strrpos($this->indexScriptName, '/');
        if ($lastSlashPos !== FALSE) {
            $this->BasePath = mb_substr($this->indexScriptName, 0, $lastSlashPos);
        } else {
            $this->BasePath = '';
        }
    }
    
    /**
     * Initialize http protocol.
     * @return void
     */
    protected function initProtocol () {
        $this->Protocol = static::PROTOCOL_HTTP;
        if (isset($this->serverGlobals['HTTPS']) && strtolower($this->serverGlobals['HTTPS']) == 'on') {
            $this->Protocol = static::PROTOCOL_HTTPS;
        }
    }
    
    /**
     * Initialize url segments parsed by parse_url() php method.
     * @return void
     */
    protected function initParsedUrlSegments () {
        $absoluteUrl = $this->Protocol . '//' . $this->serverGlobals['HTTP_HOST'] . $this->serverGlobals['REQUEST_URI'];
        $parsedUrl = parse_url($absoluteUrl);
        $keyUc = '';
        foreach ($parsedUrl as $key => $value) {
            $keyUc = ucfirst($key);
            if (isset($this->$keyUc)) {
                $this->$keyUc = (string) $value;
            }
        }
        $this->ServerName = $this->serverGlobals['SERVER_NAME'];
        $this->Host = $this->serverGlobals['HTTP_HOST'];
    }

    /**
     * Initialize params from global $_GET and (global $_POST or direct 'php://input').
     * @return void
     */
    protected function initHttpParams () {
        $params = array_merge($this->getGlobals);
        if ($this->Method == self::METHOD_POST) {
            $postValues = array();
            if (count($this->postGlobals) > 0) {
                $postValues = $this->postGlobals;
            } else {
                $postValues = $this->initParamsCompletePostData();
            }
            $params = array_merge($params, $postValues);
        }
        $this->Params = $params;
    }

    /**
     * Read and return direct php post input from 'php://input'.
     * @return array
     */
    private function initParamsCompletePostData () {
        $result = array();
        $rawPhpInput = file_get_contents('php://input');
        $decodedJsonResult = \MvcCore\Tool::DecodeJson($rawPhpInput);
        if ($decodedJsonResult->success) {
            $result = (array) $decodedJsonResult->data;
        } else {
            $rows = explode('&', $rawPhpInput);
            foreach ($rows as $row) {
                list($key, $value) = explode('=', $row);
                $result[$key] = $value;
            }
        }
        return $result;
    }

    /**
     * Initialize request path.
     * @return void
     */
    protected function initPath () {
        $requestUrl = $this->serverGlobals['REQUEST_URI'];
        $path = '/' . ltrim(mb_substr($requestUrl, mb_strlen($this->BasePath)), '/');
        if (mb_strpos($path, '?') !== FALSE) $path = mb_substr($path, 0, mb_strpos($path, '?'));
        $this->Path = $path;
    }

    /**
     * Initialize referer safely if any.
     * @return void
     */
    protected function initReferer () {
        $referer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : '';
        if ($referer) {
            $referer = filter_var($referer, FILTER_SANITIZE_URL);
            $this->Referer = $referer ? $referer : '';
        }
    }

    /**
     * Initialize url compositions.
     * @return void
     */
    protected function initUrlCompositions () {
        $this->RequestPath = $this->Path . (($this->Query) ? '?' . $this->Query : '') . $this->Fragment;
        $this->DomainUrl = $this->Protocol . '//' . $this->Host;
        $this->BaseUrl = $this->DomainUrl . $this->BasePath;
        $this->RequestUrl = $this->BaseUrl . $this->Path;
        $this->FullUrl = $this->RequestUrl . (($this->Query) ? '?' . $this->Query : '');
    }
}
MvcCore API documentation generated by ApiGen