diff options
Diffstat (limited to 'lib/prado/framework/Web/THttpRequest.php')
-rw-r--r-- | lib/prado/framework/Web/THttpRequest.php | 1406 |
1 files changed, 1406 insertions, 0 deletions
diff --git a/lib/prado/framework/Web/THttpRequest.php b/lib/prado/framework/Web/THttpRequest.php new file mode 100644 index 0000000..f89c354 --- /dev/null +++ b/lib/prado/framework/Web/THttpRequest.php @@ -0,0 +1,1406 @@ +<?php +/** + * THttpRequest, THttpCookie, THttpCookieCollection, TUri class file + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @link https://github.com/pradosoft/prado + * @copyright Copyright © 2005-2015 The PRADO Group + * @license https://github.com/pradosoft/prado/blob/master/COPYRIGHT + * @package System.Web + */ + +Prado::using('System.Web.TUrlManager'); + +/** + * THttpRequest class + * + * THttpRequest provides storage and access scheme for user request sent via HTTP. + * It also encapsulates a uniform way to parse and construct URLs. + * + * User post data can be retrieved from THttpRequest by using it like an associative array. + * For example, to test if a user supplies a variable named 'param1', you can use, + * <code> + * if(isset($request['param1'])) ... + * // equivalent to: + * // if($request->contains('param1')) ... + * </code> + * To get the value of 'param1', use, + * <code> + * $value=$request['param1']; + * // equivalent to: + * // $value=$request->itemAt('param1'); + * </code> + * To traverse the user post data, use + * <code> + * foreach($request as $name=>$value) ... + * </code> + * Note, POST and GET variables are merged together in THttpRequest. + * If a variable name appears in both POST and GET data, then POST data + * takes precedence. + * + * To construct a URL that can be recognized by Prado, use {@link constructUrl()}. + * The format of the recognizable URLs is determined according to + * {@link setUrlManager UrlManager}. By default, the following two formats + * are recognized: + * <code> + * /index.php?ServiceID=ServiceParameter&Name1=Value1&Name2=Value2 + * /index.php/ServiceID,ServiceParameter/Name1,Value1/Name2,Value2 + * </code> + * The first format is called 'Get' while the second 'Path', which is specified + * via {@link setUrlFormat UrlFormat}. For advanced users who want to use + * their own URL formats, they can write customized URL management modules + * and install the managers as application modules and set {@link setUrlManager UrlManager}. + * + * The ServiceID in the above URLs is as defined in the application configuration + * (e.g. the default page service's service ID is 'page'). + * As a consequence, your GET variable names should not conflict with the service + * IDs that your application supports. + * + * THttpRequest also provides the cookies sent by the user, user information such + * as his browser capabilities, accepted languages, etc. + * + * By default, THttpRequest is registered with {@link TApplication} as the + * request module. It can be accessed via {@link TApplication::getRequest()}. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @package System.Web + * @since 3.0 + */ +class THttpRequest extends TApplicationComponent implements IteratorAggregate,ArrayAccess,Countable,IModule +{ + const CGIFIX__PATH_INFO = 1; + const CGIFIX__SCRIPT_NAME = 2; + /** + * @var TUrlManager the URL manager module + */ + private $_urlManager=null; + /** + * @var string the ID of the URL manager module + */ + private $_urlManagerID=''; + /** + * @var string Separator used to separate GET variable name and value when URL format is Path. + */ + private $_separator=','; + /** + * @var string requested service ID + */ + private $_serviceID=null; + /** + * @var string requested service parameter + */ + private $_serviceParam=null; + /** + * @var THttpCookieCollection cookies sent from user + */ + private $_cookies=null; + /** + * @var string requested URI (URL w/o host info) + */ + private $_requestUri; + /** + * @var string path info of URL + */ + private $_pathInfo; + /** + * @var boolean whether the session ID should be kept in cookie only + */ + private $_cookieOnly=null; + private $_urlFormat=THttpRequestUrlFormat::Get; + private $_services; + private $_requestResolved=false; + private $_enableCookieValidation=false; + private $_cgiFix=0; + /** + * @var boolean whether to cache the TUrlManager class (useful with a lot of TUrlMappings) + */ + private $_enableCache=false; + /** + * @var string request URL + */ + private $_url=null; + + /** + * @var string module id + */ + private $_id; + + /** + * @var array contains all request variables + */ + private $_items=array(); + + /** + * @return string id of this module + */ + public function getID() + { + return $this->_id; + } + + /** + * @param string id of this module + */ + public function setID($value) + { + $this->_id=$value; + } + + /** + * Initializes the module. + * This method is required by IModule and is invoked by application. + * @param TXmlElement module configuration + */ + public function init($config) + { + // Fill in default request info when the script is run in command line + if(php_sapi_name()==='cli') + { + $_SERVER['REMOTE_ADDR']='127.0.0.1'; + $_SERVER['REQUEST_METHOD']='GET'; + $_SERVER['SERVER_NAME']='localhost'; + $_SERVER['SERVER_PORT']=80; + $_SERVER['HTTP_USER_AGENT']=''; + } + + // Info about server variables: + // PHP_SELF contains real URI (w/ path info, w/o query string) + // SCRIPT_NAME is the real URI for the requested script (w/o path info and query string) + // QUERY_STRING is the string following the '?' in the ur (eg the a=x part in http://foo/bar?a=x) + // REQUEST_URI contains the URI part entered in the browser address bar + // SCRIPT_FILENAME is the file path to the executing script + if(isset($_SERVER['REQUEST_URI'])) + $this->_requestUri=$_SERVER['REQUEST_URI']; + else // TBD: in this case, SCRIPT_NAME need to be escaped + $this->_requestUri=$_SERVER['SCRIPT_NAME'].(empty($_SERVER['QUERY_STRING'])?'':'?'.$_SERVER['QUERY_STRING']); + + if($this->_cgiFix&self::CGIFIX__PATH_INFO && isset($_SERVER['ORIG_PATH_INFO'])) + $this->_pathInfo=substr($_SERVER['ORIG_PATH_INFO'], strlen($_SERVER['SCRIPT_NAME'])); + elseif(isset($_SERVER['PATH_INFO'])) + $this->_pathInfo=$_SERVER['PATH_INFO']; + else if(strpos($_SERVER['PHP_SELF'],$_SERVER['SCRIPT_NAME'])===0 && $_SERVER['PHP_SELF']!==$_SERVER['SCRIPT_NAME']) + $this->_pathInfo=substr($_SERVER['PHP_SELF'],strlen($_SERVER['SCRIPT_NAME'])); + else + $this->_pathInfo=''; + + if(get_magic_quotes_gpc()) + { + if(isset($_GET)) + $_GET=$this->stripSlashes($_GET); + if(isset($_POST)) + $_POST=$this->stripSlashes($_POST); + if(isset($_REQUEST)) + $_REQUEST=$this->stripSlashes($_REQUEST); + if(isset($_COOKIE)) + $_COOKIE=$this->stripSlashes($_COOKIE); + } + + $this->getApplication()->setRequest($this); + } + + /** + * Strips slashes from input data. + * This method is applied when magic quotes is enabled. + * @param mixed input data to be processed + * @return mixed processed data + */ + public function stripSlashes(&$data) + { + return is_array($data)?array_map(array($this,'stripSlashes'),$data):stripslashes($data); + } + + /** + * @return TUri the request URL + */ + public function getUrl() + { + if($this->_url===null) + { + $secure=$this->getIsSecureConnection(); + $url=$secure?'https://':'http://'; + if(empty($_SERVER['HTTP_HOST'])) + { + $url.=$_SERVER['SERVER_NAME']; + $port=$_SERVER['SERVER_PORT']; + if(($port!=80 && !$secure) || ($port!=443 && $secure)) + $url.=':'.$port; + } + else + $url.=$_SERVER['HTTP_HOST']; + $url.=$this->getRequestUri(); + $this->_url=new TUri($url); + } + return $this->_url; + } + + /** + * Set true to cache the UrlManager instance. Consider to enable this cache + * when the application defines a lot of TUrlMappingPatterns + * @param boolean true to cache urlmanager instance. + */ + public function setEnableCache($value) + { + $this->_enableCache = TPropertyValue::ensureBoolean($value); + } + + /** + * @return boolean true if urlmanager instance should be cached, false otherwise. + */ + public function getEnableCache() + { + return $this->_enableCache; + } + + protected function getCacheKey() + { + return $this->getID(); + } + + /** + * Saves the current UrlManager instance to cache. + * @return boolean true if UrlManager instance was cached, false otherwise. + */ + protected function cacheUrlManager($manager) + { + if($this->getEnableCache()) + { + $cache = $this->getApplication()->getCache(); + if($cache !== null) + { + $dependencies = null; + if($this->getApplication()->getMode() !== TApplicationMode::Performance) + if ($manager instanceof TUrlMapping && $fn = $manager->getConfigFile()) + { + $fn = Prado::getPathOfNamespace($fn,$this->getApplication()->getConfigurationFileExt()); + $dependencies = new TFileCacheDependency($fn); + } + return $cache->set($this->getCacheKey(), $manager, 0, $dependencies); + } + } + return false; + } + + /** + * Loads UrlManager instance from cache. + * @return TUrlManager intance if load was successful, null otherwise. + */ + protected function loadCachedUrlManager() + { + if($this->getEnableCache()) + { + $cache = $this->getApplication()->getCache(); + if($cache !== null) + { + $manager = $cache->get($this->getCacheKey()); + if($manager instanceof TUrlManager) + return $manager; + } + } + return null; + } + + /** + * @return string the ID of the URL manager module + */ + public function getUrlManager() + { + return $this->_urlManagerID; + } + + /** + * Sets the URL manager module. + * By default, {@link TUrlManager} is used for managing URLs. + * You may specify a different module for URL managing tasks + * by loading it as an application module and setting this property + * with the module ID. + * @param string the ID of the URL manager module + */ + public function setUrlManager($value) + { + $this->_urlManagerID=$value; + } + + /** + * @return TUrlManager the URL manager module + */ + public function getUrlManagerModule() + { + if($this->_urlManager===null) + { + if(($this->_urlManager = $this->loadCachedUrlManager())===null) + { + if(empty($this->_urlManagerID)) + { + $this->_urlManager=new TUrlManager; + $this->_urlManager->init(null); + } + else + { + $this->_urlManager=$this->getApplication()->getModule($this->_urlManagerID); + if($this->_urlManager===null) + throw new TConfigurationException('httprequest_urlmanager_inexist',$this->_urlManagerID); + if(!($this->_urlManager instanceof TUrlManager)) + throw new TConfigurationException('httprequest_urlmanager_invalid',$this->_urlManagerID); + } + $this->cacheUrlManager($this->_urlManager); + } + } + return $this->_urlManager; + } + + /** + * @return THttpRequestUrlFormat the format of URLs. Defaults to THttpRequestUrlFormat::Get. + */ + public function getUrlFormat() + { + return $this->_urlFormat; + } + + /** + * Sets the format of URLs constructed and interpretted by the request module. + * A Get URL format is like index.php?name1=value1&name2=value2 + * while a Path URL format is like index.php/name1,value1/name2,value. + * Changing the UrlFormat will affect {@link constructUrl} and how GET variables + * are parsed. + * @param THttpRequestUrlFormat the format of URLs. + */ + public function setUrlFormat($value) + { + $this->_urlFormat=TPropertyValue::ensureEnum($value,'THttpRequestUrlFormat'); + } + + /** + * @return string separator used to separate GET variable name and value when URL format is Path. Defaults to comma ','. + */ + public function getUrlParamSeparator() + { + return $this->_separator; + } + + /** + * @param string separator used to separate GET variable name and value when URL format is Path. + * @throws TInvalidDataValueException if the separator is not a single character + */ + public function setUrlParamSeparator($value) + { + if(strlen($value)===1) + $this->_separator=$value; + else + throw new TInvalidDataValueException('httprequest_separator_invalid'); + } + + /** + * @return string request type, can be GET, POST, HEAD, or PUT + */ + public function getRequestType() + { + return isset($_SERVER['REQUEST_METHOD'])?$_SERVER['REQUEST_METHOD']:null; + } + + /** + * @param boolean $mimetypeOnly whether to return only the mimetype (default: true) + * @return string content type (e.g. 'application/json' or 'text/html; encoding=gzip') or null if not specified + */ + public function getContentType($mimetypeOnly = true) + { + if(!isset($_SERVER['CONTENT_TYPE'])) + return null; + + if($mimetypeOnly === true && ($_pos = strpos(';', $_SERVER['CONTENT_TYPE'])) !== false) + return substr($_SERVER['CONTENT_TYPE'], 0, $_pos); + + return $_SERVER['CONTENT_TYPE']; + } + + /** + * @return boolean if the request is sent via secure channel (https) + */ + public function getIsSecureConnection() + { + return isset($_SERVER['HTTPS']) && strcasecmp($_SERVER['HTTPS'],'off'); + } + + /** + * @return string part of the request URL after script name and before question mark. + */ + public function getPathInfo() + { + return $this->_pathInfo; + } + + /** + * @return string part of that request URL after the question mark + */ + public function getQueryString() + { + return isset($_SERVER['QUERY_STRING'])?$_SERVER['QUERY_STRING']:null; + } + + /** + * @return string the requested http procolol. Blank string if not defined. + */ + public function getHttpProtocolVersion() + { + return isset($_SERVER['SERVER_PROTOCOL'])?$_SERVER['SERVER_PROTOCOL']:null; + } + + /** + * @param integer|null Either {@link CASE_UPPER} or {@link CASE_LOWER} or as is null (default) + * @return array + */ + public function getHeaders($case=null) + { + static $result; + + if($result === null && function_exists('apache_request_headers')) { + $result = apache_request_headers(); + } + elseif($result === null) { + $result = array(); + foreach($_SERVER as $key=>$value) { + if(strncasecmp($key, 'HTTP_', 5) !== 0) continue; + $key = str_replace(' ','-', ucwords(strtolower(str_replace('_',' ', substr($key, 5))))); + $result[$key] = $value; + } + } + + if($case !== null) + return array_change_key_case($result, $case); + + return $result; + } + + /** + * @return string part of that request URL after the host info (including pathinfo and query string) + */ + public function getRequestUri() + { + return $this->_requestUri; + } + + /** + * @param boolean|null whether to use HTTPS instead of HTTP even if the current request is sent via HTTP or vice versa + * null - keep current schema + * true - force https + * false - force http + * @return string schema and hostname of the requested URL + */ + public function getBaseUrl($forceSecureConnection=null) + { + $url=$this->getUrl(); + $scheme=($forceSecureConnection)?"https": (($forceSecureConnection === null)?$url->getScheme():'http'); + $host=$url->getHost(); + if (($port=$url->getPort())) $host.=':'.$port; + return $scheme.'://'.$host; + } + + /** + * @return string entry script URL (w/o host part) + */ + public function getApplicationUrl() + { + if($this->_cgiFix&self::CGIFIX__SCRIPT_NAME && isset($_SERVER['ORIG_SCRIPT_NAME'])) + return $_SERVER['ORIG_SCRIPT_NAME']; + + return isset($_SERVER['SCRIPT_NAME'])?$_SERVER['SCRIPT_NAME']:null; + } + + /** + * @param boolean|null whether to use HTTPS instead of HTTP even if the current request is sent via HTTP or vice versa + * null - keep current schema + * true - force https + * false - force http + * @return string entry script URL (w/ host part) + */ + public function getAbsoluteApplicationUrl($forceSecureConnection=null) + { + return $this->getBaseUrl($forceSecureConnection) . $this->getApplicationUrl(); + } + + /** + * @return string application entry script file path (processed w/ realpath()) + */ + public function getApplicationFilePath() + { + return realpath(isset($_SERVER['SCRIPT_FILENAME'])?$_SERVER['SCRIPT_FILENAME']:null); + } + + /** + * @return string server name + */ + public function getServerName() + { + return isset($_SERVER['SERVER_NAME'])?$_SERVER['SERVER_NAME']:null; + } + + /** + * @return integer server port number + */ + public function getServerPort() + { + return isset($_SERVER['SERVER_PORT'])?$_SERVER['SERVER_PORT']:null; + } + + /** + * @return string URL referrer, null if not present + */ + public function getUrlReferrer() + { + return isset($_SERVER['HTTP_REFERER'])?$_SERVER['HTTP_REFERER']:null; + } + + /** + * @return array user browser capabilities + * @see get_browser + */ + public function getBrowser() + { + try + { + return get_browser(); + } + catch(TPhpErrorException $e) + { + throw new TConfigurationException('httprequest_browscap_required'); + } + } + + /** + * @return string user agent + */ + public function getUserAgent() + { + return isset($_SERVER['HTTP_USER_AGENT'])?$_SERVER['HTTP_USER_AGENT']:null; + } + + /** + * @return string user IP address + */ + public function getUserHostAddress() + { + return isset($_SERVER['REMOTE_ADDR'])?$_SERVER['REMOTE_ADDR']:null; + } + + /** + * @return string user host name, null if cannot be determined + */ + public function getUserHost() + { + return isset($_SERVER['REMOTE_HOST'])?$_SERVER['REMOTE_HOST']:null; + } + + /** + * @return string user browser accept types + */ + public function getAcceptTypes() + { + // TBD: break it into array?? + return isset($_SERVER['HTTP_ACCEPT'])?$_SERVER['HTTP_ACCEPT']:null; + } + + /** + * Returns a list of user preferred languages. + * The languages are returned as an array. Each array element + * represents a single language preference. The languages are ordered + * according to user preferences. The first language is the most preferred. + * @return array list of user preferred languages. + */ + public function getUserLanguages() + { + return Prado::getUserLanguages(); + } + + /** + * @return boolean whether cookies should be validated. Defaults to false. + */ + public function getEnableCookieValidation() + { + return $this->_enableCookieValidation; + } + + /** + * @param boolean whether cookies should be validated. + */ + public function setEnableCookieValidation($value) + { + $this->_enableCookieValidation=TPropertyValue::ensureBoolean($value); + } + + /** + * @return integer whether to use ORIG_PATH_INFO and/or ORIG_SCRIPT_NAME. Defaults to 0. + * @see THttpRequest::CGIFIX__PATH_INFO, THttpRequest::CGIFIX__SCRIPT_NAME + */ + public function getCgiFix() + { + return $this->_cgiFix; + } + + /** + * Enable this, if you're using PHP via CGI with php.ini setting "cgi.fix_pathinfo=1" + * and have trouble with friendly URL feature. Enable this only if you really know what you are doing! + * @param integer enable bitwise to use ORIG_PATH_INFO and/or ORIG_SCRIPT_NAME. + * @see THttpRequest::CGIFIX__PATH_INFO, THttpRequest::CGIFIX__SCRIPT_NAME + */ + public function setCgiFix($value) + { + $this->_cgiFix=TPropertyValue::ensureInteger($value); + } + + /** + * @return THttpCookieCollection list of cookies to be sent + */ + public function getCookies() + { + if($this->_cookies===null) + { + $this->_cookies=new THttpCookieCollection; + if($this->getEnableCookieValidation()) + { + $sm=$this->getApplication()->getSecurityManager(); + foreach($_COOKIE as $key=>$value) + { + if(($value=$sm->validateData($value))!==false) + $this->_cookies->add(new THttpCookie($key,$value)); + } + } + else + { + foreach($_COOKIE as $key=>$value) + $this->_cookies->add(new THttpCookie($key,$value)); + } + } + return $this->_cookies; + } + + /** + * @return array list of uploaded files. + */ + public function getUploadedFiles() + { + return $_FILES; + } + + /** + * @return array list of server variables. + */ + public function getServerVariables() + { + return $_SERVER; + } + + /** + * @return array list of environment variables. + */ + public function getEnvironmentVariables() + { + return $_ENV; + } + + /** + * Constructs a URL that can be recognized by PRADO. + * The actual construction work is done by the URL manager module. + * This method may append session information to the generated URL if needed. + * You may provide your own URL manager module by setting {@link setUrlManager UrlManager} + * to provide your own URL scheme. + * + * Note, the constructed URL does not contain the protocol and hostname part. + * You may obtain an absolute URL by prepending the constructed URL with {@link getBaseUrl BaseUrl}. + * @param string service ID + * @param string service parameter + * @param array GET parameters, null if not needed + * @param boolean whether to encode the ampersand in URL, defaults to true. + * @param boolean whether to encode the GET parameters (their names and values), defaults to false. + * @return string URL + * @see TUrlManager::constructUrl + */ + public function constructUrl($serviceID,$serviceParam,$getItems=null,$encodeAmpersand=true,$encodeGetItems=true) + { + if ($this->_cookieOnly===null) + $this->_cookieOnly=(int)ini_get('session.use_cookies') && (int)ini_get('session.use_only_cookies'); + $url=$this->getUrlManagerModule()->constructUrl($serviceID,$serviceParam,$getItems,$encodeAmpersand,$encodeGetItems); + if(defined('SID') && SID != '' && !$this->_cookieOnly) + return $url . (strpos($url,'?')===false? '?' : ($encodeAmpersand?'&':'&')) . SID; + else + return $url; + } + + /** + * Parses the request URL and returns an array of input parameters (excluding GET variables). + * You may override this method to support customized URL format. + * @return array list of input parameters, indexed by parameter names + * @see TUrlManager::parseUrl + */ + protected function parseUrl() + { + return $this->getUrlManagerModule()->parseUrl(); + } + + /** + * Resolves the requested service. + * This method implements a URL-based service resolution. + * A URL in the format of /index.php?sp=serviceID.serviceParameter + * will be resolved with the serviceID and the serviceParameter. + * You may override this method to provide your own way of service resolution. + * @param array list of valid service IDs + * @return string the currently requested service ID, null if no service ID is found + * @see constructUrl + */ + public function resolveRequest($serviceIDs) + { + Prado::trace("Resolving request from ".$_SERVER['REMOTE_ADDR'],'System.Web.THttpRequest'); + $getParams=$this->parseUrl(); + foreach($getParams as $name=>$value) + $_GET[$name]=$value; + $this->_items=array_merge($_GET,$_POST); + $this->_requestResolved=true; + foreach($serviceIDs as $serviceID) + { + if($this->contains($serviceID)) + { + $this->setServiceID($serviceID); + $this->setServiceParameter($this->itemAt($serviceID)); + return $serviceID; + } + } + return null; + } + + /** + * @return boolean true if request is already resolved, false otherwise. + */ + public function getRequestResolved() + { + return $this->_requestResolved; + } + + /** + * @return string requested service ID + */ + public function getServiceID() + { + return $this->_serviceID; + } + + /** + * Sets the requested service ID. + * @param string requested service ID + */ + public function setServiceID($value) + { + $this->_serviceID=$value; + } + + /** + * @return string requested service parameter + */ + public function getServiceParameter() + { + return $this->_serviceParam; + } + + /** + * Sets the requested service parameter. + * @param string requested service parameter + */ + public function setServiceParameter($value) + { + $this->_serviceParam=$value; + } + + //------ The following methods enable THttpRequest to be TMap-like ----- + + /** + * Returns an iterator for traversing the items in the list. + * This method is required by the interface IteratorAggregate. + * @return Iterator an iterator for traversing the items in the list. + */ + public function getIterator() + { + return new TMapIterator($this->_items); + } + + /** + * @return integer the number of items in the request + */ + public function getCount() + { + return count($this->_items); + } + + /** + * Returns the number of items in the request. + * This method is required by Countable interface. + * @return integer number of items in the request. + */ + public function count() + { + return $this->getCount(); + } + + /** + * @return array the key list + */ + public function getKeys() + { + return array_keys($this->_items); + } + + /** + * Returns the item with the specified key. + * This method is exactly the same as {@link offsetGet}. + * @param mixed the key + * @return mixed the element at the offset, null if no element is found at the offset + */ + public function itemAt($key) + { + return isset($this->_items[$key]) ? $this->_items[$key] : null; + } + + /** + * Adds an item into the request. + * Note, if the specified key already exists, the old value will be overwritten. + * @param mixed key + * @param mixed value + */ + public function add($key,$value) + { + $this->_items[$key]=$value; + } + + /** + * Removes an item from the request by its key. + * @param mixed the key of the item to be removed + * @return mixed the removed value, null if no such key exists. + * @throws TInvalidOperationException if the item cannot be removed + */ + public function remove($key) + { + if(isset($this->_items[$key]) || array_key_exists($key,$this->_items)) + { + $value=$this->_items[$key]; + unset($this->_items[$key]); + return $value; + } + else + return null; + } + + /** + * Removes all items in the request. + */ + public function clear() + { + foreach(array_keys($this->_items) as $key) + $this->remove($key); + } + + /** + * @param mixed the key + * @return boolean whether the request contains an item with the specified key + */ + public function contains($key) + { + return isset($this->_items[$key]) || array_key_exists($key,$this->_items); + } + + /** + * @return array the list of items in array + */ + public function toArray() + { + return $this->_items; + } + + /** + * Returns whether there is an element at the specified offset. + * This method is required by the interface ArrayAccess. + * @param mixed the offset to check on + * @return boolean + */ + public function offsetExists($offset) + { + return $this->contains($offset); + } + + /** + * Returns the element at the specified offset. + * This method is required by the interface ArrayAccess. + * @param integer the offset to retrieve element. + * @return mixed the element at the offset, null if no element is found at the offset + */ + public function offsetGet($offset) + { + return $this->itemAt($offset); + } + + /** + * Sets the element at the specified offset. + * This method is required by the interface ArrayAccess. + * @param integer the offset to set element + * @param mixed the element value + */ + public function offsetSet($offset,$item) + { + $this->add($offset,$item); + } + + /** + * Unsets the element at the specified offset. + * This method is required by the interface ArrayAccess. + * @param mixed the offset to unset element + */ + public function offsetUnset($offset) + { + $this->remove($offset); + } +} + +/** + * THttpCookieCollection class. + * + * THttpCookieCollection implements a collection class to store cookies. + * Besides using all functionalities from {@link TList}, you can also + * retrieve a cookie by its name using either {@link findCookieByName} or + * simply: + * <code> + * $cookie=$collection[$cookieName]; + * </code> + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @package System.Web + * @since 3.0 + */ +class THttpCookieCollection extends TList +{ + /** + * @var mixed owner of this collection + */ + private $_o; + + /** + * Constructor. + * @param mixed owner of this collection. + */ + public function __construct($owner=null) + { + $this->_o=$owner; + } + + /** + * Inserts an item at the specified position. + * This overrides the parent implementation by performing additional + * operations for each newly added THttpCookie object. + * @param integer the specified position. + * @param mixed new item + * @throws TInvalidDataTypeException if the item to be inserted is not a THttpCookie object. + */ + public function insertAt($index,$item) + { + if($item instanceof THttpCookie) + { + parent::insertAt($index,$item); + if($this->_o instanceof THttpResponse) + $this->_o->addCookie($item); + } + else + throw new TInvalidDataTypeException('httpcookiecollection_httpcookie_required'); + } + + /** + * Removes an item at the specified position. + * This overrides the parent implementation by performing additional + * cleanup work when removing a TCookie object. + * @param integer the index of the item to be removed. + * @return mixed the removed item. + */ + public function removeAt($index) + { + $item=parent::removeAt($index); + if($this->_o instanceof THttpResponse) + $this->_o->removeCookie($item); + return $item; + } + + /** + * @param integer|string index of the cookie in the collection or the cookie's name + * @return THttpCookie the cookie found + */ + public function itemAt($index) + { + if(is_integer($index)) + return parent::itemAt($index); + else + return $this->findCookieByName($index); + } + + /** + * Finds the cookie with the specified name. + * @param string the name of the cookie to be looked for + * @return THttpCookie the cookie, null if not found + */ + public function findCookieByName($name) + { + foreach($this as $cookie) + if($cookie->getName()===$name) + return $cookie; + return null; + } +} + +/** + * THttpCookie class. + * + * A THttpCookie instance stores a single cookie, including the cookie name, value, + * domain, path, expire, and secure. + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @package System.Web + * @since 3.0 + */ +class THttpCookie extends TComponent +{ + /** + * @var string domain of the cookie + */ + private $_domain=''; + /** + * @var string name of the cookie + */ + private $_name; + /** + * @var string value of the cookie + */ + private $_value=''; + /** + * @var integer expire of the cookie + */ + private $_expire=0; + /** + * @var string path of the cookie + */ + private $_path='/'; + /** + * @var boolean whether cookie should be sent via secure connection + */ + private $_secure=false; + /** + * @var boolean if true the cookie value will be unavailable to JavaScript + */ + private $_httpOnly=false; + + /** + * Constructor. + * @param string name of this cookie + * @param string value of this cookie + */ + public function __construct($name,$value) + { + $this->_name=$name; + $this->_value=$value; + } + + /** + * @return string the domain to associate the cookie with + */ + public function getDomain() + { + return $this->_domain; + } + + /** + * @param string the domain to associate the cookie with + */ + public function setDomain($value) + { + $this->_domain=$value; + } + + /** + * @return integer the time the cookie expires. This is a Unix timestamp so is in number of seconds since the epoch. + */ + public function getExpire() + { + return $this->_expire; + } + + /** + * @param integer the time the cookie expires. This is a Unix timestamp so is in number of seconds since the epoch. + */ + public function setExpire($value) + { + $this->_expire=TPropertyValue::ensureInteger($value); + } + + /** + * @return boolean if true the cookie value will be unavailable to JavaScript + */ + public function getHttpOnly() + { + return $this->_httpOnly; + } + + /** + * @param boolean $value if true the cookie value will be unavailable to JavaScript + */ + public function setHttpOnly($value) + { + $this->_httpOnly = TPropertyValue::ensureBoolean($value); + } + + /** + * @return string the name of the cookie + */ + public function getName() + { + return $this->_name; + } + + /** + * @param string the name of the cookie + */ + public function setName($value) + { + $this->_name=$value; + } + + /** + * @return string the value of the cookie + */ + public function getValue() + { + return $this->_value; + } + + /** + * @param string the value of the cookie + */ + public function setValue($value) + { + $this->_value=$value; + } + + /** + * @return string the path on the server in which the cookie will be available on, default is '/' + */ + public function getPath() + { + return $this->_path; + } + + /** + * @param string the path on the server in which the cookie will be available on + */ + public function setPath($value) + { + $this->_path=$value; + } + + /** + * @return boolean whether the cookie should only be transmitted over a secure HTTPS connection + */ + public function getSecure() + { + return $this->_secure; + } + + /** + * @param boolean ether the cookie should only be transmitted over a secure HTTPS connection + */ + public function setSecure($value) + { + $this->_secure=TPropertyValue::ensureBoolean($value); + } +} + +/** + * TUri class + * + * TUri represents a URI. Given a URI + * http://joe:whatever@example.com:8080/path/to/script.php?param=value#anchor + * it will be decomposed as follows, + * - scheme: http + * - host: example.com + * - port: 8080 + * - user: joe + * - password: whatever + * - path: /path/to/script.php + * - query: param=value + * - fragment: anchor + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @package System.Web + * @since 3.0 + */ +class TUri extends TComponent +{ + /** + * @var array list of default ports for known schemes + */ + private static $_defaultPort=array( + 'ftp'=>21, + 'gopher'=>70, + 'http'=>80, + 'https'=>443, + 'news'=>119, + 'nntp'=>119, + 'wais'=>210, + 'telnet'=>23 + ); + /** + * @var string scheme of the URI + */ + private $_scheme; + /** + * @var string host name of the URI + */ + private $_host; + /** + * @var integer port of the URI + */ + private $_port; + /** + * @var string user of the URI + */ + private $_user; + /** + * @var string password of the URI + */ + private $_pass; + /** + * @var string path of the URI + */ + private $_path; + /** + * @var string query string of the URI + */ + private $_query; + /** + * @var string fragment of the URI + */ + private $_fragment; + /** + * @var string the URI + */ + private $_uri; + + /** + * Constructor. + * Decomposes the specified URI into parts. + * @param string URI to be represented + * @throws TInvalidDataValueException if URI is of bad format + */ + public function __construct($uri) + { + if(($ret=@parse_url($uri))!==false) + { + // decoding??? + $this->_scheme=isset($ret['scheme'])?$ret['scheme']:''; + $this->_host=isset($ret['host'])?$ret['host']:''; + $this->_port=isset($ret['port'])?$ret['port']:''; + $this->_user=isset($ret['user'])?$ret['user']:''; + $this->_pass=isset($ret['pass'])?$ret['pass']:''; + $this->_path=isset($ret['path'])?$ret['path']:''; + $this->_query=isset($ret['query'])?$ret['query']:''; + $this->_fragment=isset($ret['fragment'])?$ret['fragment']:''; + $this->_uri=$uri; + } + else + { + throw new TInvalidDataValueException('uri_format_invalid',$uri); + } + } + + /** + * @return string URI + */ + public function getUri() + { + return $this->_uri; + } + + /** + * @return string scheme of the URI, such as 'http', 'https', 'ftp', etc. + */ + public function getScheme() + { + return $this->_scheme; + } + + /** + * @return string hostname of the URI + */ + public function getHost() + { + return $this->_host; + } + + /** + * @return integer port number of the URI + */ + public function getPort() + { + return $this->_port; + } + + /** + * @return string username of the URI + */ + public function getUser() + { + return $this->_user; + } + + /** + * @return string password of the URI + */ + public function getPassword() + { + return $this->_pass; + } + + /** + * @return string path of the URI + */ + public function getPath() + { + return $this->_path; + } + + /** + * @return string query string of the URI + */ + public function getQuery() + { + return $this->_query; + } + + /** + * @return string fragment of the URI + */ + public function getFragment() + { + return $this->_fragment; + } +} + +/** + * THttpRequestUrlFormat class. + * THttpRequestUrlFormat defines the enumerable type for the possible URL formats + * that can be recognized by {@link THttpRequest}. + * + * The following enumerable values are defined: + * - Get: the URL format is like /path/to/index.php?name1=value1&name2=value2... + * - Path: the URL format is like /path/to/index.php/name1,value1/name2,value2... + * - HiddenPath: the URL format is like /path/to/name1,value1/name2,value2... + * + * @author Qiang Xue <qiang.xue@gmail.com> + * @package System.Web + * @since 3.0.4 + */ +class THttpRequestUrlFormat extends TEnumerable +{ + const Get='Get'; + const Path='Path'; + const HiddenPath='HiddenPath'; +} + |