CController::pageState enhancement

Hi

It would be nice if the method for storing the page state (In the CController) could be configurable or be easier to override. Currently the only way to change the default method of storing state information (in the form of a cookie) is to override the following methods in CController: processOutput, loadPageStates, savePageStates, getPageState, setPageState. This is because access to the private variable CController::_pageStates is required in the method loadPageStates.

It would be nice if either something like an IPageState interface was configurable in the "main" configuration or if the method signature loadPageStates was changed so that it returned the page state array rather then assign it.

Thanks

nz

Could you please create a ticket for this? Thanks.

Created Ticket 284

nz

Just a quick note to say this is now in SVN !!  ;D

Thanks qiang

nz

hi

Thoughts on this implementation ?

Basically stores the state data in cache and send the client the key.

As long as the client sends the key back the state can be pulled and updated from the cache. This works very well with providing a sort of state for ajax calls. I am always concerned about security so I used the security manager to validate the data key, is that sufficient to prevent hacks ?






	/**


	 * Loads page states from a hidden input.


	 */


	protected function loadPageStates() {


	  


		$request =Yii::app()->request;


    if (($dataKey = $request->getParam(self::STATE_INPUT_NAME,false))!==false) {





      if(($dataKey=Yii::app()->getSecurityManager()->validateData($dataKey))!==false) {


        // Now us the cache


        if (($data = Yii::app()->getCache()->get($dataKey))!=false) {


    			if(($data=base64_decode($data))!==false) {


  				  if(extension_loaded('zlib')) {


  					 $data=@gzuncompress($data);


  					}


  					return unserialize($data);


					}


				}


			}


		}


    return array();		


	}





	/**


	 * Saves page states in cache, assign key to pageStateField.


	 */


	protected function savePageStates($states,&$output) {


		$request =Yii::app()->request;


    $dataKey = $oldKey = Yii::app()->getSecurityManager()->


        validateData($request->getParam(self::STATE_INPUT_NAME,false));


    


		$data=serialize($states);


		if(extension_loaded('zlib'))


			$data=gzcompress($data);


			


		$dataToSave = base64_encode($data);





		$dataKey = false;


    


    // If ajax request update the data using the existing key		


    if ($request->getIsAjaxRequest()) {


      if ($oldKey!==false) {


        $stored = Yii::app()->getCache()->set($oldKey,$dataToSave,60*60*3);


      }


    }


    else {


      if ($oldKey !=false ) {


        // Should old state information be removed ??


      }


      


  		$timestamp=(string)microtime(true);


  		$key=$this->calculateKey($timestamp, $request);


  		


  		//Store the key in the cache for 3 hours


  		Yii::app()->getCache()->set($key,$dataToSave,60*60*3);


  		


  		// hash the key


  		$dataKey=Yii::app()->getSecurityManager()->hashData($key);


  		$output=str_replace(CHtml::pageStateField(''),


                          CHtml::pageStateField($dataKey),$output);


		}		


	}


nz