* * @param string $filePath file name with full path * @param array $options additional options: * */ public function xSendFile($filePath, $options=array()) { if(!isset($options['forceDownload']) || $options['forceDownload']) $disposition='attachment'; else $disposition='inline'; if(!isset($options['saveName'])) $options['saveName']=basename($filePath); if(!isset($options['mimeType'])) { if(($options['mimeType']=CFileHelper::getMimeTypeByExtension($filePath))===null) $options['mimeType']='text/plain'; } if(!isset($options['xHeader'])) $options['xHeader']='X-Sendfile'; if($options['mimeType']!==null) header('Content-Type: '.$options['mimeType']); header('Content-Disposition: '.$disposition.'; filename="'.$options['saveName'].'"'); if(isset($options['addHeaders'])) { foreach($options['addHeaders'] as $header=>$value) header($header.': '.$value); } header(trim($options['xHeader']).': '.$filePath); if(!isset($options['terminate']) || $options['terminate']) Yii::app()->end(); } /** * Returns the random token used to perform CSRF validation. * The token will be read from cookie first. If not found, a new token * will be generated. * @return string the random token for CSRF validation. * @see enableCsrfValidation */ public function getCsrfToken() { if($this->_csrfToken===null) { $cookie=$this->getCookies()->itemAt($this->csrfTokenName); if(!$cookie || ($this->_csrfToken=$cookie->value)==null) { $cookie=$this->createCsrfCookie(); $this->_csrfToken=$cookie->value; $this->getCookies()->add($cookie->name,$cookie); } } return $this->_csrfToken; } /** * Creates a cookie with a randomly generated CSRF token. * Initial values specified in {@link csrfCookie} will be applied * to the generated cookie. * @return CHttpCookie the generated cookie * @see enableCsrfValidation */ protected function createCsrfCookie() { $cookie=new CHttpCookie($this->csrfTokenName,sha1(uniqid(mt_rand(),true))); if(is_array($this->csrfCookie)) { foreach($this->csrfCookie as $name=>$value) $cookie->$name=$value; } return $cookie; } /** * Performs the CSRF validation. * This is the event handler responding to {@link CApplication::onBeginRequest}. * The default implementation will compare the CSRF token obtained * from a cookie and from a POST field. If they are different, a CSRF attack is detected. * @param CEvent $event event parameter * @throws CHttpException if the validation fails */ public function validateCsrfToken($event) { if ($this->getIsPostRequest() || $this->getIsPutRequest() || $this->getIsDeleteRequest()) { $cookies=$this->getCookies(); $method=$this->getRequestType(); switch($method) { case 'POST': $userToken=$this->getPost($this->csrfTokenName); break; case 'PUT': $userToken=$this->getPut($this->csrfTokenName); break; case 'DELETE': $userToken=$this->getDelete($this->csrfTokenName); } if (!empty($userToken) && $cookies->contains($this->csrfTokenName)) { $cookieToken=$cookies->itemAt($this->csrfTokenName)->value; $valid=$cookieToken===$userToken; } else $valid = false; if (!$valid) throw new CHttpException(400,Yii::t('yii','The CSRF token could not be verified.')); } } } /** * CCookieCollection implements a collection class to store cookies. * * You normally access it via {@link CHttpRequest::getCookies()}. * * Since CCookieCollection extends from {@link CMap}, it can be used * like an associative array as follows: *
 * $cookies[$name]=new CHttpCookie($name,$value); // sends a cookie
 * $value=$cookies[$name]->value; // reads a cookie value
 * unset($cookies[$name]);  // removes a cookie
 * 
* * @author Qiang Xue * @package system.web * @since 1.0 */ class CCookieCollection extends CMap { private $_request; private $_initialized=false; /** * Constructor. * @param CHttpRequest $request owner of this collection. */ public function __construct(CHttpRequest $request) { $this->_request=$request; $this->copyfrom($this->getCookies()); $this->_initialized=true; } /** * @return CHttpRequest the request instance */ public function getRequest() { return $this->_request; } /** * @return array list of validated cookies */ protected function getCookies() { $cookies=array(); if($this->_request->enableCookieValidation) { $sm=Yii::app()->getSecurityManager(); foreach($_COOKIE as $name=>$value) { if(is_string($value) && ($value=$sm->validateData($value))!==false) $cookies[$name]=new CHttpCookie($name,@unserialize($value)); } } else { foreach($_COOKIE as $name=>$value) $cookies[$name]=new CHttpCookie($name,$value); } return $cookies; } /** * Adds a cookie with the specified name. * This overrides the parent implementation by performing additional * operations for each newly added CHttpCookie object. * @param mixed $name Cookie name. * @param CHttpCookie $cookie Cookie object. * @throws CException if the item to be inserted is not a CHttpCookie object. */ public function add($name,$cookie) { if($cookie instanceof CHttpCookie) { $this->remove($name); parent::add($name,$cookie); if($this->_initialized) $this->addCookie($cookie); } else throw new CException(Yii::t('yii','CHttpCookieCollection can only hold CHttpCookie objects.')); } /** * Removes a cookie with the specified name. * This overrides the parent implementation by performing additional * cleanup work when removing a CHttpCookie object. * Since version 1.1.11, the second parameter is available that can be used to specify * the options of the CHttpCookie being removed. For example, this may be useful when dealing * with ".domain.tld" where multiple subdomains are expected to be able to manage cookies: * *
	 * $options=array('domain'=>'.domain.tld');
	 * Yii::app()->request->cookies['foo']=new CHttpCookie('cookie','value',$options);
	 * Yii::app()->request->cookies->remove('cookie',$options);
	 * 
* * @param mixed $name Cookie name. * @param array $options Cookie configuration array consisting of name-value pairs, available since 1.1.11. * @return CHttpCookie The removed cookie object. */ public function remove($name,$options=array()) { if(($cookie=parent::remove($name))!==null) { if($this->_initialized) { $cookie->configure($options); $this->removeCookie($cookie); } } return $cookie; } /** * Sends a cookie. * @param CHttpCookie $cookie cookie to be sent */ protected function addCookie($cookie) { $value=$cookie->value; if($this->_request->enableCookieValidation) $value=Yii::app()->getSecurityManager()->hashData(serialize($value)); if(version_compare(PHP_VERSION,'5.2.0','>=')) setcookie($cookie->name,$value,$cookie->expire,$cookie->path,$cookie->domain,$cookie->secure,$cookie->httpOnly); else setcookie($cookie->name,$value,$cookie->expire,$cookie->path,$cookie->domain,$cookie->secure); } /** * Deletes a cookie. * @param CHttpCookie $cookie cookie to be deleted */ protected function removeCookie($cookie) { if(version_compare(PHP_VERSION,'5.2.0','>=')) setcookie($cookie->name,'',0,$cookie->path,$cookie->domain,$cookie->secure,$cookie->httpOnly); else setcookie($cookie->name,'',0,$cookie->path,$cookie->domain,$cookie->secure); } } * * @param string $filePath file name with full path * @param array $options additional options: * */ public function xSendFile($filePath, $options=array()) { if(!isset($options['forceDownload']) || $options['forceDownload']) $disposition='attachment'; else $disposition='inline'; if(!isset($options['saveName'])) $options['saveName']=basename($filePath); if(!isset($options['mimeType'])) { if(($options['mimeType']=CFileHelper::getMimeTypeByExtension($filePath))===null) $options['mimeType']='text/plain'; } if(!isset($options['xHeader'])) $options['xHeader']='X-Sendfile'; if($options['mimeType']!==null) header('Content-Type: '.$options['mimeType']); header('Content-Disposition: '.$disposition.'; filename="'.$options['saveName'].'"'); if(isset($options['addHeaders'])) { foreach($options['addHeaders'] as $header=>$value) header($header.': '.$value); } header(trim($options['xHeader']).': '.$filePath); if(!isset($options['terminate']) || $options['terminate']) Yii::app()->end(); } /** * Returns the random token used to perform CSRF validation. * The token will be read from cookie first. If not found, a new token * will be generated. * @return string the random token for CSRF validation. * @see enableCsrfValidation */ public function getCsrfToken() { if($this->_csrfToken===null) { $cookie=$this->getCookies()->itemAt($this->csrfTokenName); if(!$cookie || ($this->_csrfToken=$cookie->value)==null) { $cookie=$this->createCsrfCookie(); $this->_csrfToken=$cookie->value; $this->getCookies()->add($cookie->name,$cookie); } } return $this->_csrfToken; } /** * Creates a cookie with a randomly generated CSRF token. * Initial values specified in {@link csrfCookie} will be applied * to the generated cookie. * @return CHttpCookie the generated cookie * @see enableCsrfValidation */ protected function createCsrfCookie() { $cookie=new CHttpCookie($this->csrfTokenName,sha1(uniqid(mt_rand(),true))); if(is_array($this->csrfCookie)) { foreach($this->csrfCookie as $name=>$value) $cookie->$name=$value; } return $cookie; } /** * Performs the CSRF validation. * This is the event handler responding to {@link CApplication::onBeginRequest}. * The default implementation will compare the CSRF token obtained * from a cookie and from a POST field. If they are different, a CSRF attack is detected. * @param CEvent $event event parameter * @throws CHttpException if the validation fails */ public function validateCsrfToken($event) { if ($this->getIsPostRequest() || $this->getIsPutRequest() || $this->getIsDeleteRequest()) { $cookies=$this->getCookies(); $method=$this->getRequestType(); switch($method) { case 'POST': $userToken=$this->getPost($this->csrfTokenName); break; case 'PUT': $userToken=$this->getPut($this->csrfTokenName); break; case 'DELETE': $userToken=$this->getDelete($this->csrfTokenName); } if (!empty($userToken) && $cookies->contains($this->csrfTokenName)) { $cookieToken=$cookies->itemAt($this->csrfTokenName)->value; $valid=$cookieToken===$userToken; } else $valid = false; if (!$valid) throw new CHttpException(400,Yii::t('yii','The CSRF token could not be verified.')); } } } /** * CCookieCollection implements a collection class to store cookies. * * You normally access it via {@link CHttpRequest::getCookies()}. * * Since CCookieCollection extends from {@link CMap}, it can be used * like an associative array as follows: *
 * $cookies[$name]=new CHttpCookie($name,$value); // sends a cookie
 * $value=$cookies[$name]->value; // reads a cookie value
 * unset($cookies[$name]);  // removes a cookie
 * 
* * @author Qiang Xue * @package system.web * @since 1.0 */ class CCookieCollection extends CMap { private $_request; private $_initialized=false; /** * Constructor. * @param CHttpRequest $request owner of this collection. */ public function __construct(CHttpRequest $request) { $this->_request=$request; $this->copyfrom($this->getCookies()); $this->_initialized=true; } /** * @return CHttpRequest the request instance */ public function getRequest() { return $this->_request; } /** * @return array list of validated cookies */ protected function getCookies() { $cookies=array(); if($this->_request->enableCookieValidation) { $sm=Yii::app()->getSecurityManager(); foreach($_COOKIE as $name=>$value) { if(is_string($value) && ($value=$sm->validateData($value))!==false) $cookies[$name]=new CHttpCookie($name,@unserialize($value)); } } else { foreach($_COOKIE as $name=>$value) $cookies[$name]=new CHttpCookie($name,$value); } return $cookies; } /** * Adds a cookie with the specified name. * This overrides the parent implementation by performing additional * operations for each newly added CHttpCookie object. * @param mixed $name Cookie name. * @param CHttpCookie $cookie Cookie object. * @throws CException if the item to be inserted is not a CHttpCookie object. */ public function add($name,$cookie) { if($cookie instanceof CHttpCookie) { $this->remove($name); parent::add($name,$cookie); if($this->_initialized) $this->addCookie($cookie); } else throw new CException(Yii::t('yii','CHttpCookieCollection can only hold CHttpCookie objects.')); } /** * Removes a cookie with the specified name. * This overrides the parent implementation by performing additional * cleanup work when removing a CHttpCookie object. * Since version 1.1.11, the second parameter is available that can be used to specify * the options of the CHttpCookie being removed. For example, this may be useful when dealing * with ".domain.tld" where multiple subdomains are expected to be able to manage cookies: * *
	 * $options=array('domain'=>'.domain.tld');
	 * Yii::app()->request->cookies['foo']=new CHttpCookie('cookie','value',$options);
	 * Yii::app()->request->cookies->remove('cookie',$options);
	 * 
* * @param mixed $name Cookie name. * @param array $options Cookie configuration array consisting of name-value pairs, available since 1.1.11. * @return CHttpCookie The removed cookie object. */ public function remove($name,$options=array()) { if(($cookie=parent::remove($name))!==null) { if($this->_initialized) { $cookie->configure($options); $this->removeCookie($cookie); } } return $cookie; } /** * Sends a cookie. * @param CHttpCookie $cookie cookie to be sent */ protected function addCookie($cookie) { $value=$cookie->value; if($this->_request->enableCookieValidation) $value=Yii::app()->getSecurityManager()->hashData(serialize($value)); if(version_compare(PHP_VERSION,'5.2.0','>=')) setcookie($cookie->name,$value,$cookie->expire,$cookie->path,$cookie->domain,$cookie->secure,$cookie->httpOnly); else setcookie($cookie->name,$value,$cookie->expire,$cookie->path,$cookie->domain,$cookie->secure); } /** * Deletes a cookie. * @param CHttpCookie $cookie cookie to be deleted */ protected function removeCookie($cookie) { if(version_compare(PHP_VERSION,'5.2.0','>=')) setcookie($cookie->name,'',0,$cookie->path,$cookie->domain,$cookie->secure,$cookie->httpOnly); else setcookie($cookie->name,'',0,$cookie->path,$cookie->domain,$cookie->secure); } }