From 94e94e0a8566f23d16658a04c55b0bbfdd6689aa Mon Sep 17 00:00:00 2001 From: "godzilla80@gmx.net" <> Date: Sun, 14 Feb 2010 01:22:57 +0000 Subject: Merge Branches & Trunk /trunk:r2680,2692,2707-2736 /branches/3.1:r2682-2686,2694-2702,2705,2738-2762 --- framework/pradolite.php | 9489 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 9489 insertions(+) create mode 100644 framework/pradolite.php (limited to 'framework/pradolite.php') diff --git a/framework/pradolite.php b/framework/pradolite.php new file mode 100644 index 00000000..6d5b13fd --- /dev/null +++ b/framework/pradolite.php @@ -0,0 +1,9489 @@ +PRADO_DIR); + private static $_usings=array(); + private static $_application=null; + private static $_logger=null; + public static function getVersion() + { + return '3.1.6-dev'; + } + public static function initErrorHandlers() + { + set_error_handler(array('PradoBase','phpErrorHandler'),error_reporting()); + set_exception_handler(array('PradoBase','exceptionHandler')); + } + public static function autoload($className) + { + include_once($className.self::CLASS_FILE_EXT); + if(!class_exists($className,false) && !interface_exists($className,false)) + self::fatalError("Class file for '$className' cannot be found."); + } + public static function poweredByPrado($logoType=0) + { + $logoName=$logoType==1?'powered2':'powered'; + if(self::$_application!==null) + { + $am=self::$_application->getAssetManager(); + $url=$am->publishFilePath(self::getPathOfNamespace('System.'.$logoName,'.gif')); + } + else + $url='http://www.pradosoft.com/images/'.$logoName.'.gif'; + return 'Powered by PRADO'; + } + public static function phpErrorHandler($errno,$errstr,$errfile,$errline) + { + if(error_reporting()!=0) + throw new TPhpErrorException($errno,$errstr,$errfile,$errline); + } + public static function exceptionHandler($exception) + { + if(self::$_application!==null && ($errorHandler=self::$_application->getErrorHandler())!==null) + { + $errorHandler->handleError(null,$exception); + } + else + { + echo $exception; + } + exit(1); + } + public static function setApplication($application) + { + if(self::$_application!==null) + throw new TInvalidOperationException('prado_application_singleton_required'); + self::$_application=$application; + } + public static function getApplication() + { + return self::$_application; + } + public static function getFrameworkPath() + { + return PRADO_DIR; + } + public static function serialize($data) + { + $arr[0]=$data; + return serialize($arr); + } + public static function unserialize($str) + { + $arr=unserialize($str); + return isset($arr[0])?$arr[0]:null; + } + public static function createComponent($type) + { + self::using($type); + if(($pos=strrpos($type,'.'))!==false) + $type=substr($type,$pos+1); + if(($n=func_num_args())>1) + { + $args=func_get_args(); + $s='$args[1]'; + for($i=2;$i<$n;++$i) + $s.=",\$args[$i]"; + eval("\$component=new $type($s);"); + return $component; + } + else + return new $type; + } + public static function using($namespace,$checkClassExistence=true) + { + if(isset(self::$_usings[$namespace]) || class_exists($namespace,false)) + return; + if(($pos=strrpos($namespace,'.'))===false) { + try + { + include_once($namespace.self::CLASS_FILE_EXT); + } + catch(Exception $e) + { + if($checkClassExistence && !class_exists($namespace,false)) + throw new TInvalidOperationException('prado_component_unknown',$namespace,$e->getMessage()); + else + throw $e; + } + } + else if(($path=self::getPathOfNamespace($namespace,self::CLASS_FILE_EXT))!==null) + { + $className=substr($namespace,$pos+1); + if($className==='*') { + self::$_usings[$namespace]=$path; + set_include_path(get_include_path().PATH_SEPARATOR.$path); + } + else { + self::$_usings[$namespace]=$path; + if(!$checkClassExistence || !class_exists($className,false)) + { + try + { + include_once($path); + } + catch(Exception $e) + { + if($checkClassExistence && !class_exists($className,false)) + throw new TInvalidOperationException('prado_component_unknown',$className,$e->getMessage()); + else + throw $e; + } + } + } + } + else + throw new TInvalidDataValueException('prado_using_invalid',$namespace); + } + public static function getPathOfNamespace($namespace,$ext='') + { + if(isset(self::$_usings[$namespace])) + return self::$_usings[$namespace]; + else if(isset(self::$_aliases[$namespace])) + return self::$_aliases[$namespace]; + else + { + $segs=explode('.',$namespace); + $alias=array_shift($segs); + if(($file=array_pop($segs))!==null && ($root=self::getPathOfAlias($alias))!==null) + return rtrim($root.DIRECTORY_SEPARATOR.implode(DIRECTORY_SEPARATOR ,$segs),'/\\').(($file==='*')?'':DIRECTORY_SEPARATOR.$file.$ext); + else + return null; + } + } + public static function getPathOfAlias($alias) + { + return isset(self::$_aliases[$alias])?self::$_aliases[$alias]:null; + } + protected static function getPathAliases() + { + return self::$_aliases; + } + public static function setPathOfAlias($alias,$path) + { + if(isset(self::$_aliases[$alias])) + throw new TInvalidOperationException('prado_alias_redefined',$alias); + else if(($rp=realpath($path))!==false && is_dir($rp)) + { + if(strpos($alias,'.')===false) + self::$_aliases[$alias]=$rp; + else + throw new TInvalidDataValueException('prado_aliasname_invalid',$alias); + } + else + throw new TInvalidDataValueException('prado_alias_invalid',$alias,$path); + } + public static function fatalError($msg) + { + echo '

Fatal Error

'; + echo '

'.$msg.'

'; + if(!function_exists('debug_backtrace')) + return; + echo '

Debug Backtrace

'; + echo '
';
+		$index=-1;
+		foreach(debug_backtrace() as $t)
+		{
+			$index++;
+			if($index==0)  				continue;
+			echo '#'.$index.' ';
+			if(isset($t['file']))
+				echo basename($t['file']) . ':' . $t['line'];
+			else
+			   echo '';
+			echo ' -- ';
+			if(isset($t['class']))
+				echo $t['class'] . $t['type'];
+			echo $t['function'] . '(';
+			if(isset($t['args']) && sizeof($t['args']) > 0)
+			{
+				$count=0;
+				foreach($t['args'] as $item)
+				{
+					if(is_string($item))
+					{
+						$str=htmlentities(str_replace("\r\n", "", $item), ENT_QUOTES);
+						if (strlen($item) > 70)
+							echo "'". substr($str, 0, 70) . "...'";
+						else
+							echo "'" . $str . "'";
+					}
+					else if (is_int($item) || is_float($item))
+						echo $item;
+					else if (is_object($item))
+						echo get_class($item);
+					else if (is_array($item))
+						echo 'array(' . count($item) . ')';
+					else if (is_bool($item))
+						echo $item ? 'true' : 'false';
+					else if ($item === null)
+						echo 'NULL';
+					else if (is_resource($item))
+						echo get_resource_type($item);
+					$count++;
+					if (count($t['args']) > $count)
+						echo ', ';
+				}
+			}
+			echo ")\n";
+		}
+		echo '
'; + exit(1); + } + public static function getUserLanguages() + { + static $languages=null; + if($languages===null) + { + if(!isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) + $languages[0]='en'; + else + { + $languages=array(); + foreach(explode(',',$_SERVER['HTTP_ACCEPT_LANGUAGE']) as $language) + { + $array=explode(';q=',trim($language)); + $languages[trim($array[0])]=isset($array[1])?(float)$array[1]:1.0; + } + arsort($languages); + $languages=array_keys($languages); + if(empty($languages)) + $languages[0]='en'; + } + } + return $languages; + } + public static function getPreferredLanguage() + { + static $language=null; + if($language===null) + { + $langs=Prado::getUserLanguages(); + $lang=explode('-',$langs[0]); + if(empty($lang[0]) || !ctype_alpha($lang[0])) + $language='en'; + else + $language=$lang[0]; + } + return $language; + } + public static function trace($msg,$category='Uncategorized') + { + if(self::$_application && self::$_application->getMode()===TApplicationMode::Performance) + return; + if(!self::$_application || self::$_application->getMode()===TApplicationMode::Debug) + { + $trace=debug_backtrace(); + if(isset($trace[0]['file']) && isset($trace[0]['line'])) + $msg.=" (line {$trace[0]['line']}, {$trace[0]['file']})"; + $level=TLogger::DEBUG; + } + else + $level=TLogger::INFO; + self::log($msg,$level,$category); + } + public static function log($msg,$level=TLogger::INFO,$category='Uncategorized') + { + if(self::$_logger===null) + self::$_logger=new TLogger; + self::$_logger->log($msg,$level,$category); + } + public static function getLogger() + { + if(self::$_logger===null) + self::$_logger=new TLogger; + return self::$_logger; + } + public static function varDump($var,$depth=10,$highlight=false) + { + Prado::using('System.Util.TVarDumper'); + return TVarDumper::dump($var,$depth,$highlight); + } + public static function localize($text, $parameters=array(), $catalogue=null, $charset=null) + { + Prado::using('System.I18N.Translation'); + $app = Prado::getApplication()->getGlobalization(false); + $params = array(); + foreach($parameters as $key => $value) + $params['{'.$key.'}'] = $value; + if($app===null || ($config = $app->getTranslationConfiguration())===null) + return strtr($text, $params); + if ($catalogue===null) + $catalogue=isset($config['catalogue'])?$config['catalogue']:'messages'; + Translation::init($catalogue); + $appCharset = $app===null ? '' : $app->getCharset(); + $defaultCharset = ($app===null) ? 'UTF-8' : $app->getDefaultCharset(); + if(empty($charset)) $charset = $appCharset; + if(empty($charset)) $charset = $defaultCharset; + return Translation::formatter($catalogue)->format($text,$params,$catalogue,$charset); + } +} +class TReflectionClass extends ReflectionClass +{ +} +PradoBase::using('System.TComponent'); +PradoBase::using('System.Exceptions.TException'); +PradoBase::using('System.Util.TLogger'); +if(!class_exists('Prado',false)) +{ + class Prado extends PradoBase + { + } +} +spl_autoload_register(array('Prado','autoload')); +Prado::initErrorHandlers(); +interface IModule +{ + public function init($config); + public function getID(); + public function setID($id); +} +interface IService +{ + public function init($config); + public function getID(); + public function setID($id); + public function getEnabled(); + public function setEnabled($value); + public function run(); +} +interface ITextWriter +{ + public function write($str); + public function flush(); +} +interface IUser +{ + public function getName(); + public function setName($value); + public function getIsGuest(); + public function setIsGuest($value); + public function getRoles(); + public function setRoles($value); + public function isInRole($role); + public function saveToString(); + public function loadFromString($string); +} +interface IStatePersister +{ + public function load(); + public function save($state); +} +interface ICache +{ + public function get($id); + public function set($id,$value,$expire=0,$dependency=null); + public function add($id,$value,$expire=0,$dependency=null); + public function delete($id); + public function flush(); +} +interface ICacheDependency +{ + public function getHasChanged(); +} +interface IRenderable +{ + public function render($writer); +} +interface IBindable +{ + public function dataBind(); +} +interface IStyleable +{ + public function getHasStyle(); + public function getStyle(); + public function clearStyle(); +} +interface IActiveControl +{ + public function getActiveControl(); +} +interface ICallbackEventHandler +{ + public function raiseCallbackEvent($eventArgument); +} +interface IDataRenderer +{ + public function getData(); + public function setData($value); +} +class TApplicationComponent extends TComponent +{ + public function getApplication() + { + return Prado::getApplication(); + } + public function getService() + { + return Prado::getApplication()->getService(); + } + public function getRequest() + { + return Prado::getApplication()->getRequest(); + } + public function getResponse() + { + return Prado::getApplication()->getResponse(); + } + public function getSession() + { + return Prado::getApplication()->getSession(); + } + public function getUser() + { + return Prado::getApplication()->getUser(); + } + public function publishAsset($assetPath,$className=null) + { + if($className===null) + $className=get_class($this); + $class=new ReflectionClass($className); + $fullPath=dirname($class->getFileName()).DIRECTORY_SEPARATOR.$assetPath; + return $this->publishFilePath($fullPath); + } + public function publishFilePath($fullPath) + { + return Prado::getApplication()->getAssetManager()->publishFilePath($fullPath); + } +} +abstract class TModule extends TApplicationComponent implements IModule +{ + private $_id; + public function init($config) + { + } + public function getID() + { + return $this->_id; + } + public function setID($value) + { + $this->_id=$value; + } +} +abstract class TService extends TApplicationComponent implements IService +{ + private $_id; + private $_enabled=true; + public function init($config) + { + } + public function getID() + { + return $this->_id; + } + public function setID($value) + { + $this->_id=$value; + } + public function getEnabled() + { + return $this->_enabled; + } + public function setEnabled($value) + { + $this->_enabled=TPropertyValue::ensureBoolean($value); + } + public function run() + { + } +} +class TErrorHandler extends TModule +{ + const ERROR_FILE_NAME='error'; + const EXCEPTION_FILE_NAME='exception'; + const SOURCE_LINES=12; + private $_templatePath=null; + public function init($config) + { + $this->getApplication()->setErrorHandler($this); + } + public function getErrorTemplatePath() + { + if($this->_templatePath===null) + $this->_templatePath=Prado::getFrameworkPath().'/Exceptions/templates'; + return $this->_templatePath; + } + public function setErrorTemplatePath($value) + { + if(($templatePath=Prado::getPathOfNamespace($value))!==null && is_dir($templatePath)) + $this->_templatePath=$templatePath; + else + throw new TConfigurationException('errorhandler_errortemplatepath_invalid',$value); + } + public function handleError($sender,$param) + { + static $handling=false; + restore_error_handler(); + restore_exception_handler(); + if($handling) + $this->handleRecursiveError($param); + else + { + $handling=true; + if(($response=$this->getResponse())!==null) + $response->clear(); + if(!headers_sent()) + header('Content-Type: text/html; charset=UTF-8'); + if($param instanceof THttpException) + $this->handleExternalError($param->getStatusCode(),$param); + else if($this->getApplication()->getMode()===TApplicationMode::Debug) + $this->displayException($param); + else + $this->handleExternalError(500,$param); + } + } + protected function handleExternalError($statusCode,$exception) + { + if(!($exception instanceof THttpException)) + error_log($exception->__toString()); + $content=$this->getErrorTemplate($statusCode,$exception); + $serverAdmin=isset($_SERVER['SERVER_ADMIN'])?$_SERVER['SERVER_ADMIN']:''; + if($this->getApplication()->getMode()===TApplicationMode::Debug) + $version=$_SERVER['SERVER_SOFTWARE'].' PRADO/'.Prado::getVersion(); + else + $version=''; + $tokens=array( + '%%StatusCode%%' => "$statusCode", + '%%ErrorMessage%%' => htmlspecialchars($exception->getMessage()), + '%%ServerAdmin%%' => $serverAdmin, + '%%Version%%' => $version, + '%%Time%%' => @strftime('%Y-%m-%d %H:%M',time()) + ); + header("HTTP/1.0 $statusCode ".$exception->getMessage()); + echo strtr($content,$tokens); + } + protected function handleRecursiveError($exception) + { + if($this->getApplication()->getMode()===TApplicationMode::Debug) + { + echo "Recursive Error\n"; + echo "

Recursive Error

\n"; + echo "
".$exception->__toString()."
\n"; + echo ""; + } + else + { + error_log("Error happened while processing an existing error:\n".$exception->__toString()); + header('HTTP/1.0 500 Internal Error'); + } + } + protected function displayException($exception) + { + if(php_sapi_name()==='cli') + { + echo $exception->getMessage()."\n"; + echo $exception->getTraceAsString(); + return; + } + if($exception instanceof TTemplateException) + { + $fileName=$exception->getTemplateFile(); + $lines=empty($fileName)?explode("\n",$exception->getTemplateSource()):@file($fileName); + $source=$this->getSourceCode($lines,$exception->getLineNumber()); + if($fileName==='') + $fileName='---embedded template---'; + $errorLine=$exception->getLineNumber(); + } + else + { + if(($trace=$this->getExactTrace($exception))!==null) + { + $fileName=$trace['file']; + $errorLine=$trace['line']; + } + else + { + $fileName=$exception->getFile(); + $errorLine=$exception->getLine(); + } + $source=$this->getSourceCode(@file($fileName),$errorLine); + } + if($this->getApplication()->getMode()===TApplicationMode::Debug) + $version=$_SERVER['SERVER_SOFTWARE'].' PRADO/'.Prado::getVersion(); + else + $version=''; + $tokens=array( + '%%ErrorType%%' => get_class($exception), + '%%ErrorMessage%%' => $this->addLink(htmlspecialchars($exception->getMessage())), + '%%SourceFile%%' => htmlspecialchars($fileName).' ('.$errorLine.')', + '%%SourceCode%%' => $source, + '%%StackTrace%%' => htmlspecialchars($exception->getTraceAsString()), + '%%Version%%' => $version, + '%%Time%%' => @strftime('%Y-%m-%d %H:%M',time()) + ); + $content=$this->getExceptionTemplate($exception); + echo strtr($content,$tokens); + } + protected function getExceptionTemplate($exception) + { + $lang=Prado::getPreferredLanguage(); + $exceptionFile=Prado::getFrameworkPath().'/Exceptions/templates/'.self::EXCEPTION_FILE_NAME.'-'.$lang.'.html'; + if(!is_file($exceptionFile)) + $exceptionFile=Prado::getFrameworkPath().'/Exceptions/templates/'.self::EXCEPTION_FILE_NAME.'.html'; + if(($content=@file_get_contents($exceptionFile))===false) + die("Unable to open exception template file '$exceptionFile'."); + return $content; + } + protected function getErrorTemplate($statusCode,$exception) + { + $base=$this->getErrorTemplatePath().DIRECTORY_SEPARATOR.self::ERROR_FILE_NAME; + $lang=Prado::getPreferredLanguage(); + if(is_file("$base$statusCode-$lang.html")) + $errorFile="$base$statusCode-$lang.html"; + else if(is_file("$base$statusCode.html")) + $errorFile="$base$statusCode.html"; + else if(is_file("$base-$lang.html")) + $errorFile="$base-$lang.html"; + else + $errorFile="$base.html"; + if(($content=@file_get_contents($errorFile))===false) + die("Unable to open error template file '$errorFile'."); + return $content; + } + private function getExactTrace($exception) + { + $trace=$exception->getTrace(); + $result=null; + if($exception instanceof TPhpErrorException) + $result=isset($trace[0]['file'])?$trace[0]:$trace[1]; + else if($exception instanceof TInvalidOperationException) + { + if(($result=$this->getPropertyAccessTrace($trace,'__get'))===null) + $result=$this->getPropertyAccessTrace($trace,'__set'); + } + if($result!==null && strpos($result['file'],': eval()\'d code')!==false) + return null; + return $result; + } + private function getPropertyAccessTrace($trace,$pattern) + { + $result=null; + foreach($trace as $t) + { + if(isset($t['function']) && $t['function']===$pattern) + $result=$t; + else + break; + } + return $result; + } + private function getSourceCode($lines,$errorLine) + { + $beginLine=$errorLine-self::SOURCE_LINES>=0?$errorLine-self::SOURCE_LINES:0; + $endLine=$errorLine+self::SOURCE_LINES<=count($lines)?$errorLine+self::SOURCE_LINES:count($lines); + $source=''; + for($i=$beginLine;$i<$endLine;++$i) + { + if($i===$errorLine-1) + { + $line=htmlspecialchars(sprintf("%04d: %s",$i+1,str_replace("\t",' ',$lines[$i]))); + $source.="
".$line."
"; + } + else + $source.=htmlspecialchars(sprintf("%04d: %s",$i+1,str_replace("\t",' ',$lines[$i]))); + } + return $source; + } + private function addLink($message) + { + $baseUrl='http://www.pradosoft.com/docs/classdoc'; + return preg_replace('/\b(T[A-Z]\w+)\b/',"\${1}",$message); + } +} +class TList extends TComponent implements IteratorAggregate,ArrayAccess,Countable +{ + private $_d=array(); + private $_c=0; + private $_r=false; + public function __construct($data=null,$readOnly=false) + { + if($data!==null) + $this->copyFrom($data); + $this->setReadOnly($readOnly); + } + public function getReadOnly() + { + return $this->_r; + } + protected function setReadOnly($value) + { + $this->_r=TPropertyValue::ensureBoolean($value); + } + public function getIterator() + { + return new TListIterator($this->_d); + } + public function count() + { + return $this->getCount(); + } + public function getCount() + { + return $this->_c; + } + public function itemAt($index) + { + if($index>=0 && $index<$this->_c) + return $this->_d[$index]; + else + throw new TInvalidDataValueException('list_index_invalid',$index); + } + public function add($item) + { + $this->insertAt($this->_c,$item); + return $this->_c-1; + } + public function insertAt($index,$item) + { + if(!$this->_r) + { + if($index===$this->_c) + $this->_d[$this->_c++]=$item; + else if($index>=0 && $index<$this->_c) + { + array_splice($this->_d,$index,0,array($item)); + $this->_c++; + } + else + throw new TInvalidDataValueException('list_index_invalid',$index); + } + else + throw new TInvalidOperationException('list_readonly',get_class($this)); + } + public function remove($item) + { + if(($index=$this->indexOf($item))>=0) + { + $this->removeAt($index); + return $index; + } + else + throw new TInvalidDataValueException('list_item_inexistent'); + } + public function removeAt($index) + { + if(!$this->_r) + { + if($index>=0 && $index<$this->_c) + { + $this->_c--; + if($index===$this->_c) + return array_pop($this->_d); + else + { + $item=$this->_d[$index]; + array_splice($this->_d,$index,1); + return $item; + } + } + else + throw new TInvalidDataValueException('list_index_invalid',$index); + } + else + throw new TInvalidOperationException('list_readonly',get_class($this)); + } + public function clear() + { + for($i=$this->_c-1;$i>=0;--$i) + $this->removeAt($i); + } + public function contains($item) + { + return $this->indexOf($item)>=0; + } + public function indexOf($item) + { + if(($index=array_search($item,$this->_d,true))===false) + return -1; + else + return $index; + } + public function toArray() + { + return $this->_d; + } + public function copyFrom($data) + { + if(is_array($data) || ($data instanceof Traversable)) + { + if($this->_c>0) + $this->clear(); + foreach($data as $item) + $this->add($item); + } + else if($data!==null) + throw new TInvalidDataTypeException('list_data_not_iterable'); + } + public function mergeWith($data) + { + if(is_array($data) || ($data instanceof Traversable)) + { + foreach($data as $item) + $this->add($item); + } + else if($data!==null) + throw new TInvalidDataTypeException('list_data_not_iterable'); + } + public function offsetExists($offset) + { + return ($offset>=0 && $offset<$this->_c); + } + public function offsetGet($offset) + { + return $this->itemAt($offset); + } + public function offsetSet($offset,$item) + { + if($offset===null || $offset===$this->_c) + $this->insertAt($this->_c,$item); + else + { + $this->removeAt($offset); + $this->insertAt($offset,$item); + } + } + public function offsetUnset($offset) + { + $this->removeAt($offset); + } +} +class TListIterator implements Iterator +{ + private $_d; + private $_i; + private $_c; + public function __construct(&$data) + { + $this->_d=&$data; + $this->_i=0; + $this->_c=count($this->_d); + } + public function rewind() + { + $this->_i=0; + } + public function key() + { + return $this->_i; + } + public function current() + { + return $this->_d[$this->_i]; + } + public function next() + { + $this->_i++; + } + public function valid() + { + return $this->_i<$this->_c; + } +} +abstract class TCache extends TModule implements ICache, ArrayAccess +{ + private $_prefix=null; + private $_primary=true; + public function init($config) + { + if($this->_prefix===null) + $this->_prefix=$this->getApplication()->getUniqueID(); + if($this->_primary) + { + if($this->getApplication()->getCache()===null) + $this->getApplication()->setCache($this); + else + throw new TConfigurationException('cache_primary_duplicated',get_class($this)); + } + } + public function getPrimaryCache() + { + return $this->_primary; + } + public function setPrimaryCache($value) + { + $this->_primary=TPropertyValue::ensureBoolean($value); + } + public function getKeyPrefix() + { + return $this->_prefix; + } + public function setKeyPrefix($value) + { + $this->_prefix=$value; + } + protected function generateUniqueKey($key) + { + return md5($this->_prefix.$key); + } + public function get($id) + { + if(($value=$this->getValue($this->generateUniqueKey($id)))!==false) + { + $data=unserialize($value); + if(!is_array($data)) + return false; + if(!($data[1] instanceof ICacheDependency) || !$data[1]->getHasChanged()) + return $data[0]; + } + return false; + } + public function set($id,$value,$expire=0,$dependency=null) + { + if(empty($value) && $expire === 0) + $this->delete($id); + else + { + $data=array($value,$dependency); + return $this->setValue($this->generateUniqueKey($id),serialize($data),$expire); + } + } + public function add($id,$value,$expire=0,$dependency=null) + { + if(empty($value) && $expire === 0) + return false; + $data=array($value,$dependency); + return $this->addValue($this->generateUniqueKey($id),serialize($data),$expire); + } + public function delete($id) + { + return $this->deleteValue($this->generateUniqueKey($id)); + } + public function flush() + { + throw new TNotSupportedException('cache_flush_unsupported'); + } + abstract protected function getValue($key); + abstract protected function setValue($key,$value,$expire); + abstract protected function addValue($key,$value,$expire); + abstract protected function deleteValue($key); + public function offsetExists($id) + { + return $this->get($id) !== false; + } + public function offsetGet($id) + { + return $this->get($id); + } + public function offsetSet($id, $value) + { + $this->set($id, $value); + } + public function offsetUnset($id) + { + $this->delete($id); + } +} +abstract class TCacheDependency extends TComponent implements ICacheDependency +{ +} +class TFileCacheDependency extends TCacheDependency +{ + private $_fileName; + private $_timestamp; + public function __construct($fileName) + { + $this->setFileName($fileName); + } + public function getFileName() + { + return $this->_fileName; + } + public function setFileName($value) + { + $this->_fileName=$value; + $this->_timestamp=@filemtime($value); + } + public function getTimestamp() + { + return $this->_timestamp; + } + public function getHasChanged() + { + return @filemtime($this->_fileName)!==$this->_timestamp; + } +} +class TDirectoryCacheDependency extends TCacheDependency +{ + private $_recursiveCheck=true; + private $_recursiveLevel=-1; + private $_timestamps; + private $_directory; + public function __construct($directory) + { + $this->setDirectory($directory); + } + public function getDirectory() + { + return $this->_directory; + } + public function setDirectory($directory) + { + if(($path=realpath($directory))===false || !is_dir($path)) + throw new TInvalidDataValueException('directorycachedependency_directory_invalid',$directory); + $this->_directory=$path; + $this->_timestamps=$this->generateTimestamps($path); + } + public function getRecursiveCheck() + { + return $this->_recursiveCheck; + } + public function setRecursiveCheck($value) + { + $this->_recursiveCheck=TPropertyValue::ensureBoolean($value); + } + public function getRecursiveLevel() + { + return $this->_recursiveLevel; + } + public function setRecursiveLevel($value) + { + $this->_recursiveLevel=TPropertyValue::ensureInteger($value); + } + public function getHasChanged() + { + return $this->generateTimestamps($this->_directory)!=$this->_timestamps; + } + protected function validateFile($fileName) + { + return true; + } + protected function validateDirectory($directory) + { + return true; + } + protected function generateTimestamps($directory,$level=0) + { + if(($dir=opendir($directory))===false) + throw new TIOException('directorycachedependency_directory_invalid',$directory); + $timestamps=array(); + while(($file=readdir($dir))!==false) + { + $path=$directory.DIRECTORY_SEPARATOR.$file; + if($file==='.' || $file==='..') + continue; + else if(is_dir($path)) + { + if(($this->_recursiveLevel<0 || $level<$this->_recursiveLevel) && $this->validateDirectory($path)) + $timestamps=array_merge($this->generateTimestamps($path,$level+1)); + } + else if($this->validateFile($path)) + $timestamps[$path]=filemtime($path); + } + closedir($dir); + return $timestamps; + } +} +class TGlobalStateCacheDependency extends TCacheDependency +{ + private $_stateName; + private $_stateValue; + public function __construct($name) + { + $this->setStateName($name); + } + public function getStateName() + { + return $this->_stateName; + } + public function setStateName($value) + { + $this->_stateName=$value; + $this->_stateValue=Prado::getApplication()->getGlobalState($value); + } + public function getHasChanged() + { + return $this->_stateValue!==Prado::getApplication()->getGlobalState($this->_stateName); + } +} +class TChainedCacheDependency extends TCacheDependency +{ + private $_dependencies=null; + public function getDependencies() + { + if($this->_dependencies===null) + $this->_dependencies=new TCacheDependencyList; + return $this->_dependencies; + } + public function getHasChanged() + { + if($this->_dependencies!==null) + { + foreach($this->_dependencies as $dependency) + if($dependency->getHasChanged()) + return true; + } + return false; + } +} +class TApplicationStateCacheDependency extends TCacheDependency +{ + public function getHasChanged() + { + return Prado::getApplication()->getMode()!==TApplicationMode::Performance; + } +} +class TCacheDependencyList extends TList +{ + public function insertAt($index,$item) + { + if($item instanceof ICacheDependency) + parent::insertAt($index,$item); + else + throw new TInvalidDataTypeException('cachedependencylist_cachedependency_required'); + } +} +class TTextWriter extends TComponent implements ITextWriter +{ + private $_str=''; + public function flush() + { + $str=$this->_str; + $this->_str=''; + return $str; + } + public function write($str) + { + $this->_str.=$str; + } + public function writeLine($str='') + { + $this->write($str."\n"); + } +} +class TMap extends TComponent implements IteratorAggregate,ArrayAccess,Countable +{ + private $_d=array(); + private $_r=false; + public function __construct($data=null,$readOnly=false) + { + if($data!==null) + $this->copyFrom($data); + $this->setReadOnly($readOnly); + } + public function getReadOnly() + { + return $this->_r; + } + protected function setReadOnly($value) + { + $this->_r=TPropertyValue::ensureBoolean($value); + } + public function getIterator() + { + return new TMapIterator($this->_d); + } + public function count() + { + return $this->getCount(); + } + public function getCount() + { + return count($this->_d); + } + public function getKeys() + { + return array_keys($this->_d); + } + public function itemAt($key) + { + return isset($this->_d[$key]) ? $this->_d[$key] : null; + } + public function add($key,$value) + { + if(!$this->_r) + $this->_d[$key]=$value; + else + throw new TInvalidOperationException('map_readonly',get_class($this)); + } + public function remove($key) + { + if(!$this->_r) + { + if(isset($this->_d[$key]) || array_key_exists($key,$this->_d)) + { + $value=$this->_d[$key]; + unset($this->_d[$key]); + return $value; + } + else + return null; + } + else + throw new TInvalidOperationException('map_readonly',get_class($this)); + } + public function clear() + { + foreach(array_keys($this->_d) as $key) + $this->remove($key); + } + public function contains($key) + { + return isset($this->_d[$key]) || array_key_exists($key,$this->_d); + } + public function toArray() + { + return $this->_d; + } + public function copyFrom($data) + { + if(is_array($data) || $data instanceof Traversable) + { + if($this->getCount()>0) + $this->clear(); + foreach($data as $key=>$value) + $this->add($key,$value); + } + else if($data!==null) + throw new TInvalidDataTypeException('map_data_not_iterable'); + } + public function mergeWith($data) + { + if(is_array($data) || $data instanceof Traversable) + { + foreach($data as $key=>$value) + $this->add($key,$value); + } + else if($data!==null) + throw new TInvalidDataTypeException('map_data_not_iterable'); + } + public function offsetExists($offset) + { + return $this->contains($offset); + } + public function offsetGet($offset) + { + return $this->itemAt($offset); + } + public function offsetSet($offset,$item) + { + $this->add($offset,$item); + } + public function offsetUnset($offset) + { + $this->remove($offset); + } +} +class TMapIterator implements Iterator +{ + private $_d; + private $_keys; + private $_key; + public function __construct(&$data) + { + $this->_d=&$data; + $this->_keys=array_keys($data); + } + public function rewind() + { + $this->_key=reset($this->_keys); + } + public function key() + { + return $this->_key; + } + public function current() + { + return $this->_d[$this->_key]; + } + public function next() + { + $this->_key=next($this->_keys); + } + public function valid() + { + return $this->_key!==false; + } +} +class TStack extends TComponent implements IteratorAggregate,Countable +{ + private $_d=array(); + private $_c=0; + public function __construct($data=null) + { + if($data!==null) + $this->copyFrom($data); + } + public function toArray() + { + return $this->_d; + } + public function copyFrom($data) + { + if(is_array($data) || ($data instanceof Traversable)) + { + $this->clear(); + foreach($data as $item) + { + $this->_d[]=$item; + ++$this->_c; + } + } + else if($data!==null) + throw new TInvalidDataTypeException('stack_data_not_iterable'); + } + public function clear() + { + $this->_c=0; + $this->_d=array(); + } + public function contains($item) + { + return array_search($item,$this->_d,true)!==false; + } + public function peek() + { + if($this->_c===0) + throw new TInvalidOperationException('stack_empty'); + else + return $this->_d[$this->_c-1]; + } + public function pop() + { + if($this->_c===0) + throw new TInvalidOperationException('stack_empty'); + else + { + --$this->_c; + return array_pop($this->_d); + } + } + public function push($item) + { + ++$this->_c; + $this->_d[] = $item; + } + public function getIterator() + { + return new TStackIterator($this->_d); + } + public function getCount() + { + return $this->_c; + } + public function count() + { + return $this->getCount(); + } +} +class TStackIterator implements Iterator +{ + private $_d; + private $_i; + private $_c; + public function __construct(&$data) + { + $this->_d=&$data; + $this->_i=0; + $this->_c=count($this->_d); + } + public function rewind() + { + $this->_i=0; + } + public function key() + { + return $this->_i; + } + public function current() + { + return $this->_d[$this->_i]; + } + public function next() + { + $this->_i++; + } + public function valid() + { + return $this->_i<$this->_c; + } +} +class TXmlElement extends TComponent +{ + private $_parent=null; + private $_tagName='unknown'; + private $_value=''; + private $_elements=null; + private $_attributes=null; + public function __construct($tagName) + { + $this->setTagName($tagName); + } + public function getParent() + { + return $this->_parent; + } + public function setParent($parent) + { + $this->_parent=$parent; + } + public function getTagName() + { + return $this->_tagName; + } + public function setTagName($tagName) + { + $this->_tagName=$tagName; + } + public function getValue() + { + return $this->_value; + } + public function setValue($value) + { + $this->_value=$value; + } + public function getHasElement() + { + return $this->_elements!==null && $this->_elements->getCount()>0; + } + public function getHasAttribute() + { + return $this->_attributes!==null && $this->_attributes->getCount()>0; + } + public function getAttribute($name) + { + if($this->_attributes!==null) + return $this->_attributes->itemAt($name); + else + return null; + } + public function setAttribute($name,$value) + { + $this->getAttributes()->add($name,$value); + } + public function getElements() + { + if(!$this->_elements) + $this->_elements=new TXmlElementList($this); + return $this->_elements; + } + public function getAttributes() + { + if(!$this->_attributes) + $this->_attributes=new TMap; + return $this->_attributes; + } + public function getElementByTagName($tagName) + { + if($this->_elements) + { + foreach($this->_elements as $element) + if($element->_tagName===$tagName) + return $element; + } + return null; + } + public function getElementsByTagName($tagName) + { + $list=new TList; + if($this->_elements) + { + foreach($this->_elements as $element) + if($element->_tagName===$tagName) + $list->add($element); + } + return $list; + } + public function toString($indent=0) + { + $attr=''; + if($this->_attributes!==null) + { + foreach($this->_attributes as $name=>$value) + { + $value=$this->xmlEncode($value); + $attr.=" $name=\"$value\""; + } + } + $prefix=str_repeat(' ',$indent*4); + if($this->getHasElement()) + { + $str=$prefix."<{$this->_tagName}$attr>\n"; + foreach($this->getElements() as $element) + $str.=$element->toString($indent+1)."\n"; + $str.=$prefix."_tagName}>"; + return $str; + } + else if(($value=$this->getValue())!=='') + { + $value=$this->xmlEncode($value); + return $prefix."<{$this->_tagName}$attr>$value_tagName}>"; + } + else + return $prefix."<{$this->_tagName}$attr />"; + } + public function __toString() + { + return $this->toString(); + } + private function xmlEncode($str) + { + return strtr($str,array( + '>'=>'>', + '<'=>'<', + '&'=>'&', + '"'=>'"', + "\r"=>' ', + "\t"=>' ', + "\n"=>' ')); + } +} +class TXmlDocument extends TXmlElement +{ + private $_version; + private $_encoding; + public function __construct($version='1.0',$encoding='') + { + parent::__construct(''); + $this->setVersion($version); + $this->setEncoding($encoding); + } + public function getVersion() + { + return $this->_version; + } + public function setVersion($version) + { + $this->_version=$version; + } + public function getEncoding() + { + return $this->_encoding; + } + public function setEncoding($encoding) + { + $this->_encoding=$encoding; + } + public function loadFromFile($file) + { + if(($str=@file_get_contents($file))!==false) + return $this->loadFromString($str); + else + throw new TIOException('xmldocument_file_read_failed',$file); + } + public function loadFromString($string) + { + $doc=new DOMDocument(); + if($doc->loadXML($string)===false) + return false; + $this->setEncoding($doc->encoding); + $this->setVersion($doc->version); + $element=$doc->documentElement; + $this->setTagName($element->tagName); + $this->setValue($element->nodeValue); + $elements=$this->getElements(); + $attributes=$this->getAttributes(); + $elements->clear(); + $attributes->clear(); + static $bSimpleXml; + if($bSimpleXml === null) + $bSimpleXml = (boolean)function_exists('simplexml_load_string'); + if($bSimpleXml) + { + $simpleDoc = simplexml_load_string($string); + $docNamespaces = $simpleDoc->getDocNamespaces(false); + $simpleDoc = null; + foreach($docNamespaces as $prefix => $uri) + { + if($prefix === '') + $attributes->add('xmlns', $uri); + else + $attributes->add('xmlns:'.$prefix, $uri); + } + } + foreach($element->attributes as $name=>$attr) + $attributes->add(($attr->prefix === '' ? '' : $attr->prefix . ':') .$name,$attr->value); + foreach($element->childNodes as $child) + { + if($child instanceof DOMElement) + $elements->add($this->buildElement($child)); + } + return true; + } + public function saveToFile($file) + { + if(($fw=fopen($file,'w'))!==false) + { + fwrite($fw,$this->saveToString()); + fclose($fw); + } + else + throw new TIOException('xmldocument_file_write_failed',$file); + } + public function saveToString() + { + $version=empty($this->_version)?' version="1.0"':' version="'.$this->_version.'"'; + $encoding=empty($this->_encoding)?'':' encoding="'.$this->_encoding.'"'; + return "\n".$this->toString(0); + } + public function __toString() + { + return $this->saveToString(); + } + private function buildElement($node) + { + $element=new TXmlElement($node->tagName); + $element->setValue($node->nodeValue); + foreach($node->attributes as $name=>$attr) + $element->getAttributes()->add(($attr->prefix === '' ? '' : $attr->prefix . ':') . $name,$attr->value); + foreach($node->childNodes as $child) + { + if($child instanceof DOMElement) + $element->getElements()->add($this->buildElement($child)); + } + return $element; + } +} +class TXmlElementList extends TList +{ + private $_o; + public function __construct(TXmlElement $owner) + { + $this->_o=$owner; + } + protected function getOwner() + { + return $this->_o; + } + public function insertAt($index,$item) + { + if($item instanceof TXmlElement) + { + parent::insertAt($index,$item); + if($item->getParent()!==null) + $item->getParent()->getElements()->remove($item); + $item->setParent($this->_o); + } + else + throw new TInvalidDataTypeException('xmlelementlist_xmlelement_required'); + } + public function removeAt($index) + { + $item=parent::removeAt($index); + if($item instanceof TXmlElement) + $item->setParent(null); + return $item; + } +} +class TAuthorizationRule extends TComponent +{ + private $_action; + private $_users; + private $_roles; + private $_verb; + private $_ipRules; + private $_everyone; + private $_guest; + private $_authenticated; + public function __construct($action,$users,$roles,$verb='',$ipRules='') + { + $action=strtolower(trim($action)); + if($action==='allow' || $action==='deny') + $this->_action=$action; + else + throw new TInvalidDataValueException('authorizationrule_action_invalid',$action); + $this->_users=array(); + $this->_roles=array(); + $this->_ipRules=array(); + $this->_everyone=false; + $this->_guest=false; + $this->_authenticated=false; + if(trim($users)==='') + $users='*'; + foreach(explode(',',$users) as $user) + { + if(($user=trim(strtolower($user)))!=='') + { + if($user==='*') + { + $this->_everyone=true; + break; + } + else if($user==='?') + $this->_guest=true; + else if($user==='@') + $this->_authenticated=true; + else + $this->_users[]=$user; + } + } + if(trim($roles)==='') + $roles='*'; + foreach(explode(',',$roles) as $role) + { + if(($role=trim(strtolower($role)))!=='') + $this->_roles[]=$role; + } + if(($verb=trim(strtolower($verb)))==='') + $verb='*'; + if($verb==='*' || $verb==='get' || $verb==='post') + $this->_verb=$verb; + else + throw new TInvalidDataValueException('authorizationrule_verb_invalid',$verb); + if(trim($ipRules)==='') + $ipRules='*'; + foreach(explode(',',$ipRules) as $ipRule) + { + if(($ipRule=trim($ipRule))!=='') + $this->_ipRules[]=$ipRule; + } + } + public function getAction() + { + return $this->_action; + } + public function getUsers() + { + return $this->_users; + } + public function getRoles() + { + return $this->_roles; + } + public function getVerb() + { + return $this->_verb; + } + public function getIPRules() + { + return $this->_ipRules; + } + public function getGuestApplied() + { + return $this->_guest || $this->_everyone; + } + public function getEveryoneApplied() + { + return $this->_everyone; + } + public function getAuthenticatedApplied() + { + return $this->_authenticated || $this->_everyone; + } + public function isUserAllowed(IUser $user,$verb,$ip) + { + if($this->isVerbMatched($verb) && $this->isIpMatched($ip) && $this->isUserMatched($user) && $this->isRoleMatched($user)) + return ($this->_action==='allow')?1:-1; + else + return 0; + } + private function isIpMatched($ip) + { + if(empty($this->_ipRules)) + return 1; + foreach($this->_ipRules as $rule) + { + if($rule==='*' || $rule===$ip || (($pos=strpos($rule,'*'))!==false && strncmp($ip,$rule,$pos)===0)) + return 1; + } + return 0; + } + private function isUserMatched($user) + { + return ($this->_everyone || ($this->_guest && $user->getIsGuest()) || ($this->_authenticated && !$user->getIsGuest()) || in_array(strtolower($user->getName()),$this->_users)); + } + private function isRoleMatched($user) + { + foreach($this->_roles as $role) + { + if($role==='*' || $user->isInRole($role)) + return true; + } + return false; + } + private function isVerbMatched($verb) + { + return ($this->_verb==='*' || strcasecmp($verb,$this->_verb)===0); + } +} +class TAuthorizationRuleCollection extends TList +{ + public function isUserAllowed($user,$verb,$ip) + { + if($user instanceof IUser) + { + $verb=strtolower(trim($verb)); + foreach($this as $rule) + { + if(($decision=$rule->isUserAllowed($user,$verb,$ip))!==0) + return ($decision>0); + } + return true; + } + else + return false; + } + public function insertAt($index,$item) + { + if($item instanceof TAuthorizationRule) + parent::insertAt($index,$item); + else + throw new TInvalidDataTypeException('authorizationrulecollection_authorizationrule_required'); + } +} +class TSecurityManager extends TModule +{ + const STATE_VALIDATION_KEY='prado:securitymanager:validationkey'; + const STATE_ENCRYPTION_KEY='prado:securitymanager:encryptionkey'; + private $_validationKey=null; + private $_encryptionKey=null; + private $_validation=TSecurityManagerValidationMode::SHA1; + private $_encryption='3DES'; + public function init($config) + { + $this->getApplication()->setSecurityManager($this); + } + protected function generateRandomKey() + { + return rand().rand().rand().rand(); + } + public function getValidationKey() + { + if($this->_validationKey===null) + { + if(($this->_validationKey=$this->getApplication()->getGlobalState(self::STATE_VALIDATION_KEY))===null) + { + $this->_validationKey=$this->generateRandomKey(); + $this->getApplication()->setGlobalState(self::STATE_VALIDATION_KEY,$this->_validationKey,null); + } + } + return $this->_validationKey; + } + public function setValidationKey($value) + { + if($value!=='') + $this->_validationKey=$value; + else + throw new TInvalidDataValueException('securitymanager_validationkey_invalid'); + } + public function getEncryptionKey() + { + if($this->_encryptionKey===null) + { + if(($this->_encryptionKey=$this->getApplication()->getGlobalState(self::STATE_ENCRYPTION_KEY))===null) + { + $this->_encryptionKey=$this->generateRandomKey(); + $this->getApplication()->setGlobalState(self::STATE_ENCRYPTION_KEY,$this->_encryptionKey,null); + } + } + return $this->_encryptionKey; + } + public function setEncryptionKey($value) + { + if($value!=='') + $this->_encryptionKey=$value; + else + throw new TInvalidDataValueException('securitymanager_encryptionkey_invalid'); + } + public function getValidation() + { + return $this->_validation; + } + public function setValidation($value) + { + $this->_validation=TPropertyValue::ensureEnum($value,'TSecurityManagerValidationMode'); + } + public function getEncryption() + { + return $this->_encryption; + } + public function setEncryption($value) + { + throw new TNotSupportedException('Currently only 3DES encryption is supported'); + } + public function encrypt($data) + { + if(function_exists('mcrypt_encrypt')) + { + $module=mcrypt_module_open(MCRYPT_3DES, '', MCRYPT_MODE_CBC, ''); + $key=substr(md5($this->getEncryptionKey()),0,mcrypt_enc_get_key_size($module)); + srand(); + $iv=mcrypt_create_iv(mcrypt_enc_get_iv_size($module), MCRYPT_RAND); + mcrypt_generic_init($module,$key,$iv); + $encrypted=$iv.mcrypt_generic($module,$data); + mcrypt_generic_deinit($module); + mcrypt_module_close($module); + return $encrypted; + } + else + throw new TNotSupportedException('securitymanager_mcryptextension_required'); + } + public function decrypt($data) + { + if(function_exists('mcrypt_decrypt')) + { + $module=mcrypt_module_open(MCRYPT_3DES, '', MCRYPT_MODE_CBC, ''); + $key=substr(md5($this->getEncryptionKey()),0,mcrypt_enc_get_key_size($module)); + $ivSize=mcrypt_enc_get_iv_size($module); + $iv=substr($data,0,$ivSize); + mcrypt_generic_init($module,$key,$iv); + $decrypted=mdecrypt_generic($module,substr($data,$ivSize)); + mcrypt_generic_deinit($module); + mcrypt_module_close($module); + return rtrim($decrypted,"\0"); + } + else + throw new TNotSupportedException('securitymanager_mcryptextension_required'); + } + public function hashData($data) + { + $hmac=$this->computeHMAC($data); + return $hmac.$data; + } + public function validateData($data) + { + $len=$this->_validation==='SHA1'?40:32; + if(strlen($data)>=$len) + { + $hmac=substr($data,0,$len); + $data2=substr($data,$len); + return $hmac===$this->computeHMAC($data2)?$data2:false; + } + else + return false; + } + protected function computeHMAC($data) + { + if($this->_validation==='SHA1') + { + $pack='H40'; + $func='sha1'; + } + else + { + $pack='H32'; + $func='md5'; + } + $key=$this->getValidationKey(); + $key=str_pad($func($key), 64, chr(0)); + return $func((str_repeat(chr(0x5C), 64) ^ substr($key, 0, 64)) . pack($pack, $func((str_repeat(chr(0x36), 64) ^ substr($key, 0, 64)) . $data))); + } +} +class TSecurityManagerValidationMode extends TEnumerable +{ + const MD5='MD5'; + const SHA1='SHA1'; +} +class THttpUtility +{ + private static $_encodeTable=array('<'=>'<','>'=>'>','"'=>'"'); + private static $_decodeTable=array('<'=>'<','>'=>'>','"'=>'"'); + public static function htmlEncode($s) + { + return strtr($s,self::$_encodeTable); + } + public static function htmlDecode($s) + { + return strtr($s,self::$_decodeTable); + } +} +class TJavaScript +{ + private static $_json; + public static function renderScriptFiles($files) + { + $str=''; + foreach($files as $file) + $str.= self::renderScriptFile($file); + return $str; + } + public static function renderScriptFile($file) + { + return '\n"; + } + public static function renderScriptBlocks($scripts) + { + if(count($scripts)) + return "\n"; + else + return ''; + } + public static function renderScriptBlock($script) + { + return "\n"; + } + public static function quoteString($js,$forUrl=false) + { + if($forUrl) + return strtr($js,array('%'=>'%25',"\t"=>'\t',"\n"=>'\n',"\r"=>'\r','"'=>'\"','\''=>'\\\'','\\'=>'\\\\')); + else + return strtr($js,array("\t"=>'\t',"\n"=>'\n',"\r"=>'\r','"'=>'\"','\''=>'\\\'','\\'=>'\\\\')); + } + public static function quoteFunction($js) + { + if(self::isFunction($js)) + return $js; + else + return 'javascript:'.$js; + } + public static function isFunction($js) + { + return preg_match('/^\s*javascript:/i', $js); + } + public static function encode($value,$toMap=true,$encodeEmptyStrings=false) + { + if(is_string($value)) + { + if(($n=strlen($value))>2) + { + $first=$value[0]; + $last=$value[$n-1]; + if(($first==='[' && $last===']') || ($first==='{' && $last==='}')) + return $value; + } + if(self::isFunction($value)) + return preg_replace('/^\s*javascript:/', '', $value); + else + return "'".self::quoteString($value)."'"; + } + else if(is_bool($value)) + return $value?'true':'false'; + else if(is_array($value)) + { + $results=''; + if(($n=count($value))>0 && array_keys($value)!==range(0,$n-1)) + { + foreach($value as $k=>$v) + { + if($v!=='' || $encodeEmptyStrings) + { + if($results!=='') + $results.=','; + $results.="'$k':".self::encode($v,$toMap,$encodeEmptyStrings); + } + } + return '{'.$results.'}'; + } + else + { + foreach($value as $v) + { + if($v!=='' || $encodeEmptyStrings) + { + if($results!=='') + $results.=','; + $results.=self::encode($v,$toMap, $encodeEmptyStrings); + } + } + return '['.$results.']'; + } + } + else if(is_integer($value)) + return "$value"; + else if(is_float($value)) + { + if($value===-INF) + return 'Number.NEGATIVE_INFINITY'; + else if($value===INF) + return 'Number.POSITIVE_INFINITY'; + else + return "$value"; + } + else if(is_object($value)) + return self::encode(get_object_vars($value),$toMap); + else if($value===null) + return 'null'; + else + return ''; + } + public static function jsonEncode($value) + { + if(self::$_json === null) + self::$_json = Prado::createComponent('System.Web.Javascripts.TJSON'); + return self::$_json->encode($value); + } + public static function jsonDecode($value) + { + if(self::$_json === null) + self::$_json = Prado::createComponent('System.Web.Javascripts.TJSON'); + return self::$_json->decode($value); + } +} +class TUrlManager extends TModule +{ + public function constructUrl($serviceID,$serviceParam,$getItems,$encodeAmpersand,$encodeGetItems) + { + $url=$serviceID.'='.urlencode($serviceParam); + $amp=$encodeAmpersand?'&':'&'; + $request=$this->getRequest(); + if(is_array($getItems) || $getItems instanceof Traversable) + { + if($encodeGetItems) + { + foreach($getItems as $name=>$value) + { + if(is_array($value)) + { + $name=urlencode($name.'[]'); + foreach($value as $v) + $url.=$amp.$name.'='.urlencode($v); + } + else + $url.=$amp.urlencode($name).'='.urlencode($value); + } + } + else + { + foreach($getItems as $name=>$value) + { + if(is_array($value)) + { + foreach($value as $v) + $url.=$amp.$name.'[]='.$v; + } + else + $url.=$amp.$name.'='.$value; + } + } + } + if($request->getUrlFormat()===THttpRequestUrlFormat::Path) + return $request->getApplicationUrl().'/'.strtr($url,array($amp=>'/','?'=>'/','='=>$request->getUrlParamSeparator())); + else + return $request->getApplicationUrl().'?'.$url; + } + public function parseUrl() + { + $request=$this->getRequest(); + $pathInfo=trim($request->getPathInfo(),'/'); + if($request->getUrlFormat()===THttpRequestUrlFormat::Path && $pathInfo!=='') + { + $separator=$request->getUrlParamSeparator(); + $paths=explode('/',$pathInfo); + $getVariables=array(); + foreach($paths as $path) + { + if(($path=trim($path))!=='') + { + if(($pos=strpos($path,$separator))!==false) + { + $name=substr($path,0,$pos); + $value=substr($path,$pos+1); + if(($pos=strpos($name,'[]'))!==false) + $getVariables[substr($name,0,$pos)][]=$value; + else + $getVariables[$name]=$value; + } + else + $getVariables[$path]=''; + } + } + return $getVariables; + } + else + return array(); + } +} +class THttpRequest extends TApplicationComponent implements IteratorAggregate,ArrayAccess,Countable,IModule +{ + private $_urlManager=null; + private $_urlManagerID=''; + private $_separator=','; + private $_serviceID=null; + private $_serviceParam=null; + private $_cookies=null; + private $_requestUri; + private $_pathInfo; + private $_cookieOnly=false; + private $_urlFormat=THttpRequestUrlFormat::Get; + private $_services; + private $_requestResolved=false; + private $_enableCookieValidation=false; + private $_url=null; + private $_id; + private $_items=array(); + public function getID() + { + return $this->_id; + } + public function setID($value) + { + $this->_id=$value; + } + public function init($config) + { + 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); + } + 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']=''; + } + $this->_cookieOnly=(int)ini_get('session.use_cookies') && (int)ini_get('session.use_only_cookies'); + if(isset($_SERVER['REQUEST_URI'])) + $this->_requestUri=$_SERVER['REQUEST_URI']; + else $this->_requestUri=$_SERVER['SCRIPT_NAME'].(empty($_SERVER['QUERY_STRING'])?'':'?'.$_SERVER['QUERY_STRING']); + if(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); + } + public function stripSlashes(&$data) + { + return is_array($data)?array_map(array($this,'stripSlashes'),$data):stripslashes($data); + } + 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; + } + public function getUrlManager() + { + return $this->_urlManagerID; + } + public function setUrlManager($value) + { + $this->_urlManagerID=$value; + } + public function getUrlManagerModule() + { + return $this->_urlManager; + } + public function getUrlFormat() + { + return $this->_urlFormat; + } + public function setUrlFormat($value) + { + $this->_urlFormat=TPropertyValue::ensureEnum($value,'THttpRequestUrlFormat'); + } + public function getUrlParamSeparator() + { + return $this->_separator; + } + public function setUrlParamSeparator($value) + { + if(strlen($value)===1) + $this->_separator=$value; + else + throw new TInvalidDataValueException('httprequest_separator_invalid'); + } + public function getRequestType() + { + return $_SERVER['REQUEST_METHOD']; + } + public function getIsSecureConnection() + { + return isset($_SERVER['HTTPS']) && strcasecmp($_SERVER['HTTPS'],'off'); + } + public function getPathInfo() + { + return $this->_pathInfo; + } + public function getQueryString() + { + return isset($_SERVER['QUERY_STRING'])?$_SERVER['QUERY_STRING']:''; + } + public function getHttpProtocolVersion () + { + return isset($_SERVER['SERVER_PROTOCOL'])?$_SERVER['SERVER_PROTOCOL']:''; + } + public function getRequestUri() + { + return $this->_requestUri; + } + public function getBaseUrl($forceSecureConnection=false) + { + $url=$this->getUrl(); + $scheme=($forceSecureConnection)?"https":$url->getScheme(); + $host=$url->getHost(); + if (($port=$url->getPort())) $host.=':'.$port; + return $scheme.'://'.$host; + } + public function getApplicationUrl() + { + return $_SERVER['SCRIPT_NAME']; + } + public function getAbsoluteApplicationUrl($forceSecureConnection=false) + { + return $this->getBaseUrl($forceSecureConnection) . $this->getApplicationUrl(); + } + public function getApplicationFilePath() + { + return realpath($_SERVER['SCRIPT_FILENAME']); + } + public function getServerName() + { + return $_SERVER['SERVER_NAME']; + } + public function getServerPort() + { + return $_SERVER['SERVER_PORT']; + } + public function getUrlReferrer() + { + return isset($_SERVER['HTTP_REFERER'])?$_SERVER['HTTP_REFERER']:null; + } + public function getBrowser() + { + try + { + return get_browser(); + } + catch(TPhpErrorException $e) + { + throw new TConfigurationException('httprequest_browscap_required'); + } + } + public function getUserAgent() + { + return $_SERVER['HTTP_USER_AGENT']; + } + public function getUserHostAddress() + { + return $_SERVER['REMOTE_ADDR']; + } + public function getUserHost() + { + return isset($_SERVER['REMOTE_HOST'])?$_SERVER['REMOTE_HOST']:null; + } + public function getAcceptTypes() + { + return $_SERVER['HTTP_ACCEPT']; + } + public function getUserLanguages() + { + return Prado::getUserLanguages(); + } + public function getEnableCookieValidation() + { + return $this->_enableCookieValidation; + } + public function setEnableCookieValidation($value) + { + $this->_enableCookieValidation=TPropertyValue::ensureBoolean($value); + } + 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; + } + public function getUploadedFiles() + { + return $_FILES; + } + public function getServerVariables() + { + return $_SERVER; + } + public function getEnvironmentVariables() + { + return $_ENV; + } + public function constructUrl($serviceID,$serviceParam,$getItems=null,$encodeAmpersand=true,$encodeGetItems=true) + { + $url=$this->_urlManager->constructUrl($serviceID,$serviceParam,$getItems,$encodeAmpersand,$encodeGetItems); + if(defined('SID') && SID != '' && !$this->_cookieOnly) + return $url . (strpos($url,'?')===false? '?' : ($encodeAmpersand?'&':'&')) . SID; + else + return $url; + } + protected function parseUrl() + { + return $this->_urlManager->parseUrl(); + } + public function resolveRequest($serviceIDs) + { + $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; + } + public function getRequestResolved() + { + return $this->_requestResolved; + } + public function getServiceID() + { + return $this->_serviceID; + } + public function setServiceID($value) + { + $this->_serviceID=$value; + } + public function getServiceParameter() + { + return $this->_serviceParam; + } + public function setServiceParameter($value) + { + $this->_serviceParam=$value; + } + public function getIterator() + { + return new TMapIterator($this->_items); + } + public function getCount() + { + return count($this->_items); + } + public function count() + { + return $this->getCount(); + } + public function getKeys() + { + return array_keys($this->_items); + } + public function itemAt($key) + { + return isset($this->_items[$key]) ? $this->_items[$key] : null; + } + public function add($key,$value) + { + $this->_items[$key]=$value; + } + 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; + } + public function clear() + { + foreach(array_keys($this->_items) as $key) + $this->remove($key); + } + public function contains($key) + { + return isset($this->_items[$key]) || array_key_exists($key,$this->_items); + } + public function toArray() + { + return $this->_items; + } + public function offsetExists($offset) + { + return $this->contains($offset); + } + public function offsetGet($offset) + { + return $this->itemAt($offset); + } + public function offsetSet($offset,$item) + { + $this->add($offset,$item); + } + public function offsetUnset($offset) + { + $this->remove($offset); + } +} +class THttpCookieCollection extends TList +{ + private $_o; + public function __construct($owner=null) + { + $this->_o=$owner; + } + 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'); + } + public function removeAt($index) + { + $item=parent::removeAt($index); + if($this->_o instanceof THttpResponse) + $this->_o->removeCookie($item); + return $item; + } + public function itemAt($index) + { + if(is_integer($index)) + return parent::itemAt($index); + else + return $this->findCookieByName($index); + } + public function findCookieByName($name) + { + foreach($this as $cookie) + if($cookie->getName()===$name) + return $cookie; + return null; + } +} +class THttpCookie extends TComponent +{ + private $_domain=''; + private $_name; + private $_value=''; + private $_expire=0; + private $_path='/'; + private $_secure=false; + public function __construct($name,$value) + { + $this->_name=$name; + $this->_value=$value; + } + public function getDomain() + { + return $this->_domain; + } + public function setDomain($value) + { + $this->_domain=$value; + } + public function getExpire() + { + return $this->_expire; + } + public function setExpire($value) + { + $this->_expire=TPropertyValue::ensureInteger($value); + } + public function getName() + { + return $this->_name; + } + public function setName($value) + { + $this->_name=$value; + } + public function getValue() + { + return $this->_value; + } + public function setValue($value) + { + $this->_value=$value; + } + public function getPath() + { + return $this->_path; + } + public function setPath($value) + { + $this->_path=$value; + } + public function getSecure() + { + return $this->_secure; + } + public function setSecure($value) + { + $this->_secure=TPropertyValue::ensureBoolean($value); + } +} +class TUri extends TComponent +{ + private static $_defaultPort=array( + 'ftp'=>21, + 'gopher'=>70, + 'http'=>80, + 'https'=>443, + 'news'=>119, + 'nntp'=>119, + 'wais'=>210, + 'telnet'=>23 + ); + private $_scheme; + private $_host; + private $_port; + private $_user; + private $_pass; + private $_path; + private $_query; + private $_fragment; + private $_uri; + public function __construct($uri) + { + if(($ret=@parse_url($uri))!==false) + { + $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); + } + } + public function getUri() + { + return $this->_uri; + } + public function getScheme() + { + return $this->_scheme; + } + public function getHost() + { + return $this->_host; + } + public function getPort() + { + return $this->_port; + } + public function getUser() + { + return $this->_user; + } + public function getPassword() + { + return $this->_pass; + } + public function getPath() + { + return $this->_path; + } + public function getQuery() + { + return $this->_query; + } + public function getFragment() + { + return $this->_fragment; + } +} +class THttpRequestUrlFormat extends TEnumerable +{ + const Get='Get'; + const Path='Path'; +} +class THttpResponseAdapter extends TApplicationComponent +{ + private $_response; + public function __construct($response) + { + $this->_response=$response; + } + public function getResponse() + { + return $this->_response; + } + public function flushContent() + { + $this->_response->flushContent(); + } + public function httpRedirect($url) + { + $this->_response->httpRedirect($url); + } + public function createNewHtmlWriter($type, $writer) + { + return $this->_response->createNewHtmlWriter($type,$writer); + } +} +class THttpResponse extends TModule implements ITextWriter +{ + private static $HTTP_STATUS_CODES = array( + 100 => 'Continue', 101 => 'Switching Protocols', + 200 => 'OK', 201 => 'Created', 202 => 'Accepted', 203 => 'Non-Authoritative Information', 204 => 'No Content', 205 => 'Reset Content', 206 => 'Partial Content', + 300 => 'Multiple Choices', 301 => 'Moved Permanently', 302 => 'Found', 303 => 'See Other', 304 => 'Not Modified', 305 => 'Use Proxy', 307 => 'Temporary Redirect', + 400 => 'Bad Request', 401 => 'Unauthorized', 402 => 'Payment Required', 403 => 'Forbidden', 404 => 'Not Found', 405 => 'Method Not Allowed', 406 => 'Not Acceptable', 407 => 'Proxy Authentication Required', 408 => 'Request Time-out', 409 => 'Conflict', 410 => 'Gone', 411 => 'Length Required', 412 => 'Precondition Failed', 413 => 'Request Entity Too Large', 414 => 'Request-URI Too Large', 415 => 'Unsupported Media Type', 416 => 'Requested range not satisfiable', 417 => 'Expectation Failed', + 500 => 'Internal Server Error', 501 => 'Not Implemented', 502 => 'Bad Gateway', 503 => 'Service Unavailable', 504 => 'Gateway Time-out', 505 => 'HTTP Version not supported' + ); + private $_bufferOutput=true; + private $_initialized=false; + private $_cookies=null; + private $_status=200; + private $_reason='OK'; + private $_htmlWriterType='System.Web.UI.THtmlWriter'; + private $_contentType=null; + private $_charset=''; + private $_adapter; + public function __destruct() + { + } + public function setAdapter(THttpResponseAdapter $adapter) + { + $this->_adapter=$adapter; + } + public function getAdapter() + { + return $this->_adapter; + } + public function getHasAdapter() + { + return $this->_adapter!==null; + } + public function init($config) + { + if($this->_bufferOutput) + ob_start(); + $this->_initialized=true; + $this->getApplication()->setResponse($this); + } + public function getCacheExpire() + { + return session_cache_expire(); + } + public function setCacheExpire($value) + { + session_cache_expire(TPropertyValue::ensureInteger($value)); + } + public function getCacheControl() + { + return session_cache_limiter(); + } + public function setCacheControl($value) + { + session_cache_limiter(TPropertyValue::ensureEnum($value,array('none','nocache','private','private_no_expire','public'))); + } + public function setContentType($type) + { + $this->_contentType = $type; + } + public function getContentType() + { + return $this->_contentType; + } + public function getCharset() + { + return $this->_charset; + } + public function setCharset($charset) + { + $this->_charset = $charset; + } + public function getBufferOutput() + { + return $this->_bufferOutput; + } + public function setBufferOutput($value) + { + if($this->_initialized) + throw new TInvalidOperationException('httpresponse_bufferoutput_unchangeable'); + else + $this->_bufferOutput=TPropertyValue::ensureBoolean($value); + } + public function getStatusCode() + { + return $this->_status; + } + public function setStatusCode($status, $reason=null) + { + $status=TPropertyValue::ensureInteger($status); + if(isset(self::$HTTP_STATUS_CODES[$status])) { + $this->_reason=self::$HTTP_STATUS_CODES[$status]; + }else{ + if($reason===null || $reason==='') { + throw new TInvalidDataValueException("response_status_reason_missing"); + } + $reason=TPropertyValue::ensureString($reason); + if(strpos($reason, "\r")!=false || strpos($reason, "\n")!=false) { + throw new TInvalidDataValueException("response_status_reason_barchars"); + } + $this->_reason=$reason; + } + $this->_status=$status; + } + public function getStatusReason() { + return $this->_reason; + } + public function getCookies() + { + if($this->_cookies===null) + $this->_cookies=new THttpCookieCollection($this); + return $this->_cookies; + } + public function write($str) + { + echo $str; + } + public function writeFile($fileName,$content=null,$mimeType=null,$headers=null) + { + static $defaultMimeTypes=array( + 'css'=>'text/css', + 'gif'=>'image/gif', + 'jpg'=>'image/jpeg', + 'jpeg'=>'image/jpeg', + 'htm'=>'text/html', + 'html'=>'text/html', + 'js'=>'javascript/js', + 'pdf'=>'application/pdf', + 'xls'=>'application/vnd.ms-excel', + ); + if($mimeType===null) + { + $mimeType='text/plain'; + if(function_exists('mime_content_type')) + $mimeType=mime_content_type($fileName); + else if(($ext=strrchr($fileName,'.'))!==false) + { + $ext=substr($ext,1); + if(isset($defaultMimeTypes[$ext])) + $mimeType=$defaultMimeTypes[$ext]; + } + } + $fn=basename($fileName); + $this->sendHttpHeader(); + if(is_array($headers)) + { + foreach($headers as $h) + header($h); + } + else + { + header('Pragma: public'); + header('Expires: 0'); + header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); + } + header("Content-type: $mimeType"); + header('Content-Length: '.($content===null?filesize($fileName):strlen($content))); + header("Content-Disposition: attachment; filename=\"$fn\""); + header('Content-Transfer-Encoding: binary'); + if($content===null) + readfile($fileName); + else + echo $content; + } + public function redirect($url) + { + if($this->getHasAdapter()) + $this->_adapter->httpRedirect($url); + else + $this->httpRedirect($url); + } + public function httpRedirect($url) + { + if(!$this->getApplication()->getRequestCompleted()) + $this->getApplication()->onEndRequest(); + if($url[0]==='/') + $url=$this->getRequest()->getBaseUrl().$url; + if ($this->_status >= 300 && $this->_status < 400) + header('Location: '.str_replace('&','&',$url), true, $this->_status); + else + header('Location: '.str_replace('&','&',$url)); + exit(); + } + public function reload() + { + $this->redirect($this->getRequest()->getRequestUri()); + } + public function flush() + { + if($this->getHasAdapter()) + $this->_adapter->flushContent(); + else + $this->flushContent(); + } + public function flushContent() + { + $this->sendHttpHeader(); + $this->sendContentTypeHeader(); + if($this->_bufferOutput) + ob_flush(); + } + protected function sendHttpHeader () + { + if (($version=$this->getRequest()->getHttpProtocolVersion())==='') + header (' ', true, $this->_status); + else + header($version.' '.$this->_status.' '.$this->_reason, true, $this->_status); + } + protected function sendContentTypeHeader() + { + $charset=$this->getCharset(); + if($charset==='' && ($globalization=$this->getApplication()->getGlobalization(false))!==null) + $charset=$globalization->getCharset(); + if($charset!=='') + { + $contentType=$this->_contentType===null?'text/html':$this->_contentType; + $this->appendHeader('Content-Type: '.$contentType.';charset='.$charset); + } + else if($this->_contentType!==null) + $this->appendHeader('Content-Type: '.$this->_contentType.';charset=UTF-8'); + } + public function getContents() + { + return $this->_bufferOutput?ob_get_contents():''; + } + public function clear() + { + if($this->_bufferOutput) + ob_clean(); + } + public function appendHeader($value) + { + header($value); + } + public function appendLog($message,$messageType=0,$destination='',$extraHeaders='') + { + error_log($message,$messageType,$destination,$extraHeaders); + } + public function addCookie($cookie) + { + $request=$this->getRequest(); + if($request->getEnableCookieValidation()) + { + $value=$this->getApplication()->getSecurityManager()->hashData($cookie->getValue()); + setcookie($cookie->getName(),$value,$cookie->getExpire(),$cookie->getPath(),$cookie->getDomain(),$cookie->getSecure()); + } + else + setcookie($cookie->getName(),$cookie->getValue(),$cookie->getExpire(),$cookie->getPath(),$cookie->getDomain(),$cookie->getSecure()); + } + public function removeCookie($cookie) + { + setcookie($cookie->getName(),null,0,$cookie->getPath(),$cookie->getDomain(),$cookie->getSecure()); + } + public function getHtmlWriterType() + { + return $this->_htmlWriterType; + } + public function setHtmlWriterType($value) + { + $this->_htmlWriterType=$value; + } + public function createHtmlWriter($type=null) + { + if($type===null) + $type=$this->getHtmlWriterType(); + if($this->getHasAdapter()) + return $this->_adapter->createNewHtmlWriter($type, $this); + else + return $this->createNewHtmlWriter($type, $this); + } + public function createNewHtmlWriter($type, $writer) + { + return Prado::createComponent($type, $writer); + } +} +class THttpSession extends TApplicationComponent implements IteratorAggregate,ArrayAccess,Countable,IModule +{ + private $_initialized=false; + private $_started=false; + private $_autoStart=false; + private $_cookie=null; + private $_id; + private $_customStorage=false; + public function getID() + { + return $this->_id; + } + public function setID($value) + { + $this->_id=$value; + } + public function init($config) + { + if($this->_autoStart) + $this->open(); + $this->_initialized=true; + $this->getApplication()->setSession($this); + register_shutdown_function(array($this, "close")); + } + public function open() + { + if(!$this->_started) + { + if($this->_customStorage) + session_set_save_handler(array($this,'_open'),array($this,'_close'),array($this,'_read'),array($this,'_write'),array($this,'_destroy'),array($this,'_gc')); + if($this->_cookie!==null) + session_set_cookie_params($this->_cookie->getExpire(),$this->_cookie->getPath(),$this->_cookie->getDomain(),$this->_cookie->getSecure()); + if(ini_get('session.auto_start')!=='1') + session_start(); + $this->_started=true; + } + } + public function close() + { + if($this->_started) + { + session_write_close(); + $this->_started=false; + } + } + public function destroy() + { + if($this->_started) + { + session_destroy(); + $this->_started=false; + } + } + public function getIsStarted() + { + return $this->_started; + } + public function getSessionID() + { + return session_id(); + } + public function setSessionID($value) + { + if($this->_started) + throw new TInvalidOperationException('httpsession_sessionid_unchangeable'); + else + session_id($value); + } + public function getSessionName() + { + return session_name(); + } + public function setSessionName($value) + { + if($this->_started) + throw new TInvalidOperationException('httpsession_sessionname_unchangeable'); + else if(ctype_alnum($value)) + session_name($value); + else + throw new TInvalidDataValueException('httpsession_sessionname_invalid',$value); + } + public function getSavePath() + { + return session_save_path(); + } + public function setSavePath($value) + { + if($this->_started) + throw new TInvalidOperationException('httpsession_savepath_unchangeable'); + else if(is_dir($value)) + session_save_path($value); + else + throw new TInvalidDataValueException('httpsession_savepath_invalid',$value); + } + public function getUseCustomStorage() + { + return $this->_customStorage; + } + public function setUseCustomStorage($value) + { + $this->_customStorage=TPropertyValue::ensureBoolean($value); + } + public function getCookie() + { + if($this->_cookie===null) + $this->_cookie=new THttpCookie($this->getSessionName(),$this->getSessionID()); + return $this->_cookie; + } + public function getCookieMode() + { + if(ini_get('session.use_cookies')==='0') + return THttpSessionCookieMode::None; + else if(ini_get('session.use_only_cookies')==='0') + return THttpSessionCookieMode::Allow; + else + return THttpSessionCookieMode::Only; + } + public function setCookieMode($value) + { + if($this->_started) + throw new TInvalidOperationException('httpsession_cookiemode_unchangeable'); + else + { + $value=TPropertyValue::ensureEnum($value,'THttpSessionCookieMode'); + if($value===THttpSessionCookieMode::None) + ini_set('session.use_cookies','0'); + else if($value===THttpSessionCookieMode::Allow) + { + ini_set('session.use_cookies','1'); + ini_set('session.use_only_cookies','0'); + } + else + { + ini_set('session.use_cookies','1'); + ini_set('session.use_only_cookies','1'); + } + } + } + public function getAutoStart() + { + return $this->_autoStart; + } + public function setAutoStart($value) + { + if($this->_initialized) + throw new TInvalidOperationException('httpsession_autostart_unchangeable'); + else + $this->_autoStart=TPropertyValue::ensureBoolean($value); + } + public function getGCProbability() + { + return TPropertyValue::ensureInteger(ini_get('session.gc_probability')); + } + public function setGCProbability($value) + { + if($this->_started) + throw new TInvalidOperationException('httpsession_gcprobability_unchangeable'); + else + { + $value=TPropertyValue::ensureInteger($value); + if($value>=0 && $value<=100) + { + ini_set('session.gc_probability',$value); + ini_set('session.gc_divisor','100'); + } + else + throw new TInvalidDataValueException('httpsession_gcprobability_invalid',$value); + } + } + public function getUseTransparentSessionID() + { + return ini_get('session.use_trans_sid')==='1'; + } + public function setUseTransparentSessionID($value) + { + if($this->_started) + throw new TInvalidOperationException('httpsession_transid_unchangeable'); + else + ini_set('session.use_trans_sid',TPropertyValue::ensureBoolean($value)?'1':'0'); + } + public function getTimeout() + { + return TPropertyValue::ensureInteger(ini_get('session.gc_maxlifetime')); + } + public function setTimeout($value) + { + if($this->_started) + throw new TInvalidOperationException('httpsession_maxlifetime_unchangeable'); + else + ini_set('session.gc_maxlifetime',$value); + } + public function _open($savePath,$sessionName) + { + return true; + } + public function _close() + { + return true; + } + public function _read($id) + { + return ''; + } + public function _write($id,$data) + { + return true; + } + public function _destroy($id) + { + return true; + } + public function _gc($maxLifetime) + { + return true; + } + public function getIterator() + { + return new TSessionIterator; + } + public function getCount() + { + return count($_SESSION); + } + public function count() + { + return $this->getCount(); + } + public function getKeys() + { + return array_keys($_SESSION); + } + public function itemAt($key) + { + return isset($_SESSION[$key]) ? $_SESSION[$key] : null; + } + public function add($key,$value) + { + $_SESSION[$key]=$value; + } + public function remove($key) + { + if(isset($_SESSION[$key])) + { + $value=$_SESSION[$key]; + unset($_SESSION[$key]); + return $value; + } + else + return null; + } + public function clear() + { + foreach(array_keys($_SESSION) as $key) + unset($_SESSION[$key]); + } + public function contains($key) + { + return isset($_SESSION[$key]); + } + public function toArray() + { + return $_SESSION; + } + public function offsetExists($offset) + { + return isset($_SESSION[$offset]); + } + public function offsetGet($offset) + { + return isset($_SESSION[$offset]) ? $_SESSION[$offset] : null; + } + public function offsetSet($offset,$item) + { + $_SESSION[$offset]=$item; + } + public function offsetUnset($offset) + { + unset($_SESSION[$offset]); + } +} +class TSessionIterator implements Iterator +{ + private $_keys; + private $_key; + public function __construct() + { + $this->_keys=array_keys($_SESSION); + } + public function rewind() + { + $this->_key=reset($this->_keys); + } + public function key() + { + return $this->_key; + } + public function current() + { + return isset($_SESSION[$this->_key])?$_SESSION[$this->_key]:null; + } + public function next() + { + do + { + $this->_key=next($this->_keys); + } + while(!isset($_SESSION[$this->_key]) && $this->_key!==false); + } + public function valid() + { + return $this->_key!==false; + } +} +class THttpSessionCookieMode extends TEnumerable +{ + const None='None'; + const Allow='Allow'; + const Only='Only'; +} +Prado::using('System.Web.UI.WebControls.*'); +class TAttributeCollection extends TMap +{ + private $_caseSensitive=false; + public function __get($name) + { + return $this->contains($name)?$this->itemAt($name):parent::__get($name); + } + public function __set($name,$value) + { + $this->add($name,$value); + } + public function getCaseSensitive() + { + return $this->_caseSensitive; + } + public function setCaseSensitive($value) + { + $this->_caseSensitive=TPropertyValue::ensureBoolean($value); + } + public function itemAt($key) + { + return parent::itemAt($this->_caseSensitive?$key:strtolower($key)); + } + public function add($key,$value) + { + parent::add($this->_caseSensitive?$key:strtolower($key),$value); + } + public function remove($key) + { + return parent::remove($this->_caseSensitive?$key:strtolower($key)); + } + public function contains($key) + { + return parent::contains($this->_caseSensitive?$key:strtolower($key)); + } + public function hasProperty($name) + { + return $this->contains($name) || parent::hasProperty($name); + } + public function canGetProperty($name) + { + return $this->contains($name) || parent::canGetProperty($name); + } + public function canSetProperty($name) + { + return true; + } +} +class TControlAdapter extends TApplicationComponent +{ + private $_control; + public function __construct($control) + { + $this->_control=$control; + } + public function getControl() + { + return $this->_control; + } + public function getPage() + { + return $this->_control?$this->_control->getPage():null; + } + public function createChildControls() + { + $this->_control->createChildControls(); + } + public function loadState() + { + $this->_control->loadState(); + } + public function saveState() + { + $this->_control->saveState(); + } + public function onInit($param) + { + $this->_control->onInit($param); + } + public function onLoad($param) + { + $this->_control->onLoad($param); + } + public function onPreRender($param) + { + $this->_control->onPreRender($param); + } + public function onUnload($param) + { + $this->_control->onUnload($param); + } + public function render($writer) + { + $this->_control->render($writer); + } + public function renderChildren($writer) + { + $this->_control->renderChildren($writer); + } +} +class TControl extends TApplicationComponent implements IRenderable, IBindable +{ + const ID_FORMAT='/^[a-zA-Z_]\\w*$/'; + const ID_SEPARATOR='$'; + const CLIENT_ID_SEPARATOR='_'; + const AUTOMATIC_ID_PREFIX='ctl'; + const CS_CONSTRUCTED=0; + const CS_CHILD_INITIALIZED=1; + const CS_INITIALIZED=2; + const CS_STATE_LOADED=3; + const CS_LOADED=4; + const CS_PRERENDERED=5; + const IS_ID_SET=0x01; + const IS_DISABLE_VIEWSTATE=0x02; + const IS_SKIN_APPLIED=0x04; + const IS_STYLESHEET_APPLIED=0x08; + const IS_DISABLE_THEMING=0x10; + const IS_CHILD_CREATED=0x20; + const IS_CREATING_CHILD=0x40; + const RF_CONTROLS=0; + const RF_CHILD_STATE=1; + const RF_NAMED_CONTROLS=2; + const RF_NAMED_CONTROLS_ID=3; + const RF_SKIN_ID=4; + const RF_DATA_BINDINGS=5; + const RF_EVENTS=6; + const RF_CONTROLSTATE=7; + const RF_NAMED_OBJECTS=8; + const RF_ADAPTER=9; + const RF_AUTO_BINDINGS=10; + private $_id=''; + private $_uid; + private $_parent; + private $_page; + private $_namingContainer; + private $_tplControl; + private $_viewState=array(); + private $_tempState=array(); + private $_trackViewState=true; + private $_stage=0; + private $_flags=0; + private $_rf=array(); + public function __construct() + { + } + public function __get($name) + { + if(isset($this->_rf[self::RF_NAMED_OBJECTS][$name])) + return $this->_rf[self::RF_NAMED_OBJECTS][$name]; + else + return parent::__get($name); + } + public function getHasAdapter() + { + return isset($this->_rf[self::RF_ADAPTER]); + } + public function getAdapter() + { + return isset($this->_rf[self::RF_ADAPTER])?$this->_rf[self::RF_ADAPTER]:null; + } + public function setAdapter(TControlAdapter $adapter) + { + $this->_rf[self::RF_ADAPTER]=$adapter; + } + public function getParent() + { + return $this->_parent; + } + public function getNamingContainer() + { + if(!$this->_namingContainer && $this->_parent) + { + if($this->_parent instanceof INamingContainer) + $this->_namingContainer=$this->_parent; + else + $this->_namingContainer=$this->_parent->getNamingContainer(); + } + return $this->_namingContainer; + } + public function getPage() + { + if(!$this->_page) + { + if($this->_parent) + $this->_page=$this->_parent->getPage(); + else if($this->_tplControl) + $this->_page=$this->_tplControl->getPage(); + } + return $this->_page; + } + public function setPage($page) + { + $this->_page=$page; + } + public function setTemplateControl($control) + { + $this->_tplControl=$control; + } + public function getTemplateControl() + { + if(!$this->_tplControl && $this->_parent) + $this->_tplControl=$this->_parent->getTemplateControl(); + return $this->_tplControl; + } + public function getSourceTemplateControl() + { + $control=$this; + while(($control instanceof TControl) && ($control=$control->getTemplateControl())!==null) + { + if(($control instanceof TTemplateControl) && $control->getIsSourceTemplateControl()) + return $control; + } + return $this->getPage(); + } + protected function getControlStage() + { + return $this->_stage; + } + protected function setControlStage($value) + { + $this->_stage=$value; + } + public function getID($hideAutoID=true) + { + if($hideAutoID) + return ($this->_flags & self::IS_ID_SET) ? $this->_id : ''; + else + return $this->_id; + } + public function setID($id) + { + if(!preg_match(self::ID_FORMAT,$id)) + throw new TInvalidDataValueException('control_id_invalid',get_class($this),$id); + $this->_id=$id; + $this->_flags |= self::IS_ID_SET; + $this->clearCachedUniqueID($this instanceof INamingContainer); + if($this->_namingContainer) + $this->_namingContainer->clearNameTable(); + } + public function getUniqueID() + { + if($this->_uid==='' || $this->_uid===null) + { + $this->_uid=''; + if($namingContainer=$this->getNamingContainer()) + { + if($this->getPage()===$namingContainer) + return ($this->_uid=$this->_id); + else if(($prefix=$namingContainer->getUniqueID())==='') + return $this->_id; + else + return ($this->_uid=$prefix.self::ID_SEPARATOR.$this->_id); + } + else + return $this->_id; + } + else + return $this->_uid; + } + public function focus() + { + $this->getPage()->setFocus($this); + } + public function getClientID() + { + return strtr($this->getUniqueID(),self::ID_SEPARATOR,self::CLIENT_ID_SEPARATOR); + } + public static function convertUniqueIdToClientId($uniqueID) + { + return strtr($uniqueID,self::ID_SEPARATOR,self::CLIENT_ID_SEPARATOR); + } + public function getSkinID() + { + return isset($this->_rf[self::RF_SKIN_ID])?$this->_rf[self::RF_SKIN_ID]:''; + } + public function setSkinID($value) + { + if(($this->_flags & self::IS_SKIN_APPLIED) || $this->_stage>=self::CS_CHILD_INITIALIZED) + throw new TInvalidOperationException('control_skinid_unchangeable',get_class($this)); + else + $this->_rf[self::RF_SKIN_ID]=$value; + } + public function getEnableTheming() + { + if($this->_flags & self::IS_DISABLE_THEMING) + return false; + else + return $this->_parent?$this->_parent->getEnableTheming():true; + } + public function setEnableTheming($value) + { + if($this->_stage>=self::CS_CHILD_INITIALIZED) + throw new TInvalidOperationException('control_enabletheming_unchangeable',get_class($this),$this->getUniqueID()); + else if(TPropertyValue::ensureBoolean($value)) + $this->_flags &= ~self::IS_DISABLE_THEMING; + else + $this->_flags |= self::IS_DISABLE_THEMING; + } + public function getCustomData() + { + return $this->getViewState('CustomData',null); + } + public function setCustomData($value) + { + $this->setViewState('CustomData',$value,null); + } + public function getHasControls() + { + return isset($this->_rf[self::RF_CONTROLS]) && $this->_rf[self::RF_CONTROLS]->getCount()>0; + } + public function getControls() + { + if(!isset($this->_rf[self::RF_CONTROLS])) + $this->_rf[self::RF_CONTROLS]=$this->createControlCollection(); + return $this->_rf[self::RF_CONTROLS]; + } + protected function createControlCollection() + { + return $this->getAllowChildControls()?new TControlCollection($this):new TEmptyControlCollection($this); + } + public function getVisible($checkParents=true) + { + if($checkParents) + { + for($control=$this;$control;$control=$control->_parent) + if(!$control->getVisible(false)) + return false; + return true; + } + else + return $this->getViewState('Visible',true); + } + public function setVisible($value) + { + $this->setViewState('Visible',TPropertyValue::ensureBoolean($value),true); + } + public function getEnabled($checkParents=false) + { + if($checkParents) + { + for($control=$this;$control;$control=$control->_parent) + if(!$control->getViewState('Enabled',true)) + return false; + return true; + } + else + return $this->getViewState('Enabled',true); + } + public function setEnabled($value) + { + $this->setViewState('Enabled',TPropertyValue::ensureBoolean($value),true); + } + public function getHasAttributes() + { + if($attributes=$this->getViewState('Attributes',null)) + return $attributes->getCount()>0; + else + return false; + } + public function getAttributes() + { + if($attributes=$this->getViewState('Attributes',null)) + return $attributes; + else + { + $attributes=new TAttributeCollection; + $this->setViewState('Attributes',$attributes,null); + return $attributes; + } + } + public function hasAttribute($name) + { + if($attributes=$this->getViewState('Attributes',null)) + return $attributes->contains($name); + else + return false; + } + public function getAttribute($name) + { + if($attributes=$this->getViewState('Attributes',null)) + return $attributes->itemAt($name); + else + return null; + } + public function setAttribute($name,$value) + { + $this->getAttributes()->add($name,$value); + } + public function removeAttribute($name) + { + if($attributes=$this->getViewState('Attributes',null)) + return $attributes->remove($name); + else + return null; + } + public function getEnableViewState($checkParents=false) + { + if($checkParents) + { + for($control=$this;$control!==null;$control=$control->getParent()) + if($control->_flags & self::IS_DISABLE_VIEWSTATE) + return false; + return true; + } + else + return !($this->_flags & self::IS_DISABLE_VIEWSTATE); + } + public function setEnableViewState($value) + { + if(TPropertyValue::ensureBoolean($value)) + $this->_flags &= ~self::IS_DISABLE_VIEWSTATE; + else + $this->_flags |= self::IS_DISABLE_VIEWSTATE; + } + protected function getControlState($key,$defaultValue=null) + { + return isset($this->_rf[self::RF_CONTROLSTATE][$key])?$this->_rf[self::RF_CONTROLSTATE][$key]:$defaultValue; + } + protected function setControlState($key,$value,$defaultValue=null) + { + if($value===$defaultValue) + unset($this->_rf[self::RF_CONTROLSTATE][$key]); + else + $this->_rf[self::RF_CONTROLSTATE][$key]=$value; + } + protected function clearControlState($key) + { + unset($this->_rf[self::RF_CONTROLSTATE][$key]); + } + public function trackViewState($enabled) + { + $this->_trackViewState=TPropertyValue::ensureBoolean($enabled); + } + public function getViewState($key,$defaultValue=null) + { + if(isset($this->_viewState[$key])) + return $this->_viewState[$key]!==null?$this->_viewState[$key]:$defaultValue; + else if(isset($this->_tempState[$key])) + { + if(is_object($this->_tempState[$key]) && $this->_trackViewState) + $this->_viewState[$key]=$this->_tempState[$key]; + return $this->_tempState[$key]; + } + else + return $defaultValue; + } + public function setViewState($key,$value,$defaultValue=null) + { + if($this->_trackViewState) + { + $this->_viewState[$key]=$value; + unset($this->_tempState[$key]); + } + else + { + unset($this->_viewState[$key]); + $this->_tempState[$key]=$value; + } + } + public function clearViewState($key) + { + unset($this->_viewState[$key]); + unset($this->_tempState[$key]); + } + public function bindProperty($name,$expression) + { + $this->_rf[self::RF_DATA_BINDINGS][$name]=$expression; + } + public function unbindProperty($name) + { + unset($this->_rf[self::RF_DATA_BINDINGS][$name]); + } + public function autoBindProperty($name,$expression) + { + $this->_rf[self::RF_AUTO_BINDINGS][$name]=$expression; + } + public function dataBind() + { + $this->dataBindProperties(); + $this->onDataBinding(null); + $this->dataBindChildren(); + } + protected function dataBindProperties() + { + if(isset($this->_rf[self::RF_DATA_BINDINGS])) + { + if(($context=$this->getTemplateControl())===null) + $context=$this; + foreach($this->_rf[self::RF_DATA_BINDINGS] as $property=>$expression) + $this->setSubProperty($property,$context->evaluateExpression($expression)); + } + } + protected function autoDataBindProperties() + { + if(isset($this->_rf[self::RF_AUTO_BINDINGS])) + { + if(($context=$this->getTemplateControl())===null) + $context=$this; + foreach($this->_rf[self::RF_AUTO_BINDINGS] as $property=>$expression) + $this->setSubProperty($property,$context->evaluateExpression($expression)); + } + } + protected function dataBindChildren() + { + if(isset($this->_rf[self::RF_CONTROLS])) + { + foreach($this->_rf[self::RF_CONTROLS] as $control) + if($control instanceof IBindable) + $control->dataBind(); + } + } + final protected function getChildControlsCreated() + { + return ($this->_flags & self::IS_CHILD_CREATED)!==0; + } + final protected function setChildControlsCreated($value) + { + if($value) + $this->_flags |= self::IS_CHILD_CREATED; + else + { + if($this->getHasControls() && ($this->_flags & self::IS_CHILD_CREATED)) + $this->getControls()->clear(); + $this->_flags &= ~self::IS_CHILD_CREATED; + } + } + public function ensureChildControls() + { + if(!($this->_flags & self::IS_CHILD_CREATED) && !($this->_flags & self::IS_CREATING_CHILD)) + { + try + { + $this->_flags |= self::IS_CREATING_CHILD; + if(isset($this->_rf[self::RF_ADAPTER])) + $this->_rf[self::RF_ADAPTER]->createChildControls(); + else + $this->createChildControls(); + $this->_flags &= ~self::IS_CREATING_CHILD; + $this->_flags |= self::IS_CHILD_CREATED; + } + catch(Exception $e) + { + $this->_flags &= ~self::IS_CREATING_CHILD; + $this->_flags |= self::IS_CHILD_CREATED; + throw $e; + } + } + } + public function createChildControls() + { + } + public function findControl($id) + { + $id=strtr($id,'.',self::ID_SEPARATOR); + $container=($this instanceof INamingContainer)?$this:$this->getNamingContainer(); + if(!$container || !$container->getHasControls()) + return null; + if(!isset($container->_rf[self::RF_NAMED_CONTROLS])) + { + $container->_rf[self::RF_NAMED_CONTROLS]=array(); + $container->fillNameTable($container,$container->_rf[self::RF_CONTROLS]); + } + if(($pos=strpos($id,self::ID_SEPARATOR))===false) + return isset($container->_rf[self::RF_NAMED_CONTROLS][$id])?$container->_rf[self::RF_NAMED_CONTROLS][$id]:null; + else + { + $cid=substr($id,0,$pos); + $sid=substr($id,$pos+1); + if(isset($container->_rf[self::RF_NAMED_CONTROLS][$cid])) + return $container->_rf[self::RF_NAMED_CONTROLS][$cid]->findControl($sid); + else + return null; + } + } + public function findControlsByType($type,$strict=true) + { + $controls=array(); + if($this->getHasControls()) + { + foreach($this->_rf[self::RF_CONTROLS] as $control) + { + if(is_object($control) && (get_class($control)===$type || (!$strict && ($control instanceof $type)))) + $controls[]=$control; + if(($control instanceof TControl) && $control->getHasControls()) + $controls=array_merge($controls,$control->findControlsByType($type,$strict)); + } + } + return $controls; + } + public function findControlsByID($id) + { + $controls=array(); + if($this->getHasControls()) + { + foreach($this->_rf[self::RF_CONTROLS] as $control) + { + if($control instanceof TControl) + { + if($control->_id===$id) + $controls[]=$control; + $controls=array_merge($controls,$control->findControlsByID($id)); + } + } + } + return $controls; + } + public function clearNamingContainer() + { + unset($this->_rf[self::RF_NAMED_CONTROLS_ID]); + $this->clearNameTable(); + } + public function registerObject($name,$object) + { + if(isset($this->_rf[self::RF_NAMED_OBJECTS][$name])) + throw new TInvalidOperationException('control_object_reregistered',$name); + $this->_rf[self::RF_NAMED_OBJECTS][$name]=$object; + } + public function unregisterObject($name) + { + unset($this->_rf[self::RF_NAMED_OBJECTS][$name]); + } + public function isObjectRegistered($name) + { + return isset($this->_rf[self::RF_NAMED_OBJECTS][$name]); + } + public function getHasChildInitialized() + { + return $this->getControlStage() >= self::CS_CHILD_INITIALIZED; + } + public function getHasInitialized() + { + return $this->getControlStage() >= self::CS_INITIALIZED; + } + public function getHasLoadedPostData() + { + return $this->getControlStage() >= self::CS_STATE_LOADED; + } + public function getHasLoaded() + { + return $this->getControlStage() >= self::CS_LOADED; + } + public function getHasPreRendered() + { + return $this->getControlStage() >= self::CS_PRERENDERED; + } + public function getRegisteredObject($name) + { + return isset($this->_rf[self::RF_NAMED_OBJECTS][$name])?$this->_rf[self::RF_NAMED_OBJECTS][$name]:null; + } + public function getAllowChildControls() + { + return true; + } + public function addParsedObject($object) + { + $this->getControls()->add($object); + } + final protected function clearChildState() + { + unset($this->_rf[self::RF_CHILD_STATE]); + } + final protected function isDescendentOf($ancestor) + { + $control=$this; + while($control!==$ancestor && $control->_parent) + $control=$control->_parent; + return $control===$ancestor; + } + public function addedControl($control) + { + if($control->_parent) + $control->_parent->getControls()->remove($control); + $control->_parent=$this; + $control->_page=$this->getPage(); + $namingContainer=($this instanceof INamingContainer)?$this:$this->_namingContainer; + if($namingContainer) + { + $control->_namingContainer=$namingContainer; + if($control->_id==='') + $control->generateAutomaticID(); + else + $namingContainer->clearNameTable(); + $control->clearCachedUniqueID($control instanceof INamingContainer); + } + if($this->_stage>=self::CS_CHILD_INITIALIZED) + { + $control->initRecursive($namingContainer); + if($this->_stage>=self::CS_STATE_LOADED) + { + if(isset($this->_rf[self::RF_CHILD_STATE][$control->_id])) + { + $state=$this->_rf[self::RF_CHILD_STATE][$control->_id]; + unset($this->_rf[self::RF_CHILD_STATE][$control->_id]); + } + else + $state=null; + $control->loadStateRecursive($state,!($this->_flags & self::IS_DISABLE_VIEWSTATE)); + if($this->_stage>=self::CS_LOADED) + { + $control->loadRecursive(); + if($this->_stage>=self::CS_PRERENDERED) + $control->preRenderRecursive(); + } + } + } + } + public function removedControl($control) + { + if($this->_namingContainer) + $this->_namingContainer->clearNameTable(); + $control->unloadRecursive(); + $control->_parent=null; + $control->_page=null; + $control->_namingContainer=null; + $control->_tplControl=null; + if(!($control->_flags & self::IS_ID_SET)) + $control->_id=''; + else + unset($this->_rf[self::RF_NAMED_OBJECTS][$control->_id]); + $control->clearCachedUniqueID(true); + } + protected function initRecursive($namingContainer=null) + { + $this->ensureChildControls(); + if($this->getHasControls()) + { + if($this instanceof INamingContainer) + $namingContainer=$this; + $page=$this->getPage(); + foreach($this->_rf[self::RF_CONTROLS] as $control) + { + if($control instanceof TControl) + { + $control->_namingContainer=$namingContainer; + $control->_page=$page; + if($control->_id==='' && $namingContainer) + $control->generateAutomaticID(); + $control->initRecursive($namingContainer); + } + } + } + if($this->_stage_stage=self::CS_CHILD_INITIALIZED; + if(($page=$this->getPage()) && $this->getEnableTheming() && !($this->_flags & self::IS_SKIN_APPLIED)) + { + $page->applyControlSkin($this); + $this->_flags |= self::IS_SKIN_APPLIED; + } + if(isset($this->_rf[self::RF_ADAPTER])) + $this->_rf[self::RF_ADAPTER]->onInit(null); + else + $this->onInit(null); + $this->_stage=self::CS_INITIALIZED; + } + } + protected function loadRecursive() + { + if($this->_stage_rf[self::RF_ADAPTER])) + $this->_rf[self::RF_ADAPTER]->onLoad(null); + else + $this->onLoad(null); + } + if($this->getHasControls()) + { + foreach($this->_rf[self::RF_CONTROLS] as $control) + { + if($control instanceof TControl) + $control->loadRecursive(); + } + } + if($this->_stage_stage=self::CS_LOADED; + } + protected function preRenderRecursive() + { + $this->autoDataBindProperties(); + if($this->getVisible(false)) + { + if(isset($this->_rf[self::RF_ADAPTER])) + $this->_rf[self::RF_ADAPTER]->onPreRender(null); + else + $this->onPreRender(null); + if($this->getHasControls()) + { + foreach($this->_rf[self::RF_CONTROLS] as $control) + { + if($control instanceof TControl) + $control->preRenderRecursive(); + else if($control instanceof TCompositeLiteral) + $control->evaluateDynamicContent(); + } + } + $this->addToPostDataLoader(); + } + $this->_stage=self::CS_PRERENDERED; + } + protected function addToPostDataLoader() + { + if($this instanceof IPostBackDataHandler) + $this->getPage()->registerPostDataLoader($this); + } + protected function unloadRecursive() + { + if(!($this->_flags & self::IS_ID_SET)) + $this->_id=''; + if($this->getHasControls()) + { + foreach($this->_rf[self::RF_CONTROLS] as $control) + if($control instanceof TControl) + $control->unloadRecursive(); + } + if(isset($this->_rf[self::RF_ADAPTER])) + $this->_rf[self::RF_ADAPTER]->onUnload(null); + else + $this->onUnload(null); + } + public function onInit($param) + { + $this->raiseEvent('OnInit',$this,$param); + } + public function onLoad($param) + { + $this->raiseEvent('OnLoad',$this,$param); + } + public function onDataBinding($param) + { + $this->raiseEvent('OnDataBinding',$this,$param); + } + public function onUnload($param) + { + $this->raiseEvent('OnUnload',$this,$param); + } + public function onPreRender($param) + { + $this->raiseEvent('OnPreRender',$this,$param); + } + protected function raiseBubbleEvent($sender,$param) + { + $control=$this; + while($control=$control->_parent) + { + if($control->bubbleEvent($sender,$param)) + break; + } + } + public function bubbleEvent($sender,$param) + { + return false; + } + public function broadcastEvent($name,$sender,$param) + { + $rootControl=(($page=$this->getPage())===null)?$this:$page; + $rootControl->broadcastEventInternal($name,$sender,new TBroadcastEventParameter($name,$param)); + } + private function broadcastEventInternal($name,$sender,$param) + { + if($this->hasEvent($name)) + $this->raiseEvent($name,$sender,$param->getParameter()); + if($this instanceof IBroadcastEventReceiver) + $this->broadcastEventReceived($sender,$param); + if($this->getHasControls()) + { + foreach($this->_rf[self::RF_CONTROLS] as $control) + { + if($control instanceof TControl) + $control->broadcastEventInternal($name,$sender,$param); + } + } + } + protected function traverseChildControls($param,$preCallback=null,$postCallback=null) + { + if($preCallback!==null) + call_user_func($preCallback,$this,$param); + if($this->getHasControls()) + { + foreach($this->_rf[self::RF_CONTROLS] as $control) + { + if($control instanceof TControl) + { + $control->traverseChildControls($param,$preCallback,$postCallback); + } + } + } + if($postCallback!==null) + call_user_func($postCallback,$this,$param); + } + public function renderControl($writer) + { + if($this->getVisible(false)) + { + if(isset($this->_rf[self::RF_ADAPTER])) + $this->_rf[self::RF_ADAPTER]->render($writer); + else + $this->render($writer); + } + } + public function render($writer) + { + $this->renderChildren($writer); + } + public function renderChildren($writer) + { + if($this->getHasControls()) + { + foreach($this->_rf[self::RF_CONTROLS] as $control) + { + if(is_string($control)) + $writer->write($control); + else if($control instanceof TControl) + $control->renderControl($writer); + else if($control instanceof IRenderable) + $control->render($writer); + } + } + } + public function saveState() + { + } + public function loadState() + { + } + protected function loadStateRecursive(&$state,$needViewState=true) + { + if(is_array($state)) + { + $needViewState=($needViewState && !($this->_flags & self::IS_DISABLE_VIEWSTATE)); + if(isset($state[1])) + { + $this->_rf[self::RF_CONTROLSTATE]=&$state[1]; + unset($state[1]); + } + else + unset($this->_rf[self::RF_CONTROLSTATE]); + if($needViewState) + { + if(isset($state[0])) + $this->_viewState=&$state[0]; + else + $this->_viewState=array(); + } + unset($state[0]); + if($this->getHasControls()) + { + foreach($this->_rf[self::RF_CONTROLS] as $control) + { + if($control instanceof TControl) + { + if(isset($state[$control->_id])) + { + $control->loadStateRecursive($state[$control->_id],$needViewState); + unset($state[$control->_id]); + } + } + } + } + if(!empty($state)) + $this->_rf[self::RF_CHILD_STATE]=&$state; + } + $this->_stage=self::CS_STATE_LOADED; + if(isset($this->_rf[self::RF_ADAPTER])) + $this->_rf[self::RF_ADAPTER]->loadState(); + else + $this->loadState(); + } + protected function &saveStateRecursive($needViewState=true) + { + if(isset($this->_rf[self::RF_ADAPTER])) + $this->_rf[self::RF_ADAPTER]->saveState(); + else + $this->saveState(); + $needViewState=($needViewState && !($this->_flags & self::IS_DISABLE_VIEWSTATE)); + $state=array(); + if($this->getHasControls()) + { + foreach($this->_rf[self::RF_CONTROLS] as $control) + { + if($control instanceof TControl) + $state[$control->_id]=&$control->saveStateRecursive($needViewState); + } + } + if($needViewState && !empty($this->_viewState)) + $state[0]=&$this->_viewState; + if(isset($this->_rf[self::RF_CONTROLSTATE])) + $state[1]=&$this->_rf[self::RF_CONTROLSTATE]; + return $state; + } + public function applyStyleSheetSkin($page) + { + if($page && !($this->_flags & self::IS_STYLESHEET_APPLIED)) + { + $page->applyControlStyleSheet($this); + $this->_flags |= self::IS_STYLESHEET_APPLIED; + } + else if($this->_flags & self::IS_STYLESHEET_APPLIED) + throw new TInvalidOperationException('control_stylesheet_applied',get_class($this)); + } + private function clearCachedUniqueID($recursive) + { + if($recursive && $this->_uid!==null && isset($this->_rf[self::RF_CONTROLS])) + { + foreach($this->_rf[self::RF_CONTROLS] as $control) + if($control instanceof TControl) + $control->clearCachedUniqueID($recursive); + } + $this->_uid=null; + } + private function generateAutomaticID() + { + $this->_flags &= ~self::IS_ID_SET; + if(!isset($this->_namingContainer->_rf[self::RF_NAMED_CONTROLS_ID])) + $this->_namingContainer->_rf[self::RF_NAMED_CONTROLS_ID]=0; + $id=$this->_namingContainer->_rf[self::RF_NAMED_CONTROLS_ID]++; + $this->_id=self::AUTOMATIC_ID_PREFIX . $id; + $this->_namingContainer->clearNameTable(); + } + private function clearNameTable() + { + unset($this->_rf[self::RF_NAMED_CONTROLS]); + } + private function fillNameTable($container,$controls) + { + foreach($controls as $control) + { + if($control instanceof TControl) + { + if($control->_id!=='') + { + if(isset($container->_rf[self::RF_NAMED_CONTROLS][$control->_id])) + throw new TInvalidDataValueException('control_id_nonunique',get_class($control),$control->_id); + else + $container->_rf[self::RF_NAMED_CONTROLS][$control->_id]=$control; + } + if(!($control instanceof INamingContainer) && $control->getHasControls()) + $this->fillNameTable($container,$control->_rf[self::RF_CONTROLS]); + } + } + } +} +class TControlCollection extends TList +{ + private $_o; + public function __construct(TControl $owner,$readOnly=false) + { + $this->_o=$owner; + parent::__construct(null,$readOnly); + } + protected function getOwner() + { + return $this->_o; + } + public function insertAt($index,$item) + { + if($item instanceof TControl) + { + parent::insertAt($index,$item); + $this->_o->addedControl($item); + } + else if(is_string($item) || ($item instanceof IRenderable)) + parent::insertAt($index,$item); + else + throw new TInvalidDataTypeException('controlcollection_control_required'); + } + public function removeAt($index) + { + $item=parent::removeAt($index); + if($item instanceof TControl) + $this->_o->removedControl($item); + return $item; + } + public function clear() + { + parent::clear(); + if($this->_o instanceof INamingContainer) + $this->_o->clearNamingContainer(); + } +} +class TEmptyControlCollection extends TControlCollection +{ + public function __construct(TControl $owner) + { + parent::__construct($owner,true); + } + public function insertAt($index,$item) + { + if(!is_string($item)) + parent::insertAt($index,$item); + } +} +interface INamingContainer +{ +} +interface IPostBackEventHandler +{ + public function raisePostBackEvent($param); +} +interface IPostBackDataHandler +{ + public function loadPostData($key,$values); + public function raisePostDataChangedEvent(); + public function getDataChanged(); +} +interface IValidator +{ + public function validate(); + public function getIsValid(); + public function setIsValid($value); + public function getErrorMessage(); + public function setErrorMessage($value); +} +interface IValidatable +{ + public function getValidationPropertyValue(); + public function getIsValid(); + public function setIsValid($value); +} +interface IBroadcastEventReceiver +{ + public function broadcastEventReceived($sender,$param); +} +interface ITheme +{ + public function applySkin($control); +} +interface ITemplate +{ + public function instantiateIn($parent); +} +interface IButtonControl +{ + public function getText(); + public function setText($value); + public function getCausesValidation(); + public function setCausesValidation($value); + public function getCommandName(); + public function setCommandName($value); + public function getCommandParameter(); + public function setCommandParameter($value); + public function getValidationGroup(); + public function setValidationGroup($value); + public function onClick($param); + public function onCommand($param); + public function setIsDefaultButton($value); + public function getIsDefaultButton(); +} +interface ISurroundable +{ + public function getSurroundingTagID(); +} +class TBroadcastEventParameter extends TEventParameter +{ + private $_name; + private $_param; + public function __construct($name='',$parameter=null) + { + $this->_name=$name; + $this->_param=$parameter; + } + public function getName() + { + return $this->_name; + } + public function setName($value) + { + $this->_name=$value; + } + public function getParameter() + { + return $this->_param; + } + public function setParameter($value) + { + $this->_param=$value; + } +} +class TCommandEventParameter extends TEventParameter +{ + private $_name; + private $_param; + public function __construct($name='',$parameter='') + { + $this->_name=$name; + $this->_param=$parameter; + } + public function getCommandName() + { + return $this->_name; + } + public function getCommandParameter() + { + return $this->_param; + } +} +class TCompositeLiteral extends TComponent implements IRenderable, IBindable +{ + const TYPE_EXPRESSION=0; + const TYPE_STATEMENTS=1; + const TYPE_DATABINDING=2; + private $_container=null; + private $_items=array(); + private $_expressions=array(); + private $_statements=array(); + private $_bindings=array(); + public function __construct($items) + { + $this->_items=array(); + $this->_expressions=array(); + $this->_statements=array(); + foreach($items as $id=>$item) + { + if(is_array($item)) + { + if($item[0]===self::TYPE_EXPRESSION) + $this->_expressions[$id]=$item[1]; + else if($item[0]===self::TYPE_STATEMENTS) + $this->_statements[$id]=$item[1]; + else if($item[0]===self::TYPE_DATABINDING) + $this->_bindings[$id]=$item[1]; + $this->_items[$id]=''; + } + else + $this->_items[$id]=$item; + } + } + public function getContainer() + { + return $this->_container; + } + public function setContainer(TComponent $value) + { + $this->_container=$value; + } + public function evaluateDynamicContent() + { + $context=$this->_container===null?$this:$this->_container; + foreach($this->_expressions as $id=>$expression) + $this->_items[$id]=$context->evaluateExpression($expression); + foreach($this->_statements as $id=>$statement) + $this->_items[$id]=$context->evaluateStatements($statement); + } + public function dataBind() + { + $context=$this->_container===null?$this:$this->_container; + foreach($this->_bindings as $id=>$binding) + $this->_items[$id]=$context->evaluateExpression($binding); + } + public function render($writer) + { + $writer->write(implode('',$this->_items)); + } +} +class TFont extends TComponent +{ + const IS_BOLD=0x01; + const IS_ITALIC=0x02; + const IS_OVERLINE=0x04; + const IS_STRIKEOUT=0x08; + const IS_UNDERLINE=0x10; + const IS_SET_BOLD=0x01000; + const IS_SET_ITALIC=0x02000; + const IS_SET_OVERLINE=0x04000; + const IS_SET_STRIKEOUT=0x08000; + const IS_SET_UNDERLINE=0x10000; + const IS_SET_SIZE=0x20000; + const IS_SET_NAME=0x40000; + private $_flags=0; + private $_name=''; + private $_size=''; + public function getBold() + { + return ($this->_flags & self::IS_BOLD)!==0; + } + public function setBold($value) + { + $this->_flags |= self::IS_SET_BOLD; + if(TPropertyValue::ensureBoolean($value)) + $this->_flags |= self::IS_BOLD; + else + $this->_flags &= ~self::IS_BOLD; + } + public function getItalic() + { + return ($this->_flags & self::IS_ITALIC)!==0; + } + public function setItalic($value) + { + $this->_flags |= self::IS_SET_ITALIC; + if(TPropertyValue::ensureBoolean($value)) + $this->_flags |= self::IS_ITALIC; + else + $this->_flags &= ~self::IS_ITALIC; + } + public function getOverline() + { + return ($this->_flags & self::IS_OVERLINE)!==0; + } + public function setOverline($value) + { + $this->_flags |= self::IS_SET_OVERLINE; + if(TPropertyValue::ensureBoolean($value)) + $this->_flags |= self::IS_OVERLINE; + else + $this->_flags &= ~self::IS_OVERLINE; + } + public function getSize() + { + return $this->_size; + } + public function setSize($value) + { + $this->_flags |= self::IS_SET_SIZE; + $this->_size=$value; + } + public function getStrikeout() + { + return ($this->_flags & self::IS_STRIKEOUT)!==0; + } + public function setStrikeout($value) + { + $this->_flags |= self::IS_SET_STRIKEOUT; + if(TPropertyValue::ensureBoolean($value)) + $this->_flags |= self::IS_STRIKEOUT; + else + $this->_flags &= ~self::IS_STRIKEOUT; + } + public function getUnderline() + { + return ($this->_flags & self::IS_UNDERLINE)!==0; + } + public function setUnderline($value) + { + $this->_flags |= self::IS_SET_UNDERLINE; + if(TPropertyValue::ensureBoolean($value)) + $this->_flags |= self::IS_UNDERLINE; + else + $this->_flags &= ~self::IS_UNDERLINE; + } + public function getName() + { + return $this->_name; + } + public function setName($value) + { + $this->_flags |= self::IS_SET_NAME; + $this->_name=$value; + } + public function getIsEmpty() + { + return !$this->_flags; + } + public function reset() + { + $this->_flags=0; + $this->_name=''; + $this->_size=''; + } + public function mergeWith($font) + { + if($font===null || $font->_flags===0) + return; + if(!($this->_flags & self::IS_SET_BOLD) && ($font->_flags & self::IS_SET_BOLD)) + $this->setBold($font->getBold()); + if(!($this->_flags & self::IS_SET_ITALIC) && ($font->_flags & self::IS_SET_ITALIC)) + $this->setItalic($font->getItalic()); + if(!($this->_flags & self::IS_SET_OVERLINE) && ($font->_flags & self::IS_SET_OVERLINE)) + $this->setOverline($font->getOverline()); + if(!($this->_flags & self::IS_SET_STRIKEOUT) && ($font->_flags & self::IS_SET_STRIKEOUT)) + $this->setStrikeout($font->getStrikeout()); + if(!($this->_flags & self::IS_SET_UNDERLINE) && ($font->_flags & self::IS_SET_UNDERLINE)) + $this->setUnderline($font->getUnderline()); + if(!($this->_flags & self::IS_SET_SIZE) && ($font->_flags & self::IS_SET_SIZE)) + $this->setSize($font->getSize()); + if(!($this->_flags & self::IS_SET_NAME) && ($font->_flags & self::IS_SET_NAME)) + $this->setName($font->getName()); + } + public function copyFrom($font) + { + if($font===null || $font->_flags===0) + return; + if($font->_flags & self::IS_SET_BOLD) + $this->setBold($font->getBold()); + if($font->_flags & self::IS_SET_ITALIC) + $this->setItalic($font->getItalic()); + if($font->_flags & self::IS_SET_OVERLINE) + $this->setOverline($font->getOverline()); + if($font->_flags & self::IS_SET_STRIKEOUT) + $this->setStrikeout($font->getStrikeout()); + if($font->_flags & self::IS_SET_UNDERLINE) + $this->setUnderline($font->getUnderline()); + if($font->_flags & self::IS_SET_SIZE) + $this->setSize($font->getSize()); + if($font->_flags & self::IS_SET_NAME) + $this->setName($font->getName()); + } + public function toString() + { + if($this->_flags===0) + return ''; + $str=''; + if($this->_flags & self::IS_SET_BOLD) + $str.='font-weight:'.(($this->_flags & self::IS_BOLD)?'bold;':'normal;'); + if($this->_flags & self::IS_SET_ITALIC) + $str.='font-style:'.(($this->_flags & self::IS_ITALIC)?'italic;':'normal;'); + $textDec=''; + if($this->_flags & self::IS_UNDERLINE) + $textDec.='underline'; + if($this->_flags & self::IS_OVERLINE) + $textDec.=' overline'; + if($this->_flags & self::IS_STRIKEOUT) + $textDec.=' line-through'; + $textDec=ltrim($textDec); + if($textDec!=='') + $str.='text-decoration:'.$textDec.';'; + if($this->_size!=='') + $str.='font-size:'.$this->_size.';'; + if($this->_name!=='') + $str.='font-family:'.$this->_name.';'; + return $str; + } + public function addAttributesToRender($writer) + { + if($this->_flags===0) + return; + if($this->_flags & self::IS_SET_BOLD) + $writer->addStyleAttribute('font-weight',(($this->_flags & self::IS_BOLD)?'bold':'normal')); + if($this->_flags & self::IS_SET_ITALIC) + $writer->addStyleAttribute('font-style',(($this->_flags & self::IS_ITALIC)?'italic':'normal')); + $textDec=''; + if($this->_flags & self::IS_UNDERLINE) + $textDec.='underline'; + if($this->_flags & self::IS_OVERLINE) + $textDec.=' overline'; + if($this->_flags & self::IS_STRIKEOUT) + $textDec.=' line-through'; + $textDec=ltrim($textDec); + if($textDec!=='') + $writer->addStyleAttribute('text-decoration',$textDec); + if($this->_size!=='') + $writer->addStyleAttribute('font-size',$this->_size); + if($this->_name!=='') + $writer->addStyleAttribute('font-family',$this->_name); + } +} +class TStyle extends TComponent +{ + private $_fields=array(); + private $_font=null; + private $_class=null; + private $_customStyle=null; + private $_displayStyle='Fixed'; + public function __construct($style=null) + { + if($style!==null) + $this->copyFrom($style); + } + public function __clone() + { + if($this->_font!==null) + $this->_font = clone($this->_font); + } + public function getBackColor() + { + return isset($this->_fields['background-color'])?$this->_fields['background-color']:''; + } + public function setBackColor($value) + { + if(trim($value)==='') + unset($this->_fields['background-color']); + else + $this->_fields['background-color']=$value; + } + public function getBorderColor() + { + return isset($this->_fields['border-color'])?$this->_fields['border-color']:''; + } + public function setBorderColor($value) + { + if(trim($value)==='') + unset($this->_fields['border-color']); + else + $this->_fields['border-color']=$value; + } + public function getBorderStyle() + { + return isset($this->_fields['border-style'])?$this->_fields['border-style']:''; + } + public function setBorderStyle($value) + { + if(trim($value)==='') + unset($this->_fields['border-style']); + else + $this->_fields['border-style']=$value; + } + public function getBorderWidth() + { + return isset($this->_fields['border-width'])?$this->_fields['border-width']:''; + } + public function setBorderWidth($value) + { + if(trim($value)==='') + unset($this->_fields['border-width']); + else + $this->_fields['border-width']=$value; + } + public function getCssClass() + { + return $this->_class===null?'':$this->_class; + } + public function hasCssClass() + { + return ($this->_class!==null); + } + public function setCssClass($value) + { + $this->_class=$value; + } + public function getFont() + { + if($this->_font===null) + $this->_font=new TFont; + return $this->_font; + } + public function hasFont() + { + return $this->_font !== null; + } + public function setDisplayStyle($value) + { + $this->_displayStyle = TPropertyValue::ensureEnum($value, 'TDisplayStyle'); + switch($this->_displayStyle) + { + case TDisplayStyle::None: + $this->_fields['display'] = 'none'; + break; + case TDisplayStyle::Dynamic: + $this->_fields['display'] = ''; + break; + case TDisplayStyle::Fixed: + $this->_fields['visibility'] = 'visible'; + break; + case TDisplayStyle::Hidden: + $this->_fields['visibility'] = 'hidden'; + break; + } + } + public function getDisplayStyle() + { + return $this->_displayStyle; + } + public function getForeColor() + { + return isset($this->_fields['color'])?$this->_fields['color']:''; + } + public function setForeColor($value) + { + if(trim($value)==='') + unset($this->_fields['color']); + else + $this->_fields['color']=$value; + } + public function getHeight() + { + return isset($this->_fields['height'])?$this->_fields['height']:''; + } + public function setHeight($value) + { + if(trim($value)==='') + unset($this->_fields['height']); + else + $this->_fields['height']=$value; + } + public function getCustomStyle() + { + return $this->_customStyle===null?'':$this->_customStyle; + } + public function setCustomStyle($value) + { + $this->_customStyle=$value; + } + public function getStyleField($name) + { + return isset($this->_fields[$name])?$this->_fields[$name]:''; + } + public function setStyleField($name,$value) + { + $this->_fields[$name]=$value; + } + public function clearStyleField($name) + { + unset($this->_fields[$name]); + } + public function hasStyleField($name) + { + return isset($this->_fields[$name]); + } + public function getWidth() + { + return isset($this->_fields['width'])?$this->_fields['width']:''; + } + public function setWidth($value) + { + $this->_fields['width']=$value; + } + public function reset() + { + $this->_fields=array(); + $this->_font=null; + $this->_class=null; + $this->_customStyle=null; + } + public function copyFrom($style) + { + if($style instanceof TStyle) + { + $this->_fields=array_merge($this->_fields,$style->_fields); + if($style->_class!==null) + $this->_class=$style->_class; + if($style->_customStyle!==null) + $this->_customStyle=$style->_customStyle; + if($style->_font!==null) + $this->getFont()->copyFrom($style->_font); + } + } + public function mergeWith($style) + { + if($style instanceof TStyle) + { + $this->_fields=array_merge($style->_fields,$this->_fields); + if($this->_class===null) + $this->_class=$style->_class; + if($this->_customStyle===null) + $this->_customStyle=$style->_customStyle; + if($style->_font!==null) + $this->getFont()->mergeWith($style->_font); + } + } + public function addAttributesToRender($writer) + { + if($this->_customStyle!==null) + { + foreach(explode(';',$this->_customStyle) as $style) + { + $arr=explode(':',$style); + if(isset($arr[1]) && trim($arr[0])!=='') + $writer->addStyleAttribute(trim($arr[0]),trim($arr[1])); + } + } + $writer->addStyleAttributes($this->_fields); + if($this->_font!==null) + $this->_font->addAttributesToRender($writer); + if($this->_class!==null) + $writer->addAttribute('class',$this->_class); + } + public function getStyleFields() + { + return $this->_fields; + } +} +class TDisplayStyle extends TEnumerable +{ + const None='None'; + const Dynamic='Dynamic'; + const Fixed='Fixed'; + const Hidden='Hidden'; +} +class TTableStyle extends TStyle +{ + private $_backImageUrl=null; + private $_horizontalAlign=null; + private $_cellPadding=null; + private $_cellSpacing=null; + private $_gridLines=null; + private $_borderCollapse=null; + public function reset() + { + $this->_backImageUrl=null; + $this->_horizontalAlign=null; + $this->_cellPadding=null; + $this->_cellSpacing=null; + $this->_gridLines=null; + $this->_borderCollapse=null; + } + public function copyFrom($style) + { + parent::copyFrom($style); + if($style instanceof TTableStyle) + { + if($style->_backImageUrl!==null) + $this->_backImageUrl=$style->_backImageUrl; + if($style->_horizontalAlign!==null) + $this->_horizontalAlign=$style->_horizontalAlign; + if($style->_cellPadding!==null) + $this->_cellPadding=$style->_cellPadding; + if($style->_cellSpacing!==null) + $this->_cellSpacing=$style->_cellSpacing; + if($style->_gridLines!==null) + $this->_gridLines=$style->_gridLines; + if($style->_borderCollapse!==null) + $this->_borderCollapse=$style->_borderCollapse; + } + } + public function mergeWith($style) + { + parent::mergeWith($style); + if($style instanceof TTableStyle) + { + if($this->_backImageUrl===null && $style->_backImageUrl!==null) + $this->_backImageUrl=$style->_backImageUrl; + if($this->_horizontalAlign===null && $style->_horizontalAlign!==null) + $this->_horizontalAlign=$style->_horizontalAlign; + if($this->_cellPadding===null && $style->_cellPadding!==null) + $this->_cellPadding=$style->_cellPadding; + if($this->_cellSpacing===null && $style->_cellSpacing!==null) + $this->_cellSpacing=$style->_cellSpacing; + if($this->_gridLines===null && $style->_gridLines!==null) + $this->_gridLines=$style->_gridLines; + if($this->_borderCollapse===null && $style->_borderCollapse!==null) + $this->_borderCollapse=$style->_borderCollapse; + } + } + public function addAttributesToRender($writer) + { + if(($url=trim($this->getBackImageUrl()))!=='') + $writer->addStyleAttribute('background-image','url('.$url.')'); + if(($horizontalAlign=$this->getHorizontalAlign())!==THorizontalAlign::NotSet) + $writer->addStyleAttribute('text-align',strtolower($horizontalAlign)); + if(($cellPadding=$this->getCellPadding())>=0) + $writer->addAttribute('cellpadding',"$cellPadding"); + if(($cellSpacing=$this->getCellSpacing())>=0) + $writer->addAttribute('cellspacing',"$cellSpacing"); + if($this->getBorderCollapse()) + $writer->addStyleAttribute('border-collapse','collapse'); + switch($this->getGridLines()) + { + case TTableGridLines::Horizontal : $writer->addAttribute('rules','rows'); break; + case TTableGridLines::Vertical : $writer->addAttribute('rules','cols'); break; + case TTableGridLines::Both : $writer->addAttribute('rules','all'); break; + } + parent::addAttributesToRender($writer); + } + public function getBackImageUrl() + { + return $this->_backImageUrl===null?'':$this->_backImageUrl; + } + public function setBackImageUrl($value) + { + $this->_backImageUrl=$value; + } + public function getHorizontalAlign() + { + return $this->_horizontalAlign===null?THorizontalAlign::NotSet:$this->_horizontalAlign; + } + public function setHorizontalAlign($value) + { + $this->_horizontalAlign=TPropertyValue::ensureEnum($value,'THorizontalAlign'); + } + public function getCellPadding() + { + return $this->_cellPadding===null?-1:$this->_cellPadding; + } + public function setCellPadding($value) + { + if(($this->_cellPadding=TPropertyValue::ensureInteger($value))<-1) + throw new TInvalidDataValueException('tablestyle_cellpadding_invalid'); + } + public function getCellSpacing() + { + return $this->_cellSpacing===null?-1:$this->_cellSpacing; + } + public function setCellSpacing($value) + { + if(($this->_cellSpacing=TPropertyValue::ensureInteger($value))<-1) + throw new TInvalidDataValueException('tablestyle_cellspacing_invalid'); + } + public function getGridLines() + { + return $this->_gridLines===null?TTableGridLines::None:$this->_gridLines; + } + public function setGridLines($value) + { + $this->_gridLines=TPropertyValue::ensureEnum($value,'TTableGridLines'); + } + public function getBorderCollapse() + { + return $this->_borderCollapse===null?false:$this->_borderCollapse; + } + public function setBorderCollapse($value) + { + $this->_borderCollapse=TPropertyValue::ensureBoolean($value); + } +} +class TTableItemStyle extends TStyle +{ + private $_horizontalAlign=null; + private $_verticalAlign=null; + private $_wrap=null; + public function reset() + { + parent::reset(); + $this->_verticalAlign=null; + $this->_horizontalAlign=null; + $this->_wrap=null; + } + public function copyFrom($style) + { + parent::copyFrom($style); + if($style instanceof TTableItemStyle) + { + if($this->_verticalAlign===null && $style->_verticalAlign!==null) + $this->_verticalAlign=$style->_verticalAlign; + if($this->_horizontalAlign===null && $style->_horizontalAlign!==null) + $this->_horizontalAlign=$style->_horizontalAlign; + if($this->_wrap===null && $style->_wrap!==null) + $this->_wrap=$style->_wrap; + } + } + public function mergeWith($style) + { + parent::mergeWith($style); + if($style instanceof TTableItemStyle) + { + if($style->_verticalAlign!==null) + $this->_verticalAlign=$style->_verticalAlign; + if($style->_horizontalAlign!==null) + $this->_horizontalAlign=$style->_horizontalAlign; + if($style->_wrap!==null) + $this->_wrap=$style->_wrap; + } + } + public function addAttributesToRender($writer) + { + if(!$this->getWrap()) + $writer->addStyleAttribute('white-space','nowrap'); + if(($horizontalAlign=$this->getHorizontalAlign())!==THorizontalAlign::NotSet) + $writer->addAttribute('align',strtolower($horizontalAlign)); + if(($verticalAlign=$this->getVerticalAlign())!==TVerticalAlign::NotSet) + $writer->addAttribute('valign',strtolower($verticalAlign)); + parent::addAttributesToRender($writer); + } + public function getHorizontalAlign() + { + return $this->_horizontalAlign===null?THorizontalAlign::NotSet:$this->_horizontalAlign; + } + public function setHorizontalAlign($value) + { + $this->_horizontalAlign=TPropertyValue::ensureEnum($value,'THorizontalAlign'); + } + public function getVerticalAlign() + { + return $this->_verticalAlign===null?TVerticalAlign::NotSet:$this->_verticalAlign; + } + public function setVerticalAlign($value) + { + $this->_verticalAlign=TPropertyValue::ensureEnum($value,'TVerticalAlign'); + } + public function getWrap() + { + return $this->_wrap===null?true:$this->_wrap; + } + public function setWrap($value) + { + $this->_wrap=TPropertyValue::ensureBoolean($value); + } +} +class THorizontalAlign extends TEnumerable +{ + const NotSet='NotSet'; + const Left='Left'; + const Right='Right'; + const Center='Center'; + const Justify='Justify'; +} +class TVerticalAlign extends TEnumerable +{ + const NotSet='NotSet'; + const Top='Top'; + const Bottom='Bottom'; + const Middle='Middle'; +} +class TTableGridLines extends TEnumerable +{ + const None='None'; + const Horizontal='Horizontal'; + const Vertical='Vertical'; + const Both='Both'; +} +class TWebControlAdapter extends TControlAdapter +{ + public function render($writer) + { + $this->renderBeginTag($writer); + $this->renderContents($writer); + $this->renderEndTag($writer); + } + public function renderBeginTag($writer) + { + $this->getControl()->renderBeginTag($writer); + } + public function renderContents($writer) + { + $this->getControl()->renderContents($writer); + } + public function renderEndTag($writer) + { + $this->getControl()->renderEndTag($writer); + } +} +class TWebControl extends TControl implements IStyleable +{ + public function copyBaseAttributes(TWebControl $control) + { + $this->setAccessKey($control->getAccessKey()); + $this->setToolTip($control->getToolTip()); + $this->setTabIndex($control->getTabIndex()); + if(!$control->getEnabled()) + $this->setEnabled(false); + if($control->getHasAttributes()) + $this->getAttributes()->copyFrom($control->getAttributes()); + } + public function getAccessKey() + { + return $this->getViewState('AccessKey',''); + } + public function setAccessKey($value) + { + if(strlen($value)>1) + throw new TInvalidDataValueException('webcontrol_accesskey_invalid',get_class($this),$value); + $this->setViewState('AccessKey',$value,''); + } + public function getBackColor() + { + if($style=$this->getViewState('Style',null)) + return $style->getBackColor(); + else + return ''; + } + public function setBackColor($value) + { + $this->getStyle()->setBackColor($value); + } + public function getBorderColor() + { + if($style=$this->getViewState('Style',null)) + return $style->getBorderColor(); + else + return ''; + } + public function setBorderColor($value) + { + $this->getStyle()->setBorderColor($value); + } + public function getBorderStyle() + { + if($style=$this->getViewState('Style',null)) + return $style->getBorderStyle(); + else + return ''; + } + public function setBorderStyle($value) + { + $this->getStyle()->setBorderStyle($value); + } + public function getBorderWidth() + { + if($style=$this->getViewState('Style',null)) + return $style->getBorderWidth(); + else + return ''; + } + public function setBorderWidth($value) + { + $this->getStyle()->setBorderWidth($value); + } + public function getFont() + { + return $this->getStyle()->getFont(); + } + public function getForeColor() + { + if($style=$this->getViewState('Style',null)) + return $style->getForeColor(); + else + return ''; + } + public function setForeColor($value) + { + $this->getStyle()->setForeColor($value); + } + public function getHeight() + { + if($style=$this->getViewState('Style',null)) + return $style->getHeight(); + else + return ''; + } + public function setDisplay($value) + { + $this->getStyle()->setDisplayStyle($value); + } + public function getDisplay() + { + return $this->getStyle()->getDisplayStyle(); + } + public function setCssClass($value) + { + $this->getStyle()->setCssClass($value); + } + public function getCssClass() + { + if($style=$this->getViewState('Style',null)) + return $style->getCssClass(); + else + return ''; + } + public function setHeight($value) + { + $this->getStyle()->setHeight($value); + } + public function getHasStyle() + { + return $this->getViewState('Style',null)!==null; + } + protected function createStyle() + { + return new TStyle; + } + public function getStyle() + { + if($style=$this->getViewState('Style',null)) + return $style; + else + { + $style=$this->createStyle(); + $this->setViewState('Style',$style,null); + return $style; + } + } + public function setStyle($value) + { + if(is_string($value)) + $this->getStyle()->setCustomStyle($value); + else + throw new TInvalidDataValueException('webcontrol_style_invalid',get_class($this)); + } + public function clearStyle() + { + $this->clearViewState('Style'); + } + public function getTabIndex() + { + return $this->getViewState('TabIndex',0); + } + public function setTabIndex($value) + { + $this->setViewState('TabIndex',TPropertyValue::ensureInteger($value),0); + } + protected function getTagName() + { + return 'span'; + } + public function getToolTip() + { + return $this->getViewState('ToolTip',''); + } + public function setToolTip($value) + { + $this->setViewState('ToolTip',$value,''); + } + public function getWidth() + { + if($style=$this->getViewState('Style',null)) + return $style->getWidth(); + else + return ''; + } + public function setWidth($value) + { + $this->getStyle()->setWidth($value); + } + protected function addAttributesToRender($writer) + { + if($this->getID()!=='') + $writer->addAttribute('id',$this->getClientID()); + if(($accessKey=$this->getAccessKey())!=='') + $writer->addAttribute('accesskey',$accessKey); + if(!$this->getEnabled()) + $writer->addAttribute('disabled','disabled'); + if(($tabIndex=$this->getTabIndex())>0) + $writer->addAttribute('tabindex',"$tabIndex"); + if(($toolTip=$this->getToolTip())!=='') + $writer->addAttribute('title',$toolTip); + if($style=$this->getViewState('Style',null)) + $style->addAttributesToRender($writer); + if($this->getHasAttributes()) + { + foreach($this->getAttributes() as $name=>$value) + $writer->addAttribute($name,$value); + } + } + public function render($writer) + { + $this->renderBeginTag($writer); + $this->renderContents($writer); + $this->renderEndTag($writer); + } + public function renderBeginTag($writer) + { + $this->addAttributesToRender($writer); + $writer->renderBeginTag($this->getTagName()); + } + public function renderContents($writer) + { + parent::renderChildren($writer); + } + public function renderEndTag($writer) + { + $writer->renderEndTag(); + } +} +class TCompositeControl extends TControl implements INamingContainer +{ + protected function initRecursive($namingContainer=null) + { + $this->ensureChildControls(); + parent::initRecursive($namingContainer); + } +} +class TTemplateControl extends TCompositeControl +{ + const EXT_TEMPLATE='.tpl'; + private static $_template=array(); + private $_localTemplate=null; + private $_master=null; + private $_masterClass=''; + private $_contents=array(); + private $_placeholders=array(); + public function getTemplate() + { + if($this->_localTemplate===null) + { + $class=get_class($this); + if(!isset(self::$_template[$class])) + self::$_template[$class]=$this->loadTemplate(); + return self::$_template[$class]; + } + else + return $this->_localTemplate; + } + public function setTemplate($value) + { + $this->_localTemplate=$value; + } + public function getIsSourceTemplateControl() + { + if(($template=$this->getTemplate())!==null) + return $template->getIsSourceTemplate(); + else + return false; + } + public function getTemplateDirectory() + { + if(($template=$this->getTemplate())!==null) + return $template->getContextPath(); + else + return ''; + } + protected function loadTemplate() + { + $template=$this->getService()->getTemplateManager()->getTemplateByClassName(get_class($this)); + return $template; + } + public function createChildControls() + { + if($tpl=$this->getTemplate()) + { + foreach($tpl->getDirective() as $name=>$value) + { + if(is_string($value)) + $this->setSubProperty($name,$value); + else + throw new TConfigurationException('templatecontrol_directive_invalid',get_class($this),$name); + } + $tpl->instantiateIn($this); + } + } + public function registerContent($id,TContent $object) + { + if(isset($this->_contents[$id])) + throw new TConfigurationException('templatecontrol_contentid_duplicated',$id); + else + $this->_contents[$id]=$object; + } + public function registerContentPlaceHolder($id,TContentPlaceHolder $object) + { + if(isset($this->_placeholders[$id])) + throw new TConfigurationException('templatecontrol_placeholderid_duplicated',$id); + else + $this->_placeholders[$id]=$object; + } + public function getMasterClass() + { + return $this->_masterClass; + } + public function setMasterClass($value) + { + $this->_masterClass=$value; + } + public function getMaster() + { + return $this->_master; + } + public function injectContent($id,$content) + { + if(isset($this->_placeholders[$id])) + { + $placeholder=$this->_placeholders[$id]; + $controls=$placeholder->getParent()->getControls(); + $loc=$controls->remove($placeholder); + $controls->insertAt($loc,$content); + } + else + throw new TConfigurationException('templatecontrol_placeholder_inexistent',$id); + } + protected function initRecursive($namingContainer=null) + { + $this->ensureChildControls(); + if($this->_masterClass!=='') + { + $master=Prado::createComponent($this->_masterClass); + if(!($master instanceof TTemplateControl)) + throw new TInvalidDataValueException('templatecontrol_mastercontrol_invalid'); + $this->_master=$master; + $this->getControls()->clear(); + $this->getControls()->add($master); + $master->ensureChildControls(); + foreach($this->_contents as $id=>$content) + $master->injectContent($id,$content); + } + else if(!empty($this->_contents)) + throw new TConfigurationException('templatecontrol_mastercontrol_required',get_class($this)); + parent::initRecursive($namingContainer); + } +} +class TForm extends TControl +{ + public function onInit($param) + { + parent::onInit($param); + $this->getPage()->setForm($this); + } + protected function addAttributesToRender($writer) + { + $writer->addAttribute('id',$this->getClientID()); + $writer->addAttribute('method',$this->getMethod()); + $uri=$this->getRequest()->getRequestURI(); + $writer->addAttribute('action',str_replace('&','&',str_replace('&','&',$uri))); + if(($enctype=$this->getEnctype())!=='') + $writer->addAttribute('enctype',$enctype); + $attributes=$this->getAttributes(); + $attributes->remove('action'); + $writer->addAttributes($attributes); + if(($butt=$this->getDefaultButton())!=='') + { + if(($button=$this->findControl($butt))!==null) + $this->getPage()->getClientScript()->registerDefaultButton($this, $button); + else + throw new TInvalidDataValueException('form_defaultbutton_invalid',$butt); + } + } + public function render($writer) + { + $page=$this->getPage(); + $page->beginFormRender($writer); + $textWriter=new TTextWriter; + $this->renderChildren(new THtmlWriter($textWriter)); + $content=$textWriter->flush(); + $page->endFormRender($writer); + $this->addAttributesToRender($writer); + $writer->renderBeginTag('form'); + $cs=$page->getClientScript(); + if($page->getClientSupportsJavaScript()) + { + $cs->renderHiddenFields($writer); + $cs->renderScriptFiles($writer); + $cs->renderBeginScripts($writer); + $writer->write($content); + $cs->renderEndScripts($writer); + } + else + { + $cs->renderHiddenFields($writer); + $writer->write($content); + } + $writer->renderEndTag(); + } + public function getDefaultButton() + { + return $this->getViewState('DefaultButton',''); + } + public function setDefaultButton($value) + { + $this->setViewState('DefaultButton',$value,''); + } + public function getMethod() + { + return $this->getViewState('Method','post'); + } + public function setMethod($value) + { + $this->setViewState('Method',TPropertyValue::ensureEnum($value,'post','get'),'post'); + } + public function getEnctype() + { + return $this->getViewState('Enctype',''); + } + public function setEnctype($value) + { + $this->setViewState('Enctype',$value,''); + } + public function getName() + { + return $this->getUniqueID(); + } +} +class TClientScriptManager extends TApplicationComponent +{ + const SCRIPT_PATH='Web/Javascripts/source'; + const SCRIPT_LOADER='Web/Javascripts/clientscripts.php'; + private $_page; + private $_hiddenFields=array(); + private $_beginScripts=array(); + private $_endScripts=array(); + private $_scriptFiles=array(); + private $_headScriptFiles=array(); + private $_headScripts=array(); + private $_styleSheetFiles=array(); + private $_styleSheets=array(); + private $_registeredPradoScripts=array(); + private static $_pradoScripts; + private static $_pradoPackages; + public function __construct(TPage $owner) + { + $this->_page=$owner; + } + public function getRequiresHead() + { + return count($this->_styleSheetFiles) || count($this->_styleSheets) + || count($this->_headScriptFiles) || count($this->_headScripts); + } + public function registerPradoScript($name) + { + $this->registerPradoScriptInternal($name); + $params=func_get_args(); + $this->_page->registerCachingAction('Page.ClientScript','registerPradoScript',$params); + } + private function registerPradoScriptInternal($name) + { + if(!isset($this->_registeredPradoScripts[$name])) + { + if(self::$_pradoScripts === null) + { + $packageFile = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::SCRIPT_PATH.'/packages.php'; + list($packages,$deps)= include($packageFile); + self::$_pradoScripts = $deps; + self::$_pradoPackages = $packages; + } + if(isset(self::$_pradoScripts[$name])) + $this->_registeredPradoScripts[$name]=true; + else + throw new TInvalidOperationException('csmanager_pradoscript_invalid',$name); + } + } + public function getPradoScriptAssetUrl() + { + $base = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::SCRIPT_PATH; + $assets = Prado::getApplication()->getAssetManager(); + return $assets->getPublishedUrl($base); + } + protected function renderPradoScripts($writer) + { + if(($packages=array_keys($this->_registeredPradoScripts))!==array()) + { + if (Prado::getApplication()->getMode()!==TApplicationMode::Debug) + { + $base = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::SCRIPT_PATH; + $url = $this->registerJavascriptPackages($base, $packages); + $writer->write(TJavaScript::renderScriptFile($url)); + } + else + { + $base = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::SCRIPT_PATH; + list($path,$baseUrl)=$this->getPackagePathUrl($base); + $packagesUrl=array(); + foreach ($packages as $p) + { + foreach (self::$_pradoScripts[$p] as $dep) + { + foreach (self::$_pradoPackages[$dep] as $script) + { + if (!in_array($url=$baseUrl.'/'.$script,$packagesUrl)) + $packagesUrl[]=$url; + } + } + } + $writer->write(TJavaScript::renderScriptFiles($packagesUrl)); + } + } + } + public function registerJavascriptPackages($base, $packages, $debug=null, $gzip=true) + { + list($path,$url) = $this->getPackagePathUrl($base); + $scriptLoaderPath = $path.'/'.basename(self::SCRIPT_LOADER); + $scriptLoaderSrc = Prado::getFrameworkPath().DIRECTORY_SEPARATOR.self::SCRIPT_LOADER; + if(!is_file($scriptLoaderPath)) + { + copy($scriptLoaderSrc, $scriptLoaderPath); + chmod($scriptLoaderPath, PRADO_CHMOD); + } + $url .= '/'.basename(self::SCRIPT_LOADER).'?js='.implode(',', $packages); + if($debug!==false && $this->getApplication()->getMode()===TApplicationMode::Debug) + { + $this->verifyJavascriptPackages($base,$path,$packages); + $url.='&mode=debug'; + } + if($gzip===false) + $url.='&gzip=false'; + return $url; + } + protected function verifyJavascriptPackages($base,$path,$scripts) + { + $file = $path.'/packages.php'; + if(is_file($file)) + { + list($packs,$deps) = include($file); + if(count($missing = array_diff($scripts, array_keys($deps))) > 0) + { + throw new TConfigurationException('csmanager_invalid_packages', + $base.'/packages.php',implode(', ', $missing), implode(', ', array_keys($deps))); + } + } + } + protected function getPackagePathUrl($base) + { + $assets = Prado::getApplication()->getAssetManager(); + if(strpos($base, $assets->getBaseUrl())===false) + { + if(($dir = Prado::getPathOfNameSpace($base)) !== null) { + $base = $dir; + } + return array($assets->getPublishedPath($base), $assets->publishFilePath($base)); + } + else + { + return array($assets->getBasePath().str_replace($assets->getBaseUrl(),'',$base), $base); + } + } + public function getCallbackReference(ICallbackEventHandler $callbackHandler, $options=null) + { + $options = !is_array($options) ? array() : $options; + $class = new TReflectionClass($callbackHandler); + $clientSide = $callbackHandler->getActiveControl()->getClientSide(); + $options = array_merge($options, $clientSide->getOptions()->toArray()); + $optionString = TJavaScript::encode($options); + $this->registerPradoScriptInternal('ajax'); + $id = $callbackHandler->getUniqueID(); + return "new Prado.CallbackRequest('{$id}',{$optionString})"; + } + public function registerCallbackControl($class, $options) + { + $optionString=TJavaScript::encode($options); + $code="new {$class}({$optionString});"; + $this->_endScripts[sprintf('%08X', crc32($code))]=$code; + $this->registerPradoScriptInternal('ajax'); + $params=func_get_args(); + $this->_page->registerCachingAction('Page.ClientScript','registerCallbackControl',$params); + } + public function registerPostBackControl($class,$options) + { + if($class === null) { + return; + } + if(!isset($options['FormID']) && ($form=$this->_page->getForm())!==null) + $options['FormID']=$form->getClientID(); + $optionString=TJavaScript::encode($options); + $code="new {$class}({$optionString});"; + $this->_endScripts[sprintf('%08X', crc32($code))]=$code; + $this->_hiddenFields[TPage::FIELD_POSTBACK_TARGET]=''; + $this->_hiddenFields[TPage::FIELD_POSTBACK_PARAMETER]=''; + $this->registerPradoScriptInternal('prado'); + $params=func_get_args(); + $this->_page->registerCachingAction('Page.ClientScript','registerPostBackControl',$params); + } + public function registerDefaultButton($panel, $button) + { + $panelID=is_string($panel)?$panel:$panel->getUniqueID(); + if(is_string($button)) + $buttonID=$button; + else + { + $button->setIsDefaultButton(true); + $buttonID=$button->getUniqueID(); + } + $options = TJavaScript::encode($this->getDefaultButtonOptions($panelID, $buttonID)); + $code = "new Prado.WebUI.DefaultButton($options);"; + $this->_endScripts['prado:'.$panelID]=$code; + $this->_hiddenFields[TPage::FIELD_POSTBACK_TARGET]=''; + $this->registerPradoScriptInternal('prado'); + $params=array($panelID,$buttonID); + $this->_page->registerCachingAction('Page.ClientScript','registerDefaultButton',$params); + } + protected function getDefaultButtonOptions($panelID, $buttonID) + { + $options['Panel'] = TControl::convertUniqueIdToClientId($panelID); + $options['Target'] = TControl::convertUniqueIdToClientId($buttonID); + $options['EventTarget'] = $buttonID; + $options['Event'] = 'click'; + return $options; + } + public function registerFocusControl($target) + { + $this->registerPradoScriptInternal('effects'); + if($target instanceof TControl) + $target=$target->getClientID(); + $id = TJavaScript::quoteString($target); + $this->_endScripts['prado:focus'] = 'new Effect.ScrollTo("'.$id.'"); Prado.Element.focus("'.$id.'");'; + $params=func_get_args(); + $this->_page->registerCachingAction('Page.ClientScript','registerFocusControl',$params); + } + public function registerStyleSheetFile($key,$url,$media='') + { + if($media==='') + $this->_styleSheetFiles[$key]=$url; + else + $this->_styleSheetFiles[$key]=array($url,$media); + $params=func_get_args(); + $this->_page->registerCachingAction('Page.ClientScript','registerStyleSheetFile',$params); + } + public function registerStyleSheet($key,$css,$media='') + { + $this->_styleSheets[$key]=$css; + $params=func_get_args(); + $this->_page->registerCachingAction('Page.ClientScript','registerStyleSheet',$params); + } + public function registerHeadScriptFile($key,$url) + { + $this->_headScriptFiles[$key]=$url; + $params=func_get_args(); + $this->_page->registerCachingAction('Page.ClientScript','registerHeadScriptFile',$params); + } + public function registerHeadScript($key,$script) + { + $this->_headScripts[$key]=$script; + $params=func_get_args(); + $this->_page->registerCachingAction('Page.ClientScript','registerHeadScript',$params); + } + public function registerScriptFile($key,$url) + { + $this->_scriptFiles[$key]=$url; + $params=func_get_args(); + $this->_page->registerCachingAction('Page.ClientScript','registerScriptFile',$params); + } + public function registerBeginScript($key,$script) + { + $this->_beginScripts[$key]=$script; + $params=func_get_args(); + $this->_page->registerCachingAction('Page.ClientScript','registerBeginScript',$params); + } + public function registerEndScript($key,$script) + { + $this->_endScripts[$key]=$script; + $params=func_get_args(); + $this->_page->registerCachingAction('Page.ClientScript','registerEndScript',$params); + } + public function registerHiddenField($name,$value) + { + $this->_hiddenFields[$name]=$value; + $params=func_get_args(); + $this->_page->registerCachingAction('Page.ClientScript','registerHiddenField',$params); + } + public function isStyleSheetFileRegistered($key) + { + return isset($this->_styleSheetFiles[$key]); + } + public function isStyleSheetRegistered($key) + { + return isset($this->_styleSheets[$key]); + } + public function isHeadScriptFileRegistered($key) + { + return isset($this->_headScriptFiles[$key]); + } + public function isHeadScriptRegistered($key) + { + return isset($this->_headScripts[$key]); + } + public function isScriptFileRegistered($key) + { + return isset($this->_scriptFiles[$key]); + } + public function isBeginScriptRegistered($key) + { + return isset($this->_beginScripts[$key]); + } + public function isEndScriptRegistered($key) + { + return isset($this->_endScripts[$key]); + } + public function hasEndScripts() + { + return count($this->_endScripts) > 0; + } + public function hasBeginScripts() + { + return count($this->_beginScripts) > 0; + } + public function isHiddenFieldRegistered($key) + { + return isset($this->_hiddenFields[$key]); + } + public function renderStyleSheetFiles($writer) + { + $str=''; + foreach($this->_styleSheetFiles as $url) + { + if(is_array($url)) + $str.="\n"; + else + $str.="\n"; + } + $writer->write($str); + } + public function renderStyleSheets($writer) + { + if(count($this->_styleSheets)) + $writer->write("\n"); + } + public function renderHeadScriptFiles($writer) + { + $writer->write(TJavaScript::renderScriptFiles($this->_headScriptFiles)); + } + public function renderHeadScripts($writer) + { + $writer->write(TJavaScript::renderScriptBlocks($this->_headScripts)); + } + public function renderScriptFiles($writer) + { + $this->renderPradoScripts($writer); + if(!empty($this->_scriptFiles)) + $writer->write(TJavaScript::renderScriptFiles($this->_scriptFiles)); + } + public function renderBeginScripts($writer) + { + $writer->write(TJavaScript::renderScriptBlocks($this->_beginScripts)); + } + public function renderEndScripts($writer) + { + $writer->write(TJavaScript::renderScriptBlocks($this->_endScripts)); + } + public function renderHiddenFields($writer) + { + $str=''; + foreach($this->_hiddenFields as $name=>$value) + { + $id=strtr($name,':','_'); + if(is_array($value)) + { + foreach($value as $v) + $str.='\n"; + } + else + { + $str.='\n"; + } + } + if($str!=='') + $writer->write("
\n".$str."
\n"); + } +} +abstract class TClientSideOptions extends TComponent +{ + private $_options; + public function __construct() + { + $this->_options = Prado::createComponent('System.Collections.TMap'); + } + protected function setFunction($name, $code) + { + if(!TJavaScript::isFunction($code)) + $code = TJavaScript::quoteFunction($this->ensureFunction($code)); + $this->setOption($name, $code); + } + protected function getOption($name) + { + return $this->_options->itemAt($name); + } + protected function setOption($name, $value) + { + $this->_options->add($name, $value); + } + public function getOptions() + { + return $this->_options; + } + protected function ensureFunction($javascript) + { + return "function(sender, parameter){ {$javascript} }"; + } +} +class TPage extends TTemplateControl +{ + const FIELD_POSTBACK_TARGET='PRADO_POSTBACK_TARGET'; + const FIELD_POSTBACK_PARAMETER='PRADO_POSTBACK_PARAMETER'; + const FIELD_LASTFOCUS='PRADO_LASTFOCUS'; + const FIELD_PAGESTATE='PRADO_PAGESTATE'; + const FIELD_CALLBACK_TARGET='PRADO_CALLBACK_TARGET'; + const FIELD_CALLBACK_PARAMETER='PRADO_CALLBACK_PARAMETER'; + private static $_systemPostFields=array( + 'PRADO_POSTBACK_TARGET'=>true, + 'PRADO_POSTBACK_PARAMETER'=>true, + 'PRADO_LASTFOCUS'=>true, + 'PRADO_PAGESTATE'=>true, + 'PRADO_CALLBACK_TARGET'=>true, + 'PRADO_CALLBACK_PARAMETER'=>true + ); + private $_form; + private $_head; + private $_validators=array(); + private $_validated=false; + private $_theme; + private $_title; + private $_styleSheet; + private $_clientScript; + private $_postData; + private $_restPostData; + private $_controlsPostDataChanged=array(); + private $_controlsRequiringPostData=array(); + private $_controlsRegisteredForPostData=array(); + private $_postBackEventTarget; + private $_postBackEventParameter; + private $_formRendered=false; + private $_inFormRender=false; + private $_focus; + private $_pagePath=''; + private $_enableStateValidation=true; + private $_enableStateEncryption=false; + private $_statePersisterClass='System.Web.UI.TPageStatePersister'; + private $_statePersister; + private $_cachingStack; + private $_clientState=''; + private $_postDataLoaders=array(); + private $_isLoadingPostData=false; + private $_enableJavaScript=true; + public function __construct() + { + parent::__construct(); + $this->setPage($this); + } + public function run($writer) + { + $this->determinePostBackMode(); + if($this->getIsPostBack()) + { + if($this->getIsCallback()) + $this->processCallbackRequest($writer); + else + $this->processPostBackRequest($writer); + } + else + $this->processNormalRequest($writer); + } + protected function processNormalRequest($writer) + { + $this->onPreInit(null); + $this->initRecursive(); + $this->onInitComplete(null); + $this->onPreLoad(null); + $this->loadRecursive(); + $this->onLoadComplete(null); + $this->preRenderRecursive(); + $this->onPreRenderComplete(null); + $this->savePageState(); + $this->onSaveStateComplete(null); + $this->renderControl($writer); + $this->unloadRecursive(); + } + protected function processPostBackRequest($writer) + { + $this->onPreInit(null); + $this->initRecursive(); + $this->onInitComplete(null); + $this->_restPostData=new TMap; + $this->loadPageState(); + $this->processPostData($this->_postData,true); + $this->onPreLoad(null); + $this->loadRecursive(); + $this->processPostData($this->_restPostData,false); + $this->raiseChangedEvents(); + $this->raisePostBackEvent(); + $this->onLoadComplete(null); + $this->preRenderRecursive(); + $this->onPreRenderComplete(null); + $this->savePageState(); + $this->onSaveStateComplete(null); + $this->renderControl($writer); + $this->unloadRecursive(); + } + protected function processCallbackRequest($writer) + { + Prado::using('System.Web.UI.ActiveControls.TActivePageAdapter'); + $this->setAdapter(new TActivePageAdapter($this)); + if (($g=$this->getApplication()->getGlobalization(false))!==null && + strtoupper($enc=$g->getCharset())!='UTF-8') + foreach ($this->_postData as $k=>$v) + $this->_postData[$k]=iconv('UTF-8',$enc.'//IGNORE',$v); + $this->onPreInit(null); + $this->initRecursive(); + $this->onInitComplete(null); + $this->_restPostData=new TMap; + $this->loadPageState(); + $this->processPostData($this->_postData,true); + $this->onPreLoad(null); + $this->loadRecursive(); + $this->processPostData($this->_restPostData,false); + $this->raiseChangedEvents(); + $this->getAdapter()->processCallbackEvent($writer); + $this->onLoadComplete(null); + $this->preRenderRecursive(); + $this->onPreRenderComplete(null); + $this->savePageState(); + $this->onSaveStateComplete(null); + $this->getAdapter()->renderCallbackResponse($writer); + $this->unloadRecursive(); + } + public function getCallbackClient() + { + if($this->getAdapter() !== null) + return $this->getAdapter()->getCallbackClientHandler(); + else + return new TCallbackClientScript(); + } + public function setCallbackClient($client) + { + $this->getAdapter()->setCallbackClientHandler($client); + } + public function getCallbackEventTarget() + { + return $this->getAdapter()->getCallbackEventTarget(); + } + public function setCallbackEventTarget(TControl $control) + { + $this->getAdapter()->setCallbackEventTarget($control); + } + public function getCallbackEventParameter() + { + return $this->getAdapter()->getCallbackEventParameter(); + } + public function setCallbackEventParameter($value) + { + $this->getAdapter()->setCallbackEventParameter($value); + } + public function registerPostDataLoader($control) + { + $id=is_string($control)?$control:$control->getUniqueID(); + $this->_postDataLoaders[$id] = true; + } + public function getPostDataLoaders() + { + return array_keys($this->_postDataLoaders); + } + public function getForm() + { + return $this->_form; + } + public function setForm(TForm $form) + { + if($this->_form===null) + $this->_form=$form; + else + throw new TInvalidOperationException('page_form_duplicated'); + } + public function getValidators($validationGroup=null) + { + if(!$this->_validators) + $this->_validators=new TList; + if($validationGroup===null) + return $this->_validators; + else + { + $list=new TList; + foreach($this->_validators as $validator) + if($validator->getValidationGroup()===$validationGroup) + $list->add($validator); + return $list; + } + } + public function validate($validationGroup=null) + { + $this->_validated=true; + if($this->_validators && $this->_validators->getCount()) + { + if($validationGroup===null) + { + foreach($this->_validators as $validator) + $validator->validate(); + } + else + { + foreach($this->_validators as $validator) + { + if($validator->getValidationGroup()===$validationGroup) + $validator->validate(); + } + } + } + } + public function getIsValid() + { + if($this->_validated) + { + if($this->_validators && $this->_validators->getCount()) + { + foreach($this->_validators as $validator) + if(!$validator->getIsValid()) + return false; + } + return true; + } + else + throw new TInvalidOperationException('page_isvalid_unknown'); + } + public function getTheme() + { + if(is_string($this->_theme)) + $this->_theme=$this->getService()->getThemeManager()->getTheme($this->_theme); + return $this->_theme; + } + public function setTheme($value) + { + $this->_theme=empty($value)?null:$value; + } + public function getStyleSheetTheme() + { + if(is_string($this->_styleSheet)) + $this->_styleSheet=$this->getService()->getThemeManager()->getTheme($this->_styleSheet); + return $this->_styleSheet; + } + public function setStyleSheetTheme($value) + { + $this->_styleSheet=empty($value)?null:$value; + } + public function applyControlSkin($control) + { + if(($theme=$this->getTheme())!==null) + $theme->applySkin($control); + } + public function applyControlStyleSheet($control) + { + if(($theme=$this->getStyleSheetTheme())!==null) + $theme->applySkin($control); + } + public function getClientScript() + { + if(!$this->_clientScript) + $this->_clientScript=new TClientScriptManager($this); + return $this->_clientScript; + } + public function onPreInit($param) + { + $this->raiseEvent('OnPreInit',$this,$param); + } + public function onInitComplete($param) + { + $this->raiseEvent('OnInitComplete',$this,$param); + } + public function onPreLoad($param) + { + $this->raiseEvent('OnPreLoad',$this,$param); + } + public function onLoadComplete($param) + { + $this->raiseEvent('OnLoadComplete',$this,$param); + } + public function onPreRenderComplete($param) + { + $this->raiseEvent('OnPreRenderComplete',$this,$param); + $cs=$this->getClientScript(); + $theme=$this->getTheme(); + if($theme instanceof ITheme) + { + foreach($theme->getStyleSheetFiles() as $url) + $cs->registerStyleSheetFile($url,$url,$this->getCssMediaType($url)); + foreach($theme->getJavaScriptFiles() as $url) + $cs->registerHeadScriptFile($url,$url); + } + $styleSheet=$this->getStyleSheetTheme(); + if($styleSheet instanceof ITheme) + { + foreach($styleSheet->getStyleSheetFiles() as $url) + $cs->registerStyleSheetFile($url,$url,$this->getCssMediaType($url)); + foreach($styleSheet->getJavaScriptFiles() as $url) + $cs->registerHeadScriptFile($url,$url); + } + if($cs->getRequiresHead() && $this->getHead()===null) + throw new TConfigurationException('page_head_required'); + } + private function getCssMediaType($url) + { + $segs=explode('.',basename($url)); + if(isset($segs[2])) + return $segs[count($segs)-2]; + else + return ''; + } + public function onSaveStateComplete($param) + { + $this->raiseEvent('OnSaveStateComplete',$this,$param); + } + private function determinePostBackMode() + { + $postData=$this->getRequest(); + if($postData->contains(self::FIELD_PAGESTATE) || $postData->contains(self::FIELD_POSTBACK_TARGET)) + $this->_postData=$postData; + } + public function getIsPostBack() + { + return $this->_postData!==null; + } + public function getIsCallback() + { + return $this->getIsPostBack() && $this->getRequest()->contains(self::FIELD_CALLBACK_TARGET); + } + public function saveState() + { + parent::saveState(); + $this->setViewState('ControlsRequiringPostBack',$this->_controlsRegisteredForPostData,array()); + } + public function loadState() + { + parent::loadState(); + $this->_controlsRequiringPostData=$this->getViewState('ControlsRequiringPostBack',array()); + } + protected function loadPageState() + { + $state=$this->getStatePersister()->load(); + $this->loadStateRecursive($state,$this->getEnableViewState()); + } + protected function savePageState() + { + $state=&$this->saveStateRecursive($this->getEnableViewState()); + $this->getStatePersister()->save($state); + } + protected function isSystemPostField($field) + { + return isset(self::$_systemPostFields[$field]); + } + public function registerRequiresPostData($control) + { + $id=is_string($control)?$control:$control->getUniqueID(); + $this->_controlsRegisteredForPostData[$id]=true; + $this->registerPostDataLoader($id); + $params=func_get_args(); + foreach($this->getCachingStack() as $item) + $item->registerAction('Page','registerRequiresPostData',$id); + } + public function getPostBackEventTarget() + { + if($this->_postBackEventTarget===null && $this->_postData!==null) + { + $eventTarget=$this->_postData->itemAt(self::FIELD_POSTBACK_TARGET); + if(!empty($eventTarget)) + $this->_postBackEventTarget=$this->findControl($eventTarget); + } + return $this->_postBackEventTarget; + } + public function setPostBackEventTarget(TControl $control) + { + $this->_postBackEventTarget=$control; + } + public function getPostBackEventParameter() + { + if($this->_postBackEventParameter===null && $this->_postData!==null) + { + if(($this->_postBackEventParameter=$this->_postData->itemAt(self::FIELD_POSTBACK_PARAMETER))===null) + $this->_postBackEventParameter=''; + } + return $this->_postBackEventParameter; + } + public function setPostBackEventParameter($value) + { + $this->_postBackEventParameter=$value; + } + protected function processPostData($postData,$beforeLoad) + { + $this->_isLoadingPostData=true; + if($beforeLoad) + $this->_restPostData=new TMap; + foreach($postData as $key=>$value) + { + if($this->isSystemPostField($key)) + continue; + else if($control=$this->findControl($key)) + { + if($control instanceof IPostBackDataHandler) + { + if($control->loadPostData($key,$postData)) + $this->_controlsPostDataChanged[]=$control; + } + else if($control instanceof IPostBackEventHandler && + empty($this->_postData[self::FIELD_POSTBACK_TARGET])) + { + $this->_postData->add(self::FIELD_POSTBACK_TARGET,$key); + } + unset($this->_controlsRequiringPostData[$key]); + } + else if($beforeLoad) + $this->_restPostData->add($key,$value); + } + foreach($this->_controlsRequiringPostData as $key=>$value) + { + if($control=$this->findControl($key)) + { + if($control instanceof IPostBackDataHandler) + { + if($control->loadPostData($key,$this->_postData)) + $this->_controlsPostDataChanged[]=$control; + } + else + throw new TInvalidDataValueException('page_postbackcontrol_invalid',$key); + unset($this->_controlsRequiringPostData[$key]); + } + } + $this->_isLoadingPostData=false; + } + public function getIsLoadingPostData() + { + return $this->_isLoadingPostData; + } + private function raiseChangedEvents() + { + foreach($this->_controlsPostDataChanged as $control) + $control->raisePostDataChangedEvent(); + } + private function raisePostBackEvent() + { + if(($postBackHandler=$this->getPostBackEventTarget())===null) + $this->validate(); + else if($postBackHandler instanceof IPostBackEventHandler) + $postBackHandler->raisePostBackEvent($this->getPostBackEventParameter()); + } + public function ensureRenderInForm($control) + { + if(!$this->getIsCallback() && !$this->_inFormRender) + throw new TConfigurationException('page_control_outofform',get_class($control),$control->getUniqueID()); + } + public function beginFormRender($writer) + { + if($this->_formRendered) + throw new TConfigurationException('page_form_duplicated'); + $this->_formRendered=true; + $this->_inFormRender=true; + $this->getClientScript()->registerHiddenField(self::FIELD_PAGESTATE,$this->getClientState()); + } + public function endFormRender($writer) + { + if($this->_focus) + { + if(($this->_focus instanceof TControl) && $this->_focus->getVisible(true)) + $focus=$this->_focus->getClientID(); + else + $focus=$this->_focus; + $this->getClientScript()->registerFocusControl($focus); + } + else if($this->_postData && ($lastFocus=$this->_postData->itemAt(self::FIELD_LASTFOCUS))!==null) + $this->getClientScript()->registerFocusControl($lastFocus); + $this->_inFormRender=false; + } + public function setFocus($value) + { + $this->_focus=$value; + } + public function getClientSupportsJavaScript() + { + return $this->_enableJavaScript; + } + public function setClientSupportsJavaScript($value) + { + $this->_enableJavaScript=TPropertyValue::ensureBoolean($value); + } + public function getHead() + { + return $this->_head; + } + public function setHead(THead $value) + { + if($this->_head) + throw new TInvalidOperationException('page_head_duplicated'); + $this->_head=$value; + if($this->_title!==null) + { + $this->_head->setTitle($this->_title); + $this->_title=null; + } + } + public function getTitle() + { + if($this->_head) + return $this->_head->getTitle(); + else + return $this->_title===null ? '' : $this->_title; + } + public function setTitle($value) + { + if($this->_head) + $this->_head->setTitle($value); + else + $this->_title=$value; + } + public function getClientState() + { + return $this->_clientState; + } + public function setClientState($state) + { + $this->_clientState=$state; + } + public function getRequestClientState() + { + return $this->getRequest()->itemAt(self::FIELD_PAGESTATE); + } + public function getStatePersisterClass() + { + return $this->_statePersisterClass; + } + public function setStatePersisterClass($value) + { + $this->_statePersisterClass=$value; + } + public function getStatePersister() + { + if($this->_statePersister===null) + { + $this->_statePersister=Prado::createComponent($this->_statePersisterClass); + if(!($this->_statePersister instanceof IPageStatePersister)) + throw new TInvalidDataTypeException('page_statepersister_invalid'); + $this->_statePersister->setPage($this); + } + return $this->_statePersister; + } + public function getEnableStateValidation() + { + return $this->_enableStateValidation; + } + public function setEnableStateValidation($value) + { + $this->_enableStateValidation=TPropertyValue::ensureBoolean($value); + } + public function getEnableStateEncryption() + { + return $this->_enableStateEncryption; + } + public function setEnableStateEncryption($value) + { + $this->_enableStateEncryption=TPropertyValue::ensureBoolean($value); + } + public function getPagePath() + { + return $this->_pagePath; + } + public function setPagePath($value) + { + $this->_pagePath=$value; + } + public function registerCachingAction($context,$funcName,$funcParams) + { + if($this->_cachingStack) + { + foreach($this->_cachingStack as $cache) + $cache->registerAction($context,$funcName,$funcParams); + } + } + public function getCachingStack() + { + if(!$this->_cachingStack) + $this->_cachingStack=new TStack; + return $this->_cachingStack; + } +} +interface IPageStatePersister +{ + public function getPage(); + public function setPage(TPage $page); + public function save($state); + public function load(); +} +class TPageStateFormatter +{ + public static function serialize($page,$data) + { + $sm=$page->getApplication()->getSecurityManager(); + if($page->getEnableStateValidation()) + $str=$sm->hashData(Prado::serialize($data)); + else + $str=Prado::serialize($data); + if(extension_loaded('zlib')) + $str=gzcompress($str); + if($page->getEnableStateEncryption()) + $str=$sm->encrypt($str); + return base64_encode($str); + } + public static function unserialize($page,$data) + { + $str=base64_decode($data); + if($str==='') + return null; + if($str!==false) + { + $sm=$page->getApplication()->getSecurityManager(); + if($page->getEnableStateEncryption()) + $str=$sm->decrypt($str); + if(extension_loaded('zlib')) + $str=@gzuncompress($str); + if($page->getEnableStateValidation()) + { + if(($str=$sm->validateData($str))!==false) + return Prado::unserialize($str); + } + else + return $str; + } + return null; + } +} +class TOutputCache extends TControl implements INamingContainer +{ + const CACHE_ID_PREFIX='prado:outputcache'; + private $_cacheModuleID=''; + private $_dataCached=false; + private $_cacheAvailable=false; + private $_cacheChecked=false; + private $_cacheKey=null; + private $_duration=60; + private $_cache=null; + private $_contents; + private $_state; + private $_actions=array(); + private $_varyByParam=''; + private $_keyPrefix=''; + private $_varyBySession=false; + private $_cachePostBack=false; + private $_cacheTime=0; + public function getAllowChildControls() + { + $this->determineCacheability(); + return !$this->_dataCached; + } + private function determineCacheability() + { + if(!$this->_cacheChecked) + { + $this->_cacheChecked=true; + if($this->_duration>0 && ($this->_cachePostBack || !$this->getPage()->getIsPostBack())) + { + if($this->_cacheModuleID!=='') + { + $this->_cache=$this->getApplication()->getModule($this->_cacheModuleID); + if(!($this->_cache instanceof ICache)) + throw new TConfigurationException('outputcache_cachemoduleid_invalid',$this->_cacheModuleID); + } + else + $this->_cache=$this->getApplication()->getCache(); + if($this->_cache!==null) + { + $this->_cacheAvailable=true; + $data=$this->_cache->get($this->getCacheKey()); + if(is_array($data)) + { + $param=new TOutputCacheCheckDependencyEventParameter; + $param->setCacheTime(isset($data[3])?$data[3]:0); + $this->onCheckDependency($param); + $this->_dataCached=$param->getIsValid(); + } + else + $this->_dataCached=false; + if($this->_dataCached) + list($this->_contents,$this->_state,$this->_actions,$this->_cacheTime)=$data; + } + } + } + } + protected function initRecursive($namingContainer=null) + { + if($this->_cacheAvailable && !$this->_dataCached) + { + $stack=$this->getPage()->getCachingStack(); + $stack->push($this); + parent::initRecursive($namingContainer); + $stack->pop(); + } + else + parent::initRecursive($namingContainer); + } + protected function loadRecursive() + { + if($this->_cacheAvailable && !$this->_dataCached) + { + $stack=$this->getPage()->getCachingStack(); + $stack->push($this); + parent::loadRecursive(); + $stack->pop(); + } + else + { + if($this->_dataCached) + $this->performActions(); + parent::loadRecursive(); + } + } + private function performActions() + { + $page=$this->getPage(); + $cs=$page->getClientScript(); + foreach($this->_actions as $action) + { + if($action[0]==='Page.ClientScript') + call_user_func_array(array($cs,$action[1]),$action[2]); + else if($action[0]==='Page') + call_user_func_array(array($page,$action[1]),$action[2]); + else + call_user_func_array(array($this->getSubProperty($action[0]),$action[1]),$action[2]); + } + } + protected function preRenderRecursive() + { + if($this->_cacheAvailable && !$this->_dataCached) + { + $stack=$this->getPage()->getCachingStack(); + $stack->push($this); + parent::preRenderRecursive(); + $stack->pop(); + } + else + parent::preRenderRecursive(); + } + protected function loadStateRecursive(&$state,$needViewState=true) + { + $st=unserialize($state); + parent::loadStateRecursive($st,$needViewState); + } + protected function &saveStateRecursive($needViewState=true) + { + if($this->_dataCached) + return $this->_state; + else + { + $st=parent::saveStateRecursive($needViewState); + $this->_state=serialize($st); + return $this->_state; + } + } + public function registerAction($context,$funcName,$funcParams) + { + $this->_actions[]=array($context,$funcName,$funcParams); + } + private function getCacheKey() + { + if($this->_cacheKey===null) + $this->_cacheKey=$this->calculateCacheKey(); + return $this->_cacheKey; + } + protected function calculateCacheKey() + { + $key=$this->getBaseCacheKey(); + if($this->_varyBySession) + $key.=$this->getSession()->getSessionID(); + if($this->_varyByParam!=='') + { + $params=array(); + $request=$this->getRequest(); + foreach(explode(',',$this->_varyByParam) as $name) + { + $name=trim($name); + $params[$name]=$request->itemAt($name); + } + $key.=serialize($params); + } + $param=new TOutputCacheCalculateKeyEventParameter; + $this->onCalculateKey($param); + $key.=$param->getCacheKey(); + return $key; + } + protected function getBaseCacheKey() + { + return self::CACHE_ID_PREFIX.$this->_keyPrefix.$this->getPage()->getPagePath().$this->getUniqueID(); + } + public function getCacheModuleID() + { + return $this->_cacheModuleID; + } + public function setCacheModuleID($value) + { + $this->_cacheModuleID=$value; + } + public function setCacheKeyPrefix($value) + { + $this->_keyPrefix=$value; + } + public function getCacheTime() + { + return $this->_cacheTime; + } + protected function getCacheDependency() + { + return null; + } + public function getContentCached() + { + return $this->_dataCached; + } + public function getDuration() + { + return $this->_duration; + } + public function setDuration($value) + { + if(($value=TPropertyValue::ensureInteger($value))<0) + throw new TInvalidDataValueException('outputcache_duration_invalid',get_class($this)); + $this->_duration=$value; + } + public function getVaryByParam() + { + return $this->_varyByParam; + } + public function setVaryByParam($value) + { + $this->_varyByParam=trim($value); + } + public function getVaryBySession() + { + return $this->_varyBySession; + } + public function setVaryBySession($value) + { + $this->_varyBySession=TPropertyValue::ensureBoolean($value); + } + public function getCachingPostBack() + { + return $this->_cachePostBack; + } + public function setCachingPostBack($value) + { + $this->_cachePostBack=TPropertyValue::ensureBoolean($value); + } + public function onCheckDependency($param) + { + $this->raiseEvent('OnCheckDependency',$this,$param); + } + public function onCalculateKey($param) + { + $this->raiseEvent('OnCalculateKey',$this,$param); + } + public function render($writer) + { + if($this->_dataCached) + $writer->write($this->_contents); + else if($this->_cacheAvailable) + { + $textWriter=new TTextWriter; + $stack=$this->getPage()->getCachingStack(); + $stack->push($this); + parent::render(new THtmlWriter($textWriter)); + $stack->pop(); + $content=$textWriter->flush(); + $data=array($content,$this->_state,$this->_actions,time()); + $this->_cache->set($this->getCacheKey(),$data,$this->getDuration(),$this->getCacheDependency()); + $writer->write($content); + } + else + parent::render($writer); + } +} +class TOutputCacheCheckDependencyEventParameter extends TEventParameter +{ + private $_isValid=true; + private $_cacheTime=0; + public function getIsValid() + { + return $this->_isValid; + } + public function setIsValid($value) + { + $this->_isValid=TPropertyValue::ensureBoolean($value); + } + public function getCacheTime() + { + return $this->_cacheTime; + } + public function setCacheTime($value) + { + $this->_cacheTime=TPropertyValue::ensureInteger($value); + } +} +class TOutputCacheCalculateKeyEventParameter extends TEventParameter +{ + private $_cacheKey=''; + public function getCacheKey() + { + return $this->_cacheKey; + } + public function setCacheKey($value) + { + $this->_cacheKey=TPropertyValue::ensureString($value); + } +} +class TTemplateManager extends TModule +{ + const TEMPLATE_FILE_EXT='.tpl'; + const TEMPLATE_CACHE_PREFIX='prado:template:'; + public function init($config) + { + $this->getService()->setTemplateManager($this); + } + public function getTemplateByClassName($className) + { + $class=new ReflectionClass($className); + $tplFile=dirname($class->getFileName()).DIRECTORY_SEPARATOR.$className.self::TEMPLATE_FILE_EXT; + return $this->getTemplateByFileName($tplFile); + } + public function getTemplateByFileName($fileName) + { + if(($fileName=$this->getLocalizedTemplate($fileName))!==null) + { + if(($cache=$this->getApplication()->getCache())===null) + return new TTemplate(file_get_contents($fileName),dirname($fileName),$fileName); + else + { + $array=$cache->get(self::TEMPLATE_CACHE_PREFIX.$fileName); + if(is_array($array)) + { + list($template,$timestamps)=$array; + if($this->getApplication()->getMode()===TApplicationMode::Performance) + return $template; + $cacheValid=true; + foreach($timestamps as $tplFile=>$timestamp) + { + if(!is_file($tplFile) || filemtime($tplFile)>$timestamp) + { + $cacheValid=false; + break; + } + } + if($cacheValid) + return $template; + } + $template=new TTemplate(file_get_contents($fileName),dirname($fileName),$fileName); + $includedFiles=$template->getIncludedFiles(); + $timestamps=array(); + $timestamps[$fileName]=filemtime($fileName); + foreach($includedFiles as $includedFile) + $timestamps[$includedFile]=filemtime($includedFile); + $cache->set(self::TEMPLATE_CACHE_PREFIX.$fileName,array($template,$timestamps)); + return $template; + } + } + else + return null; + } + protected function getLocalizedTemplate($filename) + { + if(($app=$this->getApplication()->getGlobalization(false))===null) + return is_file($filename)?$filename:null; + foreach($app->getLocalizedResource($filename) as $file) + { + if(($file=realpath($file))!==false && is_file($file)) + return $file; + } + return null; + } +} +class TTemplate extends TApplicationComponent implements ITemplate +{ + const REGEX_RULES='/||<\/?com:([\w\.]+)((?:\s*[\w\.]+\s*=\s*\'.*?\'|\s*[\w\.]+\s*=\s*".*?"|\s*[\w\.]+\s*=\s*<%.*?%>)*)\s*\/?>|<\/?prop:([\w\.]+)\s*>|<%@\s*((?:\s*[\w\.]+\s*=\s*\'.*?\'|\s*[\w\.]+\s*=\s*".*?")*)\s*%>|<%[%#~\/\\$=\\[](.*?)%>|)*)\s*\/>/msS'; + const CONFIG_DATABIND=0; + const CONFIG_EXPRESSION=1; + const CONFIG_ASSET=2; + const CONFIG_PARAMETER=3; + const CONFIG_LOCALIZATION=4; + const CONFIG_TEMPLATE=5; + private $_tpl=array(); + private $_directive=array(); + private $_contextPath; + private $_tplFile=null; + private $_startingLine=0; + private $_content; + private $_sourceTemplate=true; + private $_hashCode=''; + private $_tplControl=null; + private $_includedFiles=array(); + private $_includeAtLine=array(); + private $_includeLines=array(); + public function __construct($template,$contextPath,$tplFile=null,$startingLine=0,$sourceTemplate=true) + { + $this->_sourceTemplate=$sourceTemplate; + $this->_contextPath=$contextPath; + $this->_tplFile=$tplFile; + $this->_startingLine=$startingLine; + $this->_content=$template; + $this->_hashCode=md5($template); + $this->parse($template); + $this->_content=null; + } + public function getTemplateFile() + { + return $this->_tplFile; + } + public function getIsSourceTemplate() + { + return $this->_sourceTemplate; + } + public function getContextPath() + { + return $this->_contextPath; + } + public function getDirective() + { + return $this->_directive; + } + public function getHashCode() + { + return $this->_hashCode; + } + public function &getItems() + { + return $this->_tpl; + } + public function instantiateIn($tplControl,$parentControl=null) + { + $this->_tplControl=$tplControl; + if($parentControl===null) + $parentControl=$tplControl; + if(($page=$tplControl->getPage())===null) + $page=$this->getService()->getRequestedPage(); + $controls=array(); + $directChildren=array(); + foreach($this->_tpl as $key=>$object) + { + if($object[0]===-1) + $parent=$parentControl; + else if(isset($controls[$object[0]])) + $parent=$controls[$object[0]]; + else + continue; + if(isset($object[2])) + { + $component=Prado::createComponent($object[1]); + $properties=&$object[2]; + if($component instanceof TControl) + { + if($component instanceof TOutputCache) + $component->setCacheKeyPrefix($this->_hashCode.$key); + $component->setTemplateControl($tplControl); + if(isset($properties['id'])) + { + if(is_array($properties['id'])) + $properties['id']=$component->evaluateExpression($properties['id'][1]); + $tplControl->registerObject($properties['id'],$component); + } + if(isset($properties['skinid'])) + { + if(is_array($properties['skinid'])) + $component->setSkinID($component->evaluateExpression($properties['skinid'][1])); + else + $component->setSkinID($properties['skinid']); + unset($properties['skinid']); + } + $component->trackViewState(false); + $component->applyStyleSheetSkin($page); + foreach($properties as $name=>$value) + $this->configureControl($component,$name,$value); + $component->trackViewState(true); + if($parent===$parentControl) + $directChildren[]=$component; + else + $component->createdOnTemplate($parent); + if($component->getAllowChildControls()) + $controls[$key]=$component; + } + else if($component instanceof TComponent) + { + $controls[$key]=$component; + if(isset($properties['id'])) + { + if(is_array($properties['id'])) + $properties['id']=$component->evaluateExpression($properties['id'][1]); + $tplControl->registerObject($properties['id'],$component); + if(!$component->hasProperty('id')) + unset($properties['id']); + } + foreach($properties as $name=>$value) + $this->configureComponent($component,$name,$value); + if($parent===$parentControl) + $directChildren[]=$component; + else + $component->createdOnTemplate($parent); + } + } + else + { + if($object[1] instanceof TCompositeLiteral) + { + $o=clone $object[1]; + $o->setContainer($tplControl); + if($parent===$parentControl) + $directChildren[]=$o; + else + $parent->addParsedObject($o); + } + else + { + if($parent===$parentControl) + $directChildren[]=$object[1]; + else + $parent->addParsedObject($object[1]); + } + } + } + foreach($directChildren as $control) + { + if($control instanceof TComponent) + $control->createdOnTemplate($parentControl); + else + $parentControl->addParsedObject($control); + } + } + protected function configureControl($control,$name,$value) + { + if(strncasecmp($name,'on',2)===0) + $this->configureEvent($control,$name,$value,$control); + else if(($pos=strrpos($name,'.'))===false) + $this->configureProperty($control,$name,$value); + else + $this->configureSubProperty($control,$name,$value); + } + protected function configureComponent($component,$name,$value) + { + if(strpos($name,'.')===false) + $this->configureProperty($component,$name,$value); + else + $this->configureSubProperty($component,$name,$value); + } + protected function configureEvent($control,$name,$value,$contextControl) + { + if(strpos($value,'.')===false) + $control->attachEventHandler($name,array($contextControl,'TemplateControl.'.$value)); + else + $control->attachEventHandler($name,array($contextControl,$value)); + } + protected function configureProperty($component,$name,$value) + { + if(is_array($value)) + { + switch($value[0]) + { + case self::CONFIG_DATABIND: + $component->bindProperty($name,$value[1]); + break; + case self::CONFIG_EXPRESSION: + if($component instanceof TControl) + $component->autoBindProperty($name,$value[1]); + else + { + $setter='set'.$name; + $component->$setter($this->_tplControl->evaluateExpression($value[1])); + } + break; + case self::CONFIG_TEMPLATE: + $setter='set'.$name; + $component->$setter($value[1]); + break; + case self::CONFIG_ASSET: + $setter='set'.$name; + $url=$this->publishFilePath($this->_contextPath.DIRECTORY_SEPARATOR.$value[1]); + $component->$setter($url); + break; + case self::CONFIG_PARAMETER: + $setter='set'.$name; + $component->$setter($this->getApplication()->getParameters()->itemAt($value[1])); + break; + case self::CONFIG_LOCALIZATION: + $setter='set'.$name; + $component->$setter(Prado::localize($value[1])); + break; + default: + throw new TConfigurationException('template_tag_unexpected',$name,$value[1]); + break; + } + } + else + { + $setter='set'.$name; + $component->$setter($value); + } + } + protected function configureSubProperty($component,$name,$value) + { + if(is_array($value)) + { + switch($value[0]) + { + case self::CONFIG_DATABIND: + $component->bindProperty($name,$value[1]); + break; + case self::CONFIG_EXPRESSION: + if($component instanceof TControl) + $component->autoBindProperty($name,$value[1]); + else + $component->setSubProperty($name,$this->_tplControl->evaluateExpression($value[1])); + break; + case self::CONFIG_TEMPLATE: + $component->setSubProperty($name,$value[1]); + break; + case self::CONFIG_ASSET: + $url=$this->publishFilePath($this->_contextPath.DIRECTORY_SEPARATOR.$value[1]); + $component->setSubProperty($name,$url); + break; + case self::CONFIG_PARAMETER: + $component->setSubProperty($name,$this->getApplication()->getParameters()->itemAt($value[1])); + break; + case self::CONFIG_LOCALIZATION: + $component->setSubProperty($name,Prado::localize($value[1])); + break; + default: + throw new TConfigurationException('template_tag_unexpected',$name,$value[1]); + break; + } + } + else + $component->setSubProperty($name,$value); + } + protected function parse($input) + { + $input=$this->preprocess($input); + $tpl=&$this->_tpl; + $n=preg_match_all(self::REGEX_RULES,$input,$matches,PREG_SET_ORDER|PREG_OFFSET_CAPTURE); + $expectPropEnd=false; + $textStart=0; + $stack=array(); + $container=-1; + $matchEnd=0; + $c=0; + $this->_directive=null; + try + { + for($i=0;$i<$n;++$i) + { + $match=&$matches[$i]; + $str=$match[0][0]; + $matchStart=$match[0][1]; + $matchEnd=$matchStart+strlen($str)-1; + if(strpos($str,'$textStart) + $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart)); + $textStart=$matchEnd+1; + $type=$match[1][0]; + $attributes=$this->parseAttributes($match[2][0],$match[2][1]); + $this->validateAttributes($type,$attributes); + $tpl[$c++]=array($container,$type,$attributes); + if($str[strlen($str)-2]!=='/') + { + $stack[] = $type; + $container=$c-1; + } + } + else if(strpos($str,'$textStart) + $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart)); + $textStart=$matchEnd+1; + $type=$match[1][0]; + if(empty($stack)) + throw new TConfigurationException('template_closingtag_unexpected',""); + $name=array_pop($stack); + if($name!==$type) + { + $tag=$name[0]==='@' ? '' : ""; + throw new TConfigurationException('template_closingtag_expected',$tag); + } + $container=$tpl[$container][0]; + } + else if(strpos($str,'<%@')===0) + { + if($expectPropEnd) + continue; + if($matchStart>$textStart) + $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart)); + $textStart=$matchEnd+1; + if(isset($tpl[0]) || $this->_directive!==null) + throw new TConfigurationException('template_directive_nonunique'); + $this->_directive=$this->parseAttributes($match[4][0],$match[4][1]); + } + else if(strpos($str,'<%')===0) + { + if($expectPropEnd) + continue; + if($matchStart>$textStart) + $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart)); + $textStart=$matchEnd+1; + $literal=trim($match[5][0]); + if($str[2]==='=') + $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,$literal)); + else if($str[2]==='%') + $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_STATEMENTS,$literal)); + else if($str[2]==='#') + $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_DATABINDING,$literal)); + else if($str[2]==='$') + $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"\$this->getApplication()->getParameters()->itemAt('$literal')")); + else if($str[2]==='~') + $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"\$this->publishFilePath('$this->_contextPath/$literal')")); + else if($str[2]==='/') + $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"dirname(\$this->getApplication()->getRequest()->getApplicationUrl()).'/$literal'")); + else if($str[2]==='[') + { + $literal=strtr(trim(substr($literal,0,strlen($literal)-1)),array("'"=>"\'","\\"=>"\\\\")); + $tpl[$c++]=array($container,array(TCompositeLiteral::TYPE_EXPRESSION,"Prado::localize('$literal')")); + } + } + else if(strpos($str,'')===strlen($str)-2) + { + if($expectPropEnd) + continue; + if($matchStart>$textStart) + $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart)); + $textStart=$matchEnd+1; + $prop=strtolower($match[6][0]); + $attrs=$this->parseAttributes($match[7][0],$match[7][1]); + $attributes=array(); + foreach($attrs as $name=>$value) + $attributes[$prop.'.'.$name]=$value; + $type=$tpl[$container][1]; + $this->validateAttributes($type,$attributes); + foreach($attributes as $name=>$value) + { + if(isset($tpl[$container][2][$name])) + throw new TConfigurationException('template_property_duplicated',$name); + $tpl[$container][2][$name]=$value; + } + } + else + { + $prop=strtolower($match[3][0]); + $stack[] = '@'.$prop; + if(!$expectPropEnd) + { + if($matchStart>$textStart) + $tpl[$c++]=array($container,substr($input,$textStart,$matchStart-$textStart)); + $textStart=$matchEnd+1; + $expectPropEnd=true; + } + } + } + else if(strpos($str,'"); + $name=array_pop($stack); + if($name!=='@'.$prop) + { + $tag=$name[0]==='@' ? '' : ""; + throw new TConfigurationException('template_closingtag_expected',$tag); + } + if(($last=count($stack))<1 || $stack[$last-1][0]!=='@') + { + if($matchStart>$textStart) + { + $value=substr($input,$textStart,$matchStart-$textStart); + if(substr($prop,-8,8)==='template') + $value=$this->parseTemplateProperty($value,$textStart); + else + $value=$this->parseAttribute($value); + if($container>=0) + { + $type=$tpl[$container][1]; + $this->validateAttributes($type,array($prop=>$value)); + if(isset($tpl[$container][2][$prop])) + throw new TConfigurationException('template_property_duplicated',$prop); + $tpl[$container][2][$prop]=$value; + } + else + $this->_directive[$prop]=$value; + $textStart=$matchEnd+1; + } + $expectPropEnd=false; + } + } + else if(strpos($str,'