summaryrefslogtreecommitdiff
path: root/framework/utils
diff options
context:
space:
mode:
Diffstat (limited to 'framework/utils')
-rw-r--r--framework/utils/CDateTimeParser.php277
-rw-r--r--framework/utils/CFileHelper.php261
-rw-r--r--framework/utils/CFormatter.php247
-rw-r--r--framework/utils/CMarkdownParser.php195
-rw-r--r--framework/utils/CPropertyValue.php158
-rw-r--r--framework/utils/CTimestamp.php377
-rw-r--r--framework/utils/CVarDumper.php140
-rw-r--r--framework/utils/mimeTypes.php178
8 files changed, 1833 insertions, 0 deletions
diff --git a/framework/utils/CDateTimeParser.php b/framework/utils/CDateTimeParser.php
new file mode 100644
index 0000000..2f09f93
--- /dev/null
+++ b/framework/utils/CDateTimeParser.php
@@ -0,0 +1,277 @@
+<?php
+/**
+ * CDateTimeParser class file
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @author Tomasz Suchanek <tomasz[dot]suchanek[at]gmail[dot]com>
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright &copy; 2008-2011 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+/**
+ * CDateTimeParser converts a date/time string to a UNIX timestamp according to the specified pattern.
+ *
+ * The following pattern characters are recognized:
+ * <pre>
+ * Pattern | Description
+ * ----------------------------------------------------
+ * d | Day of month 1 to 31, no padding
+ * dd | Day of month 01 to 31, zero leading
+ * M | Month digit 1 to 12, no padding
+ * MM | Month digit 01 to 12, zero leading
+ * yy | 2 year digit, e.g., 96, 05
+ * yyyy | 4 year digit, e.g., 2005
+ * h | Hour in 0 to 23, no padding
+ * hh | Hour in 00 to 23, zero leading
+ * H | Hour in 0 to 23, no padding
+ * HH | Hour in 00 to 23, zero leading
+ * m | Minutes in 0 to 59, no padding
+ * mm | Minutes in 00 to 59, zero leading
+ * s | Seconds in 0 to 59, no padding
+ * ss | Seconds in 00 to 59, zero leading
+ * a | AM or PM, case-insensitive (since version 1.1.5)
+ * ----------------------------------------------------
+ * </pre>
+ * All other characters must appear in the date string at the corresponding positions.
+ *
+ * For example, to parse a date string '21/10/2008', use the following:
+ * <pre>
+ * $timestamp=CDateTimeParser::parse('21/10/2008','dd/MM/yyyy');
+ * </pre>
+ *
+ * To format a timestamp to a date string, please use {@link CDateFormatter}.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id: CDateTimeParser.php 2928 2011-02-01 17:41:51Z alexander.makarow $
+ * @package system.utils
+ * @since 1.0
+ */
+class CDateTimeParser
+{
+ /**
+ * Converts a date string to a timestamp.
+ * @param string $value the date string to be parsed
+ * @param string $pattern the pattern that the date string is following
+ * @param array $defaults the default values for year, month, day, hour, minute and second.
+ * The default values will be used in case when the pattern doesn't specify the
+ * corresponding fields. For example, if the pattern is 'MM/dd/yyyy' and this
+ * parameter is array('minute'=>0, 'second'=>0), then the actual minute and second
+ * for the parsing result will take value 0, while the actual hour value will be
+ * the current hour obtained by date('H'). This parameter has been available since version 1.1.5.
+ * @return integer timestamp for the date string. False if parsing fails.
+ */
+ public static function parse($value,$pattern='MM/dd/yyyy',$defaults=array())
+ {
+ $tokens=self::tokenize($pattern);
+ $i=0;
+ $n=strlen($value);
+ foreach($tokens as $token)
+ {
+ switch($token)
+ {
+ case 'yyyy':
+ {
+ if(($year=self::parseInteger($value,$i,4,4))===false)
+ return false;
+ $i+=4;
+ break;
+ }
+ case 'yy':
+ {
+ if(($year=self::parseInteger($value,$i,1,2))===false)
+ return false;
+ $i+=strlen($year);
+ break;
+ }
+ case 'MM':
+ {
+ if(($month=self::parseInteger($value,$i,2,2))===false)
+ return false;
+ $i+=2;
+ break;
+ }
+ case 'M':
+ {
+ if(($month=self::parseInteger($value,$i,1,2))===false)
+ return false;
+ $i+=strlen($month);
+ break;
+ }
+ case 'dd':
+ {
+ if(($day=self::parseInteger($value,$i,2,2))===false)
+ return false;
+ $i+=2;
+ break;
+ }
+ case 'd':
+ {
+ if(($day=self::parseInteger($value,$i,1,2))===false)
+ return false;
+ $i+=strlen($day);
+ break;
+ }
+ case 'h':
+ case 'H':
+ {
+ if(($hour=self::parseInteger($value,$i,1,2))===false)
+ return false;
+ $i+=strlen($hour);
+ break;
+ }
+ case 'hh':
+ case 'HH':
+ {
+ if(($hour=self::parseInteger($value,$i,2,2))===false)
+ return false;
+ $i+=2;
+ break;
+ }
+ case 'm':
+ {
+ if(($minute=self::parseInteger($value,$i,1,2))===false)
+ return false;
+ $i+=strlen($minute);
+ break;
+ }
+ case 'mm':
+ {
+ if(($minute=self::parseInteger($value,$i,2,2))===false)
+ return false;
+ $i+=2;
+ break;
+ }
+ case 's':
+ {
+ if(($second=self::parseInteger($value,$i,1,2))===false)
+ return false;
+ $i+=strlen($second);
+ break;
+ }
+ case 'ss':
+ {
+ if(($second=self::parseInteger($value,$i,2,2))===false)
+ return false;
+ $i+=2;
+ break;
+ }
+ case 'a':
+ {
+ if(($ampm=self::parseAmPm($value,$i))===false)
+ return false;
+ if(isset($hour))
+ {
+ if($hour==12 && $ampm==='am')
+ $hour=0;
+ else if($hour<12 && $ampm==='pm')
+ $hour+=12;
+ }
+ $i+=2;
+ break;
+ }
+ default:
+ {
+ $tn=strlen($token);
+ if($i>=$n || substr($value,$i,$tn)!==$token)
+ return false;
+ $i+=$tn;
+ break;
+ }
+ }
+ }
+ if($i<$n)
+ return false;
+
+ if(!isset($year))
+ $year=isset($defaults['year']) ? $defaults['year'] : date('Y');
+ if(!isset($month))
+ $month=isset($defaults['month']) ? $defaults['month'] : date('n');
+ if(!isset($day))
+ $day=isset($defaults['day']) ? $defaults['day'] : date('j');
+
+ if(strlen($year)===2)
+ {
+ if($year>=70)
+ $year+=1900;
+ else
+ $year+=2000;
+ }
+ $year=(int)$year;
+ $month=(int)$month;
+ $day=(int)$day;
+
+ if(
+ !isset($hour) && !isset($minute) && !isset($second)
+ && !isset($defaults['hour']) && !isset($defaults['minute']) && !isset($defaults['second'])
+ )
+ $hour=$minute=$second=0;
+ else
+ {
+ if(!isset($hour))
+ $hour=isset($defaults['hour']) ? $defaults['hour'] : date('H');
+ if(!isset($minute))
+ $minute=isset($defaults['minute']) ? $defaults['minute'] : date('i');
+ if(!isset($second))
+ $second=isset($defaults['second']) ? $defaults['second'] : date('s');
+ $hour=(int)$hour;
+ $minute=(int)$minute;
+ $second=(int)$second;
+ }
+
+ if(CTimestamp::isValidDate($year,$month,$day) && CTimestamp::isValidTime($hour,$minute,$second))
+ return CTimestamp::getTimestamp($hour,$minute,$second,$month,$day,$year);
+ else
+ return false;
+ }
+
+ /*
+ * @param string $pattern the pattern that the date string is following
+ */
+ private static function tokenize($pattern)
+ {
+ if(!($n=strlen($pattern)))
+ return array();
+ $tokens=array();
+ for($c0=$pattern[0],$start=0,$i=1;$i<$n;++$i)
+ {
+ if(($c=$pattern[$i])!==$c0)
+ {
+ $tokens[]=substr($pattern,$start,$i-$start);
+ $c0=$c;
+ $start=$i;
+ }
+ }
+ $tokens[]=substr($pattern,$start,$n-$start);
+ return $tokens;
+ }
+
+ /*
+ * @param string $value the date string to be parsed
+ * @param integer $offset starting offset
+ * @param integer $minLength minimum length
+ * @param integer $maxLength maximum length
+ */
+ protected static function parseInteger($value,$offset,$minLength,$maxLength)
+ {
+ for($len=$maxLength;$len>=$minLength;--$len)
+ {
+ $v=substr($value,$offset,$len);
+ if(ctype_digit($v) && strlen($v)>=$minLength)
+ return $v;
+ }
+ return false;
+ }
+
+ /*
+ * @param string $value the date string to be parsed
+ * @param integer $offset starting offset
+ */
+ protected static function parseAmPm($value, $offset)
+ {
+ $v=strtolower(substr($value,$offset,2));
+ return $v==='am' || $v==='pm' ? $v : false;
+ }
+}
diff --git a/framework/utils/CFileHelper.php b/framework/utils/CFileHelper.php
new file mode 100644
index 0000000..4a1f1de
--- /dev/null
+++ b/framework/utils/CFileHelper.php
@@ -0,0 +1,261 @@
+<?php
+/**
+ * CFileHelper class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright &copy; 2008-2011 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+/**
+ * CFileHelper provides a set of helper methods for common file system operations.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id: CFileHelper.php 3289 2011-06-18 21:20:13Z qiang.xue $
+ * @package system.utils
+ * @since 1.0
+ */
+class CFileHelper
+{
+ /**
+ * Returns the extension name of a file path.
+ * For example, the path "path/to/something.php" would return "php".
+ * @param string $path the file path
+ * @return string the extension name without the dot character.
+ * @since 1.1.2
+ */
+ public static function getExtension($path)
+ {
+ return pathinfo($path, PATHINFO_EXTENSION);
+ }
+
+ /**
+ * Copies a directory recursively as another.
+ * If the destination directory does not exist, it will be created.
+ * @param string $src the source directory
+ * @param string $dst the destination directory
+ * @param array $options options for directory copy. Valid options are:
+ * <ul>
+ * <li>fileTypes: array, list of file name suffix (without dot). Only files with these suffixes will be copied.</li>
+ * <li>exclude: array, list of directory and file exclusions. Each exclusion can be either a name or a path.
+ * If a file or directory name or path matches the exclusion, it will not be copied. For example, an exclusion of
+ * '.svn' will exclude all files and directories whose name is '.svn'. And an exclusion of '/a/b' will exclude
+ * file or directory '$src/a/b'. Note, that '/' should be used as separator regardless of the value of the DIRECTORY_SEPARATOR constant.
+ * </li>
+ * <li>level: integer, recursion depth, default=-1.
+ * Level -1 means copying all directories and files under the directory;
+ * Level 0 means copying only the files DIRECTLY under the directory;
+ * level N means copying those directories that are within N levels.
+ * </li>
+ * </ul>
+ */
+ public static function copyDirectory($src,$dst,$options=array())
+ {
+ $fileTypes=array();
+ $exclude=array();
+ $level=-1;
+ extract($options);
+ self::copyDirectoryRecursive($src,$dst,'',$fileTypes,$exclude,$level,$options);
+ }
+
+ /**
+ * Returns the files found under the specified directory and subdirectories.
+ * @param string $dir the directory under which the files will be looked for
+ * @param array $options options for file searching. Valid options are:
+ * <ul>
+ * <li>fileTypes: array, list of file name suffix (without dot). Only files with these suffixes will be returned.</li>
+ * <li>exclude: array, list of directory and file exclusions. Each exclusion can be either a name or a path.
+ * If a file or directory name or path matches the exclusion, it will not be copied. For example, an exclusion of
+ * '.svn' will exclude all files and directories whose name is '.svn'. And an exclusion of '/a/b' will exclude
+ * file or directory '$src/a/b'. Note, that '/' should be used as separator regardless of the value of the DIRECTORY_SEPARATOR constant.
+ * </li>
+ * <li>level: integer, recursion depth, default=-1.
+ * Level -1 means searching for all directories and files under the directory;
+ * Level 0 means searching for only the files DIRECTLY under the directory;
+ * level N means searching for those directories that are within N levels.
+ * </li>
+ * </ul>
+ * @return array files found under the directory. The file list is sorted.
+ */
+ public static function findFiles($dir,$options=array())
+ {
+ $fileTypes=array();
+ $exclude=array();
+ $level=-1;
+ extract($options);
+ $list=self::findFilesRecursive($dir,'',$fileTypes,$exclude,$level);
+ sort($list);
+ return $list;
+ }
+
+ /**
+ * Copies a directory.
+ * This method is mainly used by {@link copyDirectory}.
+ * @param string $src the source directory
+ * @param string $dst the destination directory
+ * @param string $base the path relative to the original source directory
+ * @param array $fileTypes list of file name suffix (without dot). Only files with these suffixes will be copied.
+ * @param array $exclude list of directory and file exclusions. Each exclusion can be either a name or a path.
+ * If a file or directory name or path matches the exclusion, it will not be copied. For example, an exclusion of
+ * '.svn' will exclude all files and directories whose name is '.svn'. And an exclusion of '/a/b' will exclude
+ * file or directory '$src/a/b'. Note, that '/' should be used as separator regardless of the value of the DIRECTORY_SEPARATOR constant.
+ * @param integer $level recursion depth. It defaults to -1.
+ * Level -1 means copying all directories and files under the directory;
+ * Level 0 means copying only the files DIRECTLY under the directory;
+ * level N means copying those directories that are within N levels.
+ * @param array $options additional options. The following options are supported:
+ * newDirMode - the permission to be set for newly copied directories (defaults to 0777);
+ * newFileMode - the permission to be set for newly copied files (defaults to the current environment setting).
+ */
+ protected static function copyDirectoryRecursive($src,$dst,$base,$fileTypes,$exclude,$level,$options)
+ {
+ if(!is_dir($dst))
+ mkdir($dst);
+ if(isset($options['newDirMode']))
+ @chmod($dst,$options['newDirMode']);
+ else
+ @chmod($dst,0777);
+ $folder=opendir($src);
+ while(($file=readdir($folder))!==false)
+ {
+ if($file==='.' || $file==='..')
+ continue;
+ $path=$src.DIRECTORY_SEPARATOR.$file;
+ $isFile=is_file($path);
+ if(self::validatePath($base,$file,$isFile,$fileTypes,$exclude))
+ {
+ if($isFile)
+ {
+ copy($path,$dst.DIRECTORY_SEPARATOR.$file);
+ if(isset($options['newFileMode']))
+ @chmod($dst.DIRECTORY_SEPARATOR.$file, $options['newFileMode']);
+ }
+ else if($level)
+ self::copyDirectoryRecursive($path,$dst.DIRECTORY_SEPARATOR.$file,$base.'/'.$file,$fileTypes,$exclude,$level-1,$options);
+ }
+ }
+ closedir($folder);
+ }
+
+ /**
+ * Returns the files found under the specified directory and subdirectories.
+ * This method is mainly used by {@link findFiles}.
+ * @param string $dir the source directory
+ * @param string $base the path relative to the original source directory
+ * @param array $fileTypes list of file name suffix (without dot). Only files with these suffixes will be returned.
+ * @param array $exclude list of directory and file exclusions. Each exclusion can be either a name or a path.
+ * If a file or directory name or path matches the exclusion, it will not be copied. For example, an exclusion of
+ * '.svn' will exclude all files and directories whose name is '.svn'. And an exclusion of '/a/b' will exclude
+ * file or directory '$src/a/b'. Note, that '/' should be used as separator regardless of the value of the DIRECTORY_SEPARATOR constant.
+ * @param integer $level recursion depth. It defaults to -1.
+ * Level -1 means searching for all directories and files under the directory;
+ * Level 0 means searching for only the files DIRECTLY under the directory;
+ * level N means searching for those directories that are within N levels.
+ * @return array files found under the directory.
+ */
+ protected static function findFilesRecursive($dir,$base,$fileTypes,$exclude,$level)
+ {
+ $list=array();
+ $handle=opendir($dir);
+ while(($file=readdir($handle))!==false)
+ {
+ if($file==='.' || $file==='..')
+ continue;
+ $path=$dir.DIRECTORY_SEPARATOR.$file;
+ $isFile=is_file($path);
+ if(self::validatePath($base,$file,$isFile,$fileTypes,$exclude))
+ {
+ if($isFile)
+ $list[]=$path;
+ else if($level)
+ $list=array_merge($list,self::findFilesRecursive($path,$base.'/'.$file,$fileTypes,$exclude,$level-1));
+ }
+ }
+ closedir($handle);
+ return $list;
+ }
+
+ /**
+ * Validates a file or directory.
+ * @param string $base the path relative to the original source directory
+ * @param string $file the file or directory name
+ * @param boolean $isFile whether this is a file
+ * @param array $fileTypes list of file name suffix (without dot). Only files with these suffixes will be copied.
+ * @param array $exclude list of directory and file exclusions. Each exclusion can be either a name or a path.
+ * If a file or directory name or path matches the exclusion, it will not be copied. For example, an exclusion of
+ * '.svn' will exclude all files and directories whose name is '.svn'. And an exclusion of '/a/b' will exclude
+ * file or directory '$src/a/b'. Note, that '/' should be used as separator regardless of the value of the DIRECTORY_SEPARATOR constant.
+ * @return boolean whether the file or directory is valid
+ */
+ protected static function validatePath($base,$file,$isFile,$fileTypes,$exclude)
+ {
+ foreach($exclude as $e)
+ {
+ if($file===$e || strpos($base.'/'.$file,$e)===0)
+ return false;
+ }
+ if(!$isFile || empty($fileTypes))
+ return true;
+ if(($type=pathinfo($file, PATHINFO_EXTENSION))!=='')
+ return in_array($type,$fileTypes);
+ else
+ return false;
+ }
+
+ /**
+ * Determines the MIME type of the specified file.
+ * This method will attempt the following approaches in order:
+ * <ol>
+ * <li>finfo</li>
+ * <li>mime_content_type</li>
+ * <li>{@link getMimeTypeByExtension}, when $checkExtension is set true.</li>
+ * </ol>
+ * @param string $file the file name.
+ * @param string $magicFile name of a magic database file, usually something like /path/to/magic.mime.
+ * This will be passed as the second parameter to {@link http://php.net/manual/en/function.finfo-open.php finfo_open}.
+ * This parameter has been available since version 1.1.3.
+ * @param boolean $checkExtension whether to check the file extension in case the MIME type cannot be determined
+ * based on finfo and mim_content_type. Defaults to true. This parameter has been available since version 1.1.4.
+ * @return string the MIME type. Null is returned if the MIME type cannot be determined.
+ */
+ public static function getMimeType($file,$magicFile=null,$checkExtension=true)
+ {
+ if(function_exists('finfo_open'))
+ {
+ $options=defined('FILEINFO_MIME_TYPE') ? FILEINFO_MIME_TYPE : FILEINFO_MIME;
+ $info=$magicFile===null ? finfo_open($options) : finfo_open($options,$magicFile);
+
+ if($info && ($result=finfo_file($info,$file))!==false)
+ return $result;
+ }
+
+ if(function_exists('mime_content_type') && ($result=mime_content_type($file))!==false)
+ return $result;
+
+ return $checkExtension ? self::getMimeTypeByExtension($file) : null;
+ }
+
+ /**
+ * Determines the MIME type based on the extension name of the specified file.
+ * This method will use a local map between extension name and MIME type.
+ * @param string $file the file name.
+ * @param string $magicFile the path of the file that contains all available MIME type information.
+ * If this is not set, the default 'system.utils.mimeTypes' file will be used.
+ * This parameter has been available since version 1.1.3.
+ * @return string the MIME type. Null is returned if the MIME type cannot be determined.
+ */
+ public static function getMimeTypeByExtension($file,$magicFile=null)
+ {
+ static $extensions;
+ if($extensions===null)
+ $extensions=$magicFile===null ? require(Yii::getPathOfAlias('system.utils.mimeTypes').'.php') : $magicFile;
+ if(($ext=pathinfo($file, PATHINFO_EXTENSION))!=='')
+ {
+ $ext=strtolower($ext);
+ if(isset($extensions[$ext]))
+ return $extensions[$ext];
+ }
+ return null;
+ }
+}
diff --git a/framework/utils/CFormatter.php b/framework/utils/CFormatter.php
new file mode 100644
index 0000000..277814a
--- /dev/null
+++ b/framework/utils/CFormatter.php
@@ -0,0 +1,247 @@
+<?php
+/**
+ * CFormatter class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright &copy; 2008-2011 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+/**
+ * CFormatter provides a set of commonly used data formatting methods.
+ *
+ * The formatting methods provided by CFormatter are all named in the form of <code>formatXyz</code>.
+ * The behavior of some of them may be configured via the properties of CFormatter. For example,
+ * by configuring {@link dateFormat}, one may control how {@link formatDate} formats the value into a date string.
+ *
+ * For convenience, CFormatter also implements the mechanism of calling formatting methods with their shortcuts (called types).
+ * In particular, if a formatting method is named <code>formatXyz</code>, then its shortcut method is <code>xyz</code>
+ * (case-insensitive). For example, calling <code>$formatter->date($value)</code> is equivalent to calling
+ * <code>$formatter->formatDate($value)</code>.
+ *
+ * Currently, the following types are recognizable:
+ * <ul>
+ * <li>raw: the attribute value will not be changed at all.</li>
+ * <li>text: the attribute value will be HTML-encoded when rendering.</li>
+ * <li>ntext: the {@link formatNtext} method will be called to format the attribute value as a HTML-encoded plain text with newlines converted as the HTML &lt;br /&gt; tags.</li>
+ * <li>html: the attribute value will be purified and then returned.</li>
+ * <li>date: the {@link formatDate} method will be called to format the attribute value as a date.</li>
+ * <li>time: the {@link formatTime} method will be called to format the attribute value as a time.</li>
+ * <li>datetime: the {@link formatDatetime} method will be called to format the attribute value as a date with time.</li>
+ * <li>boolean: the {@link formatBoolean} method will be called to format the attribute value as a boolean display.</li>
+ * <li>number: the {@link formatNumber} method will be called to format the attribute value as a number display.</li>
+ * <li>email: the {@link formatEmail} method will be called to format the attribute value as a mailto link.</li>
+ * <li>image: the {@link formatImage} method will be called to format the attribute value as an image tag where the attribute value is the image URL.</li>
+ * <li>url: the {@link formatUrl} method will be called to format the attribute value as a hyperlink where the attribute value is the URL.</li>
+ * </ul>
+ *
+ * By default, {@link CApplication} registers {@link CFormatter} as an application component whose ID is 'format'.
+ * Therefore, one may call <code>Yii::app()->format->boolean(1)</code>.
+ *
+ * @property CHtmlPurifier $htmlPurifier The HTML purifier instance.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id: CFormatter.php 3553 2012-02-06 22:07:58Z alexander.makarow $
+ * @package system.utils
+ * @since 1.1.0
+ */
+class CFormatter extends CApplicationComponent
+{
+ private $_htmlPurifier;
+
+ /**
+ * @var string the format string to be used to format a date using PHP date() function. Defaults to 'Y/m/d'.
+ */
+ public $dateFormat='Y/m/d';
+ /**
+ * @var string the format string to be used to format a time using PHP date() function. Defaults to 'h:i:s A'.
+ */
+ public $timeFormat='h:i:s A';
+ /**
+ * @var string the format string to be used to format a date and time using PHP date() function. Defaults to 'Y/m/d h:i:s A'.
+ */
+ public $datetimeFormat='Y/m/d h:i:s A';
+ /**
+ * @var array the format used to format a number with PHP number_format() function.
+ * Three elements may be specified: "decimals", "decimalSeparator" and "thousandSeparator". They
+ * correspond to the number of digits after the decimal point, the character displayed as the decimal point,
+ * and the thousands separator character.
+ */
+ public $numberFormat=array('decimals'=>null, 'decimalSeparator'=>null, 'thousandSeparator'=>null);
+ /**
+ * @var array the text to be displayed when formatting a boolean value. The first element corresponds
+ * to the text display for false, the second element for true. Defaults to <code>array('No', 'Yes')</code>.
+ */
+ public $booleanFormat=array('No','Yes');
+
+ /**
+ * Calls the format method when its shortcut is invoked.
+ * This is a PHP magic method that we override to implement the shortcut format methods.
+ * @param string $name the method name
+ * @param array $parameters method parameters
+ * @return mixed the method return value
+ */
+ public function __call($name,$parameters)
+ {
+ if(method_exists($this,'format'.$name))
+ return call_user_func_array(array($this,'format'.$name),$parameters);
+ else
+ return parent::__call($name,$parameters);
+ }
+
+ /**
+ * Formats a value based on the given type.
+ * @param mixed $value the value to be formatted
+ * @param string $type the data type. This must correspond to a format method available in CFormatter.
+ * For example, we can use 'text' here because there is method named {@link formatText}.
+ * @return string the formatted data
+ */
+ public function format($value,$type)
+ {
+ $method='format'.$type;
+ if(method_exists($this,$method))
+ return $this->$method($value);
+ else
+ throw new CException(Yii::t('yii','Unknown type "{type}".',array('{type}'=>$type)));
+ }
+
+ /**
+ * Formats the value as is without any formatting.
+ * This method simply returns back the parameter without any format.
+ * @param mixed $value the value to be formatted
+ * @return string the formatted result
+ */
+ public function formatRaw($value)
+ {
+ return $value;
+ }
+
+ /**
+ * Formats the value as a HTML-encoded plain text.
+ * @param mixed $value the value to be formatted
+ * @return string the formatted result
+ */
+ public function formatText($value)
+ {
+ return CHtml::encode($value);
+ }
+
+ /**
+ * Formats the value as a HTML-encoded plain text and converts newlines with HTML br tags.
+ * @param mixed $value the value to be formatted
+ * @return string the formatted result
+ */
+ public function formatNtext($value)
+ {
+ return nl2br(CHtml::encode($value));
+ }
+
+ /**
+ * Formats the value as HTML text without any encoding.
+ * @param mixed $value the value to be formatted
+ * @return string the formatted result
+ */
+ public function formatHtml($value)
+ {
+ return $this->getHtmlPurifier()->purify($value);
+ }
+
+ /**
+ * Formats the value as a date.
+ * @param mixed $value the value to be formatted
+ * @return string the formatted result
+ * @see dateFormat
+ */
+ public function formatDate($value)
+ {
+ return date($this->dateFormat,$value);
+ }
+
+ /**
+ * Formats the value as a time.
+ * @param mixed $value the value to be formatted
+ * @return string the formatted result
+ * @see timeFormat
+ */
+ public function formatTime($value)
+ {
+ return date($this->timeFormat,$value);
+ }
+
+ /**
+ * Formats the value as a date and time.
+ * @param mixed $value the value to be formatted
+ * @return string the formatted result
+ * @see datetimeFormat
+ */
+ public function formatDatetime($value)
+ {
+ return date($this->datetimeFormat,$value);
+ }
+
+ /**
+ * Formats the value as a boolean.
+ * @param mixed $value the value to be formatted
+ * @return string the formatted result
+ * @see booleanFormat
+ */
+ public function formatBoolean($value)
+ {
+ return $value ? $this->booleanFormat[1] : $this->booleanFormat[0];
+ }
+
+ /**
+ * Formats the value as a mailto link.
+ * @param mixed $value the value to be formatted
+ * @return string the formatted result
+ */
+ public function formatEmail($value)
+ {
+ return CHtml::mailto($value);
+ }
+
+ /**
+ * Formats the value as an image tag.
+ * @param mixed $value the value to be formatted
+ * @return string the formatted result
+ */
+ public function formatImage($value)
+ {
+ return CHtml::image($value);
+ }
+
+ /**
+ * Formats the value as a hyperlink.
+ * @param mixed $value the value to be formatted
+ * @return string the formatted result
+ */
+ public function formatUrl($value)
+ {
+ $url=$value;
+ if(strpos($url,'http://')!==0 && strpos($url,'https://')!==0)
+ $url='http://'.$url;
+ return CHtml::link(CHtml::encode($value),$url);
+ }
+
+ /**
+ * Formats the value as a number using PHP number_format() function.
+ * @param mixed $value the value to be formatted
+ * @return string the formatted result
+ * @see numberFormat
+ */
+ public function formatNumber($value)
+ {
+ return number_format($value,$this->numberFormat['decimals'],$this->numberFormat['decimalSeparator'],$this->numberFormat['thousandSeparator']);
+ }
+
+ /**
+ * @return CHtmlPurifier the HTML purifier instance
+ */
+ public function getHtmlPurifier()
+ {
+ if($this->_htmlPurifier===null)
+ $this->_htmlPurifier=new CHtmlPurifier;
+ return $this->_htmlPurifier;
+ }
+}
diff --git a/framework/utils/CMarkdownParser.php b/framework/utils/CMarkdownParser.php
new file mode 100644
index 0000000..bbdc9bc
--- /dev/null
+++ b/framework/utils/CMarkdownParser.php
@@ -0,0 +1,195 @@
+<?php
+/**
+ * CMarkdownParser class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright &copy; 2008-2011 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+require_once(Yii::getPathOfAlias('system.vendors.markdown.markdown').'.php');
+if(!class_exists('HTMLPurifier_Bootstrap',false))
+{
+ require_once(Yii::getPathOfAlias('system.vendors.htmlpurifier').DIRECTORY_SEPARATOR.'HTMLPurifier.standalone.php');
+ HTMLPurifier_Bootstrap::registerAutoload();
+}
+
+/**
+ * CMarkdownParser is a wrapper of {@link http://michelf.com/projects/php-markdown/extra/ MarkdownExtra_Parser}.
+ *
+ * CMarkdownParser extends MarkdownExtra_Parser by using Text_Highlighter
+ * to highlight code blocks with specific language syntax.
+ * In particular, if a code block starts with the following:
+ * <pre>
+ * [language]
+ * </pre>
+ * The syntax for the specified language will be used to highlight
+ * code block. The languages supported include (case-insensitive):
+ * ABAP, CPP, CSS, DIFF, DTD, HTML, JAVA, JAVASCRIPT,
+ * MYSQL, PERL, PHP, PYTHON, RUBY, SQL, XML
+ *
+ * You can also specify options to be passed to the syntax highlighter. For example:
+ * <pre>
+ * [php showLineNumbers=1]
+ * </pre>
+ * which will show line numbers in each line of the code block.
+ *
+ * For details about the standard markdown syntax, please check the following:
+ * <ul>
+ * <li>{@link http://daringfireball.net/projects/markdown/syntax official markdown syntax}</li>
+ * <li>{@link http://michelf.com/projects/php-markdown/extra/ markdown extra syntax}</li>
+ * </ul>
+ *
+ * @property string $defaultCssFile The default CSS file that is used to highlight code blocks.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id: CMarkdownParser.php 3515 2011-12-28 12:29:24Z mdomba $
+ * @package system.utils
+ * @since 1.0
+ */
+class CMarkdownParser extends MarkdownExtra_Parser
+{
+ /**
+ * @var string the css class for the div element containing
+ * the code block that is highlighted. Defaults to 'hl-code'.
+ */
+ public $highlightCssClass='hl-code';
+ /**
+ * @var mixed the options to be passed to {@link http://htmlpurifier.org HTML Purifier}.
+ * This can be a HTMLPurifier_Config object, an array of directives (Namespace.Directive => Value)
+ * or the filename of an ini file.
+ * This property is used only when {@link safeTransform} is invoked.
+ * @see http://htmlpurifier.org/live/configdoc/plain.html
+ * @since 1.1.4
+ */
+ public $purifierOptions=null;
+
+ /**
+ * Transforms the content and purifies the result.
+ * This method calls the transform() method to convert
+ * markdown content into HTML content. It then
+ * uses {@link CHtmlPurifier} to purify the HTML content
+ * to avoid XSS attacks.
+ * @param string $content the markdown content
+ * @return string the purified HTML content
+ */
+ public function safeTransform($content)
+ {
+ $content=$this->transform($content);
+ $purifier=new HTMLPurifier($this->purifierOptions);
+ $purifier->config->set('Cache.SerializerPath',Yii::app()->getRuntimePath());
+ return $purifier->purify($content);
+ }
+
+ /**
+ * @return string the default CSS file that is used to highlight code blocks.
+ */
+ public function getDefaultCssFile()
+ {
+ return Yii::getPathOfAlias('system.vendors.TextHighlighter.highlight').'.css';
+ }
+
+ /**
+ * Callback function when a code block is matched.
+ * @param array $matches matches
+ * @return string the highlighted code block
+ */
+ public function _doCodeBlocks_callback($matches)
+ {
+ $codeblock = $this->outdent($matches[1]);
+ if(($codeblock = $this->highlightCodeBlock($codeblock)) !== null)
+ return "\n\n".$this->hashBlock($codeblock)."\n\n";
+ else
+ return parent::_doCodeBlocks_callback($matches);
+ }
+
+ /**
+ * Callback function when a fenced code block is matched.
+ * @param array $matches matches
+ * @return string the highlighted code block
+ */
+ public function _doFencedCodeBlocks_callback($matches)
+ {
+ return "\n\n".$this->hashBlock($this->highlightCodeBlock($matches[2]))."\n\n";
+ }
+
+ /**
+ * Highlights the code block.
+ * @param string $codeblock the code block
+ * @return string the highlighted code block. Null if the code block does not need to highlighted
+ */
+ protected function highlightCodeBlock($codeblock)
+ {
+ if(($tag=$this->getHighlightTag($codeblock))!==null && ($highlighter=$this->createHighLighter($tag)))
+ {
+ $codeblock = preg_replace('/\A\n+|\n+\z/', '', $codeblock);
+ $tagLen = strpos($codeblock, $tag)+strlen($tag);
+ $codeblock = ltrim(substr($codeblock, $tagLen));
+ $output=preg_replace('/<span\s+[^>]*>(\s*)<\/span>/', '\1', $highlighter->highlight($codeblock));
+ return "<div class=\"{$this->highlightCssClass}\">".$output."</div>";
+ }
+ else
+ return "<pre>".CHtml::encode($codeblock)."</pre>";
+ }
+
+ /**
+ * Returns the user-entered highlighting options.
+ * @param string $codeblock code block with highlighting options.
+ * @return string the user-entered highlighting options. Null if no option is entered.
+ */
+ protected function getHighlightTag($codeblock)
+ {
+ $str = trim(current(preg_split("/\r|\n/", $codeblock,2)));
+ if(strlen($str) > 2 && $str[0] === '[' && $str[strlen($str)-1] === ']')
+ return $str;
+ }
+
+ /**
+ * Creates a highlighter instance.
+ * @param string $options the user-entered options
+ * @return Text_Highlighter the highlighter instance
+ */
+ protected function createHighLighter($options)
+ {
+ if(!class_exists('Text_Highlighter', false))
+ {
+ require_once(Yii::getPathOfAlias('system.vendors.TextHighlighter.Text.Highlighter').'.php');
+ require_once(Yii::getPathOfAlias('system.vendors.TextHighlighter.Text.Highlighter.Renderer.Html').'.php');
+ }
+ $lang = current(preg_split('/\s+/', substr(substr($options,1), 0,-1),2));
+ $highlighter = Text_Highlighter::factory($lang);
+ if($highlighter)
+ $highlighter->setRenderer(new Text_Highlighter_Renderer_Html($this->getHiglightConfig($options)));
+ return $highlighter;
+ }
+
+ /**
+ * Generates the config for the highlighter.
+ * @param string $options user-entered options
+ * @return array the highlighter config
+ */
+ public function getHiglightConfig($options)
+ {
+ $config['use_language'] = true;
+ if( $this->getInlineOption('showLineNumbers', $options, false) )
+ $config['numbers'] = HL_NUMBERS_LI;
+ $config['tabsize'] = $this->getInlineOption('tabSize', $options, 4);
+ return $config;
+ }
+
+ /**
+ * Retrieves the specified configuration.
+ * @param string $name the configuration name
+ * @param string $str the user-entered options
+ * @param mixed $defaultValue default value if the configuration is not present
+ * @return mixed the configuration value
+ */
+ protected function getInlineOption($name, $str, $defaultValue)
+ {
+ if(preg_match('/'.$name.'(\s*=\s*(\d+))?/i', $str, $v) && count($v) > 2)
+ return $v[2];
+ else
+ return $defaultValue;
+ }
+}
diff --git a/framework/utils/CPropertyValue.php b/framework/utils/CPropertyValue.php
new file mode 100644
index 0000000..03e9ba2
--- /dev/null
+++ b/framework/utils/CPropertyValue.php
@@ -0,0 +1,158 @@
+<?php
+/**
+ * CPropertyValue class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright &copy; 2008-2011 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+/**
+ * CPropertyValue is a helper class that provides static methods to convert component property values to specific types.
+ *
+ * CPropertyValue is commonly used in component setter methods to ensure
+ * the new property value is of the specific type.
+ * For example, a boolean-typed property setter method would be as follows,
+ * <pre>
+ * public function setPropertyName($value)
+ * {
+ * $value=CPropertyValue::ensureBoolean($value);
+ * // $value is now of boolean type
+ * }
+ * </pre>
+ *
+ * Properties can be of the following types with specific type conversion rules:
+ * <ul>
+ * <li>string: a boolean value will be converted to 'true' or 'false'.</li>
+ * <li>boolean: string 'true' (case-insensitive) will be converted to true,
+ * string 'false' (case-insensitive) will be converted to false.</li>
+ * <li>integer</li>
+ * <li>float</li>
+ * <li>array: string starting with '(' and ending with ')' will be considered as
+ * as an array expression and will be evaluated. Otherwise, an array
+ * with the value to be ensured is returned.</li>
+ * <li>object</li>
+ * <li>enum: enumerable type, represented by an array of strings.</li>
+ * </ul>
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id: CPropertyValue.php 2799 2011-01-01 19:31:13Z qiang.xue $
+ * @package system.utils
+ * @since 1.0
+ */
+class CPropertyValue
+{
+ /**
+ * Converts a value to boolean type.
+ * Note, string 'true' (case-insensitive) will be converted to true,
+ * string 'false' (case-insensitive) will be converted to false.
+ * If a string represents a non-zero number, it will be treated as true.
+ * @param mixed $value the value to be converted.
+ * @return boolean
+ */
+ public static function ensureBoolean($value)
+ {
+ if (is_string($value))
+ return !strcasecmp($value,'true') || $value!=0;
+ else
+ return (boolean)$value;
+ }
+
+ /**
+ * Converts a value to string type.
+ * Note, a boolean value will be converted to 'true' if it is true
+ * and 'false' if it is false.
+ * @param mixed $value the value to be converted.
+ * @return string
+ */
+ public static function ensureString($value)
+ {
+ if (is_bool($value))
+ return $value?'true':'false';
+ else
+ return (string)$value;
+ }
+
+ /**
+ * Converts a value to integer type.
+ * @param mixed $value the value to be converted.
+ * @return integer
+ */
+ public static function ensureInteger($value)
+ {
+ return (integer)$value;
+ }
+
+ /**
+ * Converts a value to float type.
+ * @param mixed $value the value to be converted.
+ * @return float
+ */
+ public static function ensureFloat($value)
+ {
+ return (float)$value;
+ }
+
+ /**
+ * Converts a value to array type. If the value is a string and it is
+ * in the form (a,b,c) then an array consisting of each of the elements
+ * will be returned. If the value is a string and it is not in this form
+ * then an array consisting of just the string will be returned. If the value
+ * is not a string then
+ * @param mixed $value the value to be converted.
+ * @return array
+ */
+ public static function ensureArray($value)
+ {
+ if(is_string($value))
+ {
+ $value = trim($value);
+ $len = strlen($value);
+ if ($len >= 2 && $value[0] == '(' && $value[$len-1] == ')')
+ {
+ eval('$array=array'.$value.';');
+ return $array;
+ }
+ else
+ return $len>0?array($value):array();
+ }
+ else
+ return (array)$value;
+ }
+
+ /**
+ * Converts a value to object type.
+ * @param mixed $value the value to be converted.
+ * @return object
+ */
+ public static function ensureObject($value)
+ {
+ return (object)$value;
+ }
+
+ /**
+ * Converts a value to enum type.
+ *
+ * This method checks if the value is of the specified enumerable type.
+ * A value is a valid enumerable value if it is equal to the name of a constant
+ * in the specified enumerable type (class).
+ * For more details about enumerable, see {@link CEnumerable}.
+ *
+ * @param string $value the enumerable value to be checked.
+ * @param string $enumType the enumerable class name (make sure it is included before calling this function).
+ * @return string the valid enumeration value
+ * @throws CException if the value is not a valid enumerable value
+ */
+ public static function ensureEnum($value,$enumType)
+ {
+ static $types=array();
+ if(!isset($types[$enumType]))
+ $types[$enumType]=new ReflectionClass($enumType);
+ if($types[$enumType]->hasConstant($value))
+ return $value;
+ else
+ throw new CException(Yii::t('yii','Invalid enumerable value "{value}". Please make sure it is among ({enum}).',
+ array('{value}'=>$value, '{enum}'=>implode(', ',$types[$enumType]->getConstants()))));
+ }
+}
diff --git a/framework/utils/CTimestamp.php b/framework/utils/CTimestamp.php
new file mode 100644
index 0000000..d8f12ae
--- /dev/null
+++ b/framework/utils/CTimestamp.php
@@ -0,0 +1,377 @@
+<?php
+/**
+ * CTimestamp class file.
+ *
+ * @author Wei Zhuo <weizhuo[at]gamil[dot]com>
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright &copy; 2008-2011 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+/**
+ * CTimestamp represents a timestamp.
+ *
+ * Part of this class was adapted from the ADOdb Date Library
+ * {@link http://phplens.com/phpeverywhere/ ADOdb abstraction library}.
+ * The original source code was released under both BSD and GNU Lesser GPL
+ * library license, with the following copyright notice:
+ * Copyright (c) 2000, 2001, 2002, 2003, 2004 John Lim
+ * All rights reserved.
+ *
+ * This class is provided to support UNIX timestamp that is beyond the range
+ * of 1901-2038 on Unix and1970-2038 on Windows. Except {@link getTimestamp},
+ * all other methods in this class can work with the extended timestamp range.
+ * For {@link getTimestamp}, because it is merely a wrapper of
+ * {@link mktime http://php.net/manual/en/function.mktime.php}, it may still
+ * be subject to the limit of timestamp range on certain platforms. Please refer
+ * to the PHP manual for more information.
+ *
+ * @author Wei Zhuo <weizhuo[at]gmail[dot]com>
+ * @version $Id: CTimestamp.php 3515 2011-12-28 12:29:24Z mdomba $
+ * @package system.utils
+ * @since 1.0
+ */
+class CTimestamp
+{
+ /**
+ * Gets day of week, 0 = Sunday,... 6=Saturday.
+ * Algorithm from PEAR::Date_Calc
+ * @param integer $year year
+ * @param integer $month month
+ * @param integer $day day
+ * @return integer day of week
+ */
+ public static function getDayofWeek($year, $month, $day)
+ {
+ /*
+ Pope Gregory removed 10 days - October 5 to October 14 - from the year 1582 and
+ proclaimed that from that time onwards 3 days would be dropped from the calendar
+ every 400 years.
+
+ Thursday, October 4, 1582 (Julian) was followed immediately by Friday, October 15, 1582 (Gregorian).
+ */
+ if ($year <= 1582)
+ {
+ if ($year < 1582 ||
+ ($year == 1582 && ($month < 10 || ($month == 10 && $day < 15))))
+ {
+ $greg_correction = 3;
+ }
+ else
+ {
+ $greg_correction = 0;
+ }
+ }
+ else
+ {
+ $greg_correction = 0;
+ }
+
+ if($month > 2)
+ $month -= 2;
+ else
+ {
+ $month += 10;
+ $year--;
+ }
+
+ $day = floor((13 * $month - 1) / 5) +
+ $day + ($year % 100) +
+ floor(($year % 100) / 4) +
+ floor(($year / 100) / 4) - 2 *
+ floor($year / 100) + 77 + $greg_correction;
+
+ return $day - 7 * floor($day / 7);
+ }
+
+ /**
+ * Checks for leap year, returns true if it is. No 2-digit year check. Also
+ * handles julian calendar correctly.
+ * @param integer $year year to check
+ * @return boolean true if is leap year
+ */
+ public static function isLeapYear($year)
+ {
+ $year = self::digitCheck($year);
+ if ($year % 4 != 0)
+ return false;
+
+ if ($year % 400 == 0)
+ return true;
+ // if gregorian calendar (>1582), century not-divisible by 400 is not leap
+ else if ($year > 1582 && $year % 100 == 0 )
+ return false;
+ return true;
+ }
+
+ /**
+ * Fix 2-digit years. Works for any century.
+ * Assumes that if 2-digit is more than 30 years in future, then previous century.
+ * @param integer $y year
+ * @return integer change two digit year into multiple digits
+ */
+ protected static function digitCheck($y)
+ {
+ if ($y < 100){
+ $yr = (integer) date("Y");
+ $century = (integer) ($yr /100);
+
+ if ($yr%100 > 50) {
+ $c1 = $century + 1;
+ $c0 = $century;
+ } else {
+ $c1 = $century;
+ $c0 = $century - 1;
+ }
+ $c1 *= 100;
+ // if 2-digit year is less than 30 years in future, set it to this century
+ // otherwise if more than 30 years in future, then we set 2-digit year to the prev century.
+ if (($y + $c1) < $yr+30) $y = $y + $c1;
+ else $y = $y + $c0*100;
+ }
+ return $y;
+ }
+
+ /**
+ * Returns 4-digit representation of the year.
+ * @param integer $y year
+ * @return integer 4-digit representation of the year
+ */
+ public static function get4DigitYear($y)
+ {
+ return self::digitCheck($y);
+ }
+
+ /**
+ * @return integer get local time zone offset from GMT
+ */
+ public static function getGMTDiff()
+ {
+ static $TZ;
+ if (isset($TZ)) return $TZ;
+
+ $TZ = mktime(0,0,0,1,2,1970) - gmmktime(0,0,0,1,2,1970);
+ return $TZ;
+ }
+
+ /**
+ * Returns the getdate() array.
+ * @param integer|boolean $d original date timestamp. False to use the current timestamp.
+ * @param boolean $fast false to compute the day of the week, default is true
+ * @param boolean $gmt true to calculate the GMT dates
+ * @return array an array with date info.
+ */
+ public static function getDate($d=false,$fast=false,$gmt=false)
+ {
+ if($d===false)
+ $d=time();
+ if($gmt)
+ {
+ $tz = date_default_timezone_get();
+ date_default_timezone_set('GMT');
+ $result = getdate($d);
+ date_default_timezone_set($tz);
+ }
+ else
+ {
+ $result = getdate($d);
+ }
+ return $result;
+ }
+
+ /**
+ * Checks to see if the year, month, day are valid combination.
+ * @param integer $y year
+ * @param integer $m month
+ * @param integer $d day
+ * @return boolean true if valid date, semantic check only.
+ */
+ public static function isValidDate($y,$m,$d)
+ {
+ return checkdate($m, $d, $y);
+ }
+
+ /**
+ * Checks to see if the hour, minute and second are valid.
+ * @param integer $h hour
+ * @param integer $m minute
+ * @param integer $s second
+ * @param boolean $hs24 whether the hours should be 0 through 23 (default) or 1 through 12.
+ * @return boolean true if valid date, semantic check only.
+ */
+ public static function isValidTime($h,$m,$s,$hs24=true)
+ {
+ if($hs24 && ($h < 0 || $h > 23) || !$hs24 && ($h < 1 || $h > 12)) return false;
+ if($m > 59 || $m < 0) return false;
+ if($s > 59 || $s < 0) return false;
+ return true;
+ }
+
+ /**
+ * Formats a timestamp to a date string.
+ * @param string $fmt format pattern
+ * @param integer|boolean $d timestamp
+ * @param boolean $is_gmt whether this is a GMT timestamp
+ * @return string formatted date based on timestamp $d
+ */
+ public static function formatDate($fmt,$d=false,$is_gmt=false)
+ {
+ if ($d === false)
+ return ($is_gmt)? @gmdate($fmt): @date($fmt);
+
+ // check if number in 32-bit signed range
+ if ((abs($d) <= 0x7FFFFFFF))
+ {
+ // if windows, must be +ve integer
+ if ($d >= 0)
+ return ($is_gmt)? @gmdate($fmt,$d): @date($fmt,$d);
+ }
+
+ $_day_power = 86400;
+
+ $arr = self::getDate($d,true,$is_gmt);
+
+ $year = $arr['year'];
+ $month = $arr['mon'];
+ $day = $arr['mday'];
+ $hour = $arr['hours'];
+ $min = $arr['minutes'];
+ $secs = $arr['seconds'];
+
+ $max = strlen($fmt);
+ $dates = '';
+
+ /*
+ at this point, we have the following integer vars to manipulate:
+ $year, $month, $day, $hour, $min, $secs
+ */
+ for ($i=0; $i < $max; $i++)
+ {
+ switch($fmt[$i])
+ {
+ case 'T': $dates .= date('T');break;
+ // YEAR
+ case 'L': $dates .= $arr['leap'] ? '1' : '0'; break;
+ case 'r': // Thu, 21 Dec 2000 16:01:07 +0200
+
+ // 4.3.11 uses '04 Jun 2004'
+ // 4.3.8 uses ' 4 Jun 2004'
+ $dates .= gmdate('D',$_day_power*(3+self::getDayOfWeek($year,$month,$day))).', '
+ . ($day<10?'0'.$day:$day) . ' '.date('M',mktime(0,0,0,$month,2,1971)).' '.$year.' ';
+
+ if ($hour < 10) $dates .= '0'.$hour; else $dates .= $hour;
+
+ if ($min < 10) $dates .= ':0'.$min; else $dates .= ':'.$min;
+
+ if ($secs < 10) $dates .= ':0'.$secs; else $dates .= ':'.$secs;
+
+ $gmt = self::getGMTDiff();
+ $dates .= sprintf(' %s%04d',($gmt<=0)?'+':'-',abs($gmt)/36);
+ break;
+
+ case 'Y': $dates .= $year; break;
+ case 'y': $dates .= substr($year,strlen($year)-2,2); break;
+ // MONTH
+ case 'm': if ($month<10) $dates .= '0'.$month; else $dates .= $month; break;
+ case 'Q': $dates .= ($month+3)>>2; break;
+ case 'n': $dates .= $month; break;
+ case 'M': $dates .= date('M',mktime(0,0,0,$month,2,1971)); break;
+ case 'F': $dates .= date('F',mktime(0,0,0,$month,2,1971)); break;
+ // DAY
+ case 't': $dates .= $arr['ndays']; break;
+ case 'z': $dates .= $arr['yday']; break;
+ case 'w': $dates .= self::getDayOfWeek($year,$month,$day); break;
+ case 'l': $dates .= gmdate('l',$_day_power*(3+self::getDayOfWeek($year,$month,$day))); break;
+ case 'D': $dates .= gmdate('D',$_day_power*(3+self::getDayOfWeek($year,$month,$day))); break;
+ case 'j': $dates .= $day; break;
+ case 'd': if ($day<10) $dates .= '0'.$day; else $dates .= $day; break;
+ case 'S':
+ $d10 = $day % 10;
+ if ($d10 == 1) $dates .= 'st';
+ else if ($d10 == 2 && $day != 12) $dates .= 'nd';
+ else if ($d10 == 3) $dates .= 'rd';
+ else $dates .= 'th';
+ break;
+
+ // HOUR
+ case 'Z':
+ $dates .= ($is_gmt) ? 0 : -self::getGMTDiff(); break;
+ case 'O':
+ $gmt = ($is_gmt) ? 0 : self::getGMTDiff();
+
+ $dates .= sprintf('%s%04d',($gmt<=0)?'+':'-',abs($gmt)/36);
+ break;
+
+ case 'H':
+ if ($hour < 10) $dates .= '0'.$hour;
+ else $dates .= $hour;
+ break;
+ case 'h':
+ if ($hour > 12) $hh = $hour - 12;
+ else {
+ if ($hour == 0) $hh = '12';
+ else $hh = $hour;
+ }
+
+ if ($hh < 10) $dates .= '0'.$hh;
+ else $dates .= $hh;
+ break;
+
+ case 'G':
+ $dates .= $hour;
+ break;
+
+ case 'g':
+ if ($hour > 12) $hh = $hour - 12;
+ else {
+ if ($hour == 0) $hh = '12';
+ else $hh = $hour;
+ }
+ $dates .= $hh;
+ break;
+ // MINUTES
+ case 'i': if ($min < 10) $dates .= '0'.$min; else $dates .= $min; break;
+ // SECONDS
+ case 'U': $dates .= $d; break;
+ case 's': if ($secs < 10) $dates .= '0'.$secs; else $dates .= $secs; break;
+ // AM/PM
+ // Note 00:00 to 11:59 is AM, while 12:00 to 23:59 is PM
+ case 'a':
+ if ($hour>=12) $dates .= 'pm';
+ else $dates .= 'am';
+ break;
+ case 'A':
+ if ($hour>=12) $dates .= 'PM';
+ else $dates .= 'AM';
+ break;
+ default:
+ $dates .= $fmt[$i]; break;
+ // ESCAPE
+ case "\\":
+ $i++;
+ if ($i < $max) $dates .= $fmt[$i];
+ break;
+ }
+ }
+ return $dates;
+ }
+
+ /**
+ * Generates a timestamp.
+ * This is the same as the PHP function {@link mktime http://php.net/manual/en/function.mktime.php}.
+ * @param integer $hr hour
+ * @param integer $min minute
+ * @param integer $sec second
+ * @param integer|boolean $mon month
+ * @param integer|boolean $day day
+ * @param integer|boolean $year year
+ * @param boolean $is_gmt whether this is GMT time. If true, gmmktime() will be used.
+ * @return integer|float a timestamp given a local time.
+ */
+ public static function getTimestamp($hr,$min,$sec,$mon=false,$day=false,$year=false,$is_gmt=false)
+ {
+ if ($mon === false)
+ return $is_gmt? @gmmktime($hr,$min,$sec): @mktime($hr,$min,$sec);
+ return $is_gmt ? @gmmktime($hr,$min,$sec,$mon,$day,$year) : @mktime($hr,$min,$sec,$mon,$day,$year);
+ }
+}
diff --git a/framework/utils/CVarDumper.php b/framework/utils/CVarDumper.php
new file mode 100644
index 0000000..c9b0d18
--- /dev/null
+++ b/framework/utils/CVarDumper.php
@@ -0,0 +1,140 @@
+<?php
+/**
+ * CVarDumper class file.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright &copy; 2008-2011 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ */
+
+/**
+ * CVarDumper is intended to replace the buggy PHP function var_dump and print_r.
+ * It can correctly identify the recursively referenced objects in a complex
+ * object structure. It also has a recursive depth control to avoid indefinite
+ * recursive display of some peculiar variables.
+ *
+ * CVarDumper can be used as follows,
+ * <pre>
+ * CVarDumper::dump($var);
+ * </pre>
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @version $Id: CVarDumper.php 2799 2011-01-01 19:31:13Z qiang.xue $
+ * @package system.utils
+ * @since 1.0
+ */
+class CVarDumper
+{
+ private static $_objects;
+ private static $_output;
+ private static $_depth;
+
+ /**
+ * Displays a variable.
+ * This method achieves the similar functionality as var_dump and print_r
+ * but is more robust when handling complex objects such as Yii controllers.
+ * @param mixed $var variable to be dumped
+ * @param integer $depth maximum depth that the dumper should go into the variable. Defaults to 10.
+ * @param boolean $highlight whether the result should be syntax-highlighted
+ */
+ public static function dump($var,$depth=10,$highlight=false)
+ {
+ echo self::dumpAsString($var,$depth,$highlight);
+ }
+
+ /**
+ * Dumps a variable in terms of a string.
+ * This method achieves the similar functionality as var_dump and print_r
+ * but is more robust when handling complex objects such as Yii controllers.
+ * @param mixed $var variable to be dumped
+ * @param integer $depth maximum depth that the dumper should go into the variable. Defaults to 10.
+ * @param boolean $highlight whether the result should be syntax-highlighted
+ * @return string the string representation of the variable
+ */
+ public static function dumpAsString($var,$depth=10,$highlight=false)
+ {
+ self::$_output='';
+ self::$_objects=array();
+ self::$_depth=$depth;
+ self::dumpInternal($var,0);
+ if($highlight)
+ {
+ $result=highlight_string("<?php\n".self::$_output,true);
+ self::$_output=preg_replace('/&lt;\\?php<br \\/>/','',$result,1);
+ }
+ return self::$_output;
+ }
+
+ /*
+ * @param mixed $var variable to be dumped
+ * @param integer $level depth level
+ */
+ private static function dumpInternal($var,$level)
+ {
+ switch(gettype($var))
+ {
+ case 'boolean':
+ self::$_output.=$var?'true':'false';
+ break;
+ case 'integer':
+ self::$_output.="$var";
+ break;
+ case 'double':
+ self::$_output.="$var";
+ break;
+ case 'string':
+ self::$_output.="'".addslashes($var)."'";
+ break;
+ case 'resource':
+ self::$_output.='{resource}';
+ break;
+ case 'NULL':
+ self::$_output.="null";
+ break;
+ case 'unknown type':
+ self::$_output.='{unknown}';
+ break;
+ case 'array':
+ if(self::$_depth<=$level)
+ self::$_output.='array(...)';
+ else if(empty($var))
+ self::$_output.='array()';
+ else
+ {
+ $keys=array_keys($var);
+ $spaces=str_repeat(' ',$level*4);
+ self::$_output.="array\n".$spaces.'(';
+ foreach($keys as $key)
+ {
+ $key2=str_replace("'","\\'",$key);
+ self::$_output.="\n".$spaces." '$key2' => ";
+ self::$_output.=self::dumpInternal($var[$key],$level+1);
+ }
+ self::$_output.="\n".$spaces.')';
+ }
+ break;
+ case 'object':
+ if(($id=array_search($var,self::$_objects,true))!==false)
+ self::$_output.=get_class($var).'#'.($id+1).'(...)';
+ else if(self::$_depth<=$level)
+ self::$_output.=get_class($var).'(...)';
+ else
+ {
+ $id=array_push(self::$_objects,$var);
+ $className=get_class($var);
+ $members=(array)$var;
+ $spaces=str_repeat(' ',$level*4);
+ self::$_output.="$className#$id\n".$spaces.'(';
+ foreach($members as $key=>$value)
+ {
+ $keyDisplay=strtr(trim($key),array("\0"=>':'));
+ self::$_output.="\n".$spaces." [$keyDisplay] => ";
+ self::$_output.=self::dumpInternal($value,$level+1);
+ }
+ self::$_output.="\n".$spaces.')';
+ }
+ break;
+ }
+ }
+}
diff --git a/framework/utils/mimeTypes.php b/framework/utils/mimeTypes.php
new file mode 100644
index 0000000..c077c02
--- /dev/null
+++ b/framework/utils/mimeTypes.php
@@ -0,0 +1,178 @@
+<?php
+/**
+ * MIME types.
+ *
+ * This file contains most commonly used MIME types
+ * according to file extension names.
+ *
+ * @author Qiang Xue <qiang.xue@gmail.com>
+ * @link http://www.yiiframework.com/
+ * @copyright Copyright &copy; 2008-2011 Yii Software LLC
+ * @license http://www.yiiframework.com/license/
+ * @version $Id: mimeTypes.php 3181 2011-04-15 01:26:52Z alexander.makarow $
+ */
+
+return array(
+ 'ai'=>'application/postscript',
+ 'aif'=>'audio/x-aiff',
+ 'aifc'=>'audio/x-aiff',
+ 'aiff'=>'audio/x-aiff',
+ 'asc'=>'text/plain',
+ 'au'=>'audio/basic',
+ 'avi'=>'video/x-msvideo',
+ 'bcpio'=>'application/x-bcpio',
+ 'bin'=>'application/octet-stream',
+ 'bmp'=>'image/bmp',
+ 'c'=>'text/plain',
+ 'cc'=>'text/plain',
+ 'ccad'=>'application/clariscad',
+ 'cdf'=>'application/x-netcdf',
+ 'class'=>'application/octet-stream',
+ 'cpio'=>'application/x-cpio',
+ 'cpt'=>'application/mac-compactpro',
+ 'csh'=>'application/x-csh',
+ 'css'=>'text/css',
+ 'dcr'=>'application/x-director',
+ 'dir'=>'application/x-director',
+ 'dms'=>'application/octet-stream',
+ 'doc'=>'application/msword',
+ 'drw'=>'application/drafting',
+ 'dvi'=>'application/x-dvi',
+ 'dwg'=>'application/acad',
+ 'dxf'=>'application/dxf',
+ 'dxr'=>'application/x-director',
+ 'eps'=>'application/postscript',
+ 'etx'=>'text/x-setext',
+ 'exe'=>'application/octet-stream',
+ 'ez'=>'application/andrew-inset',
+ 'f'=>'text/plain',
+ 'f90'=>'text/plain',
+ 'fli'=>'video/x-fli',
+ 'flv'=>'video/x-flv',
+ 'gif'=>'image/gif',
+ 'gtar'=>'application/x-gtar',
+ 'gz'=>'application/x-gzip',
+ 'h'=>'text/plain',
+ 'hdf'=>'application/x-hdf',
+ 'hh'=>'text/plain',
+ 'hqx'=>'application/mac-binhex40',
+ 'htm'=>'text/html',
+ 'html'=>'text/html',
+ 'ice'=>'x-conference/x-cooltalk',
+ 'ief'=>'image/ief',
+ 'iges'=>'model/iges',
+ 'igs'=>'model/iges',
+ 'ips'=>'application/x-ipscript',
+ 'ipx'=>'application/x-ipix',
+ 'jpe'=>'image/jpeg',
+ 'jpeg'=>'image/jpeg',
+ 'jpg'=>'image/jpeg',
+ 'js'=>'application/x-javascript',
+ 'kar'=>'audio/midi',
+ 'latex'=>'application/x-latex',
+ 'lha'=>'application/octet-stream',
+ 'lsp'=>'application/x-lisp',
+ 'lzh'=>'application/octet-stream',
+ 'm'=>'text/plain',
+ 'man'=>'application/x-troff-man',
+ 'me'=>'application/x-troff-me',
+ 'mesh'=>'model/mesh',
+ 'mid'=>'audio/midi',
+ 'midi'=>'audio/midi',
+ 'mif'=>'application/vnd.mif',
+ 'mime'=>'www/mime',
+ 'mov'=>'video/quicktime',
+ 'movie'=>'video/x-sgi-movie',
+ 'mp2'=>'audio/mpeg',
+ 'mp3'=>'audio/mpeg',
+ 'mpe'=>'video/mpeg',
+ 'mpeg'=>'video/mpeg',
+ 'mpg'=>'video/mpeg',
+ 'mpga'=>'audio/mpeg',
+ 'ms'=>'application/x-troff-ms',
+ 'msh'=>'model/mesh',
+ 'nc'=>'application/x-netcdf',
+ 'oda'=>'application/oda',
+ 'pbm'=>'image/x-portable-bitmap',
+ 'pdb'=>'chemical/x-pdb',
+ 'pdf'=>'application/pdf',
+ 'pgm'=>'image/x-portable-graymap',
+ 'pgn'=>'application/x-chess-pgn',
+ 'png'=>'image/png',
+ 'pnm'=>'image/x-portable-anymap',
+ 'pot'=>'application/mspowerpoint',
+ 'ppm'=>'image/x-portable-pixmap',
+ 'pps'=>'application/mspowerpoint',
+ 'ppt'=>'application/mspowerpoint',
+ 'ppz'=>'application/mspowerpoint',
+ 'pre'=>'application/x-freelance',
+ 'prt'=>'application/pro_eng',
+ 'ps'=>'application/postscript',
+ 'qt'=>'video/quicktime',
+ 'ra'=>'audio/x-realaudio',
+ 'ram'=>'audio/x-pn-realaudio',
+ 'ras'=>'image/cmu-raster',
+ 'rgb'=>'image/x-rgb',
+ 'rm'=>'audio/x-pn-realaudio',
+ 'roff'=>'application/x-troff',
+ 'rpm'=>'audio/x-pn-realaudio-plugin',
+ 'rtf'=>'text/rtf',
+ 'rtx'=>'text/richtext',
+ 'scm'=>'application/x-lotusscreencam',
+ 'set'=>'application/set',
+ 'sgm'=>'text/sgml',
+ 'sgml'=>'text/sgml',
+ 'sh'=>'application/x-sh',
+ 'shar'=>'application/x-shar',
+ 'silo'=>'model/mesh',
+ 'sit'=>'application/x-stuffit',
+ 'skd'=>'application/x-koan',
+ 'skm'=>'application/x-koan',
+ 'skp'=>'application/x-koan',
+ 'skt'=>'application/x-koan',
+ 'smi'=>'application/smil',
+ 'smil'=>'application/smil',
+ 'snd'=>'audio/basic',
+ 'sol'=>'application/solids',
+ 'spl'=>'application/x-futuresplash',
+ 'src'=>'application/x-wais-source',
+ 'step'=>'application/STEP',
+ 'stl'=>'application/SLA',
+ 'stp'=>'application/STEP',
+ 'sv4cpio'=>'application/x-sv4cpio',
+ 'sv4crc'=>'application/x-sv4crc',
+ 'swf'=>'application/x-shockwave-flash',
+ 't'=>'application/x-troff',
+ 'tar'=>'application/x-tar',
+ 'tcl'=>'application/x-tcl',
+ 'tex'=>'application/x-tex',
+ 'texi'=>'application/x-texinfo',
+ 'texinfo'=>'application/x-texinfo',
+ 'tif'=>'image/tiff',
+ 'tiff'=>'image/tiff',
+ 'tr'=>'application/x-troff',
+ 'tsi'=>'audio/TSP-audio',
+ 'tsp'=>'application/dsptype',
+ 'tsv'=>'text/tab-separated-values',
+ 'txt'=>'text/plain',
+ 'unv'=>'application/i-deas',
+ 'ustar'=>'application/x-ustar',
+ 'vcd'=>'application/x-cdlink',
+ 'vda'=>'application/vda',
+ 'viv'=>'video/vnd.vivo',
+ 'vivo'=>'video/vnd.vivo',
+ 'vrml'=>'model/vrml',
+ 'wav'=>'audio/x-wav',
+ 'wrl'=>'model/vrml',
+ 'xbm'=>'image/x-xbitmap',
+ 'xlc'=>'application/vnd.ms-excel',
+ 'xll'=>'application/vnd.ms-excel',
+ 'xlm'=>'application/vnd.ms-excel',
+ 'xls'=>'application/vnd.ms-excel',
+ 'xlw'=>'application/vnd.ms-excel',
+ 'xml'=>'application/xml',
+ 'xpm'=>'image/x-xpixmap',
+ 'xwd'=>'image/x-xwindowdump',
+ 'xyz'=>'chemical/x-pdb',
+ 'zip'=>'application/zip',
+);