Browse Source

add senthot php fw

Hendrawan Kuncoro 12 years ago
parent
commit
d3fe652f64
56 changed files with 9990 additions and 0 deletions
  1. 41 0
      php-senthot/README.md
  2. 24 0
      php-senthot/Senthot/Addons/README.txt
  3. 605 0
      php-senthot/Senthot/Common/common.php
  4. 751 0
      php-senthot/Senthot/Common/functions.php
  5. 240 0
      php-senthot/Senthot/Common/runtime.php
  6. 21 0
      php-senthot/Senthot/Conf/alias.php
  7. 141 0
      php-senthot/Senthot/Conf/convention.php
  8. 30 0
      php-senthot/Senthot/Conf/debug.php
  9. 40 0
      php-senthot/Senthot/Conf/tags.php
  10. 30 0
      php-senthot/Senthot/LICENSE.txt
  11. 50 0
      php-senthot/Senthot/Lang/en-us.php
  12. 51 0
      php-senthot/Senthot/Lang/id-id.php
  13. 210 0
      php-senthot/Senthot/Lib/Behavior/CheckRouteBehavior.class.php
  14. 55 0
      php-senthot/Senthot/Lib/Behavior/ContentReplaceBehavior.class.php
  15. 52 0
      php-senthot/Senthot/Lib/Behavior/LocationTemplateBehavior.class.php
  16. 119 0
      php-senthot/Senthot/Lib/Behavior/ParseTemplateBehavior.class.php
  17. 121 0
      php-senthot/Senthot/Lib/Behavior/ReadHtmlCacheBehavior.class.php
  18. 125 0
      php-senthot/Senthot/Lib/Behavior/ShowPageTraceBehavior.class.php
  19. 82 0
      php-senthot/Senthot/Lib/Behavior/ShowRuntimeBehavior.class.php
  20. 59 0
      php-senthot/Senthot/Lib/Behavior/TokenBuildBehavior.class.php
  21. 32 0
      php-senthot/Senthot/Lib/Behavior/WriteHtmlCacheBehavior.class.php
  22. 426 0
      php-senthot/Senthot/Lib/Core/Action.class.php
  23. 216 0
      php-senthot/Senthot/Lib/Core/App.class.php
  24. 52 0
      php-senthot/Senthot/Lib/Core/Behavior.class.php
  25. 125 0
      php-senthot/Senthot/Lib/Core/Cache.class.php
  26. 876 0
      php-senthot/Senthot/Lib/Core/Db.class.php
  27. 250 0
      php-senthot/Senthot/Lib/Core/Dispatcher.class.php
  28. 113 0
      php-senthot/Senthot/Lib/Core/Log.class.php
  29. 1522 0
      php-senthot/Senthot/Lib/Core/Model.class.php
  30. 292 0
      php-senthot/Senthot/Lib/Core/Sen.class.php
  31. 85 0
      php-senthot/Senthot/Lib/Core/SenException.class.php
  32. 128 0
      php-senthot/Senthot/Lib/Core/View.class.php
  33. 105 0
      php-senthot/Senthot/Lib/Core/Widget.class.php
  34. 185 0
      php-senthot/Senthot/Lib/Driver/Cache/CacheFile.class.php
  35. 347 0
      php-senthot/Senthot/Lib/Driver/Db/DbMysql.class.php
  36. 343 0
      php-senthot/Senthot/Lib/Driver/Db/DbMysqli.class.php
  37. 640 0
      php-senthot/Senthot/Lib/Driver/TagLib/TagLibCx.class.php
  38. 688 0
      php-senthot/Senthot/Lib/Template/SenTemplate.class.php
  39. 229 0
      php-senthot/Senthot/Lib/Template/TagLib.class.php
  40. 123 0
      php-senthot/Senthot/README.txt
  41. 29 0
      php-senthot/Senthot/Senthot.php
  42. 7 0
      php-senthot/Senthot/Tpl/default_index.tpl
  43. 44 0
      php-senthot/Senthot/Tpl/dispatch_jump.tpl
  44. 67 0
      php-senthot/Senthot/Tpl/page_trace.tpl
  45. 55 0
      php-senthot/Senthot/Tpl/sen_exception.tpl
  46. BIN
      php-senthot/Senthot/logo.png
  47. 0 0
      php-senthot/__init__.py
  48. 6 0
      php-senthot/app/.htaccess
  49. 12 0
      php-senthot/app/Conf/config.php
  50. 36 0
      php-senthot/app/Lib/Action/BenchAction.class.php
  51. 9 0
      php-senthot/app/Lib/Action/IndexAction.class.php
  52. 14 0
      php-senthot/app/Tpl/bench/rawfortunes.html
  53. 3 0
      php-senthot/app/index.php
  54. 14 0
      php-senthot/benchmark_config
  55. 43 0
      php-senthot/deploy/nginx.conf
  56. 27 0
      php-senthot/setup.py

+ 41 - 0
php-senthot/README.md

@@ -0,0 +1,41 @@
+# Senthot PHP Benchmarking Test
+
+This is the Senthot PHP portion of a [benchmarking test suite](../) comparing a variety of web development platforms.
+
+### JSON Encoding Test
+Use the PHP standard [JSON encoder](http://www.php.net/manual/en/function.json-encode.php)
+
+* [Test RawController::jsonAction()](app/modules/Bench/controllers/Raw.php)
+
+### Data-Store/Database Mapping Test
+
+* [Test RawController::dbAction()](app/modules/Bench/controllers/Raw.php)
+
+### Template (Fortunes) Test
+
+* [Test RawController::fortunesAction()](app/modules/Bench/controllers/Raw.php)
+
+## Infrastructure Software Versions
+
+The tests were run with:
+
+* [Senthot 2.2.2](http://www.senthot.com/)
+* [PHP Version 5.3.14](http://www.php.net/)
+* [MySQL 5.5.25](https://dev.mysql.com/)
+
+## Test URLs
+### JSON Encoding Test
+
+http://localhost:8080/bench/raw/json
+
+### Data-Store/Database Mapping Test
+
+http://localhost:8080/bench/raw/db
+
+### Variable Query Test
+
+http://localhost:8080/bench/raw/db?queries=5
+
+### Fortunes (Template) Test
+
+http://localhost:8080/bench/raw/fortunes

+ 24 - 0
php-senthot/Senthot/Addons/README.txt

@@ -0,0 +1,24 @@
+
+Addons directory is system extensions directory (core version without any extensions), a subdirectory structure:
+
+|-Action	Controller Extension
+|-Behavior	Behavior Extension
+|-Driver	Drive Expansion
+|  ├Driver/Cache	Cache Drives
+|  ├Driver/Db		Database-driven
+|  ├Driver/Session	SESSION drive
+|  ├Driver/TagLib	Tag library drive
+|  ├Driver/Template	Template engine driven
+|
+|-Engine	Engine Expansion
+|-Function	Function Expansion
+|-Library	Library Expansion
+|  ├ORG	ORG library package
+|  ├COM	COM library package
+|
+|-Mode		Mode Extended
+|-Model		Model extensions
+|-Tool		Other extensions or tools
+|-Vendor	Third-party libraries directory
+
+For details about the addons use, please refer to development manual extensions section.

+ 605 - 0
php-senthot/Senthot/Common/common.php

@@ -0,0 +1,605 @@
+<?php
+// +--------------------------------------------------------------------------
+// | Senthot [ DEVELOPED BY ME ]
+// +--------------------------------------------------------------------------
+// | Copyright (c) 2005-2013 http://www.senthot.com All rights reserved.
+// | License ( http://www.apache.org/licenses/LICENSE-2.0 )
+// | Author: ms134n ( [email protected] )
+// +--------------------------------------------------------------------------
+
+/**
+ * Sen Basic function library
+ * @category	Sen
+ * @package		Common
+ * @author		ms134n <[email protected]>
+ */
+
+/**
+ * Records and statistical time ( microseconds ) and memory usage
+ * Use method:
+ * <code>
+ * G('begin'); // Records the start tag
+ * // ... Interval running code
+ * G('end'); // End of record tag
+ * echo G('begin','end',6); // Running time interval statistics Accurate to six decimal
+ * echo G('begin','end','m'); // Memory usage statistics interval
+ * If the end tag bit is not defined, it will automatically mark the current position as
+ * Which requires memory usage statistics MEMORY_LIMIT_ON Constant is true only valid
+ * </code>
+ * @param string $start Start tag
+ * @param string $end End tag
+ * @param integer|string $dec Decimal places or m
+ * @return mixed
+ */
+function G($start,$end='',$dec=4) {
+    static $_info       =   array();
+    static $_mem        =   array();
+    if(is_float($end)) { // Record Time
+        $_info[$start]  =   $end;
+    }elseif(!empty($end)){ // Time and memory usage statistics
+        if(!isset($_info[$end])) $_info[$end]       =  microtime(TRUE);
+        if(MEMORY_LIMIT_ON && $dec=='m'){
+            if(!isset($_mem[$end])) $_mem[$end]     =  memory_get_usage();
+            return number_format(($_mem[$end]-$_mem[$start])/1024);
+        }else{
+            return number_format(($_info[$end]-$_info[$start]),$dec);
+        }
+
+    }else{ // Record Time and memory usage
+        $_info[$start]  =  microtime(TRUE);
+        if(MEMORY_LIMIT_ON) $_mem[$start]           =  memory_get_usage();
+    }
+}
+
+/**
+ * Set and get statistics
+ * Use method:
+ * <code>
+ * N('db',1); // Record the number of database operations
+ * N('read',1); // Record reads
+ * echo N('db'); // Get the current page number of all database operations
+ * echo N('read'); // Get the current page reads
+ * </code>
+ * @param string $key Identify the location
+ * @param integer $step Step value
+ * @return mixed
+ */
+function N($key, $step=0,$save=false) {
+    static $_num    = array();
+    if (!isset($_num[$key])) {
+        $_num[$key] = (false !== $save)? S('N_'.$key) :  0;
+    }
+    if (empty($step))
+        return $_num[$key];
+    else
+        $_num[$key] = $_num[$key] + (int) $step;
+    if(false !== $save){ // Save Results
+        S('N_'.$key,$_num[$key],$save);
+    }
+}
+
+/**
+ * Convert string naming style
+ * type 0 The Java-style converted to C style 1 The C-style into Java style
+ * @param string $name String
+ * @param integer $type Conversion Type
+ * @return string
+ */
+function parse_name($name, $type=0) {
+    if ($type) {
+        return ucfirst(preg_replace("/_([a-zA-Z])/e", "strtoupper('\\1')", $name));
+    } else {
+        return strtolower(trim(preg_replace("/[A-Z]/", "_\\0", $name), "_"));
+    }
+}
+
+/**
+ * Optimized require_once
+ * @param string $filename File address
+ * @return boolean
+ */
+function require_cache($filename) {
+    static $_importFiles = array();
+    if (!isset($_importFiles[$filename])) {
+        if (file_exists_case($filename)) {
+            require $filename;
+            $_importFiles[$filename] = true;
+        } else {
+            $_importFiles[$filename] = false;
+        }
+    }
+    return $_importFiles[$filename];
+}
+
+/**
+ * Batch import file Success, returns
+ * @param array $array Array of files
+ * @param boolean $return Loaded successfully whether to return
+ * @return boolean
+ */
+function require_array($array,$return=false){
+    foreach ($array as $file){
+        if (require_cache($file) && $return) return true;
+    }
+    if($return) return false;
+}
+
+/**
+ * Judged case-sensitive file exists
+ * @param string $filename File address
+ * @return boolean
+ */
+function file_exists_case($filename) {
+    if (is_file($filename)) {
+        if (IS_WIN && C('APP_FILE_CASE')) {
+            if (basename(realpath($filename)) != basename($filename))
+                return false;
+        }
+        return true;
+    }
+    return false;
+}
+
+/**
+ * Import the required class libraries With Java Import This function has the cache function
+ * @param string $class Class Library namespace string
+ * @param string $baseUrl Start Path
+ * @param string $ext Importing the file extension
+ * @return boolean
+ */
+function import($class, $baseUrl = '', $ext='.class.php') {
+    static $_file = array();
+    $class = str_replace(array('.', '#'), array('/', '.'), $class);
+    if ('' === $baseUrl && false === strpos($class, '/')) {
+        // Check the alias import
+        return alias_import($class);
+    }
+    if (isset($_file[$class . $baseUrl]))
+        return true;
+    else
+        $_file[$class . $baseUrl] = true;
+    $class_strut     = explode('/', $class);
+    if (empty($baseUrl)) {
+        $libPath    =   defined('BASE_LIB_PATH')?BASE_LIB_PATH:LIB_PATH;
+        if ('@' == $class_strut[0] || APP_NAME == $class_strut[0]) {
+            //Load current project application library
+            $baseUrl = dirname($libPath);
+            $class   = substr_replace($class, basename($libPath).'/', 0, strlen($class_strut[0]) + 1);
+        }elseif ('sen' == strtolower($class_strut[0])){ // sen Official Base Class Library
+            $baseUrl = CORE_PATH;
+            $class   = substr($class,6);
+        }elseif (in_array(strtolower($class_strut[0]), array('org', 'com'))) {
+            // org Third-party public libraries com Corporate public library
+            $baseUrl = LIBRARY_PATH;
+        }else { // Other items loaded application library
+            $class   = substr_replace($class, '', 0, strlen($class_strut[0]) + 1);
+            $baseUrl = APP_PATH . '../' . $class_strut[0] . '/'.basename($libPath).'/';
+        }
+    }
+    if (substr($baseUrl, -1) != '/')
+        $baseUrl    .= '/';
+    $classfile       = $baseUrl . $class . $ext;
+    if (!class_exists(basename($class),false)) {
+        // If the class does not exist The import library file
+        return require_cache($classfile);
+    }
+}
+
+/**
+ * Way based on namespaces imported library
+ * load('@.Util.Array')
+ * @param string $name Library namespace string
+ * @param string $baseUrl Start Path
+ * @param string $ext Importing the file extension
+ * @return void
+ */
+function load($name, $baseUrl='', $ext='.php') {
+    $name = str_replace(array('.', '#'), array('/', '.'), $name);
+    if (empty($baseUrl)) {
+        if (0 === strpos($name, '@/')) {
+            //Load current project library
+            $baseUrl    = COMMON_PATH;
+            $name       = substr($name, 2);
+        } else {
+            //Load Senthot System Function Library
+            $baseUrl    = ADDONS_PATH . 'Function/';
+        }
+    }
+    if (substr($baseUrl, -1) != '/')
+        $baseUrl       .= '/';
+    require_cache($baseUrl . $name . $ext);
+}
+
+/**
+ * Quickly import third-party frameworks library All third-party frameworks into a unified library files System, Vendor directory
+ * @param string $class Library
+ * @param string $baseUrl Base directory
+ * @param string $ext Library suffix
+ * @return boolean
+ */
+function vendor($class, $baseUrl = '', $ext='.php') {
+    if (empty($baseUrl))
+        $baseUrl = VENDOR_PATH;
+    return import($class, $baseUrl, $ext);
+}
+
+/**
+ * Quickly define and import alias Support batch Definition
+ * @param string|array $alias Alias library
+ * @param string $classfile Corresponding library
+ * @return boolean
+ */
+function alias_import($alias, $classfile='') {
+    static $_alias = array();
+    if (is_string($alias)) {
+        if(isset($_alias[$alias])) {
+            return require_cache($_alias[$alias]);
+        }elseif ('' !== $classfile) {
+            // Defining aliases import
+            $_alias[$alias] = $classfile;
+            return;
+        }
+    }elseif (is_array($alias)) {
+        $_alias   =  array_merge($_alias,$alias);
+        return;
+    }
+    return false;
+}
+
+/**
+ * D Functions Use for instantiating Model Format Project://Grouping/Module
+ * @param string $name Model resource address
+ * @param string $layer Business layer name
+ * @return Model
+ */
+function D($name='',$layer='') {
+    if(empty($name)) return new Model;
+    static $_model  =   array();
+    $layer          =   $layer?$layer:C('DEFAULT_M_LAYER');
+    if(strpos($name,'://')) {// Specify the project
+        $name       =   str_replace('://','/'.$layer.'/',$name);
+    }else{
+        $name       =   C('DEFAULT_APP').'/'.$layer.'/'.$name;
+    }
+    if(isset($_model[$name]))   return $_model[$name];
+    import($name.$layer);
+    $class          =   basename($name.$layer);
+    if(class_exists($class)) {
+        $model      =   new $class();
+    }else {
+        $model      =   new Model(basename($name));
+    }
+    $_model[$name]  =  $model;
+    return $model;
+}
+
+/**
+ * M function Use for instantiating a no model file Model
+ * @param string $name Model Name Support base model designation For example, MongoModel:User
+ * @param string $tablePrefix Table Prefix
+ * @param mixed $connection Database connection information
+ * @return Model
+ */
+function M($name='', $tablePrefix='',$connection='') {
+    static $_model  = array();
+    if(strpos($name,':')) {
+        list($class,$name)    =  explode(':',$name);
+    }else{
+        $class      =   'Model';
+    }
+    $guid           =   $tablePrefix . $name . '_' . $class;
+    if (!isset($_model[$guid]))
+        $_model[$guid] = new $class($name,$tablePrefix,$connection);
+    return $_model[$guid];
+}
+
+/**
+ * A function Use for instantiation Action Format:[Project://][Grouping/]Module
+ * @param string $name Action Resources Address
+ * @param string $layer Control layer name
+ * @param boolean $common Whether public directory
+ * @return Action|false
+ */
+function A($name,$layer='',$common=false) {
+    static $_action = array();
+    $layer      =   $layer?$layer:C('DEFAULT_C_LAYER');
+    if(strpos($name,'://')) {// Specify the project
+        $name   =  str_replace('://','/'.$layer.'/',$name);
+    }else{
+        $name   =  '@/'.$layer.'/'.$name;
+    }
+    if(isset($_action[$name]))  return $_action[$name];
+    if($common){ // Independent groups case Loading public directories library
+        import(str_replace('@/','',$name).$layer,LIB_PATH);
+    }else{
+        import($name.$layer);
+    }
+    $class      =   basename($name.$layer);
+    if(class_exists($class,false)) {
+        $action             = new $class();
+        $_action[$name]     =  $action;
+        return $action;
+    }else {
+        return false;
+    }
+}
+
+/**
+ * Remote method invocation module operation URL Parameter format [Project://][Grouping/]Module/Operating
+ * @param string $url Call address
+ * @param string|array $vars Call parameters Support strings and arrays
+ * @param string $layer To invoke the name of the control layer
+ * @return mixed
+ */
+function R($url,$vars=array(),$layer='') {
+    $info   =   pathinfo($url);
+    $action =   $info['basename'];
+    $module =   $info['dirname'];
+    $class  =   A($module,$layer);
+    if($class){
+        if(is_string($vars)) {
+            parse_str($vars,$vars);
+        }
+        return call_user_func_array(array(&$class,$action.C('ACTION_SUFFIX')),$vars);
+    }else{
+        return false;
+    }
+}
+
+/**
+ * Get and Set language definition(Insensitive)
+ * @param string|array $name Linguistic variables
+ * @param string $value Language values
+ * @return mixed
+ */
+function L($name=null, $value=null) {
+    static $_lang = array();
+    // Empty parameter returns all definitions
+    if (empty($name))
+        return $_lang;
+    // Determine the language for(Or set up)
+    // If there, direct return all uppercase $name
+    if (is_string($name)) {
+        $name = strtoupper($name);
+        if (is_null($value))
+            return isset($_lang[$name]) ? $_lang[$name] : $name;
+        $_lang[$name] = $value; // Language definition
+        return;
+    }
+    // Batch Definition
+    if (is_array($name))
+        $_lang = array_merge($_lang, array_change_key_case($name, CASE_UPPER));
+    return;
+}
+
+/**
+ * Get and set configuration parameters Support batch Definition
+ * @param string|array $name Configuration Variables
+ * @param mixed $value Configuration values
+ * @return mixed
+ */
+function C($name=null, $value=null) {
+    static $_config = array();
+    // No parameters for all
+    if (empty($name)) {
+        if(!empty($value) && $array = S('c_'.$value)) {
+            $_config = array_merge($_config, array_change_key_case($array));
+        }
+        return $_config;
+    }
+    // Get or set the precedence assignment
+    if (is_string($name)) {
+        if (!strpos($name, '.')) {
+            $name = strtolower($name);
+            if (is_null($value))
+                return isset($_config[$name]) ? $_config[$name] : null;
+            $_config[$name] = $value;
+            return;
+        }
+        // Dimensional array set and get Support
+        $name = explode('.', $name);
+        $name[0]   =  strtolower($name[0]);
+        if (is_null($value))
+            return isset($_config[$name[0]][$name[1]]) ? $_config[$name[0]][$name[1]] : null;
+        $_config[$name[0]][$name[1]] = $value;
+        return;
+    }
+    // Batch settings
+    if (is_array($name)){
+        $_config = array_merge($_config, array_change_key_case($name));
+        if(!empty($value)) {// Save the configuration values
+            S('c_'.$value,$_config);
+        }
+        return;
+    }
+    return null; // Avoid illegal argument
+}
+
+/**
+ * Tag extension treatment
+ * @param string $tag Tag name
+ * @param mixed $params Incoming parameters
+ * @return mixed
+ */
+function tag($tag, &$params=NULL) {
+    // System tab expansion
+    $extends    = C('extends.' . $tag);
+    // Apply Tag Expansion
+    $tags       = C('tags.' . $tag);
+    if (!empty($tags)) {
+        if(empty($tags['_overlay']) && !empty($extends)) { // Merge extended
+            $tags = array_unique(array_merge($extends,$tags));
+        }elseif(isset($tags['_overlay'])){ // By setting '_overlay'=>1 coverSystem tag
+            unset($tags['_overlay']);
+        }
+    }elseif(!empty($extends)) {
+        $tags = $extends;
+    }
+    if($tags) {
+        if(APP_DEBUG) {
+            G($tag.'Start');
+            trace('[ '.$tag.' ] --START--','','INFO');
+        }
+        // Execute extended
+        foreach ($tags as $key=>$name) {
+            if(!is_int($key)) { // Specify the full path of the class acts Use forMode extended
+                $name   = $key;
+            }
+            B($name, $params);
+        }
+        if(APP_DEBUG) { // Record the behavior of execution log
+            trace('[ '.$tag.' ] --END-- [ RunTime:'.G($tag.'Start',$tag.'End',6).'s ]','','INFO');
+        }
+    }else{ // Did not perform any act Return false
+        return false;
+    }
+}
+
+/**
+ * Behavior extended to dynamically add a tag
+ * @param string $tag Tag name
+ * @param string $behavior Behavior name
+ * @param string $path Behavior Path
+ * @return void
+ */
+function add_tag_behavior($tag,$behavior,$path='') {
+    $array      =  C('tags.'.$tag);
+    if(!$array) {
+        $array  =  array();
+    }
+    if($path) {
+        $array[$behavior] = $path;
+    }else{
+        $array[] =  $behavior;
+    }
+    C('tags.'.$tag,$array);
+}
+
+/**
+ * Perform an action
+ * @param string $name Behavior name
+ * @param Mixed $params Transmission parameters
+ * @return void
+ */
+function B($name, &$params=NULL) {
+    $class      = $name.'Behavior';
+    if(APP_DEBUG) {
+        G('behaviorStart');
+    }
+    $behavior   = new $class();
+    $behavior->run($params);
+    if(APP_DEBUG) { // Record the behavior of execution log
+        G('behaviorEnd');
+        trace('Run '.$name.' Behavior [ RunTime:'.G('behaviorStart','behaviorEnd',6).'s ]','','INFO');
+    }
+}
+
+/**
+ * Removing whitespace and comments in the code
+ * @param string $content Code Contents
+ * @return string
+ */
+function strip_whitespace($content) {
+    $stripStr   = '';
+    //Php source code analysis
+    $tokens     = token_get_all($content);
+    $last_space = false;
+    for ($i = 0, $j = count($tokens); $i < $j; $i++) {
+        if (is_string($tokens[$i])) {
+            $last_space = false;
+            $stripStr  .= $tokens[$i];
+        } else {
+            switch ($tokens[$i][0]) {
+                //Filter various PHP comments
+                case T_COMMENT:
+                case T_DOC_COMMENT:
+                    break;
+                //Filter spaces
+                case T_WHITESPACE:
+                    if (!$last_space) {
+                        $stripStr  .= ' ';
+                        $last_space = true;
+                    }
+                    break;
+                case T_START_HEREDOC:
+                    $stripStr .= "<<<SEN\n";
+                    break;
+                case T_END_HEREDOC:
+                    $stripStr .= "SEN;\n";
+                    for($k = $i+1; $k < $j; $k++) {
+                        if(is_string($tokens[$k]) && $tokens[$k] == ';') {
+                            $i = $k;
+                            break;
+                        } else if($tokens[$k][0] == T_CLOSE_TAG) {
+                            break;
+                        }
+                    }
+                    break;
+                default:
+                    $last_space = false;
+                    $stripStr  .= $tokens[$i][1];
+            }
+        }
+    }
+    return $stripStr;
+}
+
+//[RUNTIME]
+// Compiled file
+function compile($filename) {
+    $content        = file_get_contents($filename);
+    // Replace pre-compiler directives
+    $content        = preg_replace('/\/\/\[RUNTIME\](.*?)\/\/\[\/RUNTIME\]/s', '', $content);
+    $content        = substr(trim($content), 5);
+    if ('?>' == substr($content, -2))
+        $content    = substr($content, 0, -2);
+    return $content;
+}
+
+// According to the array generates constant definitions
+function array_define($array,$check=true) {
+    $content = "\n";
+    foreach ($array as $key => $val) {
+        $key = strtoupper($key);
+        if($check)   $content .= 'defined(\'' . $key . '\') or ';
+        if (is_int($val) || is_float($val)) {
+            $content .= "define('" . $key . "'," . $val . ');';
+        } elseif (is_bool($val)) {
+            $val = ($val) ? 'true' : 'false';
+            $content .= "define('" . $key . "'," . $val . ');';
+        } elseif (is_string($val)) {
+            $content .= "define('" . $key . "','" . addslashes($val) . "');";
+        }
+        $content    .= "\n";
+    }
+    return $content;
+}
+//[/RUNTIME]
+
+/**
+ * Trace records to add and get the page
+ * @param string $value Variable
+ * @param string $label Tag
+ * @param string $level Log Level
+ * @param boolean $record Whether logging
+ * @return void
+ */
+function trace($value='[sen]',$label='',$level='DEBUG',$record=false) {
+    static $_trace =  array();
+    if('[sen]' === $value){ // Gets the trace information
+        return $_trace;
+    }else{
+        $info   =   ($label?$label.':':'').print_r($value,true);
+        if('ERR' == $level && C('TRACE_EXCEPTION')) {// throw an exception
+            throw_exception($info);
+        }
+        $level  =   strtoupper($level);
+        if(!isset($_trace[$level])) {
+                $_trace[$level] =   array();
+            }
+        $_trace[$level][]   = $info;
+        if((defined('IS_AJAX') && IS_AJAX) || !C('SHOW_PAGE_TRACE')  || $record) {
+            Log::record($info,$level,$record);
+        }
+    }
+}

+ 751 - 0
php-senthot/Senthot/Common/functions.php

@@ -0,0 +1,751 @@
+<?php
+// +--------------------------------------------------------------------------
+// | Senthot [ DEVELOPED BY ME ]
+// +--------------------------------------------------------------------------
+// | Copyright (c) 2005-2013 http://www.senthot.com All rights reserved.
+// | License ( http://www.apache.org/licenses/LICENSE-2.0 )
+// | Author: ms134n ( [email protected] )
+// +--------------------------------------------------------------------------
+
+/**
+ * Sen Standard Mode public library
+ * @category	Sen
+ * @package		Common
+ * @author		ms134n <[email protected]>
+ */
+
+/**
+ * Error Output
+ * @param mixed $error Error
+ * @return void
+ */
+function halt($error) {
+    $e = array();
+    if (APP_DEBUG) {
+        //The following error message is output Debug Mode
+        if (!is_array($error)) {
+            $trace          = debug_backtrace();
+            $e['message']   = $error;
+            $e['file']      = $trace[0]['file'];
+            $e['class']     = isset($trace[0]['class'])?$trace[0]['class']:'';
+            $e['function']  = isset($trace[0]['function'])?$trace[0]['function']:'';
+            $e['line']      = $trace[0]['line'];
+            $traceInfo      = '';
+            $time = date('y-m-d H:i:m');
+            foreach ($trace as $t) {
+                $traceInfo .= '[' . $time . '] ' . $t['file'] . ' (' . $t['line'] . ') ';
+                $traceInfo .= $t['class'] . $t['type'] . $t['function'] . '(';
+                $traceInfo .= implode(', ', $t['args']);
+                $traceInfo .=')<br/>';
+            }
+            $e['trace']     = $traceInfo;
+        } else {
+            $e              = $error;
+        }
+    } else {
+        //Otherwise directed to the error page
+        $error_page         = C('ERROR_PAGE');
+        if (!empty($error_page)) {
+            redirect($error_page);
+        } else {
+            if (C('SHOW_ERROR_MSG'))
+                $e['message'] = is_array($error) ? $error['message'] : $error;
+            else
+                $e['message'] = C('ERROR_MESSAGE');
+        }
+    }
+    // Contains an exception page templates
+    include C('TMPL_EXCEPTION_FILE');
+    exit;
+}
+
+/**
+ * Custom Exception Handling
+ * @param string $msg The exception message
+ * @param string $type Exception Types The default is SenException
+ * @param integer $code Exception Code The default is 0
+ * @return void
+ */
+function throw_exception($msg, $type='SenException', $code=0) {
+    if (class_exists($type, false))
+        throw new $type($msg, $code, true);
+    else
+        halt($msg);        // Exception type does not exist error message is output string
+}
+
+/**
+ * Browser-friendly variable output
+ * @param mixed $var Variable
+ * @param boolean $echo Whether to output default is True If false Output string is returned
+ * @param string $label Tag The default is empty
+ * @param boolean $strict Whether rigorous default is true
+ * @return void|string
+ */
+function dump($var, $echo=true, $label=null, $strict=true) {
+    $label = ($label === null) ? '' : rtrim($label) . ' ';
+    if (!$strict) {
+        if (ini_get('html_errors')) {
+            $output = print_r($var, true);
+            $output = '<pre>' . $label . htmlspecialchars($output, ENT_QUOTES) . '</pre>';
+        } else {
+            $output = $label . print_r($var, true);
+        }
+    } else {
+        ob_start();
+        var_dump($var);
+        $output = ob_get_clean();
+        if (!extension_loaded('xdebug')) {
+            $output = preg_replace('/\]\=\>\n(\s+)/m', '] => ', $output);
+            $output = '<pre>' . $label . htmlspecialchars($output, ENT_QUOTES) . '</pre>';
+        }
+    }
+    if ($echo) {
+        echo($output);
+        return null;
+    }else
+        return $output;
+}
+
+/**
+ * 404 Processing 
+ * Debug Mode will throw an exception 
+ * Deployment Mode Here you can specify the url parameter passed Jump page, or send 404 message
+ * @param string $msg Tips
+ * @param string $url Jump URL address
+ * @return void
+ */
+function _404($msg='',$url='') {
+    APP_DEBUG && throw_exception($msg);
+    if($msg && C('LOG_EXCEPTION_RECORD')) Log::write($msg);
+    if(empty($url) && C('URL_404_REDIRECT')) {
+        $url    =   C('URL_404_REDIRECT');
+    }
+    if($url) {
+        redirect($url);
+    }else{
+        send_http_status(404);
+        exit;
+    }
+}
+
+/**
+ * Set the current layout of the page
+ * @param string|false $layout Layout Name When the representation is false closure layout
+ * @return void
+ */
+function layout($layout) {
+    if(false !== $layout) {
+        // Open layout
+        C('LAYOUT_ON',true);
+        if(is_string($layout)) { // Set up a new layout template
+            C('LAYOUT_NAME',$layout);
+        }
+    }else{// Temporary closure layout
+        C('LAYOUT_ON',false);
+    }
+}
+
+/**
+ * URL Assembly Support different URLMode
+ * @param string $url URL expressions, Format:'[Grouping/Module/Operating#Anchor@DomainName]?Parameter1=Value1&Parameter2=Value2...'
+ * @param string|array $vars Incoming parameters, Support arrays and strings
+ * @param string $suffix Pseudo-static suffix, the default configuration values for the true means to obtain
+ * @param boolean $redirect Whether the jump, if set to true then the jump to the URL address
+ * @param boolean $domain Whether to display the name
+ * @return string
+ */
+function U($url='',$vars='',$suffix=true,$redirect=false,$domain=false) {
+    // Parse URL
+    $info   =  parse_url($url);
+    $url    =  !empty($info['path'])?$info['path']:ACTION_NAME;
+    if(isset($info['fragment'])) { // Resolution anchor
+        $anchor =   $info['fragment'];
+        if(false !== strpos($anchor,'?')) { // Analytical parameters
+            list($anchor,$info['query']) = explode('?',$anchor,2);
+        }        
+        if(false !== strpos($anchor,'@')) { // Resolve domain names
+            list($anchor,$host)    =   explode('@',$anchor, 2);
+        }
+    }elseif(false !== strpos($url,'@')) { // Resolve domain names
+        list($url,$host)    =   explode('@',$info['path'], 2);
+    }
+    // Analytic subdomain
+    if(isset($host)) {
+        $domain = $host.(strpos($host,'.')?'':strstr($_SERVER['HTTP_HOST'],'.'));
+    }elseif($domain===true){
+        $domain = $_SERVER['HTTP_HOST'];
+        if(C('APP_SUB_DOMAIN_DEPLOY') ) { // On sub-domain deployment
+            $domain = $domain=='localhost'?'localhost':'www'.strstr($_SERVER['HTTP_HOST'],'.');
+            // 'Subdomain'=>array('Project[/Grouping]');
+            foreach (C('APP_SUB_DOMAIN_RULES') as $key => $rule) {
+                if(false === strpos($key,'*') && 0=== strpos($url,$rule[0])) {
+                    $domain = $key.strstr($domain,'.'); // Generate the corresponding sub-domain
+                    $url    =  substr_replace($url,'',0,strlen($rule[0]));
+                    break;
+                }
+            }
+        }
+    }
+
+    // Analytical parameters
+    if(is_string($vars)) { // aaa=1&bbb=2 Converted into an array
+        parse_str($vars,$vars);
+    }elseif(!is_array($vars)){
+        $vars = array();
+    }
+    if(isset($info['query'])) { // Resolve the address inside the parameters Merged into vars
+        parse_str($info['query'],$params);
+        $vars = array_merge($params,$vars);
+    }
+    
+    // URL Assembly
+    $depr = C('URL_PATHINFO_DEPR');
+    if($url) {
+        if(0=== strpos($url,'/')) {// Defining Routing
+            $route      =   true;
+            $url        =   substr($url,1);
+            if('/' != $depr) {
+                $url    =   str_replace('/',$depr,$url);
+            }
+        }else{
+            if('/' != $depr) { // Secure replacement
+                $url    =   str_replace('/',$depr,$url);
+            }
+            // Packet parsing module and operating
+            $url        =   trim($url,$depr);
+            $path       =   explode($depr,$url);
+            $var        =   array();
+            $var[C('VAR_ACTION')]       =   !empty($path)?array_pop($path):ACTION_NAME;
+            $var[C('VAR_MODULE')]       =   !empty($path)?array_pop($path):MODULE_NAME;
+            if($maps = C('URL_ACTION_MAP')) {
+                if(isset($maps[strtolower($var[C('VAR_MODULE')])])) {
+                    $maps    =   $maps[strtolower($var[C('VAR_MODULE')])];
+                    if($action = array_search(strtolower($var[C('VAR_ACTION')]),$maps)){
+                        $var[C('VAR_ACTION')] = $action;
+                    }
+                }
+            }
+            if($maps = C('URL_MODULE_MAP')) {
+                if($module = array_search(strtolower($var[C('VAR_MODULE')]),$maps)){
+                    $var[C('VAR_MODULE')] = $module;
+                }
+            }            
+            if(C('URL_CASE_INSENSITIVE')) {
+                $var[C('VAR_MODULE')]   =   parse_name($var[C('VAR_MODULE')]);
+            }
+            if(!C('APP_SUB_DOMAIN_DEPLOY') && C('APP_GROUP_LIST')) {
+                if(!empty($path)) {
+                    $group                  =   array_pop($path);
+                    $var[C('VAR_GROUP')]    =   $group;
+                }else{
+                    if(GROUP_NAME != C('DEFAULT_GROUP')) {
+                        $var[C('VAR_GROUP')]=   GROUP_NAME;
+                    }
+                }
+                if(C('URL_CASE_INSENSITIVE') && isset($var[C('VAR_GROUP')])) {
+                    $var[C('VAR_GROUP')]    =  strtolower($var[C('VAR_GROUP')]);
+                }
+            }
+        }
+    }
+
+    if(C('URL_MODEL') == 0) { // Normal modeURL conversion
+        $url        =   __APP__.'?'.http_build_query(array_reverse($var));
+        if(!empty($vars)) {
+            $vars   =   urldecode(http_build_query($vars));
+            $url   .=   '&'.$vars;
+        }
+    }else{ // PATHINFOMode or compatible URLMode
+        if(isset($route)) {
+            $url    =   __APP__.'/'.rtrim($url,$depr);
+        }else{
+            $url    =   __APP__.'/'.implode($depr,array_reverse($var));
+        }
+        if(!empty($vars)) { // Adding Parameters
+            foreach ($vars as $var => $val){
+                if('' !== trim($val))   $url .= $depr . $var . $depr . urlencode($val);
+            }                
+        }
+        if($suffix) {
+            $suffix   =  $suffix===true?C('URL_HTML_SUFFIX'):$suffix;
+            if($pos = strpos($suffix, '|')){
+                $suffix = substr($suffix, 0, $pos);
+            }
+            if($suffix && '/' != substr($url,-1)){
+                $url  .=  '.'.ltrim($suffix,'.');
+            }
+        }
+    }
+    if(isset($anchor)){
+        $url  .= '#'.$anchor;
+    }
+    if($domain) {
+        $url   =  (is_ssl()?'https://':'http://').$domain.$url;
+    }
+    if($redirect) // Jump directly to URL
+        redirect($url);
+    else
+        return $url;
+}
+
+/**
+ * Render Output Widget
+ * @param string $name Widget name
+ * @param array $data Transmission parameters
+ * @param boolean $return Returns the content 
+ * @return void
+ */
+function W($name, $data=array(), $return=false) {
+    $class      =   $name . 'Widget';
+    require_cache(BASE_LIB_PATH . 'Widget/' . $class . '.class.php');
+    if (!class_exists($class))
+        throw_exception(L('_CLASS_NOT_EXIST_') . ':' . $class);
+    $widget     =   Sen::instance($class);
+    $content    =   $widget->render($data);
+    if ($return)
+        return $content;
+    else
+        echo $content;
+}
+
+/**
+ * Filter method Passing a value by reference
+ * @param string $name Filter name
+ * @param string $content To filter the content
+ * @return void
+ */
+function filter($name, &$content) {
+    $class      =   $name . 'Filter';
+    require_cache(BASE_LIB_PATH . 'Filter/' . $class . '.class.php');
+    $filter     =   new $class();
+    $content    =   $filter->run($content);
+}
+
+/**
+ * Determine whether the SSL protocol
+ * @return boolean
+ */
+function is_ssl() {
+    if(isset($_SERVER['HTTPS']) && ('1' == $_SERVER['HTTPS'] || 'on' == strtolower($_SERVER['HTTPS']))){
+        return true;
+    }elseif(isset($_SERVER['SERVER_PORT']) && ('443' == $_SERVER['SERVER_PORT'] )) {
+        return true;
+    }
+    return false;
+}
+
+/**
+ * URL Redirection
+ * @param string $url Redirect URL address
+ * @param integer $time Redirection waiting time ( sec )
+ * @param string $msg Message before redirecting
+ * @return void
+ */
+function redirect($url, $time=0, $msg='') {
+    //Support multi-line URL address
+    $url        = str_replace(array("\n", "\r"), '', $url);
+    if (empty($msg))
+        $msg    = "System will {$time}seconds automatically jump to {$url}!";
+    if (!headers_sent()) {
+        // redirect
+        if (0 === $time) {
+            header('Location: ' . $url);
+        } else {
+            header("refresh:{$time};url={$url}");
+            echo($msg);
+        }
+        exit();
+    } else {
+        $str    = "<meta http-equiv='Refresh' content='{$time};URL={$url}'>";
+        if ($time != 0)
+            $str .= $msg;
+        exit($str);
+    }
+}
+
+/**
+ * Cache Management
+ * @param mixed $name Cache name, if it is expressed as an array cache settings
+ * @param mixed $value Cached value
+ * @param mixed $options Cache parameters
+ * @return mixed
+ */
+function S($name,$value='',$options=null) {
+    static $cache   =   '';
+    if(is_array($options)){
+        // Cache operation while initializing
+        $type       =   isset($options['type'])?$options['type']:'';
+        $cache      =   Cache::getInstance($type,$options);
+    }elseif(is_array($name)) { // Cache initialization
+        $type       =   isset($name['type'])?$name['type']:'';
+        $cache      =   Cache::getInstance($type,$name);
+        return $cache;
+    }elseif(empty($cache)) { // Automatic initialization
+        $cache      =   Cache::getInstance();
+    }
+    if(''=== $value){ // Get Cache
+        return $cache->get($name);
+    }elseif(is_null($value)) { // Deleting the cache
+        return $cache->rm($name);
+    }else { // Cache data
+        $expire     =   is_numeric($options)?$options:NULL;
+        return $cache->set($name, $value, $expire);
+    }
+}
+// S method aliases has been abolished no longer recommended
+function cache($name,$value='',$options=null){
+    return S($name,$value,$options);
+}
+
+/**
+ * Fast read and save data files For simple data types Strings, arrays
+ * @param string $name Cache name
+ * @param mixed $value Cached value
+ * @param string $path Cache path
+ * @return mixed
+ */
+function F($name, $value='', $path=DATA_PATH) {
+    static $_cache  = array();
+    $filename       = $path . $name . '.php';
+    if ('' !== $value) {
+        if (is_null($value)) {
+            // Deleting the cache
+            return false !== strpos($name,'*')?array_map("unlink", glob($filename)):unlink($filename);
+        } else {
+            // Cache data
+            $dir            =   dirname($filename);
+            // Directory does not exist, create
+            if (!is_dir($dir))
+                mkdir($dir,0755,true);
+            $_cache[$name]  =   $value;
+            return file_put_contents($filename, strip_whitespace("<?php\treturn " . var_export($value, true) . ";?>"));
+        }
+    }
+    if (isset($_cache[$name]))
+        return $_cache[$name];
+    // Get cached data
+    if (is_file($filename)) {
+        $value          =   include $filename;
+        $_cache[$name]  =   $value;
+    } else {
+        $value          =   false;
+    }
+    return $value;
+}
+
+/**
+ * Get object instance Support call the class static method
+ * @param string $name Class name
+ * @param string $method Method name, if it is empty then return instantiate objects
+ * @param array $args Call parameters
+ * @return object
+ */
+function get_instance_of($name, $method='', $args=array()) {
+    static $_instance = array();
+    $identify = empty($args) ? $name . $method : $name . $method . to_guid_string($args);
+    if (!isset($_instance[$identify])) {
+        if (class_exists($name)) {
+            $o = new $name();
+            if (method_exists($o, $method)) {
+                if (!empty($args)) {
+                    $_instance[$identify] = call_user_func_array(array(&$o, $method), $args);
+                } else {
+                    $_instance[$identify] = $o->$method();
+                }
+            }
+            else
+                $_instance[$identify] = $o;
+        }
+        else
+            halt(L('_CLASS_NOT_EXIST_') . ':' . $name);
+    }
+    return $_instance[$identify];
+}
+
+/**
+ * According to PHP variable types to generate a unique identification number
+ * @param mixed $mix Variable
+ * @return string
+ */
+function to_guid_string($mix) {
+    if (is_object($mix) && function_exists('spl_object_hash')) {
+        return spl_object_hash($mix);
+    } elseif (is_resource($mix)) {
+        $mix = get_resource_type($mix) . strval($mix);
+    } else {
+        $mix = serialize($mix);
+    }
+    return md5($mix);
+}
+
+/**
+ * XML encoding
+ * @param mixed $data Data
+ * @param string $encoding Data encoding
+ * @param string $root Root name
+ * @return string
+ */
+function xml_encode($data, $encoding='utf-8', $root='sen') {
+    $xml    = '<?xml version="1.0" encoding="' . $encoding . '"?>';
+    $xml   .= '<' . $root . '>';
+    $xml   .= data_to_xml($data);
+    $xml   .= '</' . $root . '>';
+    return $xml;
+}
+
+/**
+ * XML-encoded data
+ * @param mixed $data Data
+ * @return string
+ */
+function data_to_xml($data) {
+    $xml = '';
+    foreach ($data as $key => $val) {
+        is_numeric($key) && $key = "item id=\"$key\"";
+        $xml    .=  "<$key>";
+        $xml    .=  ( is_array($val) || is_object($val)) ? data_to_xml($val) : $val;
+        list($key, ) = explode(' ', $key);
+        $xml    .=  "</$key>";
+    }
+    return $xml;
+}
+
+/**
+ * session management functions
+ * @param string|array $name session name If an array indicates settings for session
+ * @param mixed $value session value
+ * @return mixed
+ */
+function session($name,$value='') {
+    $prefix   =  C('SESSION_PREFIX');
+    if(is_array($name)) { // session initialization in session_start before calling
+        if(isset($name['prefix'])) C('SESSION_PREFIX',$name['prefix']);
+        if(C('VAR_SESSION_ID') && isset($_REQUEST[C('VAR_SESSION_ID')])){
+            session_id($_REQUEST[C('VAR_SESSION_ID')]);
+        }elseif(isset($name['id'])) {
+            session_id($name['id']);
+        }
+        ini_set('session.auto_start', 0);
+        if(isset($name['name']))            session_name($name['name']);
+        if(isset($name['path']))            session_save_path($name['path']);
+        if(isset($name['domain']))          ini_set('session.cookie_domain', $name['domain']);
+        if(isset($name['expire']))          ini_set('session.gc_maxlifetime', $name['expire']);
+        if(isset($name['use_trans_sid']))   ini_set('session.use_trans_sid', $name['use_trans_sid']?1:0);
+        if(isset($name['use_cookies']))     ini_set('session.use_cookies', $name['use_cookies']?1:0);
+        if(isset($name['cache_limiter']))   session_cache_limiter($name['cache_limiter']);
+        if(isset($name['cache_expire']))    session_cache_expire($name['cache_expire']);
+        if(isset($name['type']))            C('SESSION_TYPE',$name['type']);
+        if(C('SESSION_TYPE')) { // Reading session drive
+            $class      = 'Session'. ucwords(strtolower(C('SESSION_TYPE')));
+            // Check the driver class
+            if(require_cache(ADDONS_PATH.'Driver/Session/'.$class.'.class.php')) {
+                $hander = new $class();
+                $hander->execute();
+            }else {
+                // Class does not define
+                throw_exception(L('_CLASS_NOT_EXIST_').': ' . $class);
+            }
+        }
+        // Start session
+        if(C('SESSION_AUTO_START'))  session_start();
+    }elseif('' === $value){ 
+        if(0===strpos($name,'[')) { // session Operating
+            if('[pause]'==$name){ // Pause session
+                session_write_close();
+            }elseif('[start]'==$name){ // Start session
+                session_start();
+            }elseif('[destroy]'==$name){ // Destroys the session
+                $_SESSION =  array();
+                session_unset();
+                session_destroy();
+            }elseif('[regenerate]'==$name){ // Rebuild id
+                session_regenerate_id();
+            }
+        }elseif(0===strpos($name,'?')){ // Examination session
+            $name   =  substr($name,1);
+            if($prefix) {
+                return isset($_SESSION[$prefix][$name]);
+            }else{
+                return isset($_SESSION[$name]);
+            }
+        }elseif(is_null($name)){ // Empty session
+            if($prefix) {
+                unset($_SESSION[$prefix]);
+            }else{
+                $_SESSION = array();
+            }
+        }elseif($prefix){ // Get session
+            return isset($_SESSION[$prefix][$name])?$_SESSION[$prefix][$name]:null;
+        }else{
+            return isset($_SESSION[$name])?$_SESSION[$name]:null;
+        }
+    }elseif(is_null($value)){ // Delete session
+        if($prefix){
+            unset($_SESSION[$prefix][$name]);
+        }else{
+            unset($_SESSION[$name]);
+        }
+    }else{ // Set session
+        if($prefix){
+            if (!is_array($_SESSION[$prefix])) {
+                $_SESSION[$prefix] = array();
+            }
+            $_SESSION[$prefix][$name]   =  $value;
+        }else{
+            $_SESSION[$name]  =  $value;
+        }
+    }
+}
+
+/**
+ * Cookie set, get, delete
+ * @param string $name cookie name
+ * @param mixed $value cookie value
+ * @param mixed $options cookie parameters
+ * @return mixed
+ */
+function cookie($name, $value='', $option=null) {
+    // Default setting
+    $config = array(
+        'prefix'    =>  C('COOKIE_PREFIX'), // cookie Name Prefix
+        'expire'    =>  C('COOKIE_EXPIRE'), // cookie Save Time
+        'path'      =>  C('COOKIE_PATH'), // cookie Save path
+        'domain'    =>  C('COOKIE_DOMAIN'), // cookie Valid domain name
+    );
+    // Parameter settings(will cover the default setting Summerside)
+    if (!is_null($option)) {
+        if (is_numeric($option))
+            $option = array('expire' => $option);
+        elseif (is_string($option))
+            parse_str($option, $option);
+        $config     = array_merge($config, array_change_key_case($option));
+    }
+    // Clear all cookie specified Prefix
+    if (is_null($name)) {
+        if (empty($_COOKIE))
+            return;
+        // To delete cookiePrefix, not specified remove the config settings specified Prefix
+        $prefix = empty($value) ? $config['prefix'] : $value;
+        if (!empty($prefix)) {// If Prefix is an empty string will not be processed directly back
+            foreach ($_COOKIE as $key => $val) {
+                if (0 === stripos($key, $prefix)) {
+                    setcookie($key, '', time() - 3600, $config['path'], $config['domain']);
+                    unset($_COOKIE[$key]);
+                }
+            }
+        }
+        return;
+    }
+    $name = $config['prefix'] . $name;
+    if ('' === $value) {
+        if(isset($_COOKIE[$name])){
+            $value =    $_COOKIE[$name];
+            if(0===strpos($value,'sen:')){
+                $value  =   substr($value,6);
+                return array_map('urldecode',json_decode(MAGIC_QUOTES_GPC?stripslashes($value):$value,true));
+            }else{
+                return $value;
+            }
+        }else{
+            return null;
+        }
+    } else {
+        if (is_null($value)) {
+            setcookie($name, '', time() - 3600, $config['path'], $config['domain']);
+            unset($_COOKIE[$name]); // Deletes the specified cookie
+        } else {
+            // Set a cookie
+            if(is_array($value)){
+                $value  = 'sen:'.json_encode(array_map('urlencode',$value));
+            }
+            $expire = !empty($config['expire']) ? time() + intval($config['expire']) : 0;
+            setcookie($name, $value, $expire, $config['path'], $config['domain']);
+            $_COOKIE[$name] = $value;
+        }
+    }
+}
+
+/**
+ * Loaded dynamically expanding file
+ * @return void
+ */
+function load_ext_file() {
+    // Load custom external file
+    if(C('LOAD_EXT_FILE')) {
+        $files      =  explode(',',C('LOAD_EXT_FILE'));
+        foreach ($files as $file){
+            $file   = COMMON_PATH.$file.'.php';
+            if(is_file($file)) include $file;
+        }
+    }
+    // Dynamic load custom configuration files
+    if(C('LOAD_EXT_CONFIG')) {
+        $configs    =  C('LOAD_EXT_CONFIG');
+        if(is_string($configs)) $configs =  explode(',',$configs);
+        foreach ($configs as $key=>$config){
+            $file   = CONF_PATH.$config.'.php';
+            if(is_file($file)) {
+                is_numeric($key)?C(include $file):C($key,include $file);
+            }
+        }
+    }
+}
+
+/**
+ * Get client IP address
+ * @param integer $type Return Type 0 Returns the IP address 1 Back IPV4 address numbers
+ * @return mixed
+ */
+function get_client_ip($type = 0) {
+	$type       =  $type ? 1 : 0;
+    static $ip  =   NULL;
+    if ($ip !== NULL) return $ip[$type];
+    if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
+        $arr    =   explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
+        $pos    =   array_search('unknown',$arr);
+        if(false !== $pos) unset($arr[$pos]);
+        $ip     =   trim($arr[0]);
+    }elseif (isset($_SERVER['HTTP_CLIENT_IP'])) {
+        $ip     =   $_SERVER['HTTP_CLIENT_IP'];
+    }elseif (isset($_SERVER['REMOTE_ADDR'])) {
+        $ip     =   $_SERVER['REMOTE_ADDR'];
+    }
+    // IP address of the legal verification
+    $long = sprintf("%u",ip2long($ip));
+    $ip   = $long ? array($ip, $long) : array('0.0.0.0', 0);
+    return $ip[$type];
+}
+
+/**
+ * Send HTTP status
+ * @param integer $code Status Codes
+ * @return void
+ */
+function send_http_status($code) {
+    static $_status = array(
+        // Success 2xx
+        200 => 'OK',
+        // Redirection 3xx
+        301 => 'Moved Permanently',
+        302 => 'Moved Temporarily ',  // 1.1
+        // Client Error 4xx
+        400 => 'Bad Request',
+        403 => 'Forbidden',
+        404 => 'Not Found',
+        // Server Error 5xx
+        500 => 'Internal Server Error',
+        503 => 'Service Unavailable',
+    );
+    if(isset($_status[$code])) {
+        header('HTTP/1.1 '.$code.' '.$_status[$code]);
+        // Ensure FastCGIMode normal
+        header('Status:'.$code.' '.$_status[$code]);
+    }
+}
+
+// Filter expression in the form
+function filter_exp(&$value){
+    if (in_array(strtolower($value),array('exp','or'))){
+        $value .= ' ';
+    }
+}

+ 240 - 0
php-senthot/Senthot/Common/runtime.php

@@ -0,0 +1,240 @@
+<?php
+// +--------------------------------------------------------------------------
+// | Senthot [ DEVELOPED BY ME ]
+// +--------------------------------------------------------------------------
+// | Copyright (c) 2005-2013 http://www.senthot.com All rights reserved.
+// | License ( http://www.apache.org/licenses/LICENSE-2.0 )
+// | Author: ms134n ( [email protected] )
+// +--------------------------------------------------------------------------
+
+/**
+ * Senthot Runtime files Compiled longer loaded
+ * @category	Sen
+ * @package		Common
+ * @author		ms134n <[email protected]>
+ */
+defined('SEN_PATH') or exit();
+if(version_compare(PHP_VERSION,'5.2.0','<'))  die('require PHP > 5.2.0 !');
+
+//  Version Information
+define('SEN_VERSION', '2.2.2');
+
+//   System Information
+if(version_compare(PHP_VERSION,'5.4.0','<')) {
+    ini_set('magic_quotes_runtime',0);
+    define('MAGIC_QUOTES_GPC',get_magic_quotes_gpc()?True:False);
+}else{
+    define('MAGIC_QUOTES_GPC',false);
+}
+define('IS_CGI',substr(PHP_SAPI, 0,3)=='cgi' ? 1 : 0 );
+define('IS_WIN',strstr(PHP_OS, 'WIN') ? 1 : 0 );
+define('IS_CLI',PHP_SAPI=='cli'? 1   :   0);
+
+// Project Name
+defined('APP_NAME') or define('APP_NAME', basename(dirname($_SERVER['SCRIPT_FILENAME'])));
+
+if(!IS_CLI) {
+    // Current file name
+    if(!defined('_PHP_FILE_')) {
+        if(IS_CGI) {
+            //CGI/FASTCGIMode under
+            $_temp  = explode('.php',$_SERVER['PHP_SELF']);
+            define('_PHP_FILE_',    rtrim(str_replace($_SERVER['HTTP_HOST'],'',$_temp[0].'.php'),'/'));
+        }else {
+            define('_PHP_FILE_',    rtrim($_SERVER['SCRIPT_NAME'],'/'));
+        }
+    }
+    if(!defined('__ROOT__')) {
+        // Site URL root
+        if( strtoupper(APP_NAME) == strtoupper(basename(dirname(_PHP_FILE_))) ) {
+            $_root = dirname(dirname(_PHP_FILE_));
+        }else {
+            $_root = dirname(_PHP_FILE_);
+        }
+        define('__ROOT__',   (($_root=='/' || $_root=='\\')?'':$_root));
+    }
+
+    //Support the URLMode
+    define('URL_COMMON',      0);   //Normal mode
+    define('URL_PATHINFO',    1);   //PATHINFOMode
+    define('URL_REWRITE',     2);   //REWRITEMode
+    define('URL_COMPAT',      3);   // Compatibility Mode
+}
+
+// Path settings Can be redefined in the import documents All paths must be in constant/ End
+defined('CORE_PATH')    or define('CORE_PATH',      SEN_PATH.'Lib/'); // Core class library System catalog
+defined('ADDONS_PATH')  or define('ADDONS_PATH',    SEN_PATH.'Addons/'); // System extensions directory
+defined('MODE_PATH')    or define('MODE_PATH',      ADDONS_PATH.'Mode/'); // Mode extension directory
+defined('ENGINE_PATH')  or define('ENGINE_PATH',    ADDONS_PATH.'Engine/'); // Engine extensions directory
+defined('VENDOR_PATH')  or define('VENDOR_PATH',    ADDONS_PATH.'Vendor/'); // List of third-party class libraries
+defined('LIBRARY_PATH') or define('LIBRARY_PATH',   ADDONS_PATH.'Library/'); // Addonsing class library directory
+defined('COMMON_PATH')  or define('COMMON_PATH',    APP_PATH.'Common/'); // Public directory
+defined('LIB_PATH')     or define('LIB_PATH',       APP_PATH.'Lib/'); // Project class library directory
+defined('CONF_PATH')    or define('CONF_PATH',      APP_PATH.'Conf/'); // List of project configurations
+defined('LANG_PATH')    or define('LANG_PATH',      APP_PATH.'Lang/'); // Project language pack directory
+defined('TMPL_PATH')    or define('TMPL_PATH',      APP_PATH.'Tpl/'); // Project template directory
+defined('HTML_PATH')    or define('HTML_PATH',      APP_PATH.'Html/'); // Project static directory
+defined('LOG_PATH')     or define('LOG_PATH',       RUNTIME_PATH.'Logs/'); // Project log directory
+defined('TEMP_PATH')    or define('TEMP_PATH',      RUNTIME_PATH.'Temp/'); // Project cache directory
+defined('DATA_PATH')    or define('DATA_PATH',      RUNTIME_PATH.'Data/'); // Project data directory
+defined('CACHE_PATH')   or define('CACHE_PATH',     RUNTIME_PATH.'Cache/'); // Project template cache directory
+
+// In order to facilitate import third-party class libraries Set up Vendor Directory to the include_path
+set_include_path(get_include_path() . PATH_SEPARATOR . VENDOR_PATH);
+
+// Load the file you need to run And is responsible for the automatic list generation
+function load_runtime_file() {
+    // Loading SystemBasic function library
+    require SEN_PATH.'Common/common.php';
+    // Read the core file list
+    $list = array(
+        CORE_PATH.'Core/Sen.class.php',
+        CORE_PATH.'Core/SenException.class.php',  // Exception class
+        CORE_PATH.'Core/Behavior.class.php',
+    );
+    // Loading Mode file list
+    foreach ($list as $key=>$file){
+        if(is_file($file))  require_cache($file);
+    }
+    // System class library is loaded the alias definition
+    alias_import(include SEN_PATH.'Conf/alias.php');
+
+    // Check the project directory structure If it does not exist it is created automatically
+    if(!is_dir(LIB_PATH)) {
+        // To create the project directory structure
+        build_app_dir();
+    }elseif(!is_dir(CACHE_PATH)){
+        // Checking cache directory
+        check_runtime();
+    }elseif(APP_DEBUG){
+        // Toggle Debugging Mode delete the compiler cache
+        if(is_file(RUNTIME_FILE))   unlink(RUNTIME_FILE);
+    }
+}
+
+// Checking cache directory(Runtime) If it does not exist it is created automatically
+function check_runtime() {
+    if(!is_dir(RUNTIME_PATH)) {
+        mkdir(RUNTIME_PATH);
+    }elseif(!is_writeable(RUNTIME_PATH)) {
+        header('Content-Type:text/html; charset=utf-8');
+        exit('Directory [ '.RUNTIME_PATH.' ] Is not writable!');
+    }
+    mkdir(CACHE_PATH);  // Template cache directory
+    if(!is_dir(LOG_PATH))   mkdir(LOG_PATH);    // Log directory
+    if(!is_dir(TEMP_PATH))  mkdir(TEMP_PATH);   // Data cache directory
+    if(!is_dir(DATA_PATH))  mkdir(DATA_PATH);   // Data file directory
+    return true;
+}
+
+// Create a compiler cache
+function build_runtime_cache($append='') {
+    // Generates compiled files
+    $defs           = get_defined_constants(TRUE);
+    $content        =  '$GLOBALS[\'_beginTime\'] = microtime(TRUE);';
+    if(defined('RUNTIME_DEF_FILE')) { // Outside compiled constants file introduction
+        file_put_contents(RUNTIME_DEF_FILE,'<?php '.array_define($defs['user']));
+        $content   .=  'require \''.RUNTIME_DEF_FILE.'\';';
+    }else{
+        $content   .= array_define($defs['user']);
+    }
+    $content       .= 'set_include_path(get_include_path() . PATH_SEPARATOR . VENDOR_PATH);';
+    // Core reading list compiled file
+    $list = array(
+        SEN_PATH.'Common/common.php',
+        CORE_PATH.'Core/Sen.class.php',
+        CORE_PATH.'Core/SenException.class.php',
+        CORE_PATH.'Core/Behavior.class.php',
+    );
+    foreach ($list as $file){
+        $content .= compile($file);
+    }
+    // Addonsed File System behavior to compile
+    $content .= build_tags_cache();
+    
+    $alias      = include SEN_PATH.'Conf/alias.php';
+    $content   .= 'alias_import('.var_export($alias,true).');';
+    // Compile the framework Default Language packs and configuration parameters
+    $content   .= $append."\nL(".var_export(L(),true).");C(".var_export(C(),true).');G(\'loadTime\');Sen::Start();';
+    file_put_contents(RUNTIME_FILE,strip_whitespace('<?php '.str_replace("defined('SEN_PATH') or exit();",' ',$content)));
+}
+
+// Compilation System extension class library
+function build_tags_cache() {
+    $tags = C('extends');
+    $content = '';
+    foreach ($tags as $tag=>$item){
+        foreach ($item as $key=>$name) {
+            $content .= is_int($key)?compile(CORE_PATH.'Behavior/'.$name.'Behavior.class.php'):compile($name);
+        }
+    }
+    return $content;
+}
+
+// To create the project directory structure
+function build_app_dir() {
+    // Failed to create project directory is created automatically
+    if(!is_dir(APP_PATH)) mkdir(APP_PATH,0755,true);
+    if(is_writeable(APP_PATH)) {
+        $dirs  = array(
+            LIB_PATH,
+            RUNTIME_PATH,
+            CONF_PATH,
+            COMMON_PATH,
+            LANG_PATH,
+            CACHE_PATH,
+            TMPL_PATH,
+            TMPL_PATH.C('DEFAULT_THEME').'/',
+            LOG_PATH,
+            TEMP_PATH,
+            DATA_PATH,
+            LIB_PATH.'Model/',
+            LIB_PATH.'Action/',
+            LIB_PATH.'Behavior/',
+            LIB_PATH.'Widget/',
+            );
+        foreach ($dirs as $dir){
+            if(!is_dir($dir))  mkdir($dir,0755,true);
+        }
+        // Write to directory security file
+        build_dir_secure($dirs);
+        // Write the initial configuration file
+        if(!is_file(CONF_PATH.'config.php'))
+            file_put_contents(CONF_PATH.'config.php',"<?php\nreturn array(\n\t//'Configuration item'=>'Configuration values'\n);\n?>");
+        // Written test Action
+        if(!is_file(LIB_PATH.'Action/IndexAction.class.php'))
+            build_first_action();
+    }else{
+        header('Content-Type:text/html; charset=utf-8');
+        exit('The project directory is not writable directory cannot be automatically generated!<BR>Please use the project Builder or manually generated list of projects~');
+    }
+}
+
+// Create a test Action
+function build_first_action() {
+    $content = file_get_contents(SEN_PATH.'Tpl/default_index.tpl');
+    file_put_contents(LIB_PATH.'Action/IndexAction.class.php',$content);
+}
+
+// Build directory security file
+function build_dir_secure($dirs='') {
+    // Write directory security
+    if(defined('BUILD_DIR_SECURE') && BUILD_DIR_SECURE) {
+        defined('DIR_SECURE_FILENAME')  or define('DIR_SECURE_FILENAME',    'index.html');
+        defined('DIR_SECURE_CONTENT')   or define('DIR_SECURE_CONTENT',     ' ');
+        // Automatic write to directory security file
+        $content = DIR_SECURE_CONTENT;
+        $files = explode(',', DIR_SECURE_FILENAME);
+        foreach ($files as $filename){
+            foreach ($dirs as $dir)
+                file_put_contents($dir.$filename,$content);
+        }
+    }
+}
+
+// Required to load the runtime files
+load_runtime_file();
+// Records the time loading files
+G('loadTime');
+// Execute the entry
+Sen::Start();

+ 21 - 0
php-senthot/Senthot/Conf/alias.php

@@ -0,0 +1,21 @@
+<?php
+// +--------------------------------------------------------------------------
+// | Senthot [ DEVELOPED BY ME ]
+// +--------------------------------------------------------------------------
+// | Copyright (c) 2005-2013 http://www.senthot.com All rights reserved.
+// | License ( http://www.apache.org/licenses/LICENSE-2.0 )
+// | Author: ms134n ( [email protected] )
+// +--------------------------------------------------------------------------
+
+defined('SEN_PATH') or exit();
+// System alias definition file
+return array(
+    'Model'         => CORE_PATH.'Core/Model.class.php',
+    'Db'            => CORE_PATH.'Core/Db.class.php',
+    'Log'          	=> CORE_PATH.'Core/Log.class.php',
+    'SenTemplate' => CORE_PATH.'Template/SenTemplate.class.php',
+    'TagLib'        => CORE_PATH.'Template/TagLib.class.php',
+    'Cache'         => CORE_PATH.'Core/Cache.class.php',
+    'Widget'        => CORE_PATH.'Core/Widget.class.php',
+    'TagLibCx'      => CORE_PATH.'Driver/TagLib/TagLibCx.class.php',
+);

+ 141 - 0
php-senthot/Senthot/Conf/convention.php

@@ -0,0 +1,141 @@
+<?php
+// +--------------------------------------------------------------------------
+// | Senthot [ DEVELOPED BY ME ]
+// +--------------------------------------------------------------------------
+// | Copyright (c) 2005-2013 http://www.senthot.com All rights reserved.
+// | License ( http://www.apache.org/licenses/LICENSE-2.0 )
+// | Author: ms134n ( [email protected] )
+// +--------------------------------------------------------------------------
+
+/**
+ * Senthot practice profile
+ * Please do not modify the file , if you want to overwrite the configured value convention , the configuration file in the project settings and practices inconsistent configuration items
+ * Case of arbitrary configuration name , the system will unify converted to lowercase
+ * All configuration parameters can be dynamically changed before the commencement
+ * @category Sen
+ * @package		Common
+ * @author		ms134n <[email protected]>
+ * @version  $Id: convention.php 3088 2012-07-29 09:12:19Z [email protected] $
+ */
+defined('SEN_PATH') or exit();
+return  array(
+    /* Item Settings */
+    'APP_STATUS'            => 'debug',  // Application debugging mode status Debug mode is turned on effective The default is debug Scalable And automatically loads the corresponding configuration file
+    'APP_FILE_CASE'         => false,   // Whether to check the case file Valid for Windows platforms
+    'APP_AUTOLOAD_PATH'     => '',// Automatic loading mechanism of automatic path search, Note that the search order
+    'APP_TAGS_ON'           => true, // System tab expansion switch
+    'APP_SUB_DOMAIN_DEPLOY' => false,   // Whether to open the sub-domain deployment
+    'APP_SUB_DOMAIN_RULES'  => array(), // Subdomain deployment rules
+    'APP_SUB_DOMAIN_DENY'   => array(), //  Subdomain disabled list
+    'APP_GROUP_LIST'        => '',      // Project grouping setting, Multiple groups with commas,For example,'Home,Admin'
+    'APP_GROUP_MODE'        =>  0,  // Packet Mode 0 General Packet 1 Independent groups
+    'APP_GROUP_PATH'        =>  'Modules', // Grouping directory Independent groupsMode following effective
+    'ACTION_SUFFIX'         =>  '', // Operation suffix
+
+    /* Cookie settings */
+    'COOKIE_EXPIRE'         => 0,    // Cookie validity
+    'COOKIE_DOMAIN'         => '',      // Cookie valid domain name
+    'COOKIE_PATH'           => '/',     // Cookie Path
+    'COOKIE_PREFIX'         => '',      // Cookie prefix Avoid conflicts
+
+    /* Default setting */
+    'DEFAULT_M_LAYER'       =>  'Model', // Default name of the model layer
+    'DEFAULT_C_LAYER'       =>  'Action', // Default controller layer name
+    'DEFAULT_APP'           => '@',     // Default project name, @ indicates that the current project
+    'DEFAULT_LANG'          => 'id-id', // Default language
+    'DEFAULT_THEME'         => '',	// Default template Subject Name
+    'DEFAULT_GROUP'         => 'Home',  // Default grouping
+    'DEFAULT_MODULE'        => 'Index', // Default module name
+    'DEFAULT_ACTION'        => 'index', // Default operation name
+    'DEFAULT_CHARSET'       => 'utf-8', // Default output encoding
+    'DEFAULT_TIMEZONE'      => 'PRC',	// Default time zone
+    'DEFAULT_AJAX_RETURN'   => 'JSON',  // Default AJAX Return data format, Optional JSON XML ...
+    'DEFAULT_JSONP_HANDLER' => 'jsonpReturn', // The default format returned JSONP approach
+    'DEFAULT_FILTER'        => 'htmlspecialchars', // Default parameter filtering methods Use for $this->_get('Variable name');$this->_post('Variable name')...
+
+    /* Database Settings */
+    'DB_TYPE'               => 'mysql',     // Database Type
+    'DB_HOST'               => 'localhost', // Server Address
+    'DB_NAME'               => '',          // Database name
+    'DB_USER'               => 'root',      // Username
+    'DB_PWD'                => '',          // Password
+    'DB_PORT'               => '',        // Port
+    'DB_PREFIX'             => 'sen_',    // Database table prefix
+    'DB_FIELDTYPE_CHECK'    => false,       // Checking whether a field type
+    'DB_FIELDS_CACHE'       => true,        // Enabling field cache
+    'DB_CHARSET'            => 'utf8',      // Database encoding defaults to utf8
+    'DB_DEPLOY_TYPE'        => 0, // Database deployment:0 Centralized(Single Server), 1 Distributed(Master-slave server)
+    'DB_RW_SEPARATE'        => false,       // Whether separate database literacy Master-slave effective
+    'DB_MASTER_NUM'         => 1, // Read and write after separation Number of master server
+    'DB_SLAVE_NO'           => '', // Specifies the Server serial number
+    'DB_SQL_BUILD_CACHE'    => false, // Create a SQL database query cache
+    'DB_SQL_BUILD_QUEUE'    => 'file',   // SQL cache buffer queue mode Support file xcache and apc
+    'DB_SQL_BUILD_LENGTH'   => 20, // SQL cache queue length
+    'DB_SQL_LOG'            => false, // SQL execution logging
+
+    /* Data cache settings */
+    'DATA_CACHE_TIME'       => 0,      // Valid data cache 0 indicates persistent cache
+    'DATA_CACHE_COMPRESS'   => false,   // Whether to compress data buffer cache
+    'DATA_CACHE_CHECK'      => false,   // Whether parity cache data cache
+    'DATA_CACHE_PREFIX'     => '',     // Cache prefix
+    'DATA_CACHE_TYPE'       => 'File',  // Data cache type, support:File|Db|Apc|Memcache|Shmop|Sqlite|Xcache|Apachenote|Eaccelerator
+    'DATA_CACHE_PATH'       => TEMP_PATH,// Cache path settings (File caching is only effective way)
+    'DATA_CACHE_SUBDIR'     => false,    // Using cache subdirectory (Automatically creates a subdirectory cache hash mark)
+    'DATA_PATH_LEVEL'       => 1,        // Subdirectory cache levels
+
+    /* Incorrect settings */
+    'ERROR_MESSAGE'         => 'Page Error ! Please try again later ~',//Error display information, Non-debug mode is active
+    'ERROR_PAGE'            => '',	// Misdirected page
+    'SHOW_ERROR_MSG'        => false,    // Display an error message
+    'TRACE_EXCEPTION'       => false,   // TRACE is throwing an exception error message Methods for trace
+
+    /* Log Settings */
+    'LOG_RECORD'            => false,   // Default log does not record
+    'LOG_TYPE'              => 3, // Logging Type 0 System 1 Mail 3 File 4 SAPI The default mode for the file
+    'LOG_DEST'              => '', // Logging Target
+    'LOG_EXTRA'             => '', // Logging additional information
+    'LOG_LEVEL'             => 'EMERG,ALERT,CRIT,ERR',// Allows you to record the log level
+    'LOG_FILE_SIZE'         => 2097152,	// Log file size limit
+    'LOG_EXCEPTION_RECORD'  => false,    // Whether to log exception information log
+
+    /* SESSION settings */
+    'SESSION_AUTO_START'    => true,    // Whether to automatically open Session
+    'SESSION_OPTIONS'       => array(), // session Configuration Array Supporttype name id path expire domian And other parameters
+    'SESSION_TYPE'          => '', // session hander type No need to set the default Unless extended session hander Drive
+    'SESSION_PREFIX'        => '', // session Prefix
+    //'VAR_SESSION_ID'      => 'session_id',     //Submission of variable sessionID
+
+    /* Template engine settings */
+    'TMPL_CONTENT_TYPE'     => 'text/html', // Default Template Output Type
+    'TMPL_ACTION_ERROR'     => SEN_PATH.'Tpl/dispatch_jump.tpl', // Jump corresponding default error template file
+    'TMPL_ACTION_SUCCESS'   => SEN_PATH.'Tpl/dispatch_jump.tpl', // Successful jumps corresponding default template file
+    'TMPL_EXCEPTION_FILE'   => SEN_PATH.'Tpl/sen_exception.tpl',// Exception page template file
+    'TMPL_DETECT_THEME'     => false,       // Automatically detects the template theme
+    'TMPL_TEMPLATE_SUFFIX'  => '.html',     // The default template file suffix
+    'TMPL_FILE_DEPR'        =>  '/', //MODULE_NAME and ACTION_NAME template file delimiters between
+
+    /* URL setting */
+    'URL_CASE_INSENSITIVE'  => false,   // Default false indicates that the URL is case sensitive true indicates a case-insensitive
+    'URL_MODEL'             => 1,       // URL access mode, optional parameters 0,1,2,3, represent the following four modes:
+    // 0 (Normal mode); 1 (PATHINFO Mode); 2 (REWRITE  Mode); 3 (Compatibility Mode)  The default is PATHINFO Mode, provide the best user experience and SEOSupport
+    'URL_PATHINFO_DEPR'     => '/',	// PATHINFOMode , the division among the parameters symbols
+    'URL_PATHINFO_FETCH'    =>   'ORIG_PATH_INFO,REDIRECT_PATH_INFO,REDIRECT_URL', // Use for compatible judge PATH_INFO SERVER parameter substitution variables list
+    'URL_HTML_SUFFIX'       => '',  // URL suffix settings pseudo-static
+    'URL_PARAMS_BIND'       =>  true, // URL variables bound to the Action method parameters
+    'URL_404_REDIRECT'      =>  '', // 404 Jump page Effective Deployment Mode
+
+    /* System variable name setting */
+    'VAR_GROUP'             => 'g',     // Default grouping get variable
+    'VAR_MODULE'            => 'm',		// Default module for variable
+    'VAR_ACTION'            => 'a',		// Default action for the variable
+    'VAR_AJAX_SUBMIT'       => 'ajax',  // The default AJAX submit variables
+    'VAR_JSONP_HANDLER'     => 'callback',
+    'VAR_PATHINFO'          => 's',	// PATHINFO Compatibility Mode Gets variables such as ?s=/module/action/id/1 Subsequent parameters depend URL_PATHINFO_DEPR
+    'VAR_URL_PARAMS'        => '_URL_', // PATHINFO URL parameter variables
+    'VAR_TEMPLATE'          => 't',		// The default template switching variable
+    'VAR_FILTERS'           =>  'filter_exp',     // Global System variables default filtering method Multiple comma-separated
+
+    'OUTPUT_ENCODE'         =>  true, // Page compressed output
+    'HTTP_CACHE_CONTROL'    =>  'private', // Web Cache Control
+
+);

+ 30 - 0
php-senthot/Senthot/Conf/debug.php

@@ -0,0 +1,30 @@
+<?php
+// +--------------------------------------------------------------------------
+// | Senthot [ DEVELOPED BY ME ]
+// +--------------------------------------------------------------------------
+// | Copyright (c) 2005-2013 http://www.senthot.com All rights reserved.
+// | License ( http://www.apache.org/licenses/LICENSE-2.0 )
+// | Author: ms134n ( [email protected] )
+// +--------------------------------------------------------------------------
+
+/**
+ * Senthot The default configuration file Debug Mode
+ * If the project has Debug Mode to define your own configuration file, the file is invalid
+ * @category	Sen
+ * @package		Common
+ * @author		ms134n <[email protected]>
+ * @version  $Id: debug.php 3071 2012-07-15 07:59:23Z [email protected] $
+ */
+defined('SEN_PATH') or exit();
+// Debug Mode The following default settings You can redefine the project configuration directory debug.php cover
+return  array(
+    'LOG_RECORD'			=>	true,  // Logging
+    'LOG_EXCEPTION_RECORD'  => 	true,    // Whether to log exception information log
+    'LOG_LEVEL'       		=>  'EMERG,ALERT,CRIT,ERR,WARN,NOTIC,INFO,DEBUG,SQL',  // Allows you to record the log level
+    'DB_FIELDS_CACHE'		=> 	false, // Field cache information
+    'DB_SQL_LOG'			=>	true, // Logging SQL Information
+    'APP_FILE_CASE'  		=>  true, // Whether to check the case file Valid for Windows platforms
+    'TMPL_CACHE_ON'    		=> 	false,        // Open the compiled template caching, set to false then every will be recompiled
+    'TMPL_STRIP_SPACE'      => 	false,       // Removal of HTML template files spaces and line
+    'SHOW_ERROR_MSG'        => 	true,    // Display an error message
+);

+ 40 - 0
php-senthot/Senthot/Conf/tags.php

@@ -0,0 +1,40 @@
+<?php
+// +--------------------------------------------------------------------------
+// | Senthot [ DEVELOPED BY ME ]
+// +--------------------------------------------------------------------------
+// | Copyright (c) 2005-2013 http://www.senthot.com All rights reserved.
+// | License ( http://www.apache.org/licenses/LICENSE-2.0 )
+// | Author: ms134n ( [email protected] )
+// +--------------------------------------------------------------------------
+
+// System default list of file extensions core behavior
+return array(
+    'app_init'      =>  array(
+    ),
+    'app_begin'     =>  array(
+        'ReadHtmlCache', // Read static cache
+    ),
+    'route_check'   =>  array(
+        'CheckRoute', // Routing Detection
+    ), 
+    'app_end'       =>  array(),
+    'path_info'     =>  array(),
+    'action_begin'  =>  array(),
+    'action_end'    =>  array(),
+    'view_begin'    =>  array(),
+    'view_template' =>  array(
+        'LocationTemplate', // Automatic positioning template file
+    ),
+    'view_parse'    =>  array(
+        'ParseTemplate', // Template parsing SupportPHP, built-in template engine and third-party template engine
+    ),
+    'view_filter'   =>  array(
+        'ContentReplace', // Replace the template output
+        'TokenBuild',   // Form token
+        'WriteHtmlCache', // Write static cache
+        'ShowRuntime', // Running time display
+    ),
+    'view_end'      =>  array(
+        'ShowPageTrace', // Trace display page
+    ),
+);

+ 30 - 0
php-senthot/Senthot/LICENSE.txt

@@ -0,0 +1,30 @@
+
+
+Senthot follow the Apache2 open source release, and provided free of charge.
+Copyright © 2006-2012 by Senthot ( http://senthot.com ) All rights reserved.
+Senthot® Trademarks and copyright owner of CV. FBSCHOOL.
+
+Apache Licence is a well-known non-profit organization for open source Apache using the Protocol.
+The agreement similar to BSD, encourages code-sharing and respect for the original author's copyright
+allows code modification, and then released as open source or commercial software.
+Need to meet condition: 
+1.	Need to give the user a copy of the code Apache Licence;
+2.	If you have modified the code, explained in the file needs to be modified;
+3.	In the extension code (modifications and derived from source code) requires
+	with agreement of the original code, trademark, patent and other original author rules
+	requirements included in the description;
+4.	If we publish a Notice file included with the product, you Notice
+	accompanying this agreement is required in the content. You can add yourself to Notice
+	license, but not the performance of Apache Licence constitute a change.
+	Specific agreement reference: http://www.apache.org/licenses/LICENSE-2.0
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
+IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+POSSIBILITY OF SUCH DAMAGE. 

+ 50 - 0
php-senthot/Senthot/Lang/en-us.php

@@ -0,0 +1,50 @@
+<?php
+// +--------------------------------------------------------------------------
+// | Senthot [ DEVELOPED BY ME ]
+// +--------------------------------------------------------------------------
+// | Copyright (c) 2005-2013 http://www.senthot.com All rights reserved.
+// | License ( http://www.apache.org/licenses/LICENSE-2.0 )
+// | Author: ms134n ( [email protected] )
+// +--------------------------------------------------------------------------
+
+/**
+ * Senthot English language package
+ * @category	Sen
+ * @package		Lang
+ * @author		ms134n <[email protected]>
 */
+return array(
+	//  core
+    '_MODULE_NOT_EXIST_'	=>	'Module can not been loaded',
+    '_ERROR_ACTION_'		=>  'Error action',
+    '_LANGUAGE_NOT_LOAD_'	=>	'Can\'t load language package',
+    '_TEMPLATE_NOT_EXIST_'	=>  'Template does\'t exist',
+    '_MODULE_'				=>	'Module',
+    '_ACTION_'				=>	'Action',
+    '_ACTION_NOT_EXIST_'	=>	'Action does\'t exist Or not defined',
+    '_MODEL_NOT_EXIST_'		=>	'Model does\'t exist Or not defined',
+    '_VALID_ACCESS_'		=>	'No access',
+    '_XML_TAG_ERROR_'		=>	'XML tag syntax errors',
+    '_DATA_TYPE_INVALID_'	=>	'Invlid data type!',
+    '_OPERATION_WRONG_'		=>	'Operation error occurs',
+    '_NOT_LOAD_DB_'			=>	'Unable to load the database',
+    '_NO_DB_DRIVER_'		=>	'Unable to load database driver',
+    '_NOT_SUPPORT_DB_'		=>	'The system is temporarily not support database',
+    '_NO_DB_CONFIG_'		=>	'Not define the database configuration',
+    '_NOT_SUPPERT_'			=>	'The system does not support',
+    '_CACHE_TYPE_INVALID_'	=>	'Unable to load the cache type',
+    '_FILE_NOT_WRITEABLE_'	=>	'Directory (file) is not writable',
+    '_METHOD_NOT_EXIST_'	=>	'The method you requested  does not exist!',
+    '_CLASS_NOT_EXIST_'		=>	'Instantiating a class does not exist!',
+    '_CLASS_CONFLICT_'		=>	'Class name conflicts',
+    '_TEMPLATE_ERROR_'		=>	'Template Engine errors',
+    '_CACHE_WRITE_ERROR_'	=>	'Cache file write failed!',
+    '_TAGLIB_NOT_EXIST_'	=>	'Tag library is not defined',
+    '_OPERATION_FAIL_'		=>	'Operation failed!',
+    '_OPERATION_SUCCESS_'	=>	'Operation successed!',
+    '_SELECT_NOT_EXIST_'	=>	'Record does not exist!',
+    '_EXPRESS_ERROR_'		=>	'Expression errors',
+    '_TOKEN_ERROR_'			=>	'Form\'s token errors',
+    '_RECORD_HAS_UPDATE_'	=>	'Record has been updated',
+    '_NOT_ALLOW_PHP_'		=>	'PHP codes are not allowed in the template',
+    '_PARAM_ERROR_'			=>	'Parameter error or undefined',
+);

+ 51 - 0
php-senthot/Senthot/Lang/id-id.php

@@ -0,0 +1,51 @@
+<?php
+// +--------------------------------------------------------------------------
+// | Senthot [ DEVELOPED BY ME ]
+// +--------------------------------------------------------------------------
+// | Copyright (c) 2005-2013 http://www.senthot.com All rights reserved.
+// | License ( http://www.apache.org/licenses/LICENSE-2.0 )
+// | Author: ms134n ( [email protected] )
+// +--------------------------------------------------------------------------
+
+/**
+ * Senthot Indonesian language pack
+ * @category	Sen
+ * @package		Lang
+ * @author		ms134n <[email protected]>
+ */
+return array(
+    //  Core
+    '_MODULE_NOT_EXIST_'    =>  'Tidak dapat memuat modul',
+    '_ERROR_ACTION_'        =>  'Operasi Ilegal',
+    '_LANGUAGE_NOT_LOAD_'   =>  'Tidak dapat memuat paket bahasa',
+    '_TEMPLATE_NOT_EXIST_'  =>  'Template tidak ada',
+    '_MODULE_'              =>  'Modul',
+    '_ACTION_'              =>  'Operasi',
+    '_ACTION_NOT_EXIST_'    =>  'Kontroler tidak ada atau tidak didefinisikan',
+    '_MODEL_NOT_EXIST_'     =>  'Model tidak ada atau tidak didefinisikan',
+    '_VALID_ACCESS_'        =>  'Tidak ada otoritas',
+    '_XML_TAG_ERROR_'       =>  'Kesalahan sintaks tag XML',
+    '_DATA_TYPE_INVALID_'   =>  'Invlid tipe data!',
+    '_OPERATION_WRONG_'     =>  'Kesalahan operasi',
+    '_NOT_LOAD_DB_'         =>  'Tidak dapat memuat database',
+    '_NO_DB_DRIVER_'        =>  'Tidak dapat memuat driver database',
+    '_NOT_SUPPORT_DB_'      =>  'Sistem ini sementara tidak mendukung database',
+    '_NO_DB_CONFIG_'        =>  'Konfigurasi database tidak didefinisikan',
+    '_NOT_SUPPERT_'         =>  'Sistem tidak mendukung',
+    '_CACHE_TYPE_INVALID_'  =>  'Tidak dapat memuat jenis cache',
+    '_FILE_NOT_WRITEABLE_'  =>  'Direktori (file) tidak dapat ditulis',
+    '_METHOD_NOT_EXIST_'    =>  'Metode yang Anda minta tidak ada!',
+    '_CLASS_NOT_EXIST_'     =>  'Instantiate kelas yang tidak ada!',
+    '_CLASS_CONFLICT_'      =>  'Konflik class name',
+    '_TEMPLATE_ERROR_'      =>  'Template Engine errors',
+    '_CACHE_WRITE_ERROR_'   =>  'Penulisan file cache gagal!',
+    '_TAGLIB_NOT_EXIST_'    =>  'Tag library tidak terdefinisi',
+    '_OPERATION_FAIL_'      =>  'Operasi gagal!',
+    '_OPERATION_SUCCESS_'   =>  'Operasi berhasil!',
+    '_SELECT_NOT_EXIST_'    =>  'Catatan tidak ada!',
+    '_EXPRESS_ERROR_'       =>  'Kesalahan ekspresi',
+    '_TOKEN_ERROR_'         =>  'Bentuk kesalahan Token',
+    '_RECORD_HAS_UPDATE_'   =>  'Catatan telah diperbarui',
+    '_NOT_ALLOW_PHP_'       =>  'Kode PHP tidak diperbolehkan dalam template',
+    '_PARAM_ERROR_'         =>  'Kesalahan parameter atau tidak terdefinisi',
+);

+ 210 - 0
php-senthot/Senthot/Lib/Behavior/CheckRouteBehavior.class.php

@@ -0,0 +1,210 @@
+<?php
+// +--------------------------------------------------------------------------
+// | Senthot [ DEVELOPED BY ME ]
+// +--------------------------------------------------------------------------
+// | Copyright (c) 2005-2013 http://www.senthot.com All rights reserved.
+// | License ( http://www.apache.org/licenses/LICENSE-2.0 )
+// | Author: ms134n ( [email protected] )
+// +--------------------------------------------------------------------------
+
+defined('SEN_PATH') or exit();
+/**
+ * System behavior extension : Routing Detection
+ * @category	Sen
+ * @package		Sen
+ * @subpackage  Behavior
+ * @author		ms134n <[email protected]>
+ */
+class CheckRouteBehavior extends Behavior {
+    // Behavioral parameters defined ( the default value ) Covered in the project configuration
+    protected $options   =  array(
+        'URL_ROUTER_ON'         => false,   // Whether to open the URL routing
+        'URL_ROUTE_RULES'       => array(), // The default routing rules, Note : Packet configuration can not be replaced
+        );
+
+    // Behavior extension execution entry must be run
+    public function run(&$return){
+        // Priority detect the presence of PATH_INFO
+        $regx = trim($_SERVER['PATH_INFO'],'/');
+        if(empty($regx)) return $return = true;
+        // Whether to open the route to use
+        if(!C('URL_ROUTER_ON')) return $return = false;
+        // Routing config definition files take precedence over the configuration definition
+        $routes = C('URL_ROUTE_RULES');
+        // Route processing
+        if(!empty($routes)) {
+            $depr = C('URL_PATHINFO_DEPR');
+            // Replace separator Ensure that routing defined delimiters using uniform
+            $regx = str_replace($depr,'/',$regx);
+            foreach ($routes as $rule=>$route){
+                if(0===strpos($rule,'/') && preg_match($rule,$regx,$matches)) { // Regular routes
+                    return $return = $this->parseRegex($matches,$route,$regx);
+                }else{ // Routing rules
+                    $len1   =   substr_count($regx,'/');
+                    $len2   =   substr_count($rule,'/');
+                    if($len1>=$len2) {
+                        if('$' == substr($rule,-1,1)) {// Exact hits
+                            if($len1 != $len2) {
+                                continue;
+                            }else{
+                                $rule =  substr($rule,0,-1);
+                            }
+                        }
+                        $match  =  $this->checkUrlMatch($regx,$rule);
+                        if($match)  return $return = $this->parseRule($rule,$route,$regx);
+                    }
+                }
+            }
+        }
+        $return = false;
+    }
+
+    // Detecting URL and rules route matches
+    private function checkUrlMatch($regx,$rule) {
+        $m1 = explode('/',$regx);
+        $m2 = explode('/',$rule);
+        $match = true; // Match
+        foreach ($m2 as $key=>$val){
+            if(':' == substr($val,0,1)) {// Dynamic variables
+                if(strpos($val,'\\')) {
+                    $type = substr($val,-1);
+                    if('d'==$type && !is_numeric($m1[$key])) {
+                        $match = false;
+                        break;
+                    }
+                }elseif(strpos($val,'^')){
+                    $array   =  explode('|',substr(strstr($val,'^'),1));
+                    if(in_array($m1[$key],$array)) {
+                        $match = false;
+                        break;
+                    }
+                }
+            }elseif(0 !== strcasecmp($val,$m1[$key])){
+                $match = false;
+                break;
+            }
+        }
+        return $match;
+    }
+
+    // Analytical standard routing address
+    // Address Format [Grouping/Module/Operating?]Parameter1=Value1&Parameter2=Value2...
+    private function parseUrl($url) {
+        $var  =  array();
+        if(false !== strpos($url,'?')) { // [Grouping/Module/Operating?]Parameter1=Value1&Parameter2=Value2...
+            $info   =  parse_url($url);
+            $path   = explode('/',$info['path']);
+            parse_str($info['query'],$var);
+        }elseif(strpos($url,'/')){ // [Grouping/Module/Operating]
+            $path = explode('/',$url);
+        }else{ // Parameter1=Value1&Parameter2=Value2...
+            parse_str($url,$var);
+        }
+        if(isset($path)) {
+            $var[C('VAR_ACTION')] = array_pop($path);
+            if(!empty($path)) {
+                $var[C('VAR_MODULE')] = array_pop($path);
+            }
+            if(!empty($path)) {
+                $var[C('VAR_GROUP')]  = array_pop($path);
+            }
+        }
+        return $var;
+    }
+
+    // Routing parsing rules
+    // 'Routing rules'=>'[Grouping/Module/Operating]?Additional parameters 1=Value1&Additional parameter 2=Value2...'
+    // 'Routing rules'=>array('[Grouping/Module/Operating]','Additional parameters 1=Value1&Additional parameter 2=Value2...')
+    // 'Routing rules'=>'External Address'
+    // 'Routing rules'=>array('External Address','Redirect code')
+    // Routing rule :Beginning Represents a dynamic variable
+    // External address can be used in a dynamic variable Adoption :1 :2 Way
+    // 'news/:month/:day/:id'=>array('News/read?cate=1','status=1'),
+    // 'new/:id'=>array('/new.php?id=:1',301), Redirect
+    private function parseRule($rule,$route,$regx) {
+        // Rules for routing address
+        $url   =  is_array($route)?$route[0]:$route;
+        // Get the URL address of the parameter
+        $paths = explode('/',$regx);
+        // Resolution routing rules
+        $matches  =  array();
+        $rule =  explode('/',$rule);
+        foreach ($rule as $item){
+            if(0===strpos($item,':')) { // Dynamic variables for
+                if($pos = strpos($item,'^') ) {
+                    $var  =  substr($item,1,$pos-1);
+                }elseif(strpos($item,'\\')){
+                    $var  =  substr($item,1,-2);
+                }else{
+                    $var  =  substr($item,1);
+                }
+                $matches[$var] = array_shift($paths);
+            }else{ // Static variables in the URL filtering
+                array_shift($paths);
+            }
+        }
+        if(0=== strpos($url,'/') || 0===strpos($url,'http')) { // Jump Route Redirection
+            if(strpos($url,':')) { // Passing dynamic parameters
+                $values  =  array_values($matches);
+                $url  =  preg_replace('/:(\d+)/e','$values[\\1-1]',$url);
+            }
+            header("Location: $url", true,(is_array($route) && isset($route[1]))?$route[1]:301);
+            exit;
+        }else{
+            // Resolve routing address
+            $var  =  $this->parseUrl($url);
+            // Resolve routing address inside the dynamic parameters
+            $values  =  array_values($matches);
+            foreach ($var as $key=>$val){
+                if(0===strpos($val,':')) {
+                    $var[$key] =  $values[substr($val,1)-1];
+                }
+            }
+            $var   =   array_merge($matches,$var);
+            // Parsing URL parameters remaining
+            if($paths) {
+                preg_replace('@(\w+)\/([^\/]+)@e', '$var[strtolower(\'\\1\')]=strip_tags(\'\\2\');', implode('/',$paths));
+            }
+            // Automatic transmission parameter parsing routing
+            if(is_array($route) && isset($route[1])) {
+                parse_str($route[1],$params);
+                $var   =   array_merge($var,$params);
+            }
+            $_GET   =  array_merge($var,$_GET);
+        }
+        return true;
+    }
+
+    // Parsing regular route
+    // 'Regular routes'=>'[Grouping/Module/Operating]?Parameter1=Value1&Parameter2=Value2...'
+    // 'Regular routes'=>array('[Grouping/Module/Operating]?Parameter1=Value1&Parameter2=Value2...','Additional parameters 1=Value1&Additional parameter 2=Value2...')
+    // 'Regular routes'=>'External Address'
+    // 'Regular routes'=>array('External Address','Redirect code')
+    // Parameter value and the external address can be used in a dynamic variable Adoption :1 :2 Way
+    // '/new\/(\d+)\/(\d+)/'=>array('News/read?id=:1&page=:2&cate=1','status=1'),
+    // '/new\/(\d+)/'=>array('/new.php?id=:1&page=:2&status=1','301'), Redirect
+    private function parseRegex($matches,$route,$regx) {
+        // Rules for routing address
+        $url   =  is_array($route)?$route[0]:$route;
+        $url   =  preg_replace('/:(\d+)/e','$matches[\\1]',$url);
+        if(0=== strpos($url,'/') || 0===strpos($url,'http')) { // Jump Route Redirection
+            header("Location: $url", true,(is_array($route) && isset($route[1]))?$route[1]:301);
+            exit;
+        }else{
+            // Resolve routing address
+            $var  =  $this->parseUrl($url);
+            // Parsing URL parameters remaining
+            $regx =  substr_replace($regx,'',0,strlen($matches[0]));
+            if($regx) {
+                preg_replace('@(\w+)\/([^,\/]+)@e', '$var[strtolower(\'\\1\')]=strip_tags(\'\\2\');', $regx);
+            }
+            // Automatic transmission parameter parsing routing
+            if(is_array($route) && isset($route[1])) {
+                parse_str($route[1],$params);
+                $var   =   array_merge($var,$params);
+            }
+            $_GET   =  array_merge($var,$_GET);
+        }
+        return true;
+    }
+}

+ 55 - 0
php-senthot/Senthot/Lib/Behavior/ContentReplaceBehavior.class.php

@@ -0,0 +1,55 @@
+<?php
+// +--------------------------------------------------------------------------
+// | Senthot [ DEVELOPED BY ME ]
+// +--------------------------------------------------------------------------
+// | Copyright (c) 2005-2013 http://www.senthot.com All rights reserved.
+// | License ( http://www.apache.org/licenses/LICENSE-2.0 )
+// | Author: ms134n ( [email protected] )
+// +--------------------------------------------------------------------------
+
+defined('SEN_PATH') or exit();
+/**
+ * Behavior of the system expansion: output template content replacement
+ * @category	Sen
+ * @package		Sen
+ * @subpackage  Behavior
+ * @author		ms134n <[email protected]>
+ */
+class ContentReplaceBehavior extends Behavior {
+    // Parameter defines the behavior
+    protected $options   =  array(
+        'TMPL_PARSE_STRING' =>  array(),
+    );
+
+    // Behavior extension execution entry must be run
+    public function run(&$content){
+        $content = $this->templateContentReplace($content);
+    }
+
+    /**
+     * Replace the contents of the template
+     * @access protected
+     * @param string $content Template content
+     * @return string
+     */
+    protected function templateContentReplace($content) {
+        // Special variable substitution system default
+        $replace =  array(
+            '__TMPL__'      =>  APP_TMPL_PATH,  // Project template directory
+            '__ROOT__'      =>  __ROOT__,       // Current website address
+            '__APP__'       =>  __APP__,        // Current projects address
+            '__GROUP__'     =>  defined('GROUP_NAME')?__GROUP__:__APP__,
+            '__ACTION__'    =>  __ACTION__,     // Address the current operation
+            '__SELF__'      =>  __SELF__,       // Address of the current page
+            '__URL__'       =>  __URL__,
+            '../Public'     =>  APP_TMPL_PATH.'Public',// Public project template directory
+            '__PUBLIC__'    =>  __ROOT__.'/Public',// Public directory sites
+        );
+        // Allows users to customize the template string replacement
+        if(is_array(C('TMPL_PARSE_STRING')) )
+            $replace =  array_merge($replace,C('TMPL_PARSE_STRING'));
+        $content = str_replace(array_keys($replace),array_values($replace),$content);
+        return $content;
+    }
+
+}

+ 52 - 0
php-senthot/Senthot/Lib/Behavior/LocationTemplateBehavior.class.php

@@ -0,0 +1,52 @@
+<?php
+// +--------------------------------------------------------------------------
+// | Senthot [ DEVELOPED BY ME ]
+// +--------------------------------------------------------------------------
+// | Copyright (c) 2005-2013 http://www.senthot.com All rights reserved.
+// | License ( http://www.apache.org/licenses/LICENSE-2.0 )
+// | Author: ms134n ( [email protected] )
+// +--------------------------------------------------------------------------
+
+defined('SEN_PATH') or exit();
+/**
+ * System behavior extension : Locate the template file
+ * @category	Sen
+ * @package		Sen
+ * @subpackage  Behavior
+ * @author		ms134n <[email protected]>
+ */
+class LocationTemplateBehavior extends Behavior {
+    // Behavior extension execution entry must be run
+    public function run(&$templateFile){
+        // Automatic positioning template file
+        if(!file_exists_case($templateFile))
+            $templateFile   = $this->parseTemplateFile($templateFile);
+    }
+
+    /**
+     * Automatic positioning template file
+     * @access private
+     * @param string $templateFile File Name
+     * @return string
+     */
+    private function parseTemplateFile($templateFile) {
+        if(''==$templateFile) {
+            // If the template file name is empty Positioned in accordance with the default rule
+            $templateFile = C('TEMPLATE_NAME');
+        }elseif(false === strpos($templateFile,C('TMPL_TEMPLATE_SUFFIX'))){
+            // Parsing rules Template Theme:Module:Operating Not Support Cross-project and cross-grouping called
+            $path   =  explode(':',$templateFile);
+            $action = array_pop($path);
+            $module = !empty($path)?array_pop($path):MODULE_NAME;
+            if(!empty($path)) {// Set Template Theme
+                $path = dirname(THEME_PATH).'/'.array_pop($path).'/';
+            }else{
+                $path = THEME_PATH;
+            }
+            $templateFile  =  $path.$module.C('TMPL_FILE_DEPR').$action.C('TMPL_TEMPLATE_SUFFIX');
+        }
+        if(!file_exists_case($templateFile))
+            throw_exception(L('_TEMPLATE_NOT_EXIST_').'['.$templateFile.']');
+        return $templateFile;
+    }
+}

+ 119 - 0
php-senthot/Senthot/Lib/Behavior/ParseTemplateBehavior.class.php

@@ -0,0 +1,119 @@
+<?php
+// +--------------------------------------------------------------------------
+// | Senthot [ DEVELOPED BY ME ]
+// +--------------------------------------------------------------------------
+// | Copyright (c) 2005-2013 http://www.senthot.com All rights reserved.
+// | License ( http://www.apache.org/licenses/LICENSE-2.0 )
+// | Author: ms134n ( [email protected] )
+// +--------------------------------------------------------------------------
+
+defined('SEN_PATH') or exit();
+/**
+ * Behavior of the system expansion: template parsing
+ * @category	Sen
+ * @package		Sen
+ * @subpackage  Behavior
+ * @author		ms134n <[email protected]>
+ */
+class ParseTemplateBehavior extends Behavior {
+    // Behavioral parameters defined ( the default value ) Covered in the project configuration
+    protected $options   =  array(
+        // Layout Settings
+        'TMPL_ENGINE_TYPE'		=>  'Sen',     // The default template engine The following settings are only valid with Sen template engine
+        'TMPL_CACHFILE_SUFFIX'  =>  '.php',      // The default template cache suffix
+        'TMPL_DENY_FUNC_LIST'	=>  'echo,exit',	// Disable function template engine
+        'TMPL_DENY_PHP'         =>  false, // Whether to disable the default template engine native PHP code
+        'TMPL_L_DELIM'          =>  '{',			// Generic tag template engine start tag
+        'TMPL_R_DELIM'          =>  '}',			// Generic tag template engine end tag
+        'TMPL_VAR_IDENTIFY'     =>  'array',     // Template variables identified . Blank automatically determine, parameters 'obj' indicates that the object
+        'TMPL_STRIP_SPACE'      =>  true,       // Removal of HTML template files spaces and line
+        'TMPL_CACHE_ON'			=>  true,        // Open the compiled template caching, set to false then every will be recompiled
+        'TMPL_CACHE_PREFIX'     =>  '',         // Template cache prefix designation can be changed dynamically
+        'TMPL_CACHE_TIME'		=>	0,         // Template cache validity 0 Permanent, (In figures, the unit: Second)
+        'TMPL_LAYOUT_ITEM'      =>  '{__CONTENT__}', // Replace the contents of the layout template logo
+        'LAYOUT_ON'             =>  false, // Whether to enable layout
+        'LAYOUT_NAME'           =>  'layout', // Name of the current layout Default layout
+
+        // Sen template engine tag library related settings
+        'TAGLIB_BEGIN'          =>  '<',  // Start tag tag tag library
+        'TAGLIB_END'            =>  '>',  // End tag tag tag library
+        'TAGLIB_LOAD'           =>  true, // Whether to use the built-in tag library tag library other than the default auto-detection
+        'TAGLIB_BUILD_IN'       =>  'cx', // Built-in tag library name(Use of the tag does not have to specify the name of the tag library), separated by commas Note resolution order
+        'TAGLIB_PRE_LOAD'       =>  '',   // Require additional tag libraries loaded(Must specify the name of the tag library), multiple comma-separated
+        );
+
+    // Behavior extension execution entry must be run
+    public function run(&$_data){
+        $engine             =   strtolower(C('TMPL_ENGINE_TYPE'));
+        $_content           =   empty($_data['content'])?$_data['file']:$_data['content'];
+        $_data['prefix']    =   !empty($_data['prefix'])?$_data['prefix']:C('TMPL_CACHE_PREFIX');
+        if('sen'==$engine){ // Template engine using Sen
+            if((!empty($_data['content']) && $this->checkContentCache($_data['content'],$_data['prefix'])) 
+                ||  $this->checkCache($_data['file'],$_data['prefix'])) { // Cache is valid
+                // Decomposition and load the template cache variables
+                extract($_data['var'], EXTR_OVERWRITE);
+                //Load template cache files
+                include C('CACHE_PATH').$_data['prefix'].md5($_content).C('TMPL_CACHFILE_SUFFIX');
+            }else{
+                $tpl = Sen::instance('SenTemplate');
+                // Compile and load the template file
+                $tpl->fetch($_content,$_data['var'],$_data['prefix']);
+            }
+        }else{
+            // Called third-party template engine to parse and output
+            $class   = 'Template'.ucwords($engine);
+            if(class_exists($class)) {
+                $tpl   =  new $class;
+                $tpl->fetch($_content,$_data['var']);
+            }else {  // Class does not define
+                throw_exception(L('_NOT_SUPPERT_').': ' . $class);
+            }
+        }
+    }
+
+    /**
+     * Check the cache file is valid
+     * If this does not need to be recompiled
+     * @access public
+     * @param string $tmplTemplateFile  Template file name
+     * @return boolen
+     */
+    protected function checkCache($tmplTemplateFile,$prefix='') {
+        if (!C('TMPL_CACHE_ON')) // Preferentially detect configuration settings
+            return false;
+        $tmplCacheFile = C('CACHE_PATH').$prefix.md5($tmplTemplateFile).C('TMPL_CACHFILE_SUFFIX');
+        if(!is_file($tmplCacheFile)){
+            return false;
+        }elseif (filemtime($tmplTemplateFile) > filemtime($tmplCacheFile)) {
+            // Template files if you need to update the cache updates
+            return false;
+        }elseif (C('TMPL_CACHE_TIME') != 0 && time() > filemtime($tmplCacheFile)+C('TMPL_CACHE_TIME')) {
+            // Caching is within the validity
+            return false;
+        }
+        // Open layout templates
+        if(C('LAYOUT_ON')) {
+            $layoutFile  =  THEME_PATH.C('LAYOUT_NAME').C('TMPL_TEMPLATE_SUFFIX');
+            if(filemtime($layoutFile) > filemtime($tmplCacheFile)) {
+                return false;
+            }
+        }
+        // Cache is valid
+        return true;
+    }
+
+    /**
+     * Check the contents of the cache is valid
+     * If this does not need to be recompiled
+     * @access public
+     * @param string $tmplContent  Template content
+     * @return boolen
+     */
+    protected function checkContentCache($tmplContent,$prefix='') {
+        if(is_file(C('CACHE_PATH').$prefix.md5($tmplContent).C('TMPL_CACHFILE_SUFFIX'))){
+            return true;
+        }else{
+            return false;
+        }
+    }    
+}

+ 121 - 0
php-senthot/Senthot/Lib/Behavior/ReadHtmlCacheBehavior.class.php

@@ -0,0 +1,121 @@
+<?php
+// +--------------------------------------------------------------------------
+// | Senthot [ DEVELOPED BY ME ]
+// +--------------------------------------------------------------------------
+// | Copyright (c) 2005-2013 http://www.senthot.com All rights reserved.
+// | License ( http://www.apache.org/licenses/LICENSE-2.0 )
+// | Author: ms134n ( [email protected] )
+// +--------------------------------------------------------------------------
+
+defined('SEN_PATH') or exit();
+/**
+ * System behavior extension : static cache reads
+ * @category	Sen
+ * @package		Sen
+ * @subpackage  Behavior
+ * @author		ms134n <[email protected]>
+ */
+class ReadHtmlCacheBehavior extends Behavior {
+    protected $options   =  array(
+            'HTML_CACHE_ON'     =>  false,
+            'HTML_CACHE_TIME'   =>  60,
+            'HTML_CACHE_RULES'  =>  array(),
+            'HTML_FILE_SUFFIX'  =>  '.html',
+        );
+
+    // Behavior extension execution entry must be run
+    public function run(&$params){
+        // On static cache
+        if(C('HTML_CACHE_ON'))  {
+            $cacheTime = $this->requireHtmlCache();
+            if( false !== $cacheTime && $this->checkHTMLCache(HTML_FILE_NAME,$cacheTime)) { //Effective static pages
+                // Read static page output
+                readfile(HTML_FILE_NAME);
+                exit();
+            }
+        }
+    }
+
+    // Determine whether you need static cache
+    static private function requireHtmlCache() {
+        // Static analysis of the current rules
+         $htmls = C('HTML_CACHE_RULES'); // Read static rule
+         if(!empty($htmls)) {
+            $htmls = array_change_key_case($htmls);
+            // Static rules file defines the format actionName=>array('Static rule','Cache Time','Additional rules')
+            // 'read'=>array('{id},{name}',60,'md5') Must ensure the uniqueness of static rules and can be judged
+            // Detect static rule
+            $moduleName = strtolower(MODULE_NAME);
+            $actionName = strtolower(ACTION_NAME);
+            if(isset($htmls[$moduleName.':'.$actionName])) {
+                $html   =   $htmls[$moduleName.':'.$actionName];   // Operation of a module static rule
+            }elseif(isset($htmls[$moduleName.':'])){// A module static rules
+                $html   =   $htmls[$moduleName.':'];
+            }elseif(isset($htmls[$actionName])){
+                $html   =   $htmls[$actionName]; // All static rules
+            }elseif(isset($htmls['*'])){
+                $html   =   $htmls['*']; // Global static rules
+            }elseif(isset($htmls['empty:index']) && !class_exists(MODULE_NAME.'Action')){
+                $html   =    $htmls['empty:index']; // Empty module static rules
+            }elseif(isset($htmls[$moduleName.':_empty']) && $this->isEmptyAction(MODULE_NAME,ACTION_NAME)){
+                $html   =    $htmls[$moduleName.':_empty']; // Space operation static rules
+            }
+            if(!empty($html)) {
+                // Understanding static rules
+                $rule   = $html[0];
+                // By $_ the beginning of system variables
+                $rule   = preg_replace('/{\$(_\w+)\.(\w+)\|(\w+)}/e',"\\3(\$\\1['\\2'])",$rule);
+                $rule   = preg_replace('/{\$(_\w+)\.(\w+)}/e',"\$\\1['\\2']",$rule);
+                // {ID|FUN} GET variable DateFormat
+                $rule   = preg_replace('/{(\w+)\|(\w+)}/e',"\\2(\$_GET['\\1'])",$rule);
+                $rule   = preg_replace('/{(\w+)}/e',"\$_GET['\\1']",$rule);
+                // Special system variables
+                $rule   = str_ireplace(
+                    array('{:app}','{:module}','{:action}','{:group}'),
+                    array(APP_NAME,MODULE_NAME,ACTION_NAME,defined('GROUP_NAME')?GROUP_NAME:''),
+                    $rule);
+                // {|FUN} Alone function
+                $rule  = preg_replace('/{|(\w+)}/e',"\\1()",$rule);
+                if(!empty($html[2])) $rule    =   $html[2]($rule); // Apply additional functions
+                $cacheTime = isset($html[1])?$html[1]:C('HTML_CACHE_TIME'); // Cache validity period
+                // The current cache file
+                define('HTML_FILE_NAME',HTML_PATH . $rule.C('HTML_FILE_SUFFIX'));
+                return $cacheTime;
+            }
+        }
+        // No cache
+        return false;
+    }
+
+    /**
+     * Check effectiveness of static HTML files
+     * If you need to update
+     * @access public
+     * @param string $cacheFile  A static file name
+     * @param integer $cacheTime  Cache validity period
+     * @return boolen
+     */
+    static public function checkHTMLCache($cacheFile='',$cacheTime='') {
+        if(!is_file($cacheFile)){
+            return false;
+        }elseif (filemtime(C('TEMPLATE_NAME')) > filemtime($cacheFile)) {
+            // Static files are template files if the update needs to be updated
+            return false;
+        }elseif(!is_numeric($cacheTime) && function_exists($cacheTime)){
+            return $cacheTime($cacheFile);
+        }elseif ($cacheTime != 0 && NOW_TIME > filemtime($cacheFile)+$cacheTime) {
+            // File is valid
+            return false;
+        }
+        //Static files
+        return true;
+    }
+
+    //Test whether the action is empty
+    static private function isEmptyAction($module,$action) {
+        $className  =   $module.'Action';
+        $class      =   new $className;
+        return !method_exists($class,$action);
+    }
+
+}

+ 125 - 0
php-senthot/Senthot/Lib/Behavior/ShowPageTraceBehavior.class.php

@@ -0,0 +1,125 @@
+<?php
+// +--------------------------------------------------------------------------
+// | Senthot [ DEVELOPED BY ME ]
+// +--------------------------------------------------------------------------
+// | Copyright (c) 2005-2013 http://www.senthot.com All rights reserved.
+// | License ( http://www.apache.org/licenses/LICENSE-2.0 )
+// | Author: ms134n ( [email protected] )
+// +--------------------------------------------------------------------------
+
+defined('SEN_PATH') or exit();
+/**
+ * System behavior extension : Page Trace display output
+ * @category	Sen
+ * @package		Sen
+ * @subpackage  Behavior
+ * @author		ms134n <[email protected]>
+ */
+class ShowPageTraceBehavior extends Behavior {
+    // Parameter defines the behavior
+    protected $options   =  array(
+        'SHOW_PAGE_TRACE'   => false,   // Trace information display page
+        'TRACE_PAGE_TABS'   => array('BASE'=>'Basic','FILE'=>'File','INFO'=>'Process','ERR|NOTIC'=>'Error','SQL'=>'SQL','DEBUG'=>'Debugging'), // Trace can be customized page tabs 
+        'PAGE_TRACE_SAVE'   => false,
+    );
+
+    // Behavior extension execution entry must be run
+    public function run(&$params){
+        if(!IS_AJAX && C('SHOW_PAGE_TRACE')) {
+            echo $this->showTrace();
+        }
+    }
+
+    /**
+     * Trace information display page
+     * @access private
+     */
+    private function showTrace() {
+         // The default display information
+        $files  =  get_included_files();
+        $info   =   array();
+        foreach ($files as $key=>$file){
+            $info[] = $file.' ( '.number_format(filesize($file)/1024,2).' KB )';
+        }
+        $trace  =   array();
+        $base   =   array(
+            'Request information'  =>  date('Y-m-d H:i:s',$_SERVER['REQUEST_TIME']).' '.$_SERVER['SERVER_PROTOCOL'].' '.$_SERVER['REQUEST_METHOD'].' : '.__SELF__,
+            'Run time'  =>  $this->showTime(),
+            'Memory overhead'  =>  MEMORY_LIMIT_ON?number_format((memory_get_usage() - $GLOBALS['_startUseMems'])/1024,2).' kb':'Not Support',
+            'Query information'  =>  N('db_query').' queries '.N('db_write').' writes ',
+            'File Load'  =>  count(get_included_files()),
+            'Cache information'  =>  N('cache_read').' gets '.N('cache_write').' writes ',
+            'Configuration is loaded'  =>  count(c()),
+            'Session Information'  =>  'SESSION_ID='.session_id(),
+            );
+        // Reading the Trace project definition file
+        $traceFile  =   CONF_PATH.'trace.php';
+        if(is_file($traceFile)) {
+            $base   =   array_merge($base,include $traceFile);
+        }
+        $debug  =   trace();
+        $tabs   =   C('TRACE_PAGE_TABS');
+        foreach ($tabs as $name=>$title){
+            switch(strtoupper($name)) {
+                case 'BASE':// Basic Information
+                    $trace[$title]  =   $base;
+                    break;
+                case 'FILE': // File Information
+                    $trace[$title]  =   $info;
+                    break;
+                default:// Debugging information
+                    $name       =   strtoupper($name);
+                    if(strpos($name,'|')) {// Multiple sets of information
+                        $array  =   explode('|',$name);
+                        $result =   array();
+                        foreach($array as $name){
+                            $result   +=   isset($debug[$name])?$debug[$name]:array();
+                        }
+                        $trace[$title]  =   $result;
+                    }else{
+                        $trace[$title]  =   isset($debug[$name])?$debug[$name]:'';
+                    }
+            }
+        }
+        if($save = C('PAGE_TRACE_SAVE')) { // Save Page Trace Logs
+            if(is_array($save)) {// Select the tab to save
+                $tabs   =   C('TRACE_PAGE_TABS');
+                $array  =   array();
+                foreach ($save as $tab){
+                    $array[] =   $tabs[$tab];
+                }
+            }
+            $content    =   date('[ c ]').' '.get_client_ip().' '.$_SERVER['REQUEST_URI']."\r\n";
+            foreach ($trace as $key=>$val){
+                if(!isset($array) || in_array($key,$array)) {
+                    $content    .=  '[ '.$key." ]\r\n";
+                    if(is_array($val)) {
+                        foreach ($val as $k=>$v){
+                            $content .= (!is_numeric($k)?$k.':':'').print_r($v,true)."\r\n";
+                        }
+                    }else{
+                        $content .= print_r($val,true)."\r\n";
+                    }
+                    $content .= "\r\n";
+                }
+            }
+            error_log(str_replace('<br/>',"\r\n",$content), Log::FILE,LOG_PATH.date('y_m_d').'_trace.log');
+        }
+        unset($files,$info,$base);
+        // Call Trace page template
+        ob_start();
+        include C('TMPL_TRACE_FILE')?C('TMPL_TRACE_FILE'):SEN_PATH.'Tpl/page_trace.tpl';
+        return ob_get_clean();
+    }
+
+    /**
+     * Get running time
+     */
+    private function showTime() {
+        // Show Run Time
+        G('beginTime',$GLOBALS['_beginTime']);
+        G('viewEndTime');
+        // Show Run Time
+        return G('beginTime','viewEndTime').'s ( Load:'.G('beginTime','loadTime').'s Init:'.G('loadTime','initTime').'s Exec:'.G('initTime','viewStartTime').'s Template:'.G('viewStartTime','viewEndTime').'s )';
+    }
+}

+ 82 - 0
php-senthot/Senthot/Lib/Behavior/ShowRuntimeBehavior.class.php

@@ -0,0 +1,82 @@
+<?php
+// +--------------------------------------------------------------------------
+// | Senthot [ DEVELOPED BY ME ]
+// +--------------------------------------------------------------------------
+// | Copyright (c) 2005-2013 http://www.senthot.com All rights reserved.
+// | License ( http://www.apache.org/licenses/LICENSE-2.0 )
+// | Author: ms134n ( [email protected] )
+// +--------------------------------------------------------------------------
+
+defined('SEN_PATH') or exit();
+/**
+ * System behavior extension : Run time information display
+ * @category	Sen
+ * @package		Sen
+ * @subpackage  Behavior
+ * @author		ms134n <[email protected]>
+ */
+class ShowRuntimeBehavior extends Behavior {
+    // Parameter defines the behavior
+    protected $options   =  array(
+        'SHOW_RUN_TIME'		=> false,   // Running time display
+        'SHOW_ADV_TIME'		=> false,   // Show detailed run-time
+        'SHOW_DB_TIMES'		=> false,   // Show database queries and write times
+        'SHOW_CACHE_TIMES'	=> false,   // Display the number of cache operation
+        'SHOW_USE_MEM'		=> false,   // Display memory overhead
+        'SHOW_LOAD_FILE'    => false,   // Display the number of files loaded
+        'SHOW_FUN_TIMES'    => false ,  // Shows the number of function calls
+    );
+
+    // Behavior extension execution entry must be run
+    public function run(&$content){
+        if(C('SHOW_RUN_TIME')){
+            if(false !== strpos($content,'{__NORUNTIME__}')) {
+                $content   =  str_replace('{__NORUNTIME__}','',$content);
+            }else{
+                $runtime = $this->showTime();
+                 if(strpos($content,'{__RUNTIME__}'))
+                     $content   =  str_replace('{__RUNTIME__}',$runtime,$content);
+                 else
+                     $content   .=  $runtime;
+            }
+        }else{
+            $content   =  str_replace(array('{__NORUNTIME__}','{__RUNTIME__}'),'',$content);
+        }
+    }
+
+    /**
+     * Show running time, database operations, the number of cache , memory usage information
+     * @access private
+     * @return string
+     */
+    private function showTime() {
+        // Show Run Time
+        G('beginTime',$GLOBALS['_beginTime']);
+        G('viewEndTime');
+        $showTime   =   'Process: '.G('beginTime','viewEndTime').'s ';
+        if(C('SHOW_ADV_TIME')) {
+            // Show Run Time
+            $showTime .= '( Load:'.G('beginTime','loadTime').'s Init:'.G('loadTime','initTime').'s Exec:'.G('initTime','viewStartTime').'s Template:'.G('viewStartTime','viewEndTime').'s )';
+        }
+        if(C('SHOW_DB_TIMES') && class_exists('Db',false) ) {
+            // Shows the number of database operations
+            $showTime .= ' | DB :'.N('db_query').' queries '.N('db_write').' writes ';
+        }
+        if(C('SHOW_CACHE_TIMES') && class_exists('Cache',false)) {
+            // Display cache read and write times
+            $showTime .= ' | Cache :'.N('cache_read').' gets '.N('cache_write').' writes ';
+        }
+        if(MEMORY_LIMIT_ON && C('SHOW_USE_MEM')) {
+            // Display memory overhead
+            $showTime .= ' | UseMem:'. number_format((memory_get_usage() - $GLOBALS['_startUseMems'])/1024).' kb';
+        }
+        if(C('SHOW_LOAD_FILE')) {
+            $showTime .= ' | LoadFile:'.count(get_included_files());
+        }
+        if(C('SHOW_FUN_TIMES')) {
+            $fun  =  get_defined_functions();
+            $showTime .= ' | CallFun:'.count($fun['user']).','.count($fun['internal']);
+        }
+        return $showTime;
+    }
+}

+ 59 - 0
php-senthot/Senthot/Lib/Behavior/TokenBuildBehavior.class.php

@@ -0,0 +1,59 @@
+<?php
+// +--------------------------------------------------------------------------
+// | Senthot [ DEVELOPED BY ME ]
+// +--------------------------------------------------------------------------
+// | Copyright (c) 2010 http://www.senthot.com All rights reserved.
+// | License ( http://www.apache.org/licenses/LICENSE-2.0 )
+// | Author: ms134n ( [email protected] )
+// +--------------------------------------------------------------------------
+
+defined('SEN_PATH') or exit();
+/**
+ * System behavior extension : Form token generation
+ * @category	Sen
+ * @package		Sen
+ * @subpackage  Behavior
+ * @author		ms134n <[email protected]>
+ */
+class TokenBuildBehavior extends Behavior {
+    // Parameter defines the behavior
+    protected $options   =  array(
+        'TOKEN_ON'       => false,     // Open Token Authentication
+        'TOKEN_NAME'     => '__hash__',    // Token authentication hidden form field names
+        'TOKEN_TYPE'     => 'md5',   // Token authentication hash rule
+        'TOKEN_RESET'    => true, // Tokens are reset after an error
+    );
+
+    public function run(&$content){
+        if(C('TOKEN_ON')) {
+            if(strpos($content,'{__TOKEN__}')) {
+                // Token hidden form fields specified location
+                $content = str_replace('{__TOKEN__}',$this->buildToken(),$content);
+            }elseif(preg_match('/<\/form(\s*)>/is',$content,$match)) {
+                // Smart token generated form hidden fields
+                $content = str_replace($match[0],$this->buildToken().$match[0],$content);
+            }
+        }else{
+            $content = str_replace('{__TOKEN__}','',$content);
+        }
+    }
+
+    // Create a form token
+    private function buildToken() {
+        $tokenName  = C('TOKEN_NAME');
+        $tokenType  = C('TOKEN_TYPE');
+        if(!isset($_SESSION[$tokenName])) {
+            $_SESSION[$tokenName]  = array();
+        }
+        // Uniqueness identifies the current page
+        $tokenKey   =  md5($_SERVER['REQUEST_URI']);
+        if(isset($_SESSION[$tokenName][$tokenKey])) {// Repeat the same page does not generate session
+            $tokenValue = $_SESSION[$tokenName][$tokenKey];
+        }else{
+            $tokenValue = $tokenType(microtime(TRUE));
+            $_SESSION[$tokenName][$tokenKey]   =  $tokenValue;
+        }
+        $token      =  '<input type="hidden" name="'.$tokenName.'" value="'.$tokenKey.'_'.$tokenValue.'" />';
+        return $token;
+    }
+}

+ 32 - 0
php-senthot/Senthot/Lib/Behavior/WriteHtmlCacheBehavior.class.php

@@ -0,0 +1,32 @@
+<?php
+// +--------------------------------------------------------------------------
+// | Senthot [ DEVELOPED BY ME ]
+// +--------------------------------------------------------------------------
+// | Copyright (c) 2005-2013 http://www.senthot.com All rights reserved.
+// | License ( http://www.apache.org/licenses/LICENSE-2.0 )
+// | Author: ms134n ( [email protected] )
+// +--------------------------------------------------------------------------
+
+defined('SEN_PATH') or exit();
+/**
+ * System behavior extension : static cache write
+ * @category	Sen
+ * @package		Sen
+ * @subpackage  Behavior
+ * @author		ms134n <[email protected]>
+ */
+class WriteHtmlCacheBehavior extends Behavior {
+
+    // Behavior extension execution entry must be run
+    public function run(&$content){
+        if(C('HTML_CACHE_ON') && defined('HTML_FILE_NAME'))  {
+            //Static file write
+            // If you turn on HTML features Check and rewrite the HTML file
+            // No stencil operation does not generate static files
+            if(!is_dir(dirname(HTML_FILE_NAME)))
+                mkdir(dirname(HTML_FILE_NAME),0755,true);
+            if( false === file_put_contents( HTML_FILE_NAME , $content ))
+                throw_exception(L('_CACHE_WRITE_ERROR_').':'.HTML_FILE_NAME);
+        }
+    }
+}

+ 426 - 0
php-senthot/Senthot/Lib/Core/Action.class.php

@@ -0,0 +1,426 @@
+<?php
+// +--------------------------------------------------------------------------
+// | Senthot [ DEVELOPED BY ME ]
+// +--------------------------------------------------------------------------
+// | Copyright (c) 2005-2013 http://www.senthot.com All rights reserved.
+// | License ( http://www.apache.org/licenses/LICENSE-2.0 )
+// | Author: ms134n ( [email protected] )
+// +--------------------------------------------------------------------------
+
+/**
+ * Senthot Action Controller base class Abstract class
+ * @category	Sen
+ * @package		Sen
+ * @subpackage  Core
+ * @author		ms134n <[email protected]>
+ */
+abstract class Action {
+
+    /**
+     * View instance
+     * @var view
+     * @access protected
+     */    
+    protected $view     =  null;
+
+    /**
+     * Current controller name
+     * @var name
+     * @access protected
+     */      
+    private   $name     =  '';
+
+    /**
+     * Template Variables
+     * @var tVar
+     * @access protected
+     */      
+    protected $tVar     =   array();
+
+    /**
+     * Controller parameters
+     * @var config
+     * @access protected
+     */      
+    protected $config   =   array();
+
+   /**
+     * Architecture function Get a template object instance
+     * @access public
+     */
+    public function __construct() {
+        tag('action_begin',$this->config);
+        //Controller initialization
+        if(method_exists($this,'_initialize'))
+            $this->_initialize();
+    }
+
+   /**
+     * Gets the name of the current Action
+     * @access protected
+     */
+    protected function getActionName() {
+        if(empty($this->name)) {
+            // Get Action Name
+            $this->name     =   substr(get_class($this),0,-6);
+        }
+        return $this->name;
+    }
+
+    /**
+     * Whether AJAX request
+     * @access protected
+     * @return bool
+     */
+    protected function isAjax() {
+        if(isset($_SERVER['HTTP_X_REQUESTED_WITH']) ) {
+            if('xmlhttprequest' == strtolower($_SERVER['HTTP_X_REQUESTED_WITH']))
+                return true;
+        }
+        if(!empty($_POST[C('VAR_AJAX_SUBMIT')]) || !empty($_GET[C('VAR_AJAX_SUBMIT')]))
+            // Judgment Ajax submission
+            return true;
+        return false;
+    }
+
+    /**
+     * Template Display Invoke the built-in template engine display method
+     * @access protected
+     * @param string $templateFile Specifies the template file to be invoked
+     * The default is empty By the system automatically locates the template file
+     * @param string $charset Output Coding
+     * @param string $contentType Output Type
+     * @param string $content Output
+     * @param string $prefix Template cache prefix
+     * @return void
+     */
+    protected function display($templateFile='',$charset='',$contentType='',$content='',$prefix='') {
+        $this->initView();
+        $this->view->display($templateFile,$charset,$contentType,$content,$prefix);
+    }
+
+    /**
+     * Html output text can include Parse the content and Support
+     * @access protected
+     * @param string $content Output
+     * @param string $charset Template output character set
+     * @param string $contentType Output Type
+     * @param string $prefix Template cache prefix
+     * @return mixed
+     */
+    protected function show($content,$charset='',$contentType='',$prefix='') {
+        $this->initView();       
+        $this->view->display('',$charset,$contentType,$content,$prefix);
+    }
+
+    /**
+     * Get the output page content
+     * Invoke the built-in template engine fetch method
+     * @access protected
+     * @param string $templateFile Specifies the template file to be invoked
+     * The default is empty By the system automatically locates the template file
+     * @param string $content Template output
+     * @param string $prefix Template cache prefix* 
+     * @return string
+     */
+    protected function fetch($templateFile='',$content='',$prefix='') {
+        $this->initView();
+        return $this->view->fetch($templateFile,$content,$prefix);
+    }
+
+    /**
+     * Initialize the view
+     * @access private
+     * @return void
+     */
+    private function initView(){
+        //View class is instantiated
+        if(!$this->view)    $this->view     = Sen::instance('View');
+        // Template variables by value
+        if($this->tVar)     $this->view->assign($this->tVar);           
+    }
+    
+    /**
+     * Create static pages
+     * @access protected
+     * @htmlfile Generated static file names
+     * @htmlpath Generated static file path
+     * @param string $templateFile Specifies the template file to be invoked
+     * The default is empty By the system automatically locates the template file
+     * @return string
+     */
+    protected function buildHtml($htmlfile='',$htmlpath='',$templateFile='') {
+        $content = $this->fetch($templateFile);
+        $htmlpath   = !empty($htmlpath)?$htmlpath:HTML_PATH;
+        $htmlfile =  $htmlpath.$htmlfile.C('HTML_FILE_SUFFIX');
+        if(!is_dir(dirname($htmlfile)))
+            // If the static directory does not exist Is created
+            mkdir(dirname($htmlfile),0755,true);
+        if(false === file_put_contents($htmlfile,$content))
+            throw_exception(L('_CACHE_WRITE_ERROR_').':'.$htmlfile);
+        return $content;
+    }
+
+    /**
+     * Template variable assignment
+     * @access protected
+     * @param mixed $name To display template variables
+     * @param mixed $value Variable
+     * @return void
+     */
+    protected function assign($name,$value='') {
+        if(is_array($name)) {
+            $this->tVar   =  array_merge($this->tVar,$name);
+        }else {
+            $this->tVar[$name] = $value;
+        }        
+    }
+
+    public function __set($name,$value) {
+        $this->assign($name,$value);
+    }
+
+    /**
+     * Get template displays the values of variables
+     * @access protected
+     * @param string $name Template display variable
+     * @return mixed
+     */
+    public function get($name='') {
+        if('' === $name) {
+            return $this->tVar;
+        }
+        return isset($this->tVar[$name])?$this->tVar[$name]:false;        
+    }
+
+    public function __get($name) {
+        return $this->get($name);
+    }
+
+    /**
+     * Detection template variable value
+     * @access public
+     * @param string $name Name
+     * @return boolean
+     */
+    public function __isset($name) {
+        return isset($this->tVar[$name]);
+    }
+
+    /**
+     * Magic Methods There does not exist when the operation performed
+     * @access public
+     * @param string $method Method name
+     * @param array $args Parameter
+     * @return mixed
+     */
+    public function __call($method,$args) {
+        if( 0 === strcasecmp($method,ACTION_NAME.C('ACTION_SUFFIX'))) {
+            if(method_exists($this,'_empty')) {
+                // If you define _empty operation the call
+                $this->_empty($method,$args);
+            }elseif(file_exists_case(C('TEMPLATE_NAME'))){
+                // Check if there is a default template If there is a direct output template
+                $this->display();
+            }elseif(function_exists('__hack_action')) {
+                // hack Define the extended operation
+                __hack_action();
+            }else{
+                _404(L('_ERROR_ACTION_').':'.ACTION_NAME);
+            }
+        }else{
+            switch(strtolower($method)) {
+                // Judgment submission
+                case 'ispost'   :
+                case 'isget'    :
+                case 'ishead'   :
+                case 'isdelete' :
+                case 'isput'    :
+                    return strtolower($_SERVER['REQUEST_METHOD']) == strtolower(substr($method,2));
+                // Get Variables Support filtering and default values Invocation $this->_post($key,$filter,$default);
+                case '_get'     :   $input =& $_GET;break;
+                case '_post'    :   $input =& $_POST;break;
+                case '_put'     :   parse_str(file_get_contents('php://input'), $input);break;
+                case '_param'   :  
+                    switch($_SERVER['REQUEST_METHOD']) {
+                        case 'POST':
+                            $input  =  $_POST;
+                            break;
+                        case 'PUT':
+                            parse_str(file_get_contents('php://input'), $input);
+                            break;
+                        default:
+                            $input  =  $_GET;
+                    }
+                    if(C('VAR_URL_PARAMS')){
+                        $params = $_GET[C('VAR_URL_PARAMS')];
+                        $input  =   array_merge($input,$params);
+                    }
+                    break;
+                case '_request' :   $input =& $_REQUEST;   break;
+                case '_session' :   $input =& $_SESSION;   break;
+                case '_cookie'  :   $input =& $_COOKIE;    break;
+                case '_server'  :   $input =& $_SERVER;    break;
+                case '_globals' :   $input =& $GLOBALS;    break;
+                default:
+                    throw_exception(__CLASS__.':'.$method.L('_METHOD_NOT_EXIST_'));
+            }
+            if(!isset($args[0])) { // Access to global variables
+                $data       =   $input; // Filtered by the VAR_FILTERS configuration
+            }elseif(isset($input[$args[0]])) { // Value Operation
+                $data       =	$input[$args[0]];
+                $filters    =   isset($args[1])?$args[1]:C('DEFAULT_FILTER');
+                if($filters) {// 2012/3/23 Increase the number of ways filtration Support
+                    $filters    =   explode(',',$filters);
+                    foreach($filters as $filter){
+                        if(function_exists($filter)) {
+                            $data   =   is_array($data)?array_map($filter,$data):$filter($data); // Parameter filter
+                        }
+                    }
+                }
+            }else{ // Variable Default
+                $data       =	 isset($args[2])?$args[2]:NULL;
+            }
+            return $data;
+        }
+    }
+
+    /**
+     * A quick way to jump operator error
+     * @access protected
+     * @param string $message Error Messages
+     * @param string $jumpUrl Page jump address
+     * @param mixed $ajax Whether the Ajax way Jump designated time when the digital
+     * @return void
+     */
+    protected function error($message,$jumpUrl='',$ajax=false) {
+        $this->dispatchJump($message,0,$jumpUrl,$ajax);
+    }
+
+    /**
+     * Successful operation of a quick way to jump
+     * @access protected
+     * @param string $message Tips
+     * @param string $jumpUrl Page jump address
+     * @param mixed $ajax Whether the Ajax way Jump designated time when the digital
+     * @return void
+     */
+    protected function success($message,$jumpUrl='',$ajax=false) {
+        $this->dispatchJump($message,1,$jumpUrl,$ajax);
+    }
+
+    /**
+     * Ajax way to return data to the client
+     * @access protected
+     * @param mixed $data Data to be returned
+     * @param String $type AJAX return data format
+     * @return void
+     */
+    protected function ajaxReturn($data,$type='') {
+        if(func_num_args()>2) {// Compatible 2.0 before use
+            $args           =   func_get_args();
+            array_shift($args);
+            $info           =   array();
+            $info['data']   =   $data;
+            $info['info']   =   array_shift($args);
+            $info['status'] =   array_shift($args);
+            $data           =   $info;
+            $type           =   $args?array_shift($args):'';
+        }
+        if(empty($type)) $type  =   C('DEFAULT_AJAX_RETURN');
+        switch (strtoupper($type)){
+            case 'JSON' :
+                // Return JSON data format to the client Contains status information
+                header('Content-Type:application/json; charset=utf-8');
+                exit(json_encode($data));
+            case 'XML'  :
+                // Back xml format data
+                header('Content-Type:text/xml; charset=utf-8');
+                exit(xml_encode($data));
+            case 'JSONP':
+                // Return JSON data format to the client Contains status information
+                header('Content-Type:application/json; charset=utf-8');
+                $handler  =   isset($_GET[C('VAR_JSONP_HANDLER')]) ? $_GET[C('VAR_JSONP_HANDLER')] : C('DEFAULT_JSONP_HANDLER');
+                exit($handler.'('.json_encode($data).');');  
+            case 'EVAL' :
+                // Back js script executable
+                header('Content-Type:text/html; charset=utf-8');
+                exit($data);            
+            default     :
+                // Back to format data for the expansion of other
+                tag('ajax_return',$data);
+        }
+    }
+
+    /**
+     * Action Jump(URL Redirection) Support jumps specified module and delay
+     * @access protected
+     * @param string $url Jump to URL expression
+     * @param array $params Other URL parameters
+     * @param integer $delay The time delay jump seconds
+     * @param string $msg Jump message
+     * @return void
+     */
+    protected function redirect($url,$params=array(),$delay=0,$msg='') {
+        $url    =   U($url,$params);
+        redirect($url,$delay,$msg);
+    }
+
+    /**
+     * Default jump operations Support orientation and correct errors Jump
+     * Call template display The default directory for the public following success page
+     * Prompt page as configurable Support Template Tags
+     * @param string $message Tips
+     * @param Boolean $status State
+     * @param string $jumpUrl Page jump address
+     * @param mixed $ajax Whether the Ajax way Jump designated time when the digital
+     * @access private
+     * @return void
+     */
+    private function dispatchJump($message,$status=1,$jumpUrl='',$ajax=false) {
+        if(true === $ajax || IS_AJAX) {// AJAX submit
+            $data           =   is_array($ajax)?$ajax:array();
+            $data['info']   =   $message;
+            $data['status'] =   $status;
+            $data['url']    =   $jumpUrl;
+            $this->ajaxReturn($data);
+        }
+        if(is_int($ajax)) $this->assign('waitSecond',$ajax);
+        if(!empty($jumpUrl)) $this->assign('jumpUrl',$jumpUrl);
+        // Tips title
+        $this->assign('msgTitle',$status? L('_OPERATION_SUCCESS_') : L('_OPERATION_FAIL_'));
+        //If you set up close the window, you are prompted to close the window automatically after
+        if($this->get('closeWin'))    $this->assign('jumpUrl','javascript:window.close();');
+        $this->assign('status',$status);   // State
+        //Ensure that the output is not affected static cache
+        C('HTML_CACHE_ON',false);
+        if($status) { //Information sent successfully
+            $this->assign('message',$message);// Tips
+            // After the successful operation of the default stay one second
+            if(!isset($this->waitSecond))    $this->assign('waitSecond','1');
+            // Automatically returns to the default operation is successful before the operation page
+            if(!isset($this->jumpUrl)) $this->assign("jumpUrl",$_SERVER["HTTP_REFERER"]);
+            $this->display(C('TMPL_ACTION_SUCCESS'));
+        }else{
+            $this->assign('error',$message);// Tips
+            //An error occurred when the default stay 3 seconds
+            if(!isset($this->waitSecond))    $this->assign('waitSecond','3');
+            // Default if an error occurs automatically Back
+            if(!isset($this->jumpUrl)) $this->assign('jumpUrl',"javascript:history.back(-1);");
+            $this->display(C('TMPL_ACTION_ERROR'));
+            // Suspend the enforcement  Avoid mistakes continue
+            exit ;
+        }
+    }
+
+   /**
+     * Destructor
+     * @access public
+     */
+    public function __destruct() {
+        // Save the log
+        if(C('LOG_RECORD')) Log::save();
+        // Subsequent operations
+        tag('action_end');
+    }
+}

+ 216 - 0
php-senthot/Senthot/Lib/Core/App.class.php

@@ -0,0 +1,216 @@
+<?php
+// +--------------------------------------------------------------------------
+// | Senthot [ DEVELOPED BY ME ]
+// +--------------------------------------------------------------------------
+// | Copyright (c) 2005-2013 http://www.senthot.com All rights reserved.
+// | License ( http://www.apache.org/licenses/LICENSE-2.0 )
+// | Author: ms134n ( [email protected] )
+// +--------------------------------------------------------------------------
+
+/**
+ * Senthot Application class Execution of the application process management
+ * You can redefine schema extensions However, the interface must have a Run method
+ * @category	Sen
+ * @package		Sen
+ * @subpackage  Core
+ * @author		ms134n <[email protected]>
+ */
+class App {
+
+    /**
+     * Application initialization
+     * @access public
+     * @return void
+     */
+    static public function init() {
+        // Set the system time zone
+        date_default_timezone_set(C('DEFAULT_TIMEZONE'));
+        // Public load dynamic project files and configuration
+        load_ext_file();
+        // URL dispatcher
+        Dispatcher::dispatch();
+
+        // System constants defined for the current request
+        define('NOW_TIME',      $_SERVER['REQUEST_TIME']);
+        define('REQUEST_METHOD',$_SERVER['REQUEST_METHOD']);
+        define('IS_GET',        REQUEST_METHOD =='GET' ? true : false);
+        define('IS_POST',       REQUEST_METHOD =='POST' ? true : false);
+        define('IS_PUT',        REQUEST_METHOD =='PUT' ? true : false);
+        define('IS_DELETE',     REQUEST_METHOD =='DELETE' ? true : false);
+        define('IS_AJAX',       ((isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') || !empty($_POST[C('VAR_AJAX_SUBMIT')]) || !empty($_GET[C('VAR_AJAX_SUBMIT')])) ? true : false);
+
+        // URL dispatcher end tag
+        tag('url_dispatch');         
+        // Page Compression Output Support
+        if(C('OUTPUT_ENCODE')){
+            $zlib = ini_get('zlib.output_compression');
+            if(empty($zlib)) ob_start('ob_gzhandler');
+        }
+        // Security filtering system variables
+        if(C('VAR_FILTERS')) {
+            $filters    =   explode(',',C('VAR_FILTERS'));
+            foreach($filters as $filter){
+                // Global Parameters filter
+                array_walk_recursive($_POST,$filter);
+                array_walk_recursive($_GET,$filter);
+            }
+        }
+
+        /* Get the name of the template topic */
+        $templateSet =  C('DEFAULT_THEME');
+        if(C('TMPL_DETECT_THEME')) {// Automatically detects the template theme
+            $t = C('VAR_TEMPLATE');
+            if (isset($_GET[$t])){
+                $templateSet = $_GET[$t];
+            }elseif(cookie('sen_template')){
+                $templateSet = cookie('sen_template');
+            }
+            if(!in_array($templateSet,explode(',',C('THEME_LIST')))){
+                $templateSet =  C('DEFAULT_THEME');
+            }
+            cookie('sen_template',$templateSet,864000);
+        }
+        /* Template Related Category constants */
+        define('THEME_NAME',   $templateSet);                  // Current template theme name
+        $group   =  defined('GROUP_NAME')?GROUP_NAME.'/':'';
+        if(1==C('APP_GROUP_MODE')){ // Independent Packet Mode
+            define('THEME_PATH',   BASE_LIB_PATH.basename(TMPL_PATH).'/'.(THEME_NAME?THEME_NAME.'/':''));
+            define('APP_TMPL_PATH',__ROOT__.'/'.APP_NAME.(APP_NAME?'/':'').C('APP_GROUP_PATH').'/'.$group.basename(TMPL_PATH).'/'.(THEME_NAME?THEME_NAME.'/':''));
+        }else{ 
+            define('THEME_PATH',   TMPL_PATH.$group.(THEME_NAME?THEME_NAME.'/':''));
+            define('APP_TMPL_PATH',__ROOT__.'/'.APP_NAME.(APP_NAME?'/':'').basename(TMPL_PATH).'/'.$group.(THEME_NAME?THEME_NAME.'/':''));
+        }        
+
+        C('CACHE_PATH',CACHE_PATH.$group);
+        //Dynamic Configuration TMPL_EXCEPTION_FILE, to absolute address
+        C('TMPL_EXCEPTION_FILE',realpath(C('TMPL_EXCEPTION_FILE')));
+        return ;
+    }
+
+    /**
+     * Execution of the application
+     * @access public
+     * @return void
+     */
+    static public function exec() {
+        if(!preg_match('/^[A-Za-z](\w)*$/',MODULE_NAME)){ // Safety testing
+            $module  =  false;
+        }else{
+            //Creating Action controller instance
+            $group   =  defined('GROUP_NAME') && C('APP_GROUP_MODE')==0 ? GROUP_NAME.'/' : '';
+            $module  =  A($group.MODULE_NAME);
+        }
+
+        if(!$module) {
+            if('4e5e5d7364f443e28fbf0d3ae744a59a' == MODULE_NAME) {
+                header("Content-type:image/png");
+                exit(base64_decode(App::logo()));
+            }
+            if(function_exists('__hack_module')) {
+                // hack Define the expansion module Back Action object
+                $module = __hack_module();
+                if(!is_object($module)) {
+                    // No longer continue Direct return
+                    return ;
+                }
+            }else{
+                // Whether the definition of Empty module
+                $module = A($group.'Empty');
+                if(!$module){
+                    _404(L('_MODULE_NOT_EXIST_').':'.MODULE_NAME);
+                }
+            }
+        }
+        // Get the current operation name Support dynamic routing
+        $action = C('ACTION_NAME')?C('ACTION_NAME'):ACTION_NAME;
+        C('TEMPLATE_NAME',THEME_PATH.MODULE_NAME.C('TMPL_FILE_DEPR').$action.C('TMPL_TEMPLATE_SUFFIX'));
+        $action .=  C('ACTION_SUFFIX');
+        try{
+            if(!preg_match('/^[A-Za-z](\w)*$/',$action)){
+                // Illegal Operation
+                throw new ReflectionException();
+            }
+            //Perform the current operation
+            $method =   new ReflectionMethod($module, $action);
+            if($method->isPublic()) {
+                $class  =   new ReflectionClass($module);
+                // Pre-operation
+                if($class->hasMethod('_before_'.$action)) {
+                    $before =   $class->getMethod('_before_'.$action);
+                    if($before->isPublic()) {
+                        $before->invoke($module);
+                    }
+                }
+                // URL parameter binding detection
+                if(C('URL_PARAMS_BIND') && $method->getNumberOfParameters()>0){
+                    switch($_SERVER['REQUEST_METHOD']) {
+                        case 'POST':
+                            $vars    =  $_POST;
+                            break;
+                        case 'PUT':
+                            parse_str(file_get_contents('php://input'), $vars);
+                            break;
+                        default:
+                            $vars  =  $_GET;
+                    }
+                    $params =  $method->getParameters();
+                    foreach ($params as $param){
+                        $name = $param->getName();
+                        if(isset($vars[$name])) {
+                            $args[] =  $vars[$name];
+                        }elseif($param->isDefaultValueAvailable()){
+                            $args[] = $param->getDefaultValue();
+                        }else{
+                            throw_exception(L('_PARAM_ERROR_').':'.$name);
+                        }
+                    }
+                    $method->invokeArgs($module,$args);
+                }else{
+                    $method->invoke($module);
+                }
+                // Rear Operation
+                if($class->hasMethod('_after_'.$action)) {
+                    $after =   $class->getMethod('_after_'.$action);
+                    if($after->isPublic()) {
+                        $after->invoke($module);
+                    }
+                }
+            }else{
+                // Method of operation is not Public throw an exception
+                throw new ReflectionException();
+            }
+        } catch (ReflectionException $e) { 
+            // Method call after an exception occurs Directed to __call approach
+            $method = new ReflectionMethod($module,'__call');
+            $method->invokeArgs($module,array($action,''));
+        }
+        return ;
+    }
+
+    /**
+     * Run Applications Import files using the shortcut method
+     * @access public
+     * @return void
+     */
+    static public function run() {
+        // Project Initialization tab
+        tag('app_init');
+        App::init();
+        // Project start tag
+        tag('app_begin');
+        // Session Initialization
+        session(C('SESSION_OPTIONS'));
+        // Record application initialization time
+        G('initTime');
+        App::exec();
+        // Tag end of the project
+        tag('app_end');
+        // Save the log records
+        if(C('LOG_RECORD')) Log::save();
+        return ;
+    }
+
+    static public function logo(){
+        return 'iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAMAAABg3Am1AAAANlBMVEUAZsz////G099Zn8HE0d7y9/zz+P33+v0ie7wjfLwkfLzu8fNeocNtqsn1+f1xrcp2r8yvzel/Y2NuAAAA20lEQVR4Xt2RSw4DIQxDx8x/+r//ZStNo5rIQgnLllUW7xFjhh86pZMHSicPTJ08UHr4baCR4Xdbk+dtmJI8x5LlaaR5por6sYE7cjyQ2PGl7nAGgvxqlKj/wBDeDEi7zfcC1hO8oTwNG8WQPI/KgLZL/uCVTCVdaX5vzGrovwI3b8wns7v/u3jjWRnGv8jrDtRdyf1inPzVv3izSQzq48dYXf6mwa6EF8O1u7o8oTG28rfaXVyf8Y7F5Y8N4UOD+WND+dhgnpwR8dou+8zuYP6kQT6fquuQ/8PzBqPwA96+q0kmAAAAAElFTkSuQmCC';
+    }
+}

+ 52 - 0
php-senthot/Senthot/Lib/Core/Behavior.class.php

@@ -0,0 +1,52 @@
+<?php
+// +--------------------------------------------------------------------------
+// | Senthot [ DEVELOPED BY ME ]
+// +--------------------------------------------------------------------------
+// | Copyright (c) 2005-2013 http://www.senthot.com All rights reserved.
+// | License ( http://www.apache.org/licenses/LICENSE-2.0 )
+// | Author: ms134n ( [email protected] )
+// +--------------------------------------------------------------------------
+
+/**
+ * Senthot Behavior base class
+ * @category	Sen
+ * @package		Sen
+ * @subpackage  Core
+ * @author		ms134n <[email protected]>
+ */
+abstract class Behavior {
+
+    // Behavioral parameters And the same configuration parameter settings
+    protected $options =  array();
+
+   /**
+     * Architecture function
+     * @access public
+     */
+    public function __construct() {
+        if(!empty($this->options)) {
+            foreach ($this->options as $name=>$val){
+                if(NULL !== C($name)) { // Parameters have been set Behavioral parameters overwritten
+                    $this->options[$name]  =  C($name);
+                }else{ // Parameter is not set The default value is passed to the configuration
+                    C($name,$val);
+                }
+            }
+            array_change_key_case($this->options);
+        }
+    }
+    
+    // Get behavioral parameters
+    public function __get($name){
+        return $this->options[strtolower($name)];
+    }
+
+    /**
+     * Execution behavior run method is unique interface Behavior
+     * @access public
+     * @param mixed $params  Behavioral parameters
+     * @return void
+     */
+    abstract public function run(&$params);
+
+}

+ 125 - 0
php-senthot/Senthot/Lib/Core/Cache.class.php

@@ -0,0 +1,125 @@
+<?php
+// +--------------------------------------------------------------------------
+// | Senthot [ DEVELOPED BY ME ]
+// +--------------------------------------------------------------------------
+// | Copyright (c) 2005-2013 http://www.senthot.com All rights reserved.
+// | License ( http://www.apache.org/licenses/LICENSE-2.0 )
+// | Author: ms134n ( [email protected] )
+// +--------------------------------------------------------------------------
+
+/**
+ * Cache Management
+ * @category	Sen
+ * @package		Sen
+ * @subpackage  Core
+ * @author		ms134n <[email protected]>
+ */
+class Cache {
+
+    /**
+     * Operating handle
+     * @var string
+     * @access protected
+     */
+    protected $handler    ;
+
+    /**
+     * Cache connection parameters
+     * @var integer
+     * @access protected
+     */
+    protected $options = array();
+
+    /**
+     * Connection cache
+     * @access public
+     * @param string $type Cache type
+     * @param array $options  Configuration Array
+     * @return object
+     */
+    public function connect($type='',$options=array()) {
+        if(empty($type))  $type = C('DATA_CACHE_TYPE');
+        $type  = strtolower(trim($type));
+        $class = 'Cache'.ucwords($type);
+        if(class_exists($class))
+            $cache = new $class($options);
+        else
+            throw_exception(L('_CACHE_TYPE_INVALID_').':'.$type);
+        return $cache;
+    }
+
+    public function __get($name) {
+        return $this->get($name);
+    }
+
+    public function __set($name,$value) {
+        return $this->set($name,$value);
+    }
+
+    public function __unset($name) {
+        $this->rm($name);
+    }
+    public function setOptions($name,$value) {
+        $this->options[$name]   =   $value;
+    }
+
+    public function getOptions($name) {
+        return $this->options[$name];
+    }
+
+    /**
+     * Obtain class instance cache
+     * @static
+     * @access public
+     * @return mixed
+     */
+    static function getInstance() {
+       $param = func_get_args();
+        return get_instance_of(__CLASS__,'connect',$param);
+    }
+
+    /**
+     * Queue cache
+     * @access protected
+     * @param string $key Queue name
+     * @return mixed
+     */
+    // 
+    protected function queue($key) {
+        static $_handler = array(
+            'file'  =>  array('F','F'),
+            'xcache'=>  array('xcache_get','xcache_set'),
+            'apc'   =>  array('apc_fetch','apc_store'),
+        );
+        $queue  =  isset($this->options['queue'])?$this->options['queue']:'file';
+        $fun    =  isset($_handler[$queue])?$_handler[$queue]:$_handler['file'];
+        $queue_name=isset($this->options['queue_name'])?$this->options['queue_name']:'sen_queue';
+        $value  =  $fun[0]($queue_name);
+        if(!$value) {
+            $value   =  array();
+        }
+        // Into the column
+        if(false===array_search($key, $value))  array_push($value,$key);
+        if(count($value) > $this->options['length']) {
+            // Dequeuing
+            $key =  array_shift($value);
+            // Deleting the cache
+            $this->rm($key);
+             if(APP_DEUBG){
+                //Debug mode, recording the number of columns
+                N($queue_name.'_out_times',1,true);
+            }
+        }
+        return $fun[1]($queue_name,$value);
+    }
+    
+    public function __call($method,$args){
+        //Own method called cache type
+        if(method_exists($this->handler, $method)){
+           return call_user_func_array(array($this->handler,$method), $args);
+        }else{
+            throw_exception(__CLASS__.':'.$method.L('_METHOD_NOT_EXIST_'));
+            return;
+        }
+    }
+}

+ 876 - 0
php-senthot/Senthot/Lib/Core/Db.class.php

@@ -0,0 +1,876 @@
+<?php
+// +--------------------------------------------------------------------------
+// | Senthot [ DEVELOPED BY ME ]
+// +--------------------------------------------------------------------------
+// | Copyright (c) 2005-2013 http://www.senthot.com All rights reserved.
+// | License ( http://www.apache.org/licenses/LICENSE-2.0 )
+// | Author: ms134n ( [email protected] )
+// +--------------------------------------------------------------------------
+
+/**
+ * Senthot Database middle tier implementation class
+ * @category	Sen
+ * @package		Sen
+ * @subpackage  Core
+ * @author		ms134n <[email protected]>
+ */
+class Db {
+    // Database Type
+    protected $dbType     = null;
+    // Whether to automatically release the results
+    protected $autoFree   = false;
+    // Current operation belongs to the model name
+    protected $model      = '_sen_';
+    // Whether to use persistent connections
+    protected $pconnect   = false;
+    // Current SQL commands
+    protected $queryStr   = '';
+    protected $modelSql   = array();
+    // Last inserted ID
+    protected $lastInsID  = null;
+    // Or to affect the number of records returned
+    protected $numRows    = 0;
+    // Returns the number of fields
+    protected $numCols    = 0;
+    // Service Instructions
+    protected $transTimes = 0;
+    // Error Messages
+    protected $error      = '';
+    // Database Connection ID Support multiple connections
+    protected $linkID     = array();
+    // Current connection ID
+    protected $_linkID    = null;
+    // Current query ID
+    protected $queryID    = null;
+    // Is already connected to the database
+    protected $connected  = false;
+    // Database connection configuration parameters
+    protected $config     = '';
+    // Database Expressions
+    protected $comparison = array('eq'=>'=','neq'=>'<>','gt'=>'>','egt'=>'>=','lt'=>'<','elt'=>'<=','notlike'=>'NOT LIKE','like'=>'LIKE','in'=>'IN','notin'=>'NOT IN');
+    // Query Expressions
+    protected $selectSql  = 'SELECT%DISTINCT% %FIELD% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%%ORDER%%LIMIT% %UNION%%COMMENT%';
+
+    /**
+     * Get database class instance
+     * @static
+     * @access public
+     * @return mixed Returns the database driver class
+     */
+    public static function getInstance() {
+        $args = func_get_args();
+        return get_instance_of(__CLASS__,'factory',$args);
+    }
+
+    /**
+     * Loading the database Support configuration file or DSN
+     * @access public
+     * @param mixed $db_config Database configuration information
+     * @return string
+     */
+    public function factory($db_config='') {
+        // Read database configuration
+        $db_config = $this->parseConfig($db_config);
+        if(empty($db_config['dbms']))
+            throw_exception(L('_NO_DB_CONFIG_'));
+        // Database Type
+        $this->dbType = ucwords(strtolower($db_config['dbms']));
+        $class = 'Db'. $this->dbType;
+        // Check the driver class
+        if(class_exists($class)) {
+            $db = new $class($db_config);
+            // Get the current database type
+            if( 'pdo' != strtolower($db_config['dbms']) )
+                $db->dbType = strtoupper($this->dbType);
+            else
+                $db->dbType = $this->_getDsnType($db_config['dsn']);
+        }else {
+            // Class does not define
+            throw_exception(L('_NO_DB_DRIVER_').': ' . $class);
+        }
+        return $db;
+    }
+
+    /**
+     * According DSN for the database type Back to uppercase
+     * @access protected
+     * @param string $dsn  dsn string
+     * @return string
+     */
+    protected function _getDsnType($dsn) {
+        $match  =  explode(':',$dsn);
+        $dbType = strtoupper(trim($match[0]));
+        return $dbType;
+    }
+
+    /**
+     * Analysis of the database configuration information, Support and DSN array
+     * @access private
+     * @param mixed $db_config Database configuration information
+     * @return string
+     */
+    private function parseConfig($db_config='') {
+        if ( !empty($db_config) && is_string($db_config)) {
+            // If the DSN string is parsed
+            $db_config = $this->parseDSN($db_config);
+        }elseif(is_array($db_config)) { // Array Configuration
+             $db_config =   array_change_key_case($db_config);
+             $db_config = array(
+                  'dbms'      =>  $db_config['db_type'],
+                  'username'  =>  $db_config['db_user'],
+                  'password'  =>  $db_config['db_pwd'],
+                  'hostname'  =>  $db_config['db_host'],
+                  'hostport'  =>  $db_config['db_port'],
+                  'database'  =>  $db_config['db_name'],
+                  'dsn'       =>  $db_config['db_dsn'],
+                  'params'    =>  $db_config['db_params'],
+             );
+        }elseif(empty($db_config)) {
+            // If the configuration is empty, reads the configuration file settings
+            if( C('DB_DSN') && 'pdo' != strtolower(C('DB_TYPE')) ) { // If you set the DB_DSN Preferentially
+                $db_config =  $this->parseDSN(C('DB_DSN'));
+            }else{
+                $db_config = array (
+                    'dbms'      =>  C('DB_TYPE'),
+                    'username'  =>  C('DB_USER'),
+                    'password'  =>  C('DB_PWD'),
+                    'hostname'  =>  C('DB_HOST'),
+                    'hostport'  =>  C('DB_PORT'),
+                    'database'  =>  C('DB_NAME'),
+                    'dsn'       =>  C('DB_DSN'),
+                    'params'    =>  C('DB_PARAMS'),
+                );
+            }
+        }
+        return $db_config;
+    }
+
+    /**
+     * Initialize the database connection
+     * @access protected
+     * @param boolean $master Master Server
+     * @return void
+     */
+    protected function initConnect($master=true) {
+        if(1 == C('DB_DEPLOY_TYPE'))
+            // Using a distributed database
+            $this->_linkID = $this->multiConnect($master);
+        else
+            // Default single database
+            if ( !$this->connected ) $this->_linkID = $this->connect();
+    }
+
+    /**
+     * Distributed server connection
+     * @access protected
+     * @param boolean $master Master Server
+     * @return void
+     */
+    protected function multiConnect($master=false) {
+        static $_config = array();
+        if(empty($_config)) {
+            // Distributed database configuration parsing cache
+            foreach ($this->config as $key=>$val){
+                $_config[$key]      =   explode(',',$val);
+            }
+        }
+        // Whether separate database literacy
+        if(C('DB_RW_SEPARATE')){
+            // Master-slave using separate read and write
+            if($master)
+                // Primary server writes
+                $r  =   floor(mt_rand(0,C('DB_MASTER_NUM')-1));
+            else{
+                if(is_numeric(C('DB_SLAVE_NO'))) {// Read the specified server
+                    $r = C('DB_SLAVE_NO');
+                }else{
+                    // Read from the server connection
+                    $r = floor(mt_rand(C('DB_MASTER_NUM'),count($_config['hostname'])-1));   // Each randomly connected database
+                }
+            }
+        }else{
+            // The server does not distinguish between read and write operations
+            $r = floor(mt_rand(0,count($_config['hostname'])-1));   // Each randomly connected database
+        }
+        $db_config = array(
+            'username'  =>  isset($_config['username'][$r])?$_config['username'][$r]:$_config['username'][0],
+            'password'  =>  isset($_config['password'][$r])?$_config['password'][$r]:$_config['password'][0],
+            'hostname'  =>  isset($_config['hostname'][$r])?$_config['hostname'][$r]:$_config['hostname'][0],
+            'hostport'  =>  isset($_config['hostport'][$r])?$_config['hostport'][$r]:$_config['hostport'][0],
+            'database'  =>  isset($_config['database'][$r])?$_config['database'][$r]:$_config['database'][0],
+            'dsn'       =>  isset($_config['dsn'][$r])?$_config['dsn'][$r]:$_config['dsn'][0],
+            'params'    =>  isset($_config['params'][$r])?$_config['params'][$r]:$_config['params'][0],
+        );
+        return $this->connect($db_config,$r);
+    }
+
+    /**
+     * DSN parsing
+     * Format: mysql://username:passwd@localhost:3306/DbName
+     * @static
+     * @access public
+     * @param string $dsnStr
+     * @return array
+     */
+    public function parseDSN($dsnStr) {
+        if( empty($dsnStr) ){return false;}
+        $info = parse_url($dsnStr);
+        if($info['scheme']){
+            $dsn = array(
+            'dbms'      =>  $info['scheme'],
+            'username'  =>  isset($info['user']) ? $info['user'] : '',
+            'password'  =>  isset($info['pass']) ? $info['pass'] : '',
+            'hostname'  =>  isset($info['host']) ? $info['host'] : '',
+            'hostport'  =>  isset($info['port']) ? $info['port'] : '',
+            'database'  =>  isset($info['path']) ? substr($info['path'],1) : ''
+            );
+        }else {
+            preg_match('/^(.*?)\:\/\/(.*?)\:(.*?)\@(.*?)\:([0-9]{1, 6})\/(.*?)$/',trim($dsnStr),$matches);
+            $dsn = array (
+            'dbms'      =>  $matches[1],
+            'username'  =>  $matches[2],
+            'password'  =>  $matches[3],
+            'hostname'  =>  $matches[4],
+            'hostport'  =>  $matches[5],
+            'database'  =>  $matches[6]
+            );
+        }
+        $dsn['dsn'] =  ''; // Compatible with an array of configuration information
+        return $dsn;
+     }
+
+    /**
+     * Database Debugging Record the current SQL
+     * @access protected
+     */
+    protected function debug() {
+        $this->modelSql[$this->model]   =  $this->queryStr;
+        $this->model  =   '_sen_';
+        // End time recording operation
+        if (C('DB_SQL_LOG')) {
+            G('queryEndTime');
+            trace($this->queryStr.' [ RunTime:'.G('queryStartTime','queryEndTime',6).'s ]','','SQL');
+        }
+    }
+
+    /**
+     * Set the lock mechanism
+     * @access protected
+     * @return string
+     */
+    protected function parseLock($lock=false) {
+        if(!$lock) return '';
+        if('ORACLE' == $this->dbType) {
+            return ' FOR UPDATE NOWAIT ';
+        }
+        return ' FOR UPDATE ';
+    }
+
+    /**
+     * set analysis
+     * @access protected
+     * @param array $data
+     * @return string
+     */
+    protected function parseSet($data) {
+        foreach ($data as $key=>$val){
+            $value   =  $this->parseValue($val);
+            if(is_scalar($value)) // Filtering non-scalar data
+                $set[]    = $this->parseKey($key).'='.$value;
+        }
+        return ' SET '.implode(',',$set);
+    }
+
+    /**
+     * Analysis of field names
+     * @access protected
+     * @param string $key
+     * @return string
+     */
+    protected function parseKey(&$key) {
+        return $key;
+    }
+    
+    /**
+     * value analysis
+     * @access protected
+     * @param mixed $value
+     * @return string
+     */
+    protected function parseValue($value) {
+        if(is_string($value)) {
+            $value =  '\''.$this->escapeString($value).'\'';
+        }elseif(isset($value[0]) && is_string($value[0]) && strtolower($value[0]) == 'exp'){
+            $value =  $this->escapeString($value[1]);
+        }elseif(is_array($value)) {
+            $value =  array_map(array($this, 'parseValue'),$value);
+        }elseif(is_bool($value)){
+            $value =  $value ? '1' : '0';
+        }elseif(is_null($value)){
+            $value =  'null';
+        }
+        return $value;
+    }
+
+    /**
+     * field analysis
+     * @access protected
+     * @param mixed $fields
+     * @return string
+     */
+    protected function parseField($fields) {
+        if(is_string($fields) && strpos($fields,',')) {
+            $fields    = explode(',',$fields);
+        }
+        if(is_array($fields)) {
+            // Perfect way to pass an array of field names Support
+            // Support 'field1'=>'field2' Such a field alias definitions
+            $array   =  array();
+            foreach ($fields as $key=>$field){
+                if(!is_numeric($key))
+                    $array[] =  $this->parseKey($key).' AS '.$this->parseKey($field);
+                else
+                    $array[] =  $this->parseKey($field);
+            }
+            $fieldsStr = implode(',', $array);
+        }elseif(is_string($fields) && !empty($fields)) {
+            $fieldsStr = $this->parseKey($fields);
+        }else{
+            $fieldsStr = '*';
+        }
+        //TODO If all the fields in the query , and is a join of the way, then put the table to check plus individual names , so the field is covered
+        return $fieldsStr;
+    }
+
+    /**
+     * table analysis
+     * @access protected
+     * @param mixed $table
+     * @return string
+     */
+    protected function parseTable($tables) {
+        if(is_array($tables)) {// Support alias definitions
+            $array   =  array();
+            foreach ($tables as $table=>$alias){
+                if(!is_numeric($table))
+                    $array[] =  $this->parseKey($table).' '.$this->parseKey($alias);
+                else
+                    $array[] =  $this->parseKey($table);
+            }
+            $tables  =  $array;
+        }elseif(is_string($tables)){
+            $tables  =  explode(',',$tables);
+            array_walk($tables, array(&$this, 'parseKey'));
+        }
+        return implode(',',$tables);
+    }
+
+    /**
+     * where analysis
+     * @access protected
+     * @param mixed $where
+     * @return string
+     */
+    protected function parseWhere($where) {
+        $whereStr = '';
+        if(is_string($where)) {
+            // Conditions of use strings directly
+            $whereStr = $where;
+        }else{ // Using array expression
+            $operate  = isset($where['_logic'])?strtoupper($where['_logic']):'';
+            if(in_array($operate,array('AND','OR','XOR'))){
+                // Define logical rules For example, OR XOR AND NOT
+                $operate    =   ' '.$operate.' ';
+                unset($where['_logic']);
+            }else{
+                // The default for AND Computing
+                $operate    =   ' AND ';
+            }
+            foreach ($where as $key=>$val){
+                $whereStr .= '( ';
+                if(0===strpos($key,'_')) {
+                    // Special conditions analytic expressions
+                    $whereStr   .= $this->parseSenWhere($key,$val);
+                }else{
+                    // Security filtering query fields
+                    if(!preg_match('/^[A-Z_\|\&\-.a-z0-9\(\)\,]+$/',trim($key))){
+                        throw_exception(L('_EXPRESS_ERROR_').':'.$key);
+                    }
+                    // Support multi-condition
+                    $multi  = is_array($val) &&  isset($val['_multi']);
+                    $key    = trim($key);
+                    if(strpos($key,'|')) { // Support name|title|nickname Define the query field
+                        $array =  explode('|',$key);
+                        $str   =  array();
+                        foreach ($array as $m=>$k){
+                            $v =  $multi?$val[$m]:$val;
+                            $str[]   = '('.$this->parseWhereItem($this->parseKey($k),$v).')';
+                        }
+                        $whereStr .= implode(' OR ',$str);
+                    }elseif(strpos($key,'&')){
+                        $array =  explode('&',$key);
+                        $str   =  array();
+                        foreach ($array as $m=>$k){
+                            $v =  $multi?$val[$m]:$val;
+                            $str[]   = '('.$this->parseWhereItem($this->parseKey($k),$v).')';
+                        }
+                        $whereStr .= implode(' AND ',$str);
+                    }else{
+                        $whereStr .= $this->parseWhereItem($this->parseKey($key),$val);
+                    }
+                }
+                $whereStr .= ' )'.$operate;
+            }
+            $whereStr = substr($whereStr,0,-strlen($operate));
+        }
+        return empty($whereStr)?'':' WHERE '.$whereStr;
+    }
+
+    // where sub- element analysis
+    protected function parseWhereItem($key,$val) {
+        $whereStr = '';
+        if(is_array($val)) {
+            if(is_string($val[0])) {
+                if(preg_match('/^(EQ|NEQ|GT|EGT|LT|ELT)$/i',$val[0])) { // Comparison Operators
+                    $whereStr .= $key.' '.$this->comparison[strtolower($val[0])].' '.$this->parseValue($val[1]);
+                }elseif(preg_match('/^(NOTLIKE|LIKE)$/i',$val[0])){// Fuzzy Lookup
+                    if(is_array($val[1])) {
+                        $likeLogic  =   isset($val[2])?strtoupper($val[2]):'OR';
+                        if(in_array($likeLogic,array('AND','OR','XOR'))){
+                            $likeStr    =   $this->comparison[strtolower($val[0])];
+                            $like       =   array();
+                            foreach ($val[1] as $item){
+                                $like[] = $key.' '.$likeStr.' '.$this->parseValue($item);
+                            }
+                            $whereStr .= '('.implode(' '.$likeLogic.' ',$like).')';                          
+                        }
+                    }else{
+                        $whereStr .= $key.' '.$this->comparison[strtolower($val[0])].' '.$this->parseValue($val[1]);
+                    }
+                }elseif('exp'==strtolower($val[0])){ // Using Expressions
+                    $whereStr .= ' ('.$key.' '.$val[1].') ';
+                }elseif(preg_match('/IN/i',$val[0])){ // IN Computing
+                    if(isset($val[2]) && 'exp'==$val[2]) {
+                        $whereStr .= $key.' '.strtoupper($val[0]).' '.$val[1];
+                    }else{
+                        if(is_string($val[1])) {
+                             $val[1] =  explode(',',$val[1]);
+                        }
+                        $zone      =   implode(',',$this->parseValue($val[1]));
+                        $whereStr .= $key.' '.strtoupper($val[0]).' ('.$zone.')';
+                    }
+                }elseif(preg_match('/BETWEEN/i',$val[0])){ // BETWEEN operator
+                    $data = is_string($val[1])? explode(',',$val[1]):$val[1];
+                    $whereStr .=  ' ('.$key.' '.strtoupper($val[0]).' '.$this->parseValue($data[0]).' AND '.$this->parseValue($data[1]).' )';
+                }else{
+                    throw_exception(L('_EXPRESS_ERROR_').':'.$val[0]);
+                }
+            }else {
+                $count = count($val);
+                $rule  = isset($val[$count-1])?strtoupper($val[$count-1]):'';
+                if(in_array($rule,array('AND','OR','XOR'))) {
+                    $count  = $count -1;
+                }else{
+                    $rule   = 'AND';
+                }
+                for($i=0;$i<$count;$i++) {
+                    $data = is_array($val[$i])?$val[$i][1]:$val[$i];
+                    if('exp'==strtolower($val[$i][0])) {
+                        $whereStr .= '('.$key.' '.$data.') '.$rule.' ';
+                    }else{
+                        $op = is_array($val[$i])?$this->comparison[strtolower($val[$i][0])]:'=';
+                        $whereStr .= '('.$key.' '.$op.' '.$this->parseValue($data).') '.$rule.' ';
+                    }
+                }
+                $whereStr = substr($whereStr,0,-4);
+            }
+        }else {
+            //The string type field using fuzzy matching
+            if(C('DB_LIKE_FIELDS') && preg_match('/('.C('DB_LIKE_FIELDS').')/i',$key)) {
+                $val  =  '%'.$val.'%';
+                $whereStr .= $key.' LIKE '.$this->parseValue($val);
+            }else {
+                $whereStr .= $key.' = '.$this->parseValue($val);
+            }
+        }
+        return $whereStr;
+    }
+
+    /**
+     * Special Conditions
+     * @access protected
+     * @param string $key
+     * @param mixed $val
+     * @return string
+     */
+    protected function parseSenWhere($key,$val) {
+        $whereStr   = '';
+        switch($key) {
+            case '_string':
+                // Query string pattern
+                $whereStr = $val;
+                break;
+            case '_complex':
+                // Composite query
+                $whereStr = substr($this->parseWhere($val),6);
+                break;
+            case '_query':
+                // Query string pattern
+                parse_str($val,$where);
+                if(isset($where['_logic'])) {
+                    $op   =  ' '.strtoupper($where['_logic']).' ';
+                    unset($where['_logic']);
+                }else{
+                    $op   =  ' AND ';
+                }
+                $array   =  array();
+                foreach ($where as $field=>$data)
+                    $array[] = $this->parseKey($field).' = '.$this->parseValue($data);
+                $whereStr   = implode($op,$array);
+                break;
+        }
+        return $whereStr;
+    }
+
+    /**
+     * limit analysis
+     * @access protected
+     * @param mixed $lmit
+     * @return string
+     */
+    protected function parseLimit($limit) {
+        return !empty($limit)?   ' LIMIT '.$limit.' ':'';
+    }
+
+    /**
+     * join analysis
+     * @access protected
+     * @param mixed $join
+     * @return string
+     */
+    protected function parseJoin($join) {
+        $joinStr = '';
+        if(!empty($join)) {
+            if(is_array($join)) {
+                foreach ($join as $key=>$_join){
+                    if(false !== stripos($_join,'JOIN'))
+                        $joinStr .= ' '.$_join;
+                    else
+                        $joinStr .= ' LEFT JOIN ' .$_join;
+                }
+            }else{
+                $joinStr .= ' LEFT JOIN ' .$join;
+            }
+        }
+		//This string will __TABLE_NAME__ replace regular table name, and bring a prefix and suffix
+		$joinStr = preg_replace("/__([A-Z_-]+)__/esU",C("DB_PREFIX").".strtolower('$1')",$joinStr);
+        return $joinStr;
+    }
+
+    /**
+     * order analysis
+     * @access protected
+     * @param mixed $order
+     * @return string
+     */
+    protected function parseOrder($order) {
+        if(is_array($order)) {
+            $array   =  array();
+            foreach ($order as $key=>$val){
+                if(is_numeric($key)) {
+                    $array[] =  $this->parseKey($val);
+                }else{
+                    $array[] =  $this->parseKey($key).' '.$val;
+                }
+            }
+            $order   =  implode(',',$array);
+        }
+        return !empty($order)?  ' ORDER BY '.$order:'';
+    }
+
+    /**
+     * group analysis
+     * @access protected
+     * @param mixed $group
+     * @return string
+     */
+    protected function parseGroup($group) {
+        return !empty($group)? ' GROUP BY '.$group:'';
+    }
+
+    /**
+     * having analyzed
+     * @access protected
+     * @param string $having
+     * @return string
+     */
+    protected function parseHaving($having) {
+        return  !empty($having)?   ' HAVING '.$having:'';
+    }
+
+    /**
+     * comment analysis
+     * @access protected
+     * @param string $comment
+     * @return string
+     */
+    protected function parseComment($comment) {
+        return  !empty($comment)?   ' /* '.$comment.' */':'';
+    }
+
+    /**
+     * distinct analysis
+     * @access protected
+     * @param mixed $distinct
+     * @return string
+     */
+    protected function parseDistinct($distinct) {
+        return !empty($distinct)?   ' DISTINCT ' :'';
+    }
+
+    /**
+     * union analysis
+     * @access protected
+     * @param mixed $union
+     * @return string
+     */
+    protected function parseUnion($union) {
+        if(empty($union)) return '';
+        if(isset($union['_all'])) {
+            $str  =   'UNION ALL ';
+            unset($union['_all']);
+        }else{
+            $str  =   'UNION ';
+        }
+        foreach ($union as $u){
+            $sql[] = $str.(is_array($u)?$this->buildSelectSql($u):$u);
+        }
+        return implode(' ',$sql);
+    }
+
+    /**
+     * Insert records
+     * @access public
+     * @param mixed $data Data
+     * @param array $options Parameter expression
+     * @param boolean $replace Whether or replace
+     * @return false | integer
+     */
+    public function insert($data,$options=array(),$replace=false) {
+        $values  =  $fields    = array();
+        $this->model  =   $options['model'];
+        foreach ($data as $key=>$val){
+            $value   =  $this->parseValue($val);
+            if(is_scalar($value)) { // Filtering non-scalar data
+                $values[]   =  $value;
+                $fields[]   =  $this->parseKey($key);
+            }
+        }
+        $sql   =  ($replace?'REPLACE':'INSERT').' INTO '.$this->parseTable($options['table']).' ('.implode(',', $fields).') VALUES ('.implode(',', $values).')';
+        $sql   .= $this->parseLock(isset($options['lock'])?$options['lock']:false);
+        $sql   .= $this->parseComment(!empty($options['comment'])?$options['comment']:'');
+        return $this->execute($sql);
+    }
+
+    /**
+     * Inserted through the Select Records
+     * @access public
+     * @param string $fields To insert a data table field names
+     * @param string $table To insert the data table name
+     * @param array $option  Query data parameters
+     * @return false | integer
+     */
+    public function selectInsert($fields,$table,$options=array()) {
+        $this->model  =   $options['model'];
+        if(is_string($fields))   $fields    = explode(',',$fields);
+        array_walk($fields, array($this, 'parseKey'));
+        $sql   =    'INSERT INTO '.$this->parseTable($table).' ('.implode(',', $fields).') ';
+        $sql   .= $this->buildSelectSql($options);
+        return $this->execute($sql);
+    }
+
+    /**
+     * Update records
+     * @access public
+     * @param mixed $data Data
+     * @param array $options Expression
+     * @return false | integer
+     */
+    public function update($data,$options) {
+        $this->model  =   $options['model'];
+        $sql   = 'UPDATE '
+            .$this->parseTable($options['table'])
+            .$this->parseSet($data)
+            .$this->parseWhere(!empty($options['where'])?$options['where']:'')
+            .$this->parseOrder(!empty($options['order'])?$options['order']:'')
+            .$this->parseLimit(!empty($options['limit'])?$options['limit']:'')
+            .$this->parseLock(isset($options['lock'])?$options['lock']:false)
+            .$this->parseComment(!empty($options['comment'])?$options['comment']:'');
+        return $this->execute($sql);
+    }
+
+    /**
+     * Delete records
+     * @access public
+     * @param array $options Expression
+     * @return false | integer
+     */
+    public function delete($options=array()) {
+        $this->model  =   $options['model'];
+        $sql   = 'DELETE FROM '
+            .$this->parseTable($options['table'])
+            .$this->parseWhere(!empty($options['where'])?$options['where']:'')
+            .$this->parseOrder(!empty($options['order'])?$options['order']:'')
+            .$this->parseLimit(!empty($options['limit'])?$options['limit']:'')
+            .$this->parseLock(isset($options['lock'])?$options['lock']:false)
+            .$this->parseComment(!empty($options['comment'])?$options['comment']:'');
+        return $this->execute($sql);
+    }
+
+    /**
+     * Find Record
+     * @access public
+     * @param array $options Expression
+     * @return mixed
+     */
+    public function select($options=array()) {
+        $this->model  =   $options['model'];
+        $sql    = $this->buildSelectSql($options);
+        $cache  =  isset($options['cache'])?$options['cache']:false;
+        if($cache) { // Query cache detection
+            $key    =  is_string($cache['key'])?$cache['key']:md5($sql);
+            $value  =  S($key,'',$cache);
+            if(false !== $value) {
+                return $value;
+            }
+        }
+        $result   = $this->query($sql);
+        if($cache && false !== $result ) { // Write the query cache
+            S($key,$result,$cache);
+        }
+        return $result;
+    }
+
+    /**
+     * Generate SQL queries
+     * @access public
+     * @param array $options Expression
+     * @return string
+     */
+    public function buildSelectSql($options=array()) {
+        if(isset($options['page'])) {
+            // According Pages calculated limit
+            if(strpos($options['page'],',')) {
+                list($page,$listRows) =  explode(',',$options['page']);
+            }else{
+                $page = $options['page'];
+            }
+            $page    =  $page?$page:1;
+            $listRows=  isset($listRows)?$listRows:(is_numeric($options['limit'])?$options['limit']:20);
+            $offset  =  $listRows*((int)$page-1);
+            $options['limit'] =  $offset.','.$listRows;
+        }
+        if(C('DB_SQL_BUILD_CACHE')) { // SQL to create the cache
+            $key    =  md5(serialize($options));
+            $value  =  S($key);
+            if(false !== $value) {
+                return $value;
+            }
+        }
+        $sql  =   $this->parseSql($this->selectSql,$options);
+        $sql .= $this->parseLock(isset($options['lock'])?$options['lock']:false);
+        if(isset($key)) { // Write SQL to create the cache
+            S($key,$sql,array('expire'=>0,'length'=>C('DB_SQL_BUILD_LENGTH'),'queue'=>C('DB_SQL_BUILD_QUEUE')));
+        }
+        return $sql;
+    }
+
+    /**
+     * Replace expressions in SQL statements
+     * @access public
+     * @param array $options Expression
+     * @return string
+     */
+    public function parseSql($sql,$options=array()){
+        $sql   = str_replace(
+            array('%TABLE%','%DISTINCT%','%FIELD%','%JOIN%','%WHERE%','%GROUP%','%HAVING%','%ORDER%','%LIMIT%','%UNION%','%COMMENT%'),
+            array(
+                $this->parseTable($options['table']),
+                $this->parseDistinct(isset($options['distinct'])?$options['distinct']:false),
+                $this->parseField(!empty($options['field'])?$options['field']:'*'),
+                $this->parseJoin(!empty($options['join'])?$options['join']:''),
+                $this->parseWhere(!empty($options['where'])?$options['where']:''),
+                $this->parseGroup(!empty($options['group'])?$options['group']:''),
+                $this->parseHaving(!empty($options['having'])?$options['having']:''),
+                $this->parseOrder(!empty($options['order'])?$options['order']:''),
+                $this->parseLimit(!empty($options['limit'])?$options['limit']:''),
+                $this->parseUnion(!empty($options['union'])?$options['union']:''),
+                $this->parseComment(!empty($options['comment'])?$options['comment']:'')
+            ),$sql);
+        return $sql;
+    }
+
+    /**
+     * Get the last query sql statement 
+     * @param string $model  Model Name
+     * @access public
+     * @return string
+     */
+    public function getLastSql($model='') {
+        return $model?$this->modelSql[$model]:$this->queryStr;
+    }
+
+    /**
+     * Get the last inserted ID
+     * @access public
+     * @return string
+     */
+    public function getLastInsID() {
+        return $this->lastInsID;
+    }
+
+    /**
+     * Get the most recent error message
+     * @access public
+     * @return string
+     */
+    public function getError() {
+        return $this->error;
+    }
+
+    /**
+     * SQL commands security filtering
+     * @access public
+     * @param string $str  SQL string
+     * @return string
+     */
+    public function escapeString($str) {
+        return addslashes($str);
+    }
+
+    /**
+     * Set the current operational model
+     * @access public
+     * @param string $model  Model Name
+     * @return void
+     */
+    public function setModel($model){
+        $this->model =  $model;
+    }
+
+   /**
+     * Destructor
+     * @access public
+     */
+    public function __destruct() {
+        // Release inquiries
+        if ($this->queryID){
+            $this->free();
+        }
+        // Close the connection
+        $this->close();
+    }
+
+    // Close the database Defined by the driver class
+    public function close(){}
+}

+ 250 - 0
php-senthot/Senthot/Lib/Core/Dispatcher.class.php

@@ -0,0 +1,250 @@
+<?php
+// +--------------------------------------------------------------------------
+// | Senthot [ DEVELOPED BY ME ]
+// +--------------------------------------------------------------------------
+// | Copyright (c) 2005-2013 http://www.senthot.com All rights reserved.
+// | License ( http://www.apache.org/licenses/LICENSE-2.0 )
+// | Author: ms134n ( [email protected] )
+// +--------------------------------------------------------------------------
+
+/**
+ * Senthot built Dispatcher class
+ * Complete URL parsing , routing and scheduling
+ * @category	Sen
+ * @package		Sen
+ * @subpackage  Core
+ * @author		ms134n <[email protected]>
+ */
+class Dispatcher {
+
+    /**
+     * URL mapping to the controller
+     * @access public
+     * @return void
+     */
+    static public function dispatch() {
+        $urlMode  =  C('URL_MODEL');
+        if(!empty($_GET[C('VAR_PATHINFO')])) { // Determine whether there is compatibility mode inside the URL parameters
+            $_SERVER['PATH_INFO']   = $_GET[C('VAR_PATHINFO')];
+            unset($_GET[C('VAR_PATHINFO')]);
+        }
+        if($urlMode == URL_COMPAT ){
+            // Compatibility mode judgment
+            define('PHP_FILE',_PHP_FILE_.'?'.C('VAR_PATHINFO').'=');
+        }elseif($urlMode == URL_REWRITE ) {
+            //Current projects address
+            $url    =   dirname(_PHP_FILE_);
+            if($url == '/' || $url == '\\')
+                $url    =   '';
+            define('PHP_FILE',$url);
+        }else {
+            //Current projects address
+            define('PHP_FILE',_PHP_FILE_);
+        }
+
+        // On sub-domain deployment
+        if(C('APP_SUB_DOMAIN_DEPLOY')) {
+            $rules      = C('APP_SUB_DOMAIN_RULES');
+            $subDomain  = strtolower(substr($_SERVER['HTTP_HOST'],0,strpos($_SERVER['HTTP_HOST'],'.')));
+            define('SUB_DOMAIN',$subDomain); // Two domain defined
+            if($subDomain && isset($rules[$subDomain])) {
+                $rule =  $rules[$subDomain];
+            }elseif(isset($rules['*'])){ // Pan-domain name Support
+                if('www' != $subDomain && !in_array($subDomain,C('APP_SUB_DOMAIN_DENY'))) {
+                    $rule =  $rules['*'];
+                }
+            }
+            if(!empty($rule)) {
+                // Subdomain deployment rules 'Subdomain'=>array('Group name/[Module name]','var1=a&var2=b');
+                $array  =   explode('/',$rule[0]);
+                $module =   array_pop($array);
+                if(!empty($module)) {
+                    $_GET[C('VAR_MODULE')]  =   $module;
+                    $domainModule           =   true;
+                }
+                if(!empty($array)) {
+                    $_GET[C('VAR_GROUP')]   =   array_pop($array);
+                    $domainGroup            =   true;
+                }
+                if(isset($rule[1])) { // Incoming parameters
+                    parse_str($rule[1],$parms);
+                    $_GET   =  array_merge($_GET,$parms);
+                }
+            }
+        }
+        // Analysis PATHINFO information
+        if(empty($_SERVER['PATH_INFO'])) {
+            $types   =  explode(',',C('URL_PATHINFO_FETCH'));
+            foreach ($types as $type){
+                if(0===strpos($type,':')) {// Support function to determine
+                    $_SERVER['PATH_INFO'] =   call_user_func(substr($type,1));
+                    break;
+                }elseif(!empty($_SERVER[$type])) {
+                    $_SERVER['PATH_INFO'] = (0 === strpos($_SERVER[$type],$_SERVER['SCRIPT_NAME']))?
+                        substr($_SERVER[$type], strlen($_SERVER['SCRIPT_NAME']))   :  $_SERVER[$type];
+                    break;
+                }
+            }
+        }
+        $depr = C('URL_PATHINFO_DEPR');
+        if(!empty($_SERVER['PATH_INFO'])) {
+            tag('path_info');
+            $part =  pathinfo($_SERVER['PATH_INFO']);
+            define('__EXT__', isset($part['extension'])?strtolower($part['extension']):'');
+            if(C('URL_HTML_SUFFIX')) {
+                $_SERVER['PATH_INFO'] = preg_replace('/\.('.trim(C('URL_HTML_SUFFIX'),'.').')$/i', '', $_SERVER['PATH_INFO']);
+            }elseif(__EXT__) {
+                $_SERVER['PATH_INFO'] = preg_replace('/.'.__EXT__.'$/i','',$_SERVER['PATH_INFO']);
+            }
+            if(!self::routerCheck()){   // Detect routing rules If you do not press the default rule scheduling URL
+                $paths = explode($depr,trim($_SERVER['PATH_INFO'],'/'));
+                if(C('VAR_URL_PARAMS')) {
+                    // Directly through $_GET['_URL_'][1] $_GET['_URL_'][2] Get URL parameters Convenient access without routing parameters
+                    $_GET[C('VAR_URL_PARAMS')]   =  $paths;
+                }
+                $var  =  array();
+                if (C('APP_GROUP_LIST') && !isset($_GET[C('VAR_GROUP')])){
+                    $var[C('VAR_GROUP')] = in_array(strtolower($paths[0]),explode(',',strtolower(C('APP_GROUP_LIST'))))? array_shift($paths) : '';
+                    if(C('APP_GROUP_DENY') && in_array(strtolower($var[C('VAR_GROUP')]),explode(',',strtolower(C('APP_GROUP_DENY'))))) {
+                        // Prohibit direct access to packet
+                        exit;
+                    }
+                }
+                if(!isset($_GET[C('VAR_MODULE')])) {// Have not defined module name
+                    $var[C('VAR_MODULE')]  =   array_shift($paths);
+                }
+                $var[C('VAR_ACTION')]  =   array_shift($paths);
+                // Parsing URL parameters remaining
+                preg_replace('@(\w+)\/([^\/]+)@e', '$var[\'\\1\']=strip_tags(\'\\2\');', implode('/',$paths));
+                $_GET   =  array_merge($var,$_GET);
+            }
+            define('__INFO__',$_SERVER['PATH_INFO']);
+        }
+
+        // URL Constants
+        define('__SELF__',strip_tags($_SERVER['REQUEST_URI']));
+        // Current projects address
+        define('__APP__',strip_tags(PHP_FILE));
+
+        // Get Grouping Module and action names
+        if (C('APP_GROUP_LIST')) {
+            define('GROUP_NAME', self::getGroup(C('VAR_GROUP')));
+            // URL address of the packet
+            define('__GROUP__',(!empty($domainGroup) || strtolower(GROUP_NAME) == strtolower(C('DEFAULT_GROUP')) )?__APP__ : __APP__.'/'.GROUP_NAME);
+        }
+        
+        // Define the project based on the load path
+        define('BASE_LIB_PATH', (defined('GROUP_NAME') && C('APP_GROUP_MODE')==1) ? APP_PATH.C('APP_GROUP_PATH').'/'.GROUP_NAME.'/' : LIB_PATH);
+        if(defined('GROUP_NAME')) {
+            if(1 == C('APP_GROUP_MODE')){ // Independent Packet Mode
+                $config_path    =   BASE_LIB_PATH.'Conf/';
+                $common_path    =   BASE_LIB_PATH.'Common/';
+            }else{ // General Packet Mode
+                $config_path    =   CONF_PATH.GROUP_NAME.'/';
+                $common_path    =   COMMON_PATH.GROUP_NAME.'/';             
+            }
+            // Grouping configuration file to load
+            if(is_file($config_path.'config.php'))
+                C(include $config_path.'config.php');
+            // Loading grouping alias definitions
+            if(is_file($config_path.'alias.php'))
+                alias_import(include $config_path.'alias.php');            
+            // Grouping function to load the file
+            if(is_file($common_path.'function.php'))
+                include $common_path.'function.php';
+
+        }        
+        define('MODULE_NAME',self::getModule(C('VAR_MODULE')));
+        define('ACTION_NAME',self::getAction(C('VAR_ACTION')));
+        
+        // Current module and packet address
+        $moduleName    =   defined('MODULE_ALIAS')?MODULE_ALIAS:MODULE_NAME;
+        if(defined('GROUP_NAME')) {
+            define('__URL__',!empty($domainModule)?__GROUP__.$depr : __GROUP__.$depr.$moduleName);
+        }else{
+            define('__URL__',!empty($domainModule)?__APP__.'/' : __APP__.'/'.$moduleName);
+        }
+        // Address the current operation
+        define('__ACTION__',__URL__.$depr.(defined('ACTION_ALIAS')?ACTION_ALIAS:ACTION_NAME));
+        //Guarantee $_REQUEST Normal values
+        $_REQUEST = array_merge($_POST,$_GET);
+    }
+
+    /**
+     * Routing Detection
+     * @access public
+     * @return void
+     */
+    static public function routerCheck() {
+        $return   =  false;
+        // Routing detection tag
+        tag('route_check',$return);
+        return $return;
+    }
+
+    /**
+     * Get the actual name of the module
+     * @access private
+     * @return string
+     */
+    static private function getModule($var) {
+        $module = (!empty($_GET[$var])? $_GET[$var]:C('DEFAULT_MODULE'));
+        unset($_GET[$var]);
+        if($maps = C('URL_MODULE_MAP')) {
+            if(isset($maps[strtolower($module)])) {
+                // Record current alias
+                define('MODULE_ALIAS',strtolower($module));
+                // Get the actual name of the module
+                return   $maps[MODULE_ALIAS];
+            }elseif(array_search(strtolower($module),$maps)){
+                // Prohibit access to the original module
+                return   '';
+            }
+        }
+        if(C('URL_CASE_INSENSITIVE')) {
+            // URL address is not case sensitive
+            // Intelligent recognition method index.php/user_type/index/ Identified UserTypeAction Module
+            $module = ucfirst(parse_name($module,1));
+        }
+        return strip_tags($module);
+    }
+
+    /**
+     * Get the actual name of the operation
+     * @access private
+     * @return string
+     */
+    static private function getAction($var) {
+        $action   = !empty($_POST[$var]) ?
+            $_POST[$var] :
+            (!empty($_GET[$var])?$_GET[$var]:C('DEFAULT_ACTION'));
+        unset($_POST[$var],$_GET[$var]);
+        if($maps = C('URL_ACTION_MAP')) {
+            if(isset($maps[strtolower(MODULE_NAME)])) {
+                $maps =   $maps[strtolower(MODULE_NAME)];
+                if(isset($maps[strtolower($action)])) {
+                    // Record current alias
+                    define('ACTION_ALIAS',strtolower($action));
+                    // Get the actual name of the operation
+                    return   $maps[ACTION_ALIAS];
+                }elseif(array_search(strtolower($action),$maps)){
+                    // Prohibit access to the original operating
+                    return   '';
+                }
+            }
+        }        
+        return strip_tags(C('URL_CASE_INSENSITIVE')?strtolower($action):$action);
+    }
+
+    /**
+     * Get the actual group name
+     * @access private
+     * @return string
+     */
+    static private function getGroup($var) {
+        $group   = (!empty($_GET[$var])?$_GET[$var]:C('DEFAULT_GROUP'));
+        unset($_GET[$var]);
+        return strip_tags(C('URL_CASE_INSENSITIVE') ?ucfirst(strtolower($group)):$group);
+    }
+
+}

+ 113 - 0
php-senthot/Senthot/Lib/Core/Log.class.php

@@ -0,0 +1,113 @@
+<?php
+// +--------------------------------------------------------------------------
+// | Senthot [ DEVELOPED BY ME ]
+// +--------------------------------------------------------------------------
+// | Copyright (c) 2005-2013 http://www.senthot.com All rights reserved.
+// | License ( http://www.apache.org/licenses/LICENSE-2.0 )
+// | Author: ms134n ( [email protected] )
+// +--------------------------------------------------------------------------
+
+/**
+ * Log processing class
+ * @category	Sen
+ * @package		Sen
+ * @subpackage  Core
+ * @author		ms134n <[email protected]>
+ */
+class Log {
+
+    // Log Level From top to bottom, from low to high
+    const EMERG     = 'EMERG';  // Fatal Error: Crash the system can not be used
+    const ALERT     = 'ALERT';  // Cautionary error: Errors must be immediately modified
+    const CRIT      = 'CRIT';  // Threshold Error: Error exceeds the threshold , for example, 24 hours a day and 25 hours of this input
+    const ERR       = 'ERR';  // General Error: Generic error
+    const WARN      = 'WARN';  // Warning Error: Need to issue a warning error
+    const NOTICE    = 'NOTIC';  // Notification: Program can run but not perfect error
+    const INFO      = 'INFO';  // Information: Program output
+    const DEBUG     = 'DEBUG';  // Debugging: Debugging information
+    const SQL       = 'SQL';  // SQL: SQL Statement Note Only valid in debug mode is on
+
+    // Log mode
+    const SYSTEM    = 0;
+    const MAIL      = 1;
+    const FILE      = 3;
+    const SAPI      = 4;
+
+    // Log information
+    static $log     =  array();
+
+    // Date Format
+    static $format  =  '[ c ]';
+
+    /**
+     * Logging And will not set the level of filtering
+     * @static
+     * @access public
+     * @param string $message Log information
+     * @param string $level  Log Level
+     * @param boolean $record  Whether to force record
+     * @return void
+     */
+    static function record($message,$level=self::ERR,$record=false) {
+        if($record || false !== strpos(C('LOG_LEVEL'),$level)) {
+            self::$log[] =   "{$level}: {$message}\r\n";
+        }
+    }
+
+    /**
+     * Log Save
+     * @static
+     * @access public
+     * @param integer $type Log mode
+     * @param string $destination  Written to the target
+     * @param string $extra Additional parameters
+     * @return void
+     */
+    static function save($type='',$destination='',$extra='') {
+        if(empty(self::$log)) return ;
+        $type = $type?$type:C('LOG_TYPE');
+        if(self::FILE == $type) { // Papers logging information
+            if(empty($destination))
+                $destination = LOG_PATH.date('y_m_d').'.log';
+            //Test log file size exceeds the configured size of the backup log files to regenerate
+            if(is_file($destination) && floor(C('LOG_FILE_SIZE')) <= filesize($destination) )
+                  rename($destination,dirname($destination).'/'.time().'-'.basename($destination));
+        }else{
+            $destination   =   $destination?$destination:C('LOG_DEST');
+            $extra   =  $extra?$extra:C('LOG_EXTRA');
+        }
+        $now = date(self::$format);
+        error_log($now.' '.get_client_ip().' '.$_SERVER['REQUEST_URI']."\r\n".implode('',self::$log)."\r\n", $type,$destination ,$extra);
+        // After saving the log cache emptied
+        self::$log = array();
+        //clearstatcache();
+    }
+
+    /**
+     * Log directly into
+     * @static
+     * @access public
+     * @param string $message Log information
+     * @param string $level  Log Level
+     * @param integer $type Log mode
+     * @param string $destination  Written to the target
+     * @param string $extra Additional parameters
+     * @return void
+     */
+    static function write($message,$level=self::ERR,$type='',$destination='',$extra='') {
+        $now = date(self::$format);
+        $type = $type?$type:C('LOG_TYPE');
+        if(self::FILE == $type) { // Logging papers
+            if(empty($destination))
+                $destination = LOG_PATH.date('y_m_d').'.log';
+            //Test log file size exceeds the configured size of the backup log files to regenerate
+            if(is_file($destination) && floor(C('LOG_FILE_SIZE')) <= filesize($destination) )
+                  rename($destination,dirname($destination).'/'.time().'-'.basename($destination));
+        }else{
+            $destination   =   $destination?$destination:C('LOG_DEST');
+            $extra   =  $extra?$extra:C('LOG_EXTRA');
+        }
+        error_log("{$now} {$level}: {$message}\r\n", $type,$destination,$extra );
+        //clearstatcache();
+    }
+}

+ 1522 - 0
php-senthot/Senthot/Lib/Core/Model.class.php

@@ -0,0 +1,1522 @@
+<?php
+// +--------------------------------------------------------------------------
+// | Senthot [ DEVELOPED BY ME ]
+// +--------------------------------------------------------------------------
+// | Copyright (c) 2005-2013 http://www.senthot.com All rights reserved.
+// | License ( http://www.apache.org/licenses/LICENSE-2.0 )
+// | Author: ms134n ( [email protected] )
+// +--------------------------------------------------------------------------
+
+/**
+ * Senthot Model class that
+ * ORM and realized ActiveRecords mode
+ * @category	Sen
+ * @package		Sen
+ * @subpackage  Core
+ * @author		ms134n <[email protected]>
+ */
+class Model {
+    // Operation Status
+    const MODEL_INSERT          =   1;      //  Insert model data
+    const MODEL_UPDATE          =   2;      //  Updating model data
+    const MODEL_BOTH            =   3;      //  Contains the above two methods
+    const MUST_VALIDATE         =   1;// Must verify
+    const EXISTS_VALIDATE       =   0;// There is a form field validation
+    const VALUE_VALIDATE        =   2;// Not empty form value validation
+    // Addonsed model currently in use
+    private   $_extModel        =   null;
+    // Current object database operations
+    protected $db               =   null;
+    // Primary key name
+    protected $pk               =   'id';
+    // Table Prefix
+    protected $tablePrefix      =   '';
+    // Model Name
+    protected $name             =   '';
+    // Database Name
+    protected $dbName           =   '';
+    //Database configuration
+    protected $connection       =   '';
+    // Data table name ( does not contain a table prefix )
+    protected $tableName        =   '';
+    // Actual data table name ( including table prefix )
+    protected $trueTableName    =   '';
+    // Recent error message
+    protected $error            =   '';
+    // Field Information
+    protected $fields           =   array();
+    // Data information
+    protected $data             =   array();
+    // Query expression parameter
+    protected $options          =   array();
+    protected $_validate        =   array();  // Automatic verification Definition
+    protected $_auto            =   array();  // Auto-complete definitions
+    protected $_map             =   array();  // Field mapping definition
+    protected $_scope           =   array();  // Named range definition
+    // Whether to automatically detect the data table field information
+    protected $autoCheckFields  =   true;
+    // Whether batch verification
+    protected $patchValidate    =   false;
+    // Chain operation method list
+    protected $methods          =   array('table','order','alias','having','group','lock','distinct','auto','filter','validate');
+
+    /**
+     * Architecture function
+     * Obtain DB class instance object Field inspection
+     * @access public
+     * @param string $name Model Name
+     * @param string $tablePrefix Table Prefix
+     * @param mixed $connection Database connection information
+     */
+    public function __construct($name='',$tablePrefix='',$connection='') {
+        // Model initialization
+        $this->_initialize();
+        // Get the model name
+        if(!empty($name)) {
+            if(strpos($name,'.')) { // Support Database name. Model name Definition
+                list($this->dbName,$this->name) = explode('.',$name);
+            }else{
+                $this->name   =  $name;
+            }
+        }elseif(empty($this->name)){
+            $this->name =   $this->getModelName();
+        }
+        // Set Table Prefix
+        if(is_null($tablePrefix)) {// Null means no prefix prefix
+            $this->tablePrefix = '';
+        }elseif('' != $tablePrefix) {
+            $this->tablePrefix = $tablePrefix;
+        }else{
+            $this->tablePrefix = $this->tablePrefix?$this->tablePrefix:C('DB_PREFIX');
+        }
+
+        // Database initialization
+        // Gets an object database operations
+        // Current model has a separate database connection information
+        $this->db(0,empty($this->connection)?$connection:$this->connection);
+    }
+
+    /**
+     * Automatic detection of data table information
+     * @access protected
+     * @return void
+     */
+    protected function _checkTableInfo() {
+        // If not Model class Automatically record the data table information
+        // Only the first execution record
+        if(empty($this->fields)) {
+            // If the data table field is not defined is automatically acquired
+            if(C('DB_FIELDS_CACHE')) {
+                $db   =  $this->dbName?$this->dbName:C('DB_NAME');
+                $fields = F('_fields/'.strtolower($db.'.'.$this->name));
+                if($fields) {
+                    $version    =   C('DB_FIELD_VERISON');
+                    if(empty($version) || $fields['_version']== $version) {
+                        $this->fields   =   $fields;
+                        return ;
+                    }
+                }
+            }
+            // Read data every time table information
+            $this->flush();
+        }
+    }
+
+    /**
+     * Get field information and cache
+     * @access public
+     * @return void
+     */
+    public function flush() {
+        // Cache does not exist query data table information
+        $this->db->setModel($this->name);
+        $fields =   $this->db->getFields($this->getTableName());
+        if(!$fields) { // Unable to get field information
+            return false;
+        }
+        $this->fields   =   array_keys($fields);
+        $this->fields['_autoinc'] = false;
+        foreach ($fields as $key=>$val){
+            // Record Field Type
+            $type[$key]    =   $val['type'];
+            if($val['primary']) {
+                $this->fields['_pk'] = $key;
+                if($val['autoinc']) $this->fields['_autoinc']   =   true;
+            }
+        }
+        // Record field type information
+        $this->fields['_type'] =  $type;
+        if(C('DB_FIELD_VERISON')) $this->fields['_version'] =   C('DB_FIELD_VERISON');
+
+        // 2008-3-7 Increase the cache switch control
+        if(C('DB_FIELDS_CACHE')){
+            // Persistent cache data sheet information
+            $db   =  $this->dbName?$this->dbName:C('DB_NAME');
+            F('_fields/'.strtolower($db.'.'.$this->name),$this->fields);
+        }
+    }
+
+    /**
+     * Dynamic switching extended model
+     * @access public
+     * @param string $type Model type name
+     * @param mixed $vars To addons the model attribute variables passed
+     * @return Model
+     */
+    public function switchModel($type,$vars=array()) {
+        $class = ucwords(strtolower($type)).'Model';
+        if(!class_exists($class))
+            throw_exception($class.L('_MODEL_NOT_EXIST_'));
+        // Addonsed model instantiation
+        $this->_extModel   = new $class($this->name);
+        if(!empty($vars)) {
+            // Incoming current model to addons the model attributes
+            foreach ($vars as $var)
+                $this->_extModel->setProperty($var,$this->$var);
+        }
+        return $this->_extModel;
+    }
+
+    /**
+     * Set the value of the data object
+     * @access public
+     * @param string $name Name
+     * @param mixed $value Value
+     * @return void
+     */
+    public function __set($name,$value) {
+        // Setting Data object properties
+        $this->data[$name]  =   $value;
+    }
+
+    /**
+     * Gets the value of the data object
+     * @access public
+     * @param string $name Name
+     * @return mixed
+     */
+    public function __get($name) {
+        return isset($this->data[$name])?$this->data[$name]:null;
+    }
+
+    /**
+     * Detecting the value of the data object
+     * @access public
+     * @param string $name Name
+     * @return boolean
+     */
+    public function __isset($name) {
+        return isset($this->data[$name]);
+    }
+
+    /**
+     * Destroy the value of the data object
+     * @access public
+     * @param string $name Name
+     * @return void
+     */
+    public function __unset($name) {
+        unset($this->data[$name]);
+    }
+
+    /**
+     * Use __call method to achieve some special Model Method
+     * @access public
+     * @param string $method Method name
+     * @param array $args Call parameters
+     * @return mixed
+     */
+    public function __call($method,$args) {
+        if(in_array(strtolower($method),$this->methods,true)) {
+            // Coherent implementation of the operation
+            $this->options[strtolower($method)] =   $args[0];
+            return $this;
+        }elseif(in_array(strtolower($method),array('count','sum','min','max','avg'),true)){
+            // Achieve statistical inquiry
+            $field =  isset($args[0])?$args[0]:'*';
+            return $this->getField(strtoupper($method).'('.$field.') AS tp_'.$method);
+        }elseif(strtolower(substr($method,0,5))=='getby') {
+            // According to a field to obtain records
+            $field   =   parse_name(substr($method,5));
+            $where[$field] =  $args[0];
+            return $this->where($where)->find();
+        }elseif(strtolower(substr($method,0,10))=='getfieldby') {
+            // According to a field to a value obtained records
+            $name   =   parse_name(substr($method,10));
+            $where[$name] =$args[0];
+            return $this->where($where)->getField($args[1]);
+        }elseif(isset($this->_scope[$method])){// Individual named range called Support
+            return $this->scope($method,$args[0]);
+        }else{
+            throw_exception(__CLASS__.':'.$method.L('_METHOD_NOT_EXIST_'));
+            return;
+        }
+    }
+    // Callback method Initialize model
+    protected function _initialize() {}
+
+    /**
+     * The data saved to the database for processing
+     * @access protected
+     * @param mixed $data The data to be operated
+     * @return boolean
+     */
+     protected function _facade($data) {
+        // Check the non-data fields
+        if(!empty($this->fields)) {
+            foreach ($data as $key=>$val){
+                if(!in_array($key,$this->fields,true)){
+                    unset($data[$key]);
+                }elseif(is_scalar($val)) {
+                    // Field type checking
+                    $this->_parseType($data,$key);
+                }
+            }
+        }
+        // Security filtering
+        if(!empty($this->options['filter'])) {
+            $data = array_map($this->options['filter'],$data);
+            unset($this->options['filter']);
+        }
+        $this->_before_write($data);
+        return $data;
+     }
+
+    // Callback method before writing data Including new and updated
+    protected function _before_write(&$data) {}
+
+    /**
+     * Added Data
+     * @access public
+     * @param mixed $data Data
+     * @param array $options Expression
+     * @param boolean $replace Whether or replace
+     * @return mixed
+     */
+    public function add($data='',$options=array(),$replace=false) {
+        if(empty($data)) {
+            // No transmission of data , access to the current value of the data object
+            if(!empty($this->data)) {
+                $data           =   $this->data;
+                // Reset Data
+                $this->data     = array();
+            }else{
+                $this->error    = L('_DATA_TYPE_INVALID_');
+                return false;
+            }
+        }
+        // Analysis Expressions
+        $options    =   $this->_parseOptions($options);
+        // Data Processing
+        $data       =   $this->_facade($data);
+        if(false === $this->_before_insert($data,$options)) {
+            return false;
+        }
+        // Write data to the database
+        $result = $this->db->insert($data,$options,$replace);
+        if(false !== $result ) {
+            $insertId   =   $this->getLastInsID();
+            if($insertId) {
+                // Increment primary key to return to insert ID
+                $data[$this->getPk()]  = $insertId;
+                $this->_after_insert($data,$options);
+                return $insertId;
+            }
+            $this->_after_insert($data,$options);
+        }
+        return $result;
+    }
+    // Callback method before inserting data
+    protected function _before_insert(&$data,$options) {}
+    // Inserted after the success callback method
+    protected function _after_insert($data,$options) {}
+
+    public function addAll($dataList,$options=array(),$replace=false){
+        if(empty($dataList)) {
+            $this->error = L('_DATA_TYPE_INVALID_');
+            return false;
+        }
+        // Analysis Expressions
+        $options =  $this->_parseOptions($options);
+        // Data Processing
+        foreach ($dataList as $key=>$data){
+            $dataList[$key] = $this->_facade($data);
+        }
+        // Write data to the database
+        $result = $this->db->insertAll($dataList,$options,$replace);
+        if(false !== $result ) {
+            $insertId   =   $this->getLastInsID();
+            if($insertId) {
+                return $insertId;
+            }
+        }
+        return $result;
+    }
+
+    /**
+     * Added through Select records
+     * @access public
+     * @param string $fields To insert a data table field names
+     * @param string $table To insert the data table name
+     * @param array $options Expression
+     * @return boolean
+     */
+    public function selectAdd($fields='',$table='',$options=array()) {
+        // Analysis Expressions
+        $options =  $this->_parseOptions($options);
+        // Write data to the database
+        if(false === $result = $this->db->selectInsert($fields?$fields:$options['field'],$table?$table:$this->getTableName(),$options)){
+            // Database insert operation failed
+            $this->error = L('_OPERATION_WRONG_');
+            return false;
+        }else {
+            // Successful insertion
+            return $result;
+        }
+    }
+
+    /**
+     * Saving Data
+     * @access public
+     * @param mixed $data Data
+     * @param array $options Expression
+     * @return boolean
+     */
+    public function save($data='',$options=array()) {
+        if(empty($data)) {
+            // No transmission of data , access to the current value of the data object
+            if(!empty($this->data)) {
+                $data           =   $this->data;
+                // Reset Data
+                $this->data     =   array();
+            }else{
+                $this->error    =   L('_DATA_TYPE_INVALID_');
+                return false;
+            }
+        }
+        // Data Processing
+        $data       =   $this->_facade($data);
+        // Analysis Expressions
+        $options    =   $this->_parseOptions($options);
+        if(false === $this->_before_update($data,$options)) {
+            return false;
+        }
+        if(!isset($options['where']) ) {
+            // If there is a primary key data Is automatically updated as conditions
+            if(isset($data[$this->getPk()])) {
+                $pk                 =   $this->getPk();
+                $where[$pk]         =   $data[$pk];
+                $options['where']   =   $where;
+                $pkValue            =   $data[$pk];
+                unset($data[$pk]);
+            }else{
+                // If there are any updated conditions does
+                $this->error        =   L('_OPERATION_WRONG_');
+                return false;
+            }
+        }
+        $result     =   $this->db->update($data,$options);
+        if(false !== $result) {
+            if(isset($pkValue)) $data[$pk]   =  $pkValue;
+            $this->_after_update($data,$options);
+        }
+        return $result;
+    }
+    // The callback method before the data is updated
+    protected function _before_update(&$data,$options) {}
+    // After a successful update callback methods
+    protected function _after_update($data,$options) {}
+
+    /**
+     * Deleting data
+     * @access public
+     * @param mixed $options Expression
+     * @return mixed
+     */
+    public function delete($options=array()) {
+        if(empty($options) && empty($this->options['where'])) {
+            // If the deletion criteria is empty Delete object corresponding to the current data record
+            if(!empty($this->data) && isset($this->data[$this->getPk()]))
+                return $this->delete($this->data[$this->getPk()]);
+            else
+                return false;
+        }
+        if(is_numeric($options)  || is_string($options)) {
+            // Based on primary keys deleting records
+            $pk   =  $this->getPk();
+            if(strpos($options,',')) {
+                $where[$pk]     =  array('IN', $options);
+            }else{
+                $where[$pk]     =  $options;
+            }
+            $pkValue            =  $where[$pk];
+            $options            =  array();
+            $options['where']   =  $where;
+        }
+        // Analysis Expressions
+        $options =  $this->_parseOptions($options);
+        $result=    $this->db->delete($options);
+        if(false !== $result) {
+            $data = array();
+            if(isset($pkValue)) $data[$pk]   =  $pkValue;
+            $this->_after_delete($data,$options);
+        }
+        // Returns the deleted records number
+        return $result;
+    }
+    // Deleted after a successful callback methods
+    protected function _after_delete($data,$options) {}
+
+    /**
+     * Querying datasets
+     * @access public
+     * @param array $options Expression arguments
+     * @return mixed
+     */
+    public function select($options=array()) {
+        if(is_string($options) || is_numeric($options)) {
+            // According to the primary key query
+            $pk   =  $this->getPk();
+            if(strpos($options,',')) {
+                $where[$pk]     =  array('IN',$options);
+            }else{
+                $where[$pk]     =  $options;
+            }
+            $options            =  array();
+            $options['where']   =  $where;
+        }elseif(false === $options){ // For subqueries Not only returns SQL
+            $options            =  array();
+            // Analysis Expressions
+            $options            =  $this->_parseOptions($options);
+            return  '( '.$this->db->buildSelectSql($options).' )';
+        }
+        // Analysis Expressions
+        $options    =  $this->_parseOptions($options);
+        $resultSet  = $this->db->select($options);
+        if(false === $resultSet) {
+            return false;
+        }
+        if(empty($resultSet)) { // Query result is empty
+            return null;
+        }
+        $this->_after_select($resultSet,$options);
+        return $resultSet;
+    }
+    // After a successful query callback methods
+    protected function _after_select(&$resultSet,$options) {}
+
+    /**
+     * Generate SQL queries Can be used in a subquery
+     * @access public
+     * @param array $options Expression arguments
+     * @return string
+     */
+    public function buildSql($options=array()) {
+        // Analysis Expressions
+        $options =  $this->_parseOptions($options);
+        return  '( '.$this->db->buildSelectSql($options).' )';
+    }
+
+    /**
+     * Analysis Expressions
+     * @access proteced
+     * @param array $options Expression arguments
+     * @return array
+     */
+    protected function _parseOptions($options=array()) {
+        if(is_array($options))
+            $options =  array_merge($this->options,$options);
+        // Query after emptying the SQL expression to assemble Avoid the next query
+        $this->options  =   array();
+        if(!isset($options['table'])){
+            // Automatically get the table name
+            $options['table']   =   $this->getTableName();
+            $fields             =   $this->fields;
+        }else{
+            // Specifies the data sheet then reacquire the field list but not Support type detection
+            $fields             =   $this->getDbFields();
+        }
+
+        if(!empty($options['alias'])) {
+            $options['table']  .=   ' '.$options['alias'];
+        }
+        // Recording operation Model Name
+        $options['model']       =   $this->name;
+
+        // Field type validation
+        if(isset($options['where']) && is_array($options['where']) && !empty($fields)) {
+            // Query the array for the field type checking
+            foreach ($options['where'] as $key=>$val){
+                $key            =   trim($key);
+                if(in_array($key,$fields,true)){
+                    if(is_scalar($val)) {
+                        $this->_parseType($options['where'],$key);
+                    }
+                }elseif('_' != substr($key,0,1) && false === strpos($key,'.') && false === strpos($key,'|') && false === strpos($key,'&')){
+                    unset($options['where'][$key]);
+                }
+            }
+        }
+
+        // Expression Filter
+        $this->_options_filter($options);
+        return $options;
+    }
+    // Expression Filter callback method
+    protected function _options_filter(&$options) {}
+
+    /**
+     * Data type detection
+     * @access protected
+     * @param mixed $data Data
+     * @param string $key Field name
+     * @return void
+     */
+    protected function _parseType(&$data,$key) {
+        $fieldType = strtolower($this->fields['_type'][$key]);
+        if(false === strpos($fieldType,'bigint') && false !== strpos($fieldType,'int')) {
+            $data[$key]   =  intval($data[$key]);
+        }elseif(false !== strpos($fieldType,'float') || false !== strpos($fieldType,'double')){
+            $data[$key]   =  floatval($data[$key]);
+        }elseif(false !== strpos($fieldType,'bool')){
+            $data[$key]   =  (bool)$data[$key];
+        }
+    }
+
+    /**
+     * Query data
+     * @access public
+     * @param mixed $options Expression arguments
+     * @return mixed
+     */
+    public function find($options=array()) {
+        if(is_numeric($options) || is_string($options)) {
+            $where[$this->getPk()]  =   $options;
+            $options                =   array();
+            $options['where']       =   $where;
+        }
+        // Always find a record
+        $options['limit']   =   1;
+        // Analysis Expressions
+        $options            =   $this->_parseOptions($options);
+        $resultSet          =   $this->db->select($options);
+        if(false === $resultSet) {
+            return false;
+        }
+        if(empty($resultSet)) {// Query result is empty
+            return null;
+        }
+        $this->data         =   $resultSet[0];
+        $this->_after_find($this->data,$options);
+        return $this->data;
+    }
+    // Query success callback method
+    protected function _after_find(&$result,$options) {}
+
+    /**
+     * Processing field mapping
+     * @access public
+     * @param array $data Current Data
+     * @param integer $type Type 0 Write 1 Read
+     * @return array
+     */
+    public function parseFieldsMap($data,$type=1) {
+        // Check the field mapping
+        if(!empty($this->_map)) {
+            foreach ($this->_map as $key=>$val){
+                if($type==1) { // Read
+                    if(isset($data[$val])) {
+                        $data[$key] =   $data[$val];
+                        unset($data[$val]);
+                    }
+                }else{
+                    if(isset($data[$key])) {
+                        $data[$val] =   $data[$key];
+                        unset($data[$key]);
+                    }
+                }
+            }
+        }
+        return $data;
+    }
+
+    /**
+     * Set the value of a field record
+     * Support using the database fields and methods
+     * @access public
+     * @param string|array $field  Field name
+     * @param string $value  Field values
+     * @return boolean
+     */
+    public function setField($field,$value='') {
+        if(is_array($field)) {
+            $data           =   $field;
+        }else{
+            $data[$field]   =   $value;
+        }
+        return $this->save($data);
+    }
+
+    /**
+     * Field Value Growth
+     * @access public
+     * @param string $field  Field name
+     * @param integer $step  Growth in value
+     * @return boolean
+     */
+    public function setInc($field,$step=1) {
+        return $this->setField($field,array('exp',$field.'+'.$step));
+    }
+
+    /**
+     * Field value Decrease
+     * @access public
+     * @param string $field  Field name
+     * @param integer $step  Decrease the value
+     * @return boolean
+     */
+    public function setDec($field,$step=1) {
+        return $this->setField($field,array('exp',$field.'-'.$step));
+    }
+
+    /**
+     * Gets the value of a field in a record
+     * @access public
+     * @param string $field  Field name
+     * @param string $spea  Field data symbol interval NULL returned array
+     * @return mixed
+     */
+    public function getField($field,$sepa=null) {
+        $options['field']       =   $field;
+        $options                =   $this->_parseOptions($options);
+        $field                  =   trim($field);
+        if(strpos($field,',')) { // Multi-Field
+            if(!isset($options['limit'])){
+                $options['limit']   =   is_numeric($sepa)?$sepa:'';
+            }
+            $resultSet          =   $this->db->select($options);
+            if(!empty($resultSet)) {
+                $_field         =   explode(',', $field);
+                $field          =   array_keys($resultSet[0]);
+                $key            =   array_shift($field);
+                $key2           =   array_shift($field);
+                $cols           =   array();
+                $count          =   count($_field);
+                foreach ($resultSet as $result){
+                    $name   =  $result[$key];
+                    if(2==$count) {
+                        $cols[$name]   =  $result[$key2];
+                    }else{
+                        $cols[$name]   =  is_string($sepa)?implode($sepa,$result):$result;
+                    }
+                }
+                return $cols;
+            }
+        }else{   // Find a record
+            // Return the number of data
+            if(true !== $sepa) {// While sepa is specified as true, returns all of the data
+                $options['limit']   =   is_numeric($sepa)?$sepa:1;
+            }
+            $result = $this->db->select($options);
+            if(!empty($result)) {
+                if(true !== $sepa && 1==$options['limit']) return reset($result[0]);
+                foreach ($result as $val){
+                    $array[]    =   $val[$field];
+                }
+                return $array;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Create a data object But is not saved to the database
+     * @access public
+     * @param mixed $data Create a data
+     * @param string $type State
+     * @return mixed
+     */
+     public function create($data='',$type='') {
+        // If there are no values default to get POST data
+        if(empty($data)) {
+            $data   =   $_POST;
+        }elseif(is_object($data)){
+            $data   =   get_object_vars($data);
+        }
+        // Validating data
+        if(empty($data) || !is_array($data)) {
+            $this->error = L('_DATA_TYPE_INVALID_');
+            return false;
+        }
+
+        // Check the field mapping
+        $data = $this->parseFieldsMap($data,0);
+
+        // State
+        $type = $type?$type:(!empty($data[$this->getPk()])?self::MODEL_UPDATE:self::MODEL_INSERT);
+
+        // Detection of legitimacy of the submitted field
+        if(isset($this->options['field'])) { // $this->field('field1,field2...')->create()
+            $fields =   $this->options['field'];
+            unset($this->options['field']);
+        }elseif($type == self::MODEL_INSERT && isset($this->insertFields)) {
+            $fields =   $this->insertFields;
+        }elseif($type == self::MODEL_UPDATE && isset($this->updateFields)) {
+            $fields =   $this->updateFields;
+        }
+        if(isset($fields)) {
+            if(is_string($fields)) {
+                $fields =   explode(',',$fields);
+            }
+            // Judge token validation fields
+            if(C('TOKEN_ON'))   $fields[] = C('TOKEN_NAME');
+            foreach ($data as $key=>$val){
+                if(!in_array($key,$fields)) {
+                    unset($data[$key]);
+                }
+            }
+        }
+
+        // Automatic data validation
+        if(!$this->autoValidation($data,$type)) return false;
+
+        // Form token validation
+        if(C('TOKEN_ON') && !$this->autoCheckToken($data)) {
+            $this->error = L('_TOKEN_ERROR_');
+            return false;
+        }
+
+        // Validation complete generated data objects
+        if($this->autoCheckFields) { // Open field test You filter the illegal field data
+            $fields =   $this->getDbFields();
+            foreach ($data as $key=>$val){
+                if(!in_array($key,$fields)) {
+                    unset($data[$key]);
+                }elseif(MAGIC_QUOTES_GPC && is_string($val)){
+                    $data[$key] =   stripslashes($val);
+                }
+            }
+        }
+
+        // Create complete automated treatment of the data
+        $this->autoOperation($data,$type);
+        // The current data object assignment
+        $this->data =   $data;
+        // Return the data created for other calls
+        return $data;
+     }
+
+    // Automatic form validation token
+    // TODO  ajax no refresh multiple submissions temporarily unable to meet
+    public function autoCheckToken($data) {
+        if(C('TOKEN_ON')){
+            $name   = C('TOKEN_NAME');
+            if(!isset($data[$name]) || !isset($_SESSION[$name])) { // Invalid token data
+                return false;
+            }
+
+            // Token Authentication
+            list($key,$value)  =  explode('_',$data[$name]);
+            if($value && $_SESSION[$name][$key] === $value) { // Prevent duplicate submission
+                unset($_SESSION[$name][$key]); // Verification is complete destroys the session
+                return true;
+            }
+            // Open TOKEN reset
+            if(C('TOKEN_RESET')) unset($_SESSION[$name][$key]);
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Validate data using regular
+     * @access public
+     * @param string $value  To verify the data
+     * @param string $rule Validation rules
+     * @return boolean
+     */
+    public function regex($value,$rule) {
+        $validate = array(
+            'require'   =>  '/.+/',
+            'email'     =>  '/^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/',
+            'url'       =>  '/^http(s?):\/\/(?:[A-za-z0-9-]+\.)+[A-za-z]{2,4}(?:[\/\?#][\/=\?%\-&~`@[\]\':+!\.#\w]*)?$/',
+            'currency'  =>  '/^\d+(\.\d+)?$/',
+            'number'    =>  '/^\d+$/',
+            'zip'       =>  '/^\d{6}$/',
+            'integer'   =>  '/^[-\+]?\d+$/',
+            'double'    =>  '/^[-\+]?\d+(\.\d+)?$/',
+            'english'   =>  '/^[A-Za-z]+$/',
+        );
+        // Check whether there is a built-in regular expression
+        if(isset($validate[strtolower($rule)]))
+            $rule       =   $validate[strtolower($rule)];
+        return preg_match($rule,$value)===1;
+    }
+
+    /**
+     * Automatic Form Processing
+     * @access public
+     * @param array $data Create a data
+     * @param string $type Create type
+     * @return mixed
+     */
+    private function autoOperation(&$data,$type) {
+        if(!empty($this->options['auto'])) {
+            $_auto   =   $this->options['auto'];
+            unset($this->options['auto']);
+        }elseif(!empty($this->_auto)){
+            $_auto   =   $this->_auto;
+        }
+        // Autofill
+        if(isset($_auto)) {
+            foreach ($_auto as $auto){
+                // Fill Factor Definition Format
+                // array('field','Fill Content','Fill Conditions','Additional rules',[Additional parameters])
+                if(empty($auto[2])) $auto[2] = self::MODEL_INSERT; // The default is automatically populated when new
+                if( $type == $auto[2] || $auto[2] == self::MODEL_BOTH) {
+                    switch(trim($auto[3])) {
+                        case 'function':    //  Use function to fill Value of the field as a parameter
+                        case 'callback': // Using callback method
+                            $args = isset($auto[4])?(array)$auto[4]:array();
+                            if(isset($data[$auto[0]])) {
+                                array_unshift($args,$data[$auto[0]]);
+                            }
+                            if('function'==$auto[3]) {
+                                $data[$auto[0]]  = call_user_func_array($auto[1], $args);
+                            }else{
+                                $data[$auto[0]]  =  call_user_func_array(array(&$this,$auto[1]), $args);
+                            }
+                            break;
+                        case 'field':    // The value used to fill other fields
+                            $data[$auto[0]] = $data[$auto[1]];
+                            break;
+                        case 'ignore': // Ignore empty
+                            if(''===$data[$auto[0]])
+                                unset($data[$auto[0]]);
+                            break;
+                        case 'string':
+                        default: // The default padding as a string
+                            $data[$auto[0]] = $auto[1];
+                    }
+                    if(false === $data[$auto[0]] )   unset($data[$auto[0]]);
+                }
+            }
+        }
+        return $data;
+    }
+
+    /**
+     * Automatic form validation
+     * @access protected
+     * @param array $data Create a data
+     * @param string $type Create type
+     * @return boolean
+     */
+    protected function autoValidation($data,$type) {
+        if(!empty($this->options['validate'])) {
+            $_validate   =   $this->options['validate'];
+            unset($this->options['validate']);
+        }elseif(!empty($this->_validate)){
+            $_validate   =   $this->_validate;
+        }
+        // Property Validation
+        if(isset($_validate)) { // If you set up automatic data validation data validation is carried out
+            if($this->patchValidate) { // Reset validation error message
+                $this->error = array();
+            }
+            foreach($_validate as $key=>$val) {
+                // Verify factor Definition Format
+                // array(field,rule,message,condition,type,when,params)
+                // Determine whether validation is performed
+                if(empty($val[5]) || $val[5]== self::MODEL_BOTH || $val[5]== $type ) {
+                    if(0==strpos($val[2],'{%') && strpos($val[2],'}'))
+                        // Support multi-language message Use {%Language definition} Mode
+                        $val[2]  =  L(substr($val[2],2,-1));
+                    $val[3]  =  isset($val[3])?$val[3]:self::EXISTS_VALIDATE;
+                    $val[4]  =  isset($val[4])?$val[4]:'regex';
+                    // Determine the validation criteria
+                    switch($val[3]) {
+                        case self::MUST_VALIDATE:   // Must verify Regardless of whether the form has set this field
+                            if(false === $this->_validationField($data,$val))
+                                return false;
+                            break;
+                        case self::VALUE_VALIDATE:    // Value is not empty when it is verified
+                            if('' != trim($data[$val[0]]))
+                                if(false === $this->_validationField($data,$val))
+                                    return false;
+                            break;
+                        default:    // Default form field validation
+                            if(isset($data[$val[0]]))
+                                if(false === $this->_validationField($data,$val))
+                                    return false;
+                    }
+                }
+            }
+            // Batch validation when the last error
+            if(!empty($this->error)) return false;
+        }
+        return true;
+    }
+
+    /**
+     * Validate form fields Support batch validation
+     * If the batch validation returns an array of error information
+     * @access protected
+     * @param array $data Create a data
+     * @param array $val Authentication factors
+     * @return boolean
+     */
+    protected function _validationField($data,$val) {
+        if(false === $this->_validationFieldItem($data,$val)){
+            if($this->patchValidate) {
+                $this->error[$val[0]]   =   $val[2];
+            }else{
+                $this->error            =   $val[2];
+                return false;
+            }
+        }
+        return ;
+    }
+
+    /**
+     * Based on validation factor authentication field
+     * @access protected
+     * @param array $data Create a data
+     * @param array $val Authentication factors
+     * @return boolean
+     */
+    protected function _validationFieldItem($data,$val) {
+        switch(strtolower(trim($val[4]))) {
+            case 'function':// Validation using function
+            case 'callback':// Calling methods of verification
+                $args = isset($val[6])?(array)$val[6]:array();
+                if(is_string($val[0]) && strpos($val[0], ','))
+                    $val[0] = explode(',', $val[0]);
+                if(is_array($val[0])){
+                    // Support multiple-field validation
+                    foreach($val[0] as $field)
+                        $_data[$field] = $data[$field];
+                    array_unshift($args, $_data);
+                }else{
+                    array_unshift($args, $data[$val[0]]);
+                }
+                if('function'==$val[4]) {
+                    return call_user_func_array($val[1], $args);
+                }else{
+                    return call_user_func_array(array(&$this, $val[1]), $args);
+                }
+            case 'confirm': // Verify that the two fields is the same
+                return $data[$val[0]] == $data[$val[1]];
+            case 'unique': // To verify that a value is unique
+                if(is_string($val[0]) && strpos($val[0],','))
+                    $val[0]  =  explode(',',$val[0]);
+                $map = array();
+                if(is_array($val[0])) {
+                    // Support multiple-field validation
+                    foreach ($val[0] as $field)
+                        $map[$field]   =  $data[$field];
+                }else{
+                    $map[$val[0]] = $data[$val[0]];
+                }
+                if(!empty($data[$this->getPk()])) { // Sound editing when validation only
+                    $map[$this->getPk()] = array('neq',$data[$this->getPk()]);
+                }
+                if($this->where($map)->find())   return false;
+                return true;
+            default:  // Check additional rule
+                return $this->check($data[$val[0]],$val[1],$val[4]);
+        }
+    }
+
+    /**
+     * Validating data Support in between equal length regex expire ip_allow ip_deny
+     * @access public
+     * @param string $value Validating data
+     * @param mixed $rule Validation expression
+     * @param string $type Authentication methods supported Defaults to verify
+     * @return boolean
+     */
+    public function check($value,$rule,$type='regex'){
+        $type   =   strtolower(trim($type));
+        switch($type) {
+            case 'in': // Verifies that a specified range A comma-delimited string or array
+            case 'notin':
+                $range   = is_array($rule)? $rule : explode(',',$rule);
+                return $type == 'in' ? in_array($value ,$range) : !in_array($value ,$range);
+            case 'between': // Verify a range
+            case 'notbetween': // Verify that is not in a range
+                if (is_array($rule)){
+                    $min    =    $rule[0];
+                    $max    =    $rule[1];
+                }else{
+                    list($min,$max)   =  explode(',',$rule);
+                }
+                return $type == 'between' ? $value>=$min && $value<=$max : $value<$min || $value>$max;
+            case 'equal': // Verify that equal to a value
+            case 'notequal': // Verify that equal to a value
+                return $type == 'equal' ? $value == $rule : $value != $rule;
+            case 'length': // Verify the length
+                $length  =  mb_strlen($value,'utf-8'); // Current data length
+                if(strpos($rule,',')) { // Length range
+                    list($min,$max)   =  explode(',',$rule);
+                    return $length >= $min && $length <= $max;
+                }else{// Specified length
+                    return $length == $rule;
+                }
+            case 'expire':
+                list($start,$end)   =  explode(',',$rule);
+                if(!is_numeric($start)) $start   =  strtotime($start);
+                if(!is_numeric($end)) $end   =  strtotime($end);
+                return NOW_TIME >= $start && NOW_TIME <= $end;
+            case 'ip_allow': // IP Operating license verified
+                return in_array(get_client_ip(),explode(',',$rule));
+            case 'ip_deny': // IP Action to suppress validation
+                return !in_array(get_client_ip(),explode(',',$rule));
+            case 'regex':
+            default:    // Default use regular verification You can use validation class defined in the Authentication Name
+                // Check additional rule
+                return $this->regex($value,$rule);
+        }
+    }
+
+    /**
+     * SQL Query
+     * @access public
+     * @param string $sql  SQL commands
+     * @param mixed $parse  The need for parsing the SQL
+     * @return mixed
+     */
+    public function query($sql,$parse=false) {
+        if(!is_bool($parse) && !is_array($parse)) {
+            $parse = func_get_args();
+            array_shift($parse);
+        }
+        $sql  =   $this->parseSql($sql,$parse);
+        return $this->db->query($sql);
+    }
+
+    /**
+     * Executing SQL statements
+     * @access public
+     * @param string $sql  SQL commands
+     * @param mixed $parse  The need for parsing the SQL
+     * @return false | integer
+     */
+    public function execute($sql,$parse=false) {
+        if(!is_bool($parse) && !is_array($parse)) {
+            $parse = func_get_args();
+            array_shift($parse);
+        }
+        $sql  =   $this->parseSql($sql,$parse);
+        return $this->db->execute($sql);
+    }
+
+    /**
+     * Parsing the SQL statement
+     * @access public
+     * @param string $sql  SQL commands
+     * @param boolean $parse  The need for parsing the SQL
+     * @return string
+     */
+    protected function parseSql($sql,$parse) {
+        // Analysis Expressions
+        if(true === $parse) {
+            $options =  $this->_parseOptions();
+            $sql  =   $this->db->parseSql($sql,$options);
+        }elseif(is_array($parse)){ // SQL preprocessing
+            $sql  = vsprintf($sql,$parse);
+        }else{
+            $sql    =   strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX')));
+        }
+        $this->db->setModel($this->name);
+        return $sql;
+    }
+
+    /**
+     * Switch the current database connection
+     * @access public
+     * @param integer $linkNum  Serial Connection
+     * @param mixed $config  Database connection information
+     * @param array $params  Model parameters
+     * @return Model
+     */
+    public function db($linkNum='',$config='',$params=array()){
+        if(''===$linkNum && $this->db) {
+            return $this->db;
+        }
+        static $_linkNum    =   array();
+        static $_db = array();
+        if(!isset($_db[$linkNum]) || (isset($_db[$linkNum]) && $config && $_linkNum[$linkNum]!=$config) ) {
+            // Create a new instance
+            if(!empty($config) && is_string($config) && false === strpos($config,'/')) { // Support read configuration parameters
+                $config  =  C($config);
+            }
+            $_db[$linkNum]            =    Db::getInstance($config);
+        }elseif(NULL === $config){
+            $_db[$linkNum]->close(); // Close the database connection
+            unset($_db[$linkNum]);
+            return ;
+        }
+        if(!empty($params)) {
+            if(is_string($params))    parse_str($params,$params);
+            foreach ($params as $name=>$value){
+                $this->setProperty($name,$value);
+            }
+        }
+        // Record Connection Information
+        $_linkNum[$linkNum] =   $config;
+        // Switching the database connection
+        $this->db   =    $_db[$linkNum];
+        $this->_after_db();
+        // Field testing
+        if(!empty($this->name) && $this->autoCheckFields)    $this->_checkTableInfo();
+        return $this;
+    }
+    // Database callback method after switching
+    protected function _after_db() {}
+
+    /**
+     * Get current data object name
+     * @access public
+     * @return string
+     */
+    public function getModelName() {
+        if(empty($this->name))
+            $this->name =   substr(get_class($this),0,-5);
+        return $this->name;
+    }
+
+    /**
+     * Get complete data table name
+     * @access public
+     * @return string
+     */
+    public function getTableName() {
+        if(empty($this->trueTableName)) {
+            $tableName  = !empty($this->tablePrefix) ? $this->tablePrefix : '';
+            if(!empty($this->tableName)) {
+                $tableName .= $this->tableName;
+            }else{
+                $tableName .= ($this->name);
+            }
+            $this->trueTableName    =   ($tableName);
+        }
+        return (!empty($this->dbName)?$this->dbName.'.':'').$this->trueTableName;
+    }
+
+    /**
+     * Start transaction
+     * @access public
+     * @return void
+     */
+    public function startTrans() {
+        $this->commit();
+        $this->db->startTrans();
+        return ;
+    }
+
+    /**
+     * Commit the transaction
+     * @access public
+     * @return boolean
+     */
+    public function commit() {
+        return $this->db->commit();
+    }
+
+    /**
+     * Transaction rollback
+     * @access public
+     * @return boolean
+     */
+    public function rollback() {
+        return $this->db->rollback();
+    }
+
+    /**
+     * Returns an error message model
+     * @access public
+     * @return string
+     */
+    public function getError(){
+        return $this->error;
+    }
+
+    /**
+     * Returns the database error message
+     * @access public
+     * @return string
+     */
+    public function getDbError() {
+        return $this->db->getError();
+    }
+
+    /**
+     * Returns the last inserted ID
+     * @access public
+     * @return string
+     */
+    public function getLastInsID() {
+        return $this->db->getLastInsID();
+    }
+
+    /**
+     * Returns the last executed sql statement
+     * @access public
+     * @return string
+     */
+    public function getLastSql() {
+        return $this->db->getLastSql($this->name);
+    }
+    // Given getLastSql more common Increase _sql Aliases
+    public function _sql(){
+        return $this->getLastSql();
+    }
+
+    /**
+     * Get the name of the primary key
+     * @access public
+     * @return string
+     */
+    public function getPk() {
+        return isset($this->fields['_pk'])?$this->fields['_pk']:$this->pk;
+    }
+
+    /**
+     * Field information for a data sheet
+     * @access public
+     * @return array
+     */
+    public function getDbFields(){
+        if(isset($this->options['table'])) {// Dynamically specify the table name
+            $fields     =   $this->db->getFields($this->options['table']);
+            return  $fields?array_keys($fields):false;
+        }
+        if($this->fields) {
+            $fields     =  $this->fields;
+            unset($fields['_autoinc'],$fields['_pk'],$fields['_type'],$fields['_version']);
+            return $fields;
+        }
+        return false;
+    }
+
+    /**
+     * Set the value of the data object
+     * @access public
+     * @param mixed $data Data
+     * @return Model
+     */
+    public function data($data=''){
+        if('' === $data && !empty($this->data)) {
+            return $this->data;
+        }
+        if(is_object($data)){
+            $data   =   get_object_vars($data);
+        }elseif(is_string($data)){
+            parse_str($data,$data);
+        }elseif(!is_array($data)){
+            throw_exception(L('_DATA_TYPE_INVALID_'));
+        }
+        $this->data = $data;
+        return $this;
+    }
+
+    /**
+     * Querying SQL assembly join
+     * @access public
+     * @param mixed $join
+     * @return Model
+     */
+    public function join($join) {
+        if(is_array($join)) {
+            $this->options['join']      =   $join;
+        }elseif(!empty($join)) {
+            $this->options['join'][]    =   $join;
+        }
+        return $this;
+    }
+
+    /**
+     * Querying SQL assembly union
+     * @access public
+     * @param mixed $union
+     * @param boolean $all
+     * @return Model
+     */
+    public function union($union,$all=false) {
+        if(empty($union)) return $this;
+        if($all) {
+            $this->options['union']['_all']  =   true;
+        }
+        if(is_object($union)) {
+            $union   =  get_object_vars($union);
+        }
+        // Conversion union expression
+        if(is_string($union) ) {
+            $options =  $union;
+        }elseif(is_array($union)){
+            if(isset($union[0])) {
+                $this->options['union']  =  array_merge($this->options['union'],$union);
+                return $this;
+            }else{
+                $options =  $union;
+            }
+        }else{
+            throw_exception(L('_DATA_TYPE_INVALID_'));
+        }
+        $this->options['union'][]  =   $options;
+        return $this;
+    }
+
+    /**
+     * Query Cache
+     * @access public
+     * @param mixed $key
+     * @param integer $expire
+     * @param string $type
+     * @return Model
+     */
+    public function cache($key=true,$expire=null,$type=''){
+        if(false !== $key)
+            $this->options['cache']  =  array('key'=>$key,'expire'=>$expire,'type'=>$type);
+        return $this;
+    }
+
+    /**
+     * Specifies the query field Support field exclusion
+     * @access public
+     * @param mixed $field
+     * @param boolean $except Whether the exclusion
+     * @return Model
+     */
+    public function field($field,$except=false){
+        if(true === $field) {// Get all the fields
+            $fields     =  $this->getDbFields();
+            $field      =  $fields?$fields:'*';
+        }elseif($except) {// Fields excluded
+            if(is_string($field)) {
+                $field  =  explode(',',$field);
+            }
+            $fields     =  $this->getDbFields();
+            $field      =  $fields?array_diff($fields,$field):$field;
+        }
+        $this->options['field']   =   $field;
+        return $this;
+    }
+
+    /**
+     * Calling a named range
+     * @access public
+     * @param mixed $scope Named Range Name Support multiple and direct definition
+     * @param array $args Parameter
+     * @return Model
+     */
+    public function scope($scope='',$args=NULL){
+        if('' === $scope) {
+            if(isset($this->_scope['default'])) {
+                // Default naming scope
+                $options    =   $this->_scope['default'];
+            }else{
+                return $this;
+            }
+        }elseif(is_string($scope)){ // Support multiple named ranges called separated by commas
+            $scopes         =   explode(',',$scope);
+            $options        =   array();
+            foreach ($scopes as $name){
+                if(!isset($this->_scope[$name])) continue;
+                $options    =   array_merge($options,$this->_scope[$name]);
+            }
+            if(!empty($args) && is_array($args)) {
+                $options    =   array_merge($options,$args);
+            }
+        }elseif(is_array($scope)){ // Directly into a named range defined
+            $options        =   $scope;
+        }
+
+        if(is_array($options) && !empty($options)){
+            $this->options  =   array_merge($this->options,array_change_key_case($options));
+        }
+        return $this;
+    }
+
+    /**
+     * Specify the query criteria Support security filtering
+     * @access public
+     * @param mixed $where Conditional Expressions
+     * @param mixed $parse Pretreatment parameters
+     * @return Model
+     */
+    public function where($where,$parse=null){
+        if(!is_null($parse) && is_string($where)) {
+            if(!is_array($parse)) {
+                $parse = func_get_args();
+                array_shift($parse);
+            }
+            $parse = array_map(array($this->db,'escapeString'),$parse);
+            $where =   vsprintf($where,$parse);
+        }elseif(is_object($where)){
+            $where  =   get_object_vars($where);
+        }
+        if(is_string($where) && '' != $where){
+            $map    =   array();
+            $map['_string']   =   $where;
+            $where  =   $map;
+        }
+        if(isset($this->options['where'])){
+            $this->options['where'] =   array_merge($this->options['where'],$where);
+        }else{
+            $this->options['where'] =   $where;
+        }
+
+        return $this;
+    }
+
+    /**
+     * Specifies the number of queries
+     * @access public
+     * @param mixed $offset Starting position
+     * @param mixed $length Number of queries
+     * @return Model
+     */
+    public function limit($offset,$length=null){
+        $this->options['limit'] =   is_null($length)?$offset:$offset.','.$length;
+        return $this;
+    }
+
+    /**
+     * Specifies the paging
+     * @access public
+     * @param mixed $page Pages
+     * @param mixed $listRows Number per page
+     * @return Model
+     */
+    public function page($page,$listRows=null){
+        $this->options['page'] =   is_null($listRows)?$page:$page.','.$listRows;
+        return $this;
+    }
+
+    /**
+     * Query Comments
+     * @access public
+     * @param string $comment Note
+     * @return Model
+     */
+    public function comment($comment){
+        $this->options['comment'] =   $comment;
+        return $this;
+    }
+
+    /**
+     * Set model attribute values
+     * @access public
+     * @param string $name Name
+     * @param mixed $value Value
+     * @return Model
+     */
+    public function setProperty($name,$value) {
+        if(property_exists($this,$name))
+            $this->$name = $value;
+        return $this;
+    }
+
+}

+ 292 - 0
php-senthot/Senthot/Lib/Core/Sen.class.php

@@ -0,0 +1,292 @@
+<?php
+// +--------------------------------------------------------------------------
+// | Senthot [ DEVELOPED BY ME ]
+// +--------------------------------------------------------------------------
+// | Copyright (c) 2005-2013 http://www.senthot.com All rights reserved.
+// | License ( http://www.apache.org/licenses/LICENSE-2.0 )
+// | Author: ms134n ( [email protected] )
+// +--------------------------------------------------------------------------
+
+/**
+ * Senthot Portal category
+ * @category	Sen
+ * @package		Sen
+ * @subpackage  Core
+ * @author		ms134n <[email protected]>
+ */
+class Sen {
+
+    private static $_instance = array();
+
+    /**
+     * Application initialization
+     * @access public
+     * @return void
+     */
+    static public function start() {
+        // Setting error and exception handling
+        register_shutdown_function(array('Sen','fatalError'));
+        set_error_handler(array('Sen','appError'));
+        set_exception_handler(array('Sen','appException'));
+        // Registered AUTOLOAD method
+        spl_autoload_register(array('Sen', 'autoload'));
+        //[RUNTIME]
+        Sen::buildApp();         // Precompiled project
+        //[/RUNTIME]
+        // Run the application
+        App::run();
+        return ;
+    }
+
+    //[RUNTIME]
+    /**
+     * Read configuration information Compile the project
+     * @access private
+     * @return string
+     */
+    static private function buildApp() {
+        
+        // Read operating mode
+        if(defined('MODE_NAME')) { // Read mode setting
+            $mode   = include MODE_PATH.strtolower(MODE_NAME).'.php';
+        }else{
+            $mode   =  array();
+        }
+        // Core Conventions configuration file to load
+        C(include SEN_PATH.'Conf/convention.php');
+        if(isset($mode['config'])) {// Load mode profile
+            C( is_array($mode['config'])?$mode['config']:include $mode['config'] );
+        }
+
+        // Load project configuration file
+        if(is_file(CONF_PATH.'config.php'))
+            C(include CONF_PATH.'config.php');
+
+        // Loading framework underlying language pack
+        L(include SEN_PATH.'Lang/'.strtolower(C('DEFAULT_LANG')).'.php');
+
+        // Load model system behavior definition
+        if(C('APP_TAGS_ON')) {
+            if(isset($mode['extends'])) {
+                C('extends',is_array($mode['extends'])?$mode['extends']:include $mode['extends']);
+            }else{ // Addonsed definition of default load behavior of the system
+                C('extends', include SEN_PATH.'Conf/tags.php');
+            }
+        }
+
+        // Load application behavior definition
+        if(isset($mode['tags'])) {
+            C('tags', is_array($mode['tags'])?$mode['tags']:include $mode['tags']);
+        }elseif(is_file(CONF_PATH.'tags.php')){
+            // Default load the project file defines the configuration directory tags
+            C('tags', include CONF_PATH.'tags.php');
+        }
+
+        $compile   = '';
+        // Core reading list compiled file
+        if(isset($mode['core'])) {
+            $list  =  $mode['core'];
+        }else{
+            $list  =  array(
+                SEN_PATH.'Common/functions.php', // Standard mode function library
+                CORE_PATH.'Core/Log.class.php',    // Log processing class
+                CORE_PATH.'Core/Dispatcher.class.php', // URL scheduling class
+                CORE_PATH.'Core/App.class.php',   // Application class
+                CORE_PATH.'Core/Action.class.php', // Controller class
+                CORE_PATH.'Core/View.class.php',  // View class
+            );
+        }
+        // Compile a list of additional core project documents
+        if(is_file(CONF_PATH.'core.php')) {
+            $list  =  array_merge($list,include CONF_PATH.'core.php');
+        }
+        foreach ($list as $file){
+            if(is_file($file))  {
+                require_cache($file);
+                if(!APP_DEBUG)   $compile .= compile($file);
+            }
+        }
+
+        // Load the project public documents
+        if(is_file(COMMON_PATH.'common.php')) {
+            include COMMON_PATH.'common.php';
+            // Compiled file
+            if(!APP_DEBUG)  $compile   .= compile(COMMON_PATH.'common.php');
+        }
+
+        // Loading mode alias definitions
+        if(isset($mode['alias'])) {
+            $alias = is_array($mode['alias'])?$mode['alias']:include $mode['alias'];
+            alias_import($alias);
+            if(!APP_DEBUG) $compile .= 'alias_import('.var_export($alias,true).');';               
+        }
+     
+        // Loading a project alias definitions
+        if(is_file(CONF_PATH.'alias.php')){ 
+            $alias = include CONF_PATH.'alias.php';
+            alias_import($alias);
+            if(!APP_DEBUG) $compile .= 'alias_import('.var_export($alias,true).');';
+        }
+
+        if(APP_DEBUG) {
+            // Debug mode to load the system default configuration file
+            C(include SEN_PATH.'Conf/debug.php');
+            // Read the debug mode application status
+            $status  =  C('APP_STATUS');
+            // Project configuration file to load the corresponding
+            if(is_file(CONF_PATH.$status.'.php'))
+                // Allow the project to increase the development mode configuration definition
+                C(include CONF_PATH.$status.'.php');
+        }else{
+            // Deployment model generates compiled files below
+            build_runtime_cache($compile);
+        }
+        return ;
+    }
+    //[/RUNTIME]
+
+    /**
+     * The system automatically loads the library Senthot
+     * And Support configure automatic loading path
+     * @param string $class Object class name
+     * @return void
+     */
+    public static function autoload($class) {
+        // Check for alias definitions
+        if(alias_import($class)) return ;
+        $libPath    =   defined('BASE_LIB_PATH')?BASE_LIB_PATH:LIB_PATH;
+        $group      =   defined('GROUP_NAME') && C('APP_GROUP_MODE')==0 ?GROUP_NAME.'/':'';
+        $file       =   $class.'.class.php';
+        if(substr($class,-8)=='Behavior') { // Load Behavior
+            if(require_array(array(
+                CORE_PATH.'Behavior/'.$file,
+                ADDONS_PATH.'Behavior/'.$file,
+                LIB_PATH.'Behavior/'.$file,
+                $libPath.'Behavior/'.$file),true)
+                || (defined('MODE_NAME') && require_cache(MODE_PATH.ucwords(MODE_NAME).'/Behavior/'.$file))) {
+                return ;
+            }
+        }elseif(substr($class,-5)=='Model'){ // Load Model
+            if(require_array(array(
+                LIB_PATH.'Model/'.$group.$file,
+                $libPath.'Model/'.$file,
+                ADDONS_PATH.'Model/'.$file),true)) {
+                return ;
+            }
+        }elseif(substr($class,-6)=='Action'){ // Load Controller
+            if(require_array(array(
+                LIB_PATH.'Action/'.$group.$file,
+                $libPath.'Action/'.$file,
+                ADDONS_PATH.'Action/'.$file),true)) {
+                return ;
+            }
+        }elseif(substr($class,0,5)=='Cache'){ // Load cache drive
+            if(require_array(array(
+                ADDONS_PATH.'Driver/Cache/'.$file,
+                CORE_PATH.'Driver/Cache/'.$file),true)){
+                return ;
+            }
+        }elseif(substr($class,0,2)=='Db'){ // Load database driver
+            if(require_array(array(
+                ADDONS_PATH.'Driver/Db/'.$file,
+                CORE_PATH.'Driver/Db/'.$file),true)){
+                return ;
+            }
+        }elseif(substr($class,0,8)=='Template'){ // Loading template engine driven
+            if(require_array(array(
+                ADDONS_PATH.'Driver/Template/'.$file,
+                CORE_PATH.'Driver/Template/'.$file),true)){
+                return ;
+            }
+        }elseif(substr($class,0,6)=='TagLib'){ // Load tag library drive
+            if(require_array(array(
+                ADDONS_PATH.'Driver/TagLib/'.$file,
+                CORE_PATH.'Driver/TagLib/'.$file),true)) {
+                return ;
+            }
+        }
+
+        // According to the settings automatically load path try to search
+        $paths  =   explode(',',C('APP_AUTOLOAD_PATH'));
+        foreach ($paths as $path){
+            if(import($path.'.'.$class))
+                // If you load the class success, returns
+                return ;
+        }
+    }
+
+    /**
+     * Get object instance Support call the class static method
+     * @param string $class Object class name
+     * @param string $method Static class method name
+     * @return object
+     */
+    static public function instance($class,$method='') {
+        $identify   =   $class.$method;
+        if(!isset(self::$_instance[$identify])) {
+            if(class_exists($class)){
+                $o = new $class();
+                if(!empty($method) && method_exists($o,$method))
+                    self::$_instance[$identify] = call_user_func_array(array(&$o, $method));
+                else
+                    self::$_instance[$identify] = $o;
+            }
+            else
+                halt(L('_CLASS_NOT_EXIST_').':'.$class);
+        }
+        return self::$_instance[$identify];
+    }
+
+    /**
+     * Custom Exception Handling
+     * @access public
+     * @param mixed $e Exception object
+     */
+    static public function appException($e) {
+        halt($e->__toString());
+    }
+
+    /**
+     * Custom Error Handling
+     * @access public
+     * @param int $errno Error Type
+     * @param string $errstr Error Messages
+     * @param string $errfile Error File
+     * @param int $errline Error Rows
+     * @return void
+     */
+    static public function appError($errno, $errstr, $errfile, $errline) {
+      switch ($errno) {
+          case E_ERROR:
+          case E_PARSE:
+          case E_CORE_ERROR:
+          case E_COMPILE_ERROR:
+          case E_USER_ERROR:
+            ob_end_clean();
+            // Page Compression Output Support
+            if(C('OUTPUT_ENCODE')){
+                $zlib = ini_get('zlib.output_compression');
+                if(empty($zlib)) ob_start('ob_gzhandler');
+            }
+            $errorStr = "$errstr ".$errfile." subsection $errline line.";
+            if(C('LOG_RECORD')) Log::write("[$errno] ".$errorStr,Log::ERR);
+            function_exists('halt')?halt($errorStr):exit('ERROR:'.$errorStr);
+            break;
+          case E_STRICT:
+          case E_USER_WARNING:
+          case E_USER_NOTICE:
+          default:
+            $errorStr = "[$errno] $errstr ".$errfile." subsection $errline line.";
+            trace($errorStr,'','NOTIC');
+            break;
+      }
+    }
+    
+    // Fatal error trapping
+    static public function fatalError() {
+        if ($e = error_get_last()) {
+            Sen::appError($e['type'],$e['message'],$e['file'],$e['line']);
+        }
+    }
+
+}

+ 85 - 0
php-senthot/Senthot/Lib/Core/SenException.class.php

@@ -0,0 +1,85 @@
+<?php
+// +--------------------------------------------------------------------------
+// | Senthot [ DEVELOPED BY ME ]
+// +--------------------------------------------------------------------------
+// | Copyright (c) 2005-2013 http://www.senthot.com All rights reserved.
+// | License ( http://www.apache.org/licenses/LICENSE-2.0 )
+// | Author: ms134n ( [email protected] )
+// +--------------------------------------------------------------------------
+
+/**
+ * Senthot system exception base class
+ * @category	Sen
+ * @package		Sen
+ * @subpackage  Core
+ * @author		ms134n <[email protected]>
+ */
+class SenException extends Exception {
+
+    /**
+     * Exception Types
+     * @var string
+     * @access private
+     */
+    private $type;
+
+    // The existence of extra debugging information
+    private $extra;
+
+    /**
+     * Architecture function
+     * @access public
+     * @param string $message  Exception information
+     */
+    public function __construct($message,$code=0,$extra=false) {
+        parent::__construct($message,$code);
+        $this->type = get_class($this);
+        $this->extra = $extra;
+    }
+
+    /**
+     * Abnormal output All classes have passed __toString exception handling method output error
+     * Each exception are written to the system log
+     * This method can be overridden by child classes
+     * @access public
+     * @return array
+     */
+    public function __toString() {
+        $trace = $this->getTrace();
+        if($this->extra)
+            // By throw_exception thrown to remove excess debug information
+            array_shift($trace);
+        $this->class    =   isset($trace[0]['class'])?$trace[0]['class']:'';
+        $this->function =   isset($trace[0]['function'])?$trace[0]['function']:'';
+        $this->file     =   $trace[0]['file'];
+        $this->line     =   $trace[0]['line'];
+        $file           =   file($this->file);
+        $traceInfo      =   '';
+        $time = date('y-m-d H:i:m');
+        foreach($trace as $t) {
+            $traceInfo .= '['.$time.'] '.$t['file'].' ('.$t['line'].') ';
+            $traceInfo .= $t['class'].$t['type'].$t['function'].'(';
+            $traceInfo .= implode(', ', $t['args']);
+            $traceInfo .=")\n";
+        }
+        $error['message']   = $this->message;
+        $error['type']      = $this->type;
+        $error['detail']    = L('_MODULE_').'['.MODULE_NAME.'] '.L('_ACTION_').'['.ACTION_NAME.']'."\n";
+        $error['detail']   .=   ($this->line-2).': '.$file[$this->line-3];
+        $error['detail']   .=   ($this->line-1).': '.$file[$this->line-2];
+        $error['detail']   .=   '<font color="#FF6600" >'.($this->line).': <strong>'.$file[$this->line-1].'</strong></font>';
+        $error['detail']   .=   ($this->line+1).': '.$file[$this->line];
+        $error['detail']   .=   ($this->line+2).': '.$file[$this->line+1];
+        $error['class']     =   $this->class;
+        $error['function']  =   $this->function;
+        $error['file']      = $this->file;
+        $error['line']      = $this->line;
+        $error['trace']     = $traceInfo;
+
+        // Record Exception Journal
+        if(C('LOG_EXCEPTION_RECORD')) {
+            Log::Write('('.$this->type.') '.$this->message);
+        }
+        return $error ;
+    }
+}

+ 128 - 0
php-senthot/Senthot/Lib/Core/View.class.php

@@ -0,0 +1,128 @@
+<?php
+// +--------------------------------------------------------------------------
+// | Senthot [ DEVELOPED BY ME ]
+// +--------------------------------------------------------------------------
+// | Copyright (c) 2005-2013 http://www.senthot.com All rights reserved.
+// | License ( http://www.apache.org/licenses/LICENSE-2.0 )
+// | Author: ms134n ( [email protected] )
+// +--------------------------------------------------------------------------
+
+/**
+ * Senthot View class
+ * @category	Sen
+ * @package		Sen
+ * @subpackage  Core
+ * @author		ms134n <[email protected]>
+ */
+class View {
+    /**
+     * Template output variables
+     * @var tVar
+     * @access protected
+     */       
+    protected $tVar        =  array();
+
+    /**
+     * Template variable assignment
+     * @access public
+     * @param mixed $name
+     * @param mixed $value
+     */
+    public function assign($name,$value=''){
+        if(is_array($name)) {
+            $this->tVar   =  array_merge($this->tVar,$name);
+        }else {
+            $this->tVar[$name] = $value;
+        }
+    }
+
+    /**
+     * Template variable value obtained
+     * @access public
+     * @param string $name
+     * @return mixed
+     */
+    public function get($name=''){
+        if('' === $name) {
+            return $this->tVar;
+        }
+        return isset($this->tVar[$name])?$this->tVar[$name]:false;
+    }
+
+    /**
+     * Loaded templates and page output Can return output
+     * @access public
+     * @param string $templateFile Template file name
+     * @param string $charset Template output character set
+     * @param string $contentType Output Type
+     * @param string $content Template output
+     * @param string $prefix Template cache prefix
+     * @return mixed
+     */
+    public function display($templateFile='',$charset='',$contentType='',$content='',$prefix='') {
+        G('viewStartTime');
+        // View of the start tag
+        tag('view_begin',$templateFile);
+        // Parse and get the template content
+        $content = $this->fetch($templateFile,$content,$prefix);
+        // Output template content
+        $this->render($content,$charset,$contentType);
+        // View closing tag
+        tag('view_end');
+    }
+
+    /**
+     * Html output text can include
+     * @access private
+     * @param string $content Output
+     * @param string $charset Template output character set
+     * @param string $contentType Output Type
+     * @return mixed
+     */
+    private function render($content,$charset='',$contentType=''){
+        if(empty($charset))  $charset = C('DEFAULT_CHARSET');
+        if(empty($contentType)) $contentType = C('TMPL_CONTENT_TYPE');
+        // Web Character Encoding
+        header('Content-Type:'.$contentType.'; charset='.$charset);
+        header('Cache-control: '.C('HTTP_CACHE_CONTROL'));  // Page cache control
+        header('X-Powered-By:Senthot');
+        // Output template file
+        echo $content;
+    }
+
+    /**
+     * Parse and access template content For outputs
+     * @access public
+     * @param string $templateFile Template file name
+     * @param string $content Template output
+     * @param string $prefix Template cache prefix
+     * @return string
+     */
+    public function fetch($templateFile='',$content='',$prefix='') {
+        if(empty($content)) {
+            // Template file parsing tags
+            tag('view_template',$templateFile);
+            // Template file does not exist return directly
+            if(!is_file($templateFile)) return NULL;
+        }
+        // Page cache
+        ob_start();
+        ob_implicit_flush(0);
+        if('php' == strtolower(C('TMPL_ENGINE_TYPE'))) { // Using native PHP template
+            // Template array variable decomposed into independent variable
+            extract($this->tVar, EXTR_OVERWRITE);
+            // PHP template loaded directly
+            empty($content)?include $templateFile:eval('?>'.$content);
+        }else{
+            // View Resolution tab
+            $params = array('var'=>$this->tVar,'file'=>$templateFile,'content'=>$content,'prefix'=>$prefix);
+            tag('view_parse',$params);
+        }
+        // Obtain and empty the cache
+        $content = ob_get_clean();
+        // Content Filtering tab
+        tag('view_filter',$content);
+        // Output template file
+        return $content;
+    }
+}

+ 105 - 0
php-senthot/Senthot/Lib/Core/Widget.class.php

@@ -0,0 +1,105 @@
+<?php
+// +--------------------------------------------------------------------------
+// | Senthot [ DEVELOPED BY ME ]
+// +--------------------------------------------------------------------------
+// | Copyright (c) 2005-2013 http://www.senthot.com All rights reserved.
+// | License ( http://www.apache.org/licenses/LICENSE-2.0 )
+// | Author: ms134n ( [email protected] )
+// +--------------------------------------------------------------------------
+
+/**
+ * Senthot Widget class Abstract class
+ * @category	Sen
+ * @package		Sen
+ * @subpackage  Core
+ * @author		ms134n <[email protected]>
+ */
+abstract class Widget {
+
+    // Use template engine Each Widget can be individually configured without affecting the system
+    protected $template =  '';
+
+    /**
+     * Render Output render method is unique interface Widget
+     * Use string to return Can not have any output
+     * @access public
+     * @param mixed $data  The data to be rendered
+     * @return string
+     */
+    abstract public function render($data);
+
+    /**
+     * Render the template output For the render method is called internally
+     * @access public
+     * @param string $templateFile  Template File
+     * @param mixed $var  Template Variables
+     * @return string
+     */
+    protected function renderFile($templateFile='',$var='') {
+        ob_start();
+        ob_implicit_flush(0);
+        if(!file_exists_case($templateFile)){
+            // Automatic positioning template file
+            $name   = substr(get_class($this),0,-6);
+            $filename   =  empty($templateFile)?$name:$templateFile;
+            $templateFile = BASE_LIB_PATH.'Widget/'.$name.'/'.$filename.C('TMPL_TEMPLATE_SUFFIX');
+            if(!file_exists_case($templateFile))
+                throw_exception(L('_TEMPLATE_NOT_EXIST_').'['.$templateFile.']');
+        }
+        $template   =  strtolower($this->template?$this->template:(C('TMPL_ENGINE_TYPE')?C('TMPL_ENGINE_TYPE'):'php'));
+        if('php' == $template) {
+            // Using PHP template
+            if(!empty($var)) extract($var, EXTR_OVERWRITE);
+            // PHP template loaded directly
+            include $templateFile;
+        }elseif('sen'==$template){ // Template engine using Sen
+            if($this->checkCache($templateFile)) { // Cache is valid
+                // Decomposition and load the template cache variables
+                extract($var, EXTR_OVERWRITE);
+                //Load template cache files
+                include C('CACHE_PATH').md5($templateFile).C('TMPL_CACHFILE_SUFFIX');
+            }else{
+                $tpl = Sen::instance('SenTemplate');
+                // Compile and load the template file
+                $tpl->fetch($templateFile,$var);
+            }
+        }else{
+            $class   = 'Template'.ucwords($template);
+            if(is_file(CORE_PATH.'Driver/Template/'.$class.'.class.php')) {
+                // Internal Drive
+                $path = CORE_PATH;
+            }else{ // Expansion Drive
+                $path = ADDONS_PATH;
+            }
+            require_cache($path.'Driver/Template/'.$class.'.class.php');
+            $tpl   =  new $class;
+            $tpl->fetch($templateFile,$var);
+        }
+        $content = ob_get_clean();
+        return $content;
+    }
+
+    /**
+     * Check the cache file is valid
+     * If this does not need to be recompiled
+     * @access public
+     * @param string $tmplTemplateFile  Template file name
+     * @return boolen
+     */
+    protected function checkCache($tmplTemplateFile) {
+        if (!C('TMPL_CACHE_ON')) // Preferentially detect configuration settings
+            return false;
+        $tmplCacheFile = C('CACHE_PATH').md5($tmplTemplateFile).C('TMPL_CACHFILE_SUFFIX');
+        if(!is_file($tmplCacheFile)){
+            return false;
+        }elseif (filemtime($tmplTemplateFile) > filemtime($tmplCacheFile)) {
+            // Template files if you need to update the cache updates
+            return false;
+        }elseif (C('TMPL_CACHE_TIME') != 0 && time() > filemtime($tmplCacheFile)+C('TMPL_CACHE_TIME')) {
+            // Caching is within the validity
+            return false;
+        }
+        // Cache is valid
+        return true;
+    }
+}

+ 185 - 0
php-senthot/Senthot/Lib/Driver/Cache/CacheFile.class.php

@@ -0,0 +1,185 @@
+<?php
+// +--------------------------------------------------------------------------
+// | Senthot [ DEVELOPED BY ME ]
+// +--------------------------------------------------------------------------
+// | Copyright (c) 2005-2013 http://www.senthot.com All rights reserved.
+// | License ( http://www.apache.org/licenses/LICENSE-2.0 )
+// | Author: ms134n ( [email protected] )
+// +--------------------------------------------------------------------------
+
+defined('SEN_PATH') or exit();
+/**
+ * File type of cache class
+ * @category	Sen
+ * @package		Sen
+ * @subpackage  Driver.Cache
+ * @author		ms134n <[email protected]>
+ */
+class CacheFile extends Cache {
+
+    /**
+     * Architecture function
+     * @access public
+     */
+    public function __construct($options=array()) {
+        if(!empty($options)) {
+            $this->options =  $options;
+        }
+        $this->options['temp']      =   !empty($options['temp'])?   $options['temp']    :   C('DATA_CACHE_PATH');
+        $this->options['prefix']    =   isset($options['prefix'])?  $options['prefix']  :   C('DATA_CACHE_PREFIX');
+        $this->options['expire']    =   isset($options['expire'])?  $options['expire']  :   C('DATA_CACHE_TIME');
+        $this->options['length']    =   isset($options['length'])?  $options['length']  :   0;
+        if(substr($this->options['temp'], -1) != '/')    $this->options['temp'] .= '/';
+        $this->init();
+    }
+
+    /**
+     * Initialization check
+     * @access private
+     * @return boolen
+     */
+    private function init() {
+        $stat = stat($this->options['temp']);
+        $dir_perms = $stat['mode'] & 0007777; // Get the permission bits.
+        $file_perms = $dir_perms & 0000666; // Remove execute bits for files.
+
+        // Create a project cache directory
+        if (!is_dir($this->options['temp'])) {
+            if (!  mkdir($this->options['temp']))
+                return false;
+             chmod($this->options['temp'], $dir_perms);
+        }
+    }
+
+    /**
+     * Retrieve variables to store the file name
+     * @access private
+     * @param string $name Cache variable name
+     * @return string
+     */
+    private function filename($name) {
+        $name	=	md5($name);
+        if(C('DATA_CACHE_SUBDIR')) {
+            // Using subdirectories
+            $dir   ='';
+            for($i=0;$i<C('DATA_PATH_LEVEL');$i++) {
+                $dir	.=	$name{$i}.'/';
+            }
+            if(!is_dir($this->options['temp'].$dir)) {
+                mkdir($this->options['temp'].$dir,0755,true);
+            }
+            $filename	=	$dir.$this->options['prefix'].$name.'.php';
+        }else{
+            $filename	=	$this->options['prefix'].$name.'.php';
+        }
+        return $this->options['temp'].$filename;
+    }
+
+    /**
+     * Read caching
+     * @access public
+     * @param string $name Cache variable name
+     * @return mixed
+     */
+    public function get($name) {
+        $filename   =   $this->filename($name);
+        if (!is_file($filename)) {
+           return false;
+        }
+        N('cache_read',1);
+        $content    =   file_get_contents($filename);
+        if( false !== $content) {
+            $expire  =  (int)substr($content,8, 12);
+            if($expire != 0 && time() > filemtime($filename) + $expire) {
+                //Delete the cache file cache expires
+                unlink($filename);
+                return false;
+            }
+            if(C('DATA_CACHE_CHECK')) {//Open data validation
+                $check  =  substr($content,20, 32);
+                $content   =  substr($content,52, -3);
+                if($check != md5($content)) {//Parity error
+                    return false;
+                }
+            }else {
+            	$content   =  substr($content,20, -3);
+            }
+            if(C('DATA_CACHE_COMPRESS') && function_exists('gzcompress')) {
+                //Enable data compression
+                $content   =   gzuncompress($content);
+            }
+            $content    =   unserialize($content);
+            return $content;
+        }
+        else {
+            return false;
+        }
+    }
+
+    /**
+     * Write caching
+     * @access public
+     * @param string $name Cache variable name
+     * @param mixed $value  Stored data
+     * @param int $expire  Valid time 0 for permanent
+     * @return boolen
+     */
+    public function set($name,$value,$expire=null) {
+        N('cache_write',1);
+        if(is_null($expire)) {
+            $expire =  $this->options['expire'];
+        }
+        $filename   =   $this->filename($name);
+        $data   =   serialize($value);
+        if( C('DATA_CACHE_COMPRESS') && function_exists('gzcompress')) {
+            //Data compression
+            $data   =   gzcompress($data,3);
+        }
+        if(C('DATA_CACHE_CHECK')) {//Open data validation
+            $check  =  md5($data);
+        }else {
+            $check  =  '';
+        }
+        $data    = "<?php\n//".sprintf('%012d',$expire).$check.$data."\n?>";
+        $result  =   file_put_contents($filename,$data);
+        if($result) {
+            if($this->options['length']>0) {
+                // Record cache queue
+                $this->queue($name);
+            }
+            clearstatcache();
+            return true;
+        }else {
+            return false;
+        }
+    }
+
+    /**
+     * Deleting the cache
+     * @access public
+     * @param string $name Cache variable name
+     * @return boolen
+     */
+    public function rm($name) {
+        return unlink($this->filename($name));
+    }
+
+    /**
+     * Clearing the cache
+     * @access public
+     * @param string $name Cache variable name
+     * @return boolen
+     */
+    public function clear() {
+        $path   =  $this->options['temp'];
+        if ( $dir = opendir( $path ) ) {
+            while ( $file = readdir( $dir ) ) {
+                $check = is_dir( $file );
+                if ( !$check )
+                    unlink( $path . $file );
+            }
+            closedir( $dir );
+            return true;
+        }
+    }
+}

+ 347 - 0
php-senthot/Senthot/Lib/Driver/Db/DbMysql.class.php

@@ -0,0 +1,347 @@
+<?php
+// +--------------------------------------------------------------------------
+// | Senthot [ DEVELOPED BY ME ]
+// +--------------------------------------------------------------------------
+// | Copyright (c) 2005-2013 http://www.senthot.com All rights reserved.
+// | License ( http://www.apache.org/licenses/LICENSE-2.0 )
+// | Author: ms134n ( [email protected] )
+// +--------------------------------------------------------------------------
+
+defined('SEN_PATH') or exit();
+
+/**
+ * Mysql database driver class
+ * @category	Sen
+ * @package		Sen
+ * @subpackage  Driver.Db
+ * @author		ms134n <[email protected]>
+ */
+class DbMysql extends Db{
+
+    /**
+     * Architecture function Read the database configuration information
+     * @access public
+     * @param array $config Database configuration array
+     */
+    public function __construct($config=''){
+        if ( !extension_loaded('mysql') ) {
+            throw_exception(L('_NOT_SUPPERT_').':mysql');
+        }
+        if(!empty($config)) {
+            $this->config   =   $config;
+            if(empty($this->config['params'])) {
+                $this->config['params'] =   '';
+            }
+        }
+    }
+
+    /**
+     * Connection database method
+     * @access public
+     * @throws SenExecption
+     */
+    public function connect($config='',$linkNum=0,$force=false) {
+        if ( !isset($this->linkID[$linkNum]) ) {
+            if(empty($config))  $config =   $this->config;
+            // Deal with the port number of the socket connection
+            $host = $config['hostname'].($config['hostport']?":{$config['hostport']}":'');
+            // Whether long connection
+            $pconnect   = !empty($config['params']['persist'])? $config['params']['persist']:$this->pconnect;
+            if($pconnect) {
+                $this->linkID[$linkNum] = mysql_pconnect( $host, $config['username'], $config['password'],131072);
+            }else{
+                $this->linkID[$linkNum] = mysql_connect( $host, $config['username'], $config['password'],true,131072);
+            }
+            if ( !$this->linkID[$linkNum] || (!empty($config['database']) && !mysql_select_db($config['database'], $this->linkID[$linkNum])) ) {
+                throw_exception(mysql_error());
+            }
+            $dbVersion = mysql_get_server_info($this->linkID[$linkNum]);
+            //Access database using UTF8
+            mysql_query("SET NAMES '".C('DB_CHARSET')."'", $this->linkID[$linkNum]);
+            //Setup sql_model
+            if($dbVersion >'5.0.1'){
+                mysql_query("SET sql_mode=''",$this->linkID[$linkNum]);
+            }
+            // Mark connection successful
+            $this->connected    =   true;
+            // Unregister database connection configuration information
+            if(1 != C('DB_DEPLOY_TYPE')) unset($this->config);
+        }
+        return $this->linkID[$linkNum];
+    }
+
+    /**
+     * Query results released
+     * @access public
+     */
+    public function free() {
+        mysql_free_result($this->queryID);
+        $this->queryID = null;
+    }
+
+    /**
+     * Execute the query Returns a DataSet
+     * @access public
+     * @param string $str  SQL commands
+     * @return mixed
+     */
+    public function query($str) {
+        if(0===stripos($str, 'call')){ // Stored procedure query Support
+            $this->close();
+        }
+        $this->initConnect(false);
+        if ( !$this->_linkID ) return false;
+        $this->queryStr = $str;
+        //Release the previous query results
+        if ( $this->queryID ) {    $this->free();    }
+        N('db_query',1);
+        // Record the start time
+        G('queryStartTime');
+        $this->queryID = mysql_query($str, $this->_linkID);
+        $this->debug();
+        if ( false === $this->queryID ) {
+            $this->error();
+            return false;
+        } else {
+            $this->numRows = mysql_num_rows($this->queryID);
+            return $this->getAll();
+        }
+    }
+
+    /**
+     * Execute the statement
+     * @access public
+     * @param string $str  SQL commands
+     * @return integer|false
+     */
+    public function execute($str) {
+        $this->initConnect(true);
+        if ( !$this->_linkID ) return false;
+        $this->queryStr = $str;
+        //Release the previous query results
+        if ( $this->queryID ) {    $this->free();    }
+        N('db_write',1);
+        // Record the start time
+        G('queryStartTime');
+        $result =   mysql_query($str, $this->_linkID) ;
+        $this->debug();
+        if ( false === $result) {
+            $this->error();
+            return false;
+        } else {
+            $this->numRows = mysql_affected_rows($this->_linkID);
+            $this->lastInsID = mysql_insert_id($this->_linkID);
+            return $this->numRows;
+        }
+    }
+
+    /**
+     * Start transaction
+     * @access public
+     * @return void
+     */
+    public function startTrans() {
+        $this->initConnect(true);
+        if ( !$this->_linkID ) return false;
+        //Data rollback Support
+        if ($this->transTimes == 0) {
+            mysql_query('START TRANSACTION', $this->_linkID);
+        }
+        $this->transTimes++;
+        return ;
+    }
+
+    /**
+     * For non-autocommit State the following query submission
+     * @access public
+     * @return boolen
+     */
+    public function commit() {
+        if ($this->transTimes > 0) {
+            $result = mysql_query('COMMIT', $this->_linkID);
+            $this->transTimes = 0;
+            if(!$result){
+                $this->error();
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Transaction rollback
+     * @access public
+     * @return boolen
+     */
+    public function rollback() {
+        if ($this->transTimes > 0) {
+            $result = mysql_query('ROLLBACK', $this->_linkID);
+            $this->transTimes = 0;
+            if(!$result){
+                $this->error();
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Get all the query data
+     * @access private
+     * @return array
+     */
+    private function getAll() {
+        //Returns a DataSet
+        $result = array();
+        if($this->numRows >0) {
+            while($row = mysql_fetch_assoc($this->queryID)){
+                $result[]   =   $row;
+            }
+            mysql_data_seek($this->queryID,0);
+        }
+        return $result;
+    }
+
+    /**
+     * Information obtained field data sheet
+     * @access public
+     * @return array
+     */
+    public function getFields($tableName) {
+        $result =   $this->query('SHOW COLUMNS FROM '.$this->parseKey($tableName));
+        $info   =   array();
+        if($result) {
+            foreach ($result as $key => $val) {
+                $info[$val['Field']] = array(
+                    'name'    => $val['Field'],
+                    'type'    => $val['Type'],
+                    'notnull' => (bool) ($val['Null'] === ''), // not null is empty, null is yes
+                    'default' => $val['Default'],
+                    'primary' => (strtolower($val['Key']) == 'pri'),
+                    'autoinc' => (strtolower($val['Extra']) == 'auto_increment'),
+                );
+            }
+        }
+        return $info;
+    }
+
+    /**
+     * Obtain information about the database table
+     * @access public
+     * @return array
+     */
+    public function getTables($dbName='') {
+        if(!empty($dbName)) {
+           $sql    = 'SHOW TABLES FROM '.$dbName;
+        }else{
+           $sql    = 'SHOW TABLES ';
+        }
+        $result =   $this->query($sql);
+        $info   =   array();
+        foreach ($result as $key => $val) {
+            $info[$key] = current($val);
+        }
+        return $info;
+    }
+
+    /**
+     * Replace Record
+     * @access public
+     * @param mixed $data Data
+     * @param array $options Parameter expression
+     * @return false | integer
+     */
+    public function replace($data,$options=array()) {
+        foreach ($data as $key=>$val){
+            $value   =  $this->parseValue($val);
+            if(is_scalar($value)) { // Filtering non-scalar data
+                $values[]   =  $value;
+                $fields[]     =  $this->parseKey($key);
+            }
+        }
+        $sql   =  'REPLACE INTO '.$this->parseTable($options['table']).' ('.implode(',', $fields).') VALUES ('.implode(',', $values).')';
+        return $this->execute($sql);
+    }
+
+    /**
+     * Insert records
+     * @access public
+     * @param mixed $datas Data
+     * @param array $options Parameter expression
+     * @param boolean $replace Whether or replace
+     * @return false | integer
+     */
+    public function insertAll($datas,$options=array(),$replace=false) {
+        if(!is_array($datas[0])) return false;
+        $fields = array_keys($datas[0]);
+        array_walk($fields, array($this, 'parseKey'));
+        $values  =  array();
+        foreach ($datas as $data){
+            $value   =  array();
+            foreach ($data as $key=>$val){
+                $val   =  $this->parseValue($val);
+                if(is_scalar($val)) { // Filtering non-scalar data
+                    $value[]   =  $val;
+                }
+            }
+            $values[]    = '('.implode(',', $value).')';
+        }
+        $sql   =  ($replace?'REPLACE':'INSERT').' INTO '.$this->parseTable($options['table']).' ('.implode(',', $fields).') VALUES '.implode(',',$values);
+        return $this->execute($sql);
+    }
+
+    /**
+     * Close the database
+     * @access public
+     * @return void
+     */
+    public function close() {
+        if ($this->_linkID){
+            mysql_close($this->_linkID);
+        }
+        $this->_linkID = null;
+    }
+
+    /**
+     * Database Error Messages
+     * And displays the current SQL statement
+     * @access public
+     * @return string
+     */
+    public function error() {
+        $this->error = mysql_error($this->_linkID);
+        if('' != $this->queryStr){
+            $this->error .= "\n [ SQL statement ] : ".$this->queryStr;
+        }
+        trace($this->error,'','ERR');
+        return $this->error;
+    }
+
+    /**
+     * SQL commands security filtering
+     * @access public
+     * @param string $str  SQL string
+     * @return string
+     */
+    public function escapeString($str) {
+        if($this->_linkID) {
+            return mysql_real_escape_string($str,$this->_linkID);
+        }else{
+            return mysql_escape_string($str);
+        }
+    }
+
+    /**
+     * Field and table names added processing`
+     * @access protected
+     * @param string $key
+     * @return string
+     */
+    protected function parseKey(&$key) {
+        $key   =  trim($key);
+        if(!preg_match('/[,\'\"\*\(\)`.\s]/',$key)) {
+           $key = '`'.$key.'`';
+        }
+        return $key;
+    }
+}

+ 343 - 0
php-senthot/Senthot/Lib/Driver/Db/DbMysqli.class.php

@@ -0,0 +1,343 @@
+<?php
+// +--------------------------------------------------------------------------
+// | Senthot [ DEVELOPED BY ME ]
+// +--------------------------------------------------------------------------
+// | Copyright (c) 2007 http://www.senthot.com All rights reserved.
+// | License ( http://www.apache.org/licenses/LICENSE-2.0 )
+// | Author: ms134n ( [email protected] )
+// +--------------------------------------------------------------------------
+
+defined('SEN_PATH') or exit();
+/**
+ * Mysqli database driver class
+ * @category	Sen
+ * @package		Sen
+ * @subpackage  Driver.Db
+ * @author		ms134n <[email protected]>
+ */
+class DbMysqli extends Db{
+
+    /**
+     * Architecture function Read the database configuration information
+     * @access public
+     * @param array $config Database configuration array
+     */
+    public function __construct($config=''){
+        if ( !extension_loaded('mysqli') ) {
+            throw_exception(L('_NOT_SUPPERT_').':mysqli');
+        }
+        if(!empty($config)) {
+            $this->config   =   $config;
+            if(empty($this->config['params'])) {
+                $this->config['params'] =   '';
+            }
+        }
+    }
+
+    /**
+     * Connection database method
+     * @access public
+     * @throws SenExecption
+     */
+    public function connect($config='',$linkNum=0) {
+        if ( !isset($this->linkID[$linkNum]) ) {
+            if(empty($config))  $config =   $this->config;
+            $this->linkID[$linkNum] = new mysqli($config['hostname'],$config['username'],$config['password'],$config['database'],$config['hostport']?intval($config['hostport']):3306);
+            if (mysqli_connect_errno()) throw_exception(mysqli_connect_error());
+            $dbVersion = $this->linkID[$linkNum]->server_version;
+            
+            // Set the database encoding
+            $this->linkID[$linkNum]->query("SET NAMES '".C('DB_CHARSET')."'");
+            //Setup sql_model
+            if($dbVersion >'5.0.1'){
+                $this->linkID[$linkNum]->query("SET sql_mode=''");
+            }
+            // Mark connection successful
+            $this->connected    =   true;
+            //Unregister database security information
+            if(1 != C('DB_DEPLOY_TYPE')) unset($this->config);
+        }
+        return $this->linkID[$linkNum];
+    }
+
+    /**
+     * Query results released
+     * @access public
+     */
+    public function free() {
+        $this->queryID->free_result();
+        $this->queryID = null;
+    }
+
+    /**
+     * Execute the query Returns a DataSet
+     * @access public
+     * @param string $str  SQL commands
+     * @return mixed
+     */
+    public function query($str) {
+        $this->initConnect(false);
+        if ( !$this->_linkID ) return false;
+        $this->queryStr = $str;
+        //Release the previous query results
+        if ( $this->queryID ) $this->free();
+        N('db_query',1);
+        // Record the start time
+        G('queryStartTime');
+        $this->queryID = $this->_linkID->query($str);
+        // Stored procedures improve
+        if( $this->_linkID->more_results() ){
+            while (($res = $this->_linkID->next_result()) != NULL) {
+                $res->free_result();
+            }
+        }
+        $this->debug();
+        if ( false === $this->queryID ) {
+            $this->error();
+            return false;
+        } else {
+            $this->numRows  = $this->queryID->num_rows;
+            $this->numCols    = $this->queryID->field_count;
+            return $this->getAll();
+        }
+    }
+
+    /**
+     * Execute the statement
+     * @access public
+     * @param string $str  SQL commands
+     * @return integer
+     */
+    public function execute($str) {
+        $this->initConnect(true);
+        if ( !$this->_linkID ) return false;
+        $this->queryStr = $str;
+        //Release the previous query results
+        if ( $this->queryID ) $this->free();
+        N('db_write',1);
+        // Record the start time
+        G('queryStartTime');
+        $result =   $this->_linkID->query($str);
+        $this->debug();
+        if ( false === $result ) {
+            $this->error();
+            return false;
+        } else {
+            $this->numRows = $this->_linkID->affected_rows;
+            $this->lastInsID = $this->_linkID->insert_id;
+            return $this->numRows;
+        }
+    }
+
+    /**
+     * Start transaction
+     * @access public
+     * @return void
+     */
+    public function startTrans() {
+        $this->initConnect(true);
+        //Data rollback Support
+        if ($this->transTimes == 0) {
+            $this->_linkID->autocommit(false);
+        }
+        $this->transTimes++;
+        return ;
+    }
+
+    /**
+     * For non-autocommit State the following query submission
+     * @access public
+     * @return boolen
+     */
+    public function commit() {
+        if ($this->transTimes > 0) {
+            $result = $this->_linkID->commit();
+            $this->_linkID->autocommit( true);
+            $this->transTimes = 0;
+            if(!$result){
+                $this->error();
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Transaction rollback
+     * @access public
+     * @return boolen
+     */
+    public function rollback() {
+        if ($this->transTimes > 0) {
+            $result = $this->_linkID->rollback();
+            $this->transTimes = 0;
+            if(!$result){
+                $this->error();
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Get all the query data
+     * @access private
+     * @param string $sql  SQL statement
+     * @return array
+     */
+    private function getAll() {
+        //Returns a DataSet
+        $result = array();
+        if($this->numRows>0) {
+            //Returns a DataSet
+            for($i=0;$i<$this->numRows ;$i++ ){
+                $result[$i] = $this->queryID->fetch_assoc();
+            }
+            $this->queryID->data_seek(0);
+        }
+        return $result;
+    }
+
+    /**
+     * Information obtained field data sheet
+     * @access public
+     * @return array
+     */
+    public function getFields($tableName) {
+        $result =   $this->query('SHOW COLUMNS FROM '.$this->parseKey($tableName));
+        $info   =   array();
+        if($result) {
+            foreach ($result as $key => $val) {
+                $info[$val['Field']] = array(
+                    'name'    => $val['Field'],
+                    'type'    => $val['Type'],
+                    'notnull' => (bool) ($val['Null'] === ''), // not null is empty, null is yes
+                    'default' => $val['Default'],
+                    'primary' => (strtolower($val['Key']) == 'pri'),
+                    'autoinc' => (strtolower($val['Extra']) == 'auto_increment'),
+                );
+            }
+        }
+        return $info;
+    }
+
+    /**
+     * Information obtained field data sheet
+     * @access public
+     * @return array
+     */
+    public function getTables($dbName='') {
+        $sql    = !empty($dbName)?'SHOW TABLES FROM '.$dbName:'SHOW TABLES ';
+        $result =   $this->query($sql);
+        $info   =   array();
+        if($result) {
+            foreach ($result as $key => $val) {
+                $info[$key] = current($val);
+            }
+        }
+        return $info;
+    }
+
+    /**
+     * Replace Record
+     * @access public
+     * @param mixed $data Data
+     * @param array $options Parameter expression
+     * @return false | integer
+     */
+    public function replace($data,$options=array()) {
+        foreach ($data as $key=>$val){
+            $value   =  $this->parseValue($val);
+            if(is_scalar($value)) { // Filtering non-scalar data
+                $values[]   =  $value;
+                $fields[]   =  $this->parseKey($key);
+            }
+        }
+        $sql   =  'REPLACE INTO '.$this->parseTable($options['table']).' ('.implode(',', $fields).') VALUES ('.implode(',', $values).')';
+        return $this->execute($sql);
+    }
+
+    /**
+     * Insert records
+     * @access public
+     * @param mixed $datas Data
+     * @param array $options Parameter expression
+     * @param boolean $replace Whether or replace
+     * @return false | integer
+     */
+    public function insertAll($datas,$options=array(),$replace=false) {
+        if(!is_array($datas[0])) return false;
+        $fields = array_keys($datas[0]);
+        array_walk($fields, array($this, 'parseKey'));
+        $values  =  array();
+        foreach ($datas as $data){
+            $value   =  array();
+            foreach ($data as $key=>$val){
+                $val   =  $this->parseValue($val);
+                if(is_scalar($val)) { // Filtering non-scalar data
+                    $value[]   =  $val;
+                }
+            }
+            $values[]    = '('.implode(',', $value).')';
+        }
+        $sql   =  ($replace?'REPLACE':'INSERT').' INTO '.$this->parseTable($options['table']).' ('.implode(',', $fields).') VALUES '.implode(',',$values);
+        return $this->execute($sql);
+    }
+
+    /**
+     * Close the database
+     * @access public
+     * @return volid
+     */
+    public function close() {
+        if ($this->_linkID){
+            $this->_linkID->close();
+        }
+        $this->_linkID = null;
+    }
+
+    /**
+     * Database Error Messages
+     * And displays the current SQL statement
+     * @static
+     * @access public
+     * @return string
+     */
+    public function error() {
+        $this->error = $this->_linkID->error;
+        if('' != $this->queryStr){
+            $this->error .= "\n [ SQL statement ] : ".$this->queryStr;
+        }
+        trace($this->error,'','ERR');
+        return $this->error;
+    }
+
+    /**
+     * SQL commands security filtering
+     * @static
+     * @access public
+     * @param string $str  SQL commands
+     * @return string
+     */
+    public function escapeString($str) {
+        if($this->_linkID) {
+            return  $this->_linkID->real_escape_string($str);
+        }else{
+            return addslashes($str);
+        }
+    }
+
+    /**
+     * Field and table names added processing`
+     * @access protected
+     * @param string $key
+     * @return string
+     */
+    protected function parseKey(&$key) {
+        $key   =  trim($key);
+        if(!preg_match('/[,\'\"\*\(\)`.\s]/',$key)) {
+           $key = '`'.$key.'`';
+        }
+        return $key;
+    }
+}

+ 640 - 0
php-senthot/Senthot/Lib/Driver/TagLib/TagLibCx.class.php

@@ -0,0 +1,640 @@
+<?php
+// +--------------------------------------------------------------------------
+// | Senthot [ DEVELOPED BY ME ]
+// +--------------------------------------------------------------------------
+// | Copyright (c) 2005-2013 http://www.senthot.com All rights reserved.
+// | License ( http://www.apache.org/licenses/LICENSE-2.0 )
+// | Author: ms134n ( [email protected] )
+// +--------------------------------------------------------------------------
+
+defined('SEN_PATH') or exit();
+/**
+ * CX tag library analytic categories
+ * @category	Sen
+ * @package		Sen
+ * @subpackage  Driver.Taglib
+ * @author		ms134n <[email protected]>
+ */
+class TagLibCx extends TagLib {
+
+    // Tag definition
+    protected $tags   =  array(
+        // Tag definition: attr Property List close Is closed ( 0 Or 1  default 1) alias Tags alias level nesting level
+        'php'       =>  array(),
+        'volist'    =>  array('attr'=>'name,id,offset,length,key,mod','level'=>3,'alias'=>'iterate'),
+        'foreach'   =>  array('attr'=>'name,item,key','level'=>3),
+        'if'        =>  array('attr'=>'condition','level'=>2),
+        'elseif'    =>  array('attr'=>'condition','close'=>0),
+        'else'      =>  array('attr'=>'','close'=>0),
+        'switch'    =>  array('attr'=>'name','level'=>2),
+        'case'      =>  array('attr'=>'value,break'),
+        'default'   =>  array('attr'=>'','close'=>0),
+        'compare'   =>  array('attr'=>'name,value,type','level'=>3,'alias'=>'eq,equal,notequal,neq,gt,lt,egt,elt,heq,nheq'),
+        'range'     =>  array('attr'=>'name,value,type','level'=>3,'alias'=>'in,notin,between,notbetween'),
+        'empty'     =>  array('attr'=>'name','level'=>3),
+        'notempty'  =>  array('attr'=>'name','level'=>3),
+        'present'   =>  array('attr'=>'name','level'=>3),
+        'notpresent'=>  array('attr'=>'name','level'=>3),
+        'defined'   =>  array('attr'=>'name','level'=>3),
+        'notdefined'=>  array('attr'=>'name','level'=>3),
+        'import'    =>  array('attr'=>'file,href,type,value,basepath','close'=>0,'alias'=>'load,css,js'),
+        'assign'    =>  array('attr'=>'name,value','close'=>0),
+        'define'    =>  array('attr'=>'name,value','close'=>0),
+        'for'       =>  array('attr'=>'start,end,name,comparison,step', 'level'=>3),
+        );
+
+    /**
+     * php tags parsing
+     * @access public
+     * @param string $attr Tag attributes
+     * @param string $content  Tag contents
+     * @return string
+     */
+    public function _php($attr,$content) {
+        $parseStr = '<?php '.$content.' ?>';
+        return $parseStr;
+    }
+
+    /**
+     * volist tag resolution Cyclic output data sets
+     * Format:
+     * <volist name="userList" id="user" empty="" >
+     * {user.username}
+     * {user.email}
+     * </volist>
+     * @access public
+     * @param string $attr Tag attributes
+     * @param string $content  Tag contents
+     * @return string|void
+     */
+    public function _volist($attr,$content) {
+        static $_iterateParseCache = array();
+        //If you have already parsed, simply return the variable value
+        $cacheIterateId = md5($attr.$content);
+        if(isset($_iterateParseCache[$cacheIterateId]))
+            return $_iterateParseCache[$cacheIterateId];
+        $tag   =    $this->parseXmlAttr($attr,'volist');
+        $name  =    $tag['name'];
+        $id    =    $tag['id'];
+        $empty =    isset($tag['empty'])?$tag['empty']:'';
+        $key   =    !empty($tag['key'])?$tag['key']:'i';
+        $mod   =    isset($tag['mod'])?$tag['mod']:'2';
+        // Allows the use of function setting data sets <volist name=":fun('arg')" id="vo">{$vo.name}</volist>
+        $parseStr   =  '<?php ';
+        if(0===strpos($name,':')) {
+            $parseStr   .= '$_result='.substr($name,1).';';
+            $name   = '$_result';
+        }else{
+            $name   = $this->autoBuildVar($name);
+        }
+        $parseStr  .=  'if(is_array('.$name.')): $'.$key.' = 0;';
+		if(isset($tag['length']) && '' !=$tag['length'] ) {
+			$parseStr  .= ' $__LIST__ = array_slice('.$name.','.$tag['offset'].','.$tag['length'].',true);';
+		}elseif(isset($tag['offset'])  && '' !=$tag['offset']){
+            $parseStr  .= ' $__LIST__ = array_slice('.$name.','.$tag['offset'].',null,true);';
+        }else{
+            $parseStr .= ' $__LIST__ = '.$name.';';
+        }
+        $parseStr .= 'if( count($__LIST__)==0 ) : echo "'.$empty.'" ;';
+        $parseStr .= 'else: ';
+        $parseStr .= 'foreach($__LIST__ as $key=>$'.$id.'): ';
+        $parseStr .= '$mod = ($'.$key.' % '.$mod.' );';
+        $parseStr .= '++$'.$key.';?>';
+        $parseStr .= $this->tpl->parse($content);
+        $parseStr .= '<?php endforeach; endif; else: echo "'.$empty.'" ;endif; ?>';
+        $_iterateParseCache[$cacheIterateId] = $parseStr;
+
+        if(!empty($parseStr)) {
+            return $parseStr;
+        }
+        return ;
+    }
+
+    /**
+     * foreach tag resolution Cyclic output data sets
+     * @access public
+     * @param string $attr Tag attributes
+     * @param string $content  Tag contents
+     * @return string|void
+     */
+    public function _foreach($attr,$content) {
+        static $_iterateParseCache = array();
+        //If you have already parsed, simply return the variable value
+        $cacheIterateId = md5($attr.$content);
+        if(isset($_iterateParseCache[$cacheIterateId]))
+            return $_iterateParseCache[$cacheIterateId];
+        $tag        =   $this->parseXmlAttr($attr,'foreach');
+        $name       =   $tag['name'];
+        $item       =   $tag['item'];
+        $key        =   !empty($tag['key'])?$tag['key']:'key';
+        $name       =   $this->autoBuildVar($name);
+        $parseStr   =   '<?php if(is_array('.$name.')): foreach('.$name.' as $'.$key.'=>$'.$item.'): ?>';
+        $parseStr  .=   $this->tpl->parse($content);
+        $parseStr  .=   '<?php endforeach; endif; ?>';
+        $_iterateParseCache[$cacheIterateId] = $parseStr;
+        if(!empty($parseStr)) {
+            return $parseStr;
+        }
+        return ;
+    }
+
+    /**
+     * if tag resolution
+     * Format:
+     * <if condition=" $a eq 1" >
+     * <elseif condition="$a eq 2" />
+     * <else />
+     * </if>
+     * Expression support eq neq gt egt lt elt == > >= < <= or and || &&
+     * @access public
+     * @param string $attr Tag attributes
+     * @param string $content  Tag contents
+     * @return string
+     */
+    public function _if($attr,$content) {
+        $tag        =   $this->parseXmlAttr($attr,'if');
+        $condition  =   $this->parseCondition($tag['condition']);
+        $parseStr   =   '<?php if('.$condition.'): ?>'.$content.'<?php endif; ?>';
+        return $parseStr;
+    }
+
+    /**
+     * else tag resolution
+     * Format:See if tag
+     * @access public
+     * @param string $attr Tag attributes
+     * @param string $content  Tag contents
+     * @return string
+     */
+    public function _elseif($attr,$content) {
+        $tag        =   $this->parseXmlAttr($attr,'elseif');
+        $condition  =   $this->parseCondition($tag['condition']);
+        $parseStr   =   '<?php elseif('.$condition.'): ?>';
+        return $parseStr;
+    }
+
+    /**
+     * else tag resolution
+     * @access public
+     * @param string $attr Tag attributes
+     * @return string
+     */
+    public function _else($attr) {
+        $parseStr = '<?php else: ?>';
+        return $parseStr;
+    }
+
+    /**
+     * switch tag resolution
+     * Format:
+     * <switch name="a.name" >
+     * <case value="1" break="false">1</case>
+     * <case value="2" >2</case>
+     * <default />other
+     * </switch>
+     * @access public
+     * @param string $attr Tag attributes
+     * @param string $content  Tag contents
+     * @return string
+     */
+    public function _switch($attr,$content) {
+        $tag        =   $this->parseXmlAttr($attr,'switch');
+        $name       =   $tag['name'];
+        $varArray   =   explode('|',$name);
+        $name       =   array_shift($varArray);
+        $name       =   $this->autoBuildVar($name);
+        if(count($varArray)>0)
+            $name   =   $this->tpl->parseVarFunction($name,$varArray);
+        $parseStr   =   '<?php switch('.$name.'): ?>'.$content.'<?php endswitch;?>';
+        return $parseStr;
+    }
+
+    /**
+     * analytic case tag Need to meet the switch to be effective
+     * @access public
+     * @param string $attr Tag attributes
+     * @param string $content  Tag contents
+     * @return string
+     */
+    public function _case($attr,$content) {
+        $tag    = $this->parseXmlAttr($attr,'case');
+        $value  = $tag['value'];
+        if('$' == substr($value,0,1)) {
+            $varArray   =   explode('|',$value);
+            $value	    =	array_shift($varArray);
+            $value      =   $this->autoBuildVar(substr($value,1));
+            if(count($varArray)>0)
+                $value  =   $this->tpl->parseVarFunction($value,$varArray);
+            $value      =   'case '.$value.': ';
+        }elseif(strpos($value,'|')){
+            $values     =   explode('|',$value);
+            $value      =   '';
+            foreach ($values as $val){
+                $value   .=  'case "'.addslashes($val).'": ';
+            }
+        }else{
+            $value	=    'case "'.$value.'": ';
+        }
+        $parseStr = '<?php '.$value.' ?>'.$content;
+        $isBreak  = isset($tag['break']) ? $tag['break'] : '';
+        if('' ==$isBreak || $isBreak) {
+            $parseStr .= '<?php break;?>';
+        }
+        return $parseStr;
+    }
+
+    /**
+     * default tag resolution Need to meet the switch to be effective
+     * Use: <default />ddfdf
+     * @access public
+     * @param string $attr Tag attributes
+     * @param string $content  Tag contents
+     * @return string
+     */
+    public function _default($attr) {
+        $parseStr = '<?php default: ?>';
+        return $parseStr;
+    }
+
+    /**
+     * compare tag resolution
+     * For value comparison Support eq neq gt lt egt elt heq nheq default is EQ
+     * Format: <compare name="" type="eq" value="" >content</compare>
+     * @access public
+     * @param string $attr Tag attributes
+     * @param string $content  Tag contents
+     * @return string
+     */
+    public function _compare($attr,$content,$type='eq') {
+        $tag        =   $this->parseXmlAttr($attr,'compare');
+        $name       =   $tag['name'];
+        $value      =   $tag['value'];
+        $type       =   isset($tag['type'])?$tag['type']:$type;
+        $type       =   $this->parseCondition(' '.$type.' ');
+        $varArray   =   explode('|',$name);
+        $name       =   array_shift($varArray);
+        $name       =   $this->autoBuildVar($name);
+        if(count($varArray)>0)
+            $name = $this->tpl->parseVarFunction($name,$varArray);
+        if('$' == substr($value,0,1)) {
+            $value  =  $this->autoBuildVar(substr($value,1));
+        }else {
+            $value  =   '"'.$value.'"';
+        }
+        $parseStr   =   '<?php if(('.$name.') '.$type.' '.$value.'): ?>'.$content.'<?php endif; ?>';
+        return $parseStr;
+    }
+
+    public function _eq($attr,$content) {
+        return $this->_compare($attr,$content,'eq');
+    }
+
+    public function _equal($attr,$content) {
+        return $this->_compare($attr,$content,'eq');
+    }
+
+    public function _neq($attr,$content) {
+        return $this->_compare($attr,$content,'neq');
+    }
+
+    public function _notequal($attr,$content) {
+        return $this->_compare($attr,$content,'neq');
+    }
+
+    public function _gt($attr,$content) {
+        return $this->_compare($attr,$content,'gt');
+    }
+
+    public function _lt($attr,$content) {
+        return $this->_compare($attr,$content,'lt');
+    }
+
+    public function _egt($attr,$content) {
+        return $this->_compare($attr,$content,'egt');
+    }
+
+    public function _elt($attr,$content) {
+        return $this->_compare($attr,$content,'elt');
+    }
+
+    public function _heq($attr,$content) {
+        return $this->_compare($attr,$content,'heq');
+    }
+
+    public function _nheq($attr,$content) {
+        return $this->_compare($attr,$content,'nheq');
+    }
+
+    /**
+     * range tag parsing
+     * If a variable exists in a range The contents of the output type= in Indicate the range it says out of range
+     * Format: <range name="var|function"  value="val" type='in|notin' >content</range>
+     * example: <range name="a"  value="1,2,3" type='in' >content</range>
+     * @access public
+     * @param string $attr Tag attributes
+     * @param string $content  Tag contents
+     * @param string $type  Type of comparison
+     * @return string
+     */
+    public function _range($attr,$content,$type='in') {
+        $tag        =   $this->parseXmlAttr($attr,'range');
+        $name       =   $tag['name'];
+        $value      =   $tag['value'];
+        $varArray   =   explode('|',$name);
+        $name       =   array_shift($varArray);
+        $name       =   $this->autoBuildVar($name);
+        if(count($varArray)>0)
+            $name   =   $this->tpl->parseVarFunction($name,$varArray);
+
+        $type       =   isset($tag['type'])?$tag['type']:$type;
+
+        if('$' == substr($value,0,1)) {
+            $value  =   $this->autoBuildVar(substr($value,1));
+            $str    =   'is_array('.$value.')?'.$value.':explode(\',\','.$value.')';
+        }else{
+            $value  =   '"'.$value.'"';
+            $str    =   'explode(\',\','.$value.')';
+        }
+        if($type=='between') {
+            $parseStr = '<?php $_RANGE_VAR_='.$str.';if('.$name.'>= $_RANGE_VAR_[0] && '.$name.'<= $_RANGE_VAR_[1]):?>'.$content.'<?php endif; ?>';
+        }elseif($type=='notbetween'){
+            $parseStr = '<?php $_RANGE_VAR_='.$str.';if('.$name.'<$_RANGE_VAR_[0] && '.$name.'>$_RANGE_VAR_[1]):?>'.$content.'<?php endif; ?>';
+        }else{
+            $fun        =  ($type == 'in')? 'in_array'    :   '!in_array';
+            $parseStr   = '<?php if('.$fun.'(('.$name.'), '.$str.')): ?>'.$content.'<?php endif; ?>';
+        }
+        return $parseStr;
+    }
+
+    // range tag alias Used in judgment
+    public function _in($attr,$content) {
+        return $this->_range($attr,$content,'in');
+    }
+
+    // range tag alias Judge for notin
+    public function _notin($attr,$content) {
+        return $this->_range($attr,$content,'notin');
+    }
+
+    public function _between($attr,$content){
+        return $this->_range($attr,$content,'between');
+    }
+
+    public function _notbetween($attr,$content){
+        return $this->_range($attr,$content,'notbetween');
+    }
+
+    /**
+     * present tag resolution
+     * If a variable has been set The contents of the output
+     * Format: <present name="" >content</present>
+     * @access public
+     * @param string $attr Tag attributes
+     * @param string $content  Tag contents
+     * @return string
+     */
+    public function _present($attr,$content) {
+        $tag        =   $this->parseXmlAttr($attr,'present');
+        $name       =   $tag['name'];
+        $name       =   $this->autoBuildVar($name);
+        $parseStr   =   '<?php if(isset('.$name.')): ?>'.$content.'<?php endif; ?>';
+        return $parseStr;
+    }
+
+    /**
+     * notpresent tag resolution
+     * If a variable is not set, The contents of the output
+     * Format: <notpresent name="" >content</notpresent>
+     * @access public
+     * @param string $attr Tag attributes
+     * @param string $content  Tag contents
+     * @return string
+     */
+    public function _notpresent($attr,$content) {
+        $tag        =   $this->parseXmlAttr($attr,'notpresent');
+        $name       =   $tag['name'];
+        $name       =   $this->autoBuildVar($name);
+        $parseStr   =   '<?php if(!isset('.$name.')): ?>'.$content.'<?php endif; ?>';
+        return $parseStr;
+    }
+
+    /**
+     * empty tag resolution
+     * If a variable is empty The contents of the output
+     * Format: <empty name="" >content</empty>
+     * @access public
+     * @param string $attr Tag attributes
+     * @param string $content  Tag contents
+     * @return string
+     */
+    public function _empty($attr,$content) {
+        $tag        =   $this->parseXmlAttr($attr,'empty');
+        $name       =   $tag['name'];
+        $name       =   $this->autoBuildVar($name);
+        $parseStr   =   '<?php if(empty('.$name.')): ?>'.$content.'<?php endif; ?>';
+        return $parseStr;
+    }
+
+    public function _notempty($attr,$content) {
+        $tag        =   $this->parseXmlAttr($attr,'notempty');
+        $name       =   $tag['name'];
+        $name       =   $this->autoBuildVar($name);
+        $parseStr   =   '<?php if(!empty('.$name.')): ?>'.$content.'<?php endif; ?>';
+        return $parseStr;
+    }
+
+    /**
+     * Determine whether this constant has been defined
+     * <defined name='TXT'>Defined</defined>
+     * @param <type> $attr
+     * @param <type> $content
+     * @return string
+     */
+    public function _defined($attr,$content) {
+        $tag        =   $this->parseXmlAttr($attr,'defined');
+        $name       =   $tag['name'];
+        $parseStr   =   '<?php if(defined("'.$name.'")): ?>'.$content.'<?php endif; ?>';
+        return $parseStr;
+    }
+
+    public function _notdefined($attr,$content) {
+        $tag        =   $this->parseXmlAttr($attr,'_notdefined');
+        $name       =   $tag['name'];
+        $parseStr   =   '<?php if(!defined("'.$name.'")): ?>'.$content.'<?php endif; ?>';
+        return $parseStr;
+    }
+
+    /**
+     * import Tag resolution <import file="Js.Base" /> 
+     * <import file="Css.Base" type="css" />
+     * @access public
+     * @param string $attr Tag attributes
+     * @param string $content  Tag contents
+     * @param boolean $isFile  Whether papers
+     * @param string $type  Type
+     * @return string
+     */
+    public function _import($attr,$content,$isFile=false,$type='') {
+        $tag        =   $this->parseXmlAttr($attr,'import');
+        $file       =   isset($tag['file'])?$tag['file']:$tag['href'];
+        $parseStr   =   '';
+        $endStr     =   '';
+        // Determine if there are load conditions Allows the use of function to determine (The default is isset)
+        if (isset($tag['value'])) {
+            $varArray  =    explode('|',$tag['value']);
+            $name      =    array_shift($varArray);
+            $name      =    $this->autoBuildVar($name);
+            if (!empty($varArray))
+                $name  =    $this->tpl->parseVarFunction($name,$varArray);
+            else
+                $name  =    'isset('.$name.')';
+            $parseStr .=    '<?php if('.$name.'): ?>';
+            $endStr    =    '<?php endif; ?>';
+        }
+        if($isFile) {
+            // Automatic recognition based on the file name suffix
+            $type  = $type?$type:(!empty($tag['type'])?strtolower($tag['type']):null);
+            // Import papers
+            $array =  explode(',',$file);
+            foreach ($array as $val){
+                if (!$type || isset($reset)) {
+                    $type = $reset = strtolower(substr(strrchr($val, '.'),1));
+                }
+                switch($type) {
+                case 'js':
+                    $parseStr .= '<script type="text/javascript" src="'.$val.'"></script>';
+                    break;
+                case 'css':
+                    $parseStr .= '<link rel="stylesheet" type="text/css" href="'.$val.'" />';
+                    break;
+                case 'php':
+                    $parseStr .= '<?php require_cache("'.$val.'"); ?>';
+                    break;
+                }
+            }
+        }else{
+            // Namespace import mode The default is js
+            $type       =   $type?$type:(!empty($tag['type'])?strtolower($tag['type']):'js');
+            $basepath   =   !empty($tag['basepath'])?$tag['basepath']:__ROOT__.'/Public';
+            // Way to import an external file namespaces
+            $array      =   explode(',',$file);
+            foreach ($array as $val){
+                list($val,$version) =   explode('?',$val);
+                switch($type) {
+                case 'js':
+                    $parseStr .= '<script type="text/javascript" src="'.$basepath.'/'.str_replace(array('.','#'), array('/','.'),$val).'.js'.($version?'?'.$version:'').'"></script>';
+                    break;
+                case 'css':
+                    $parseStr .= '<link rel="stylesheet" type="text/css" href="'.$basepath.'/'.str_replace(array('.','#'), array('/','.'),$val).'.css'.($version?'?'.$version:'').'" />';
+                    break;
+                case 'php':
+                    $parseStr .= '<?php import("'.$val.'"); ?>';
+                    break;
+                }
+            }
+        }
+        return $parseStr.$endStr;
+    }
+
+    // import alias Be loaded using the file (To use the namespace must import) For example, <load file="__PUBLIC__/Js/Base.js" />
+    public function _load($attr,$content) {
+        return $this->_import($attr,$content,true);
+    }
+
+    // import aliases Import CSS file <css file="__PUBLIC__/Css/Base.css" />
+    public function _css($attr,$content) {
+        return $this->_import($attr,$content,true,'css');
+    }
+
+    // import aliases Import a js file <js file="__PUBLIC__/Js/Base.js" />
+    public function _js($attr,$content) {
+        return $this->_import($attr,$content,true,'js');
+    }
+
+    /**
+     * assignTag resolution
+     * In the template to a variable assignment Support variable assignment
+     * Format: <assign name="" value="" />
+     * @access public
+     * @param string $attr Tag attributes
+     * @param string $content  Tag contents
+     * @return string
+     */
+    public function _assign($attr,$content) {
+        $tag        =   $this->parseXmlAttr($attr,'assign');
+        $name       =   $this->autoBuildVar($tag['name']);
+        if('$'==substr($tag['value'],0,1)) {
+            $value  =   $this->autoBuildVar(substr($tag['value'],1));
+        }else{
+            $value  =   '\''.$tag['value']. '\'';
+        }
+        $parseStr   =   '<?php '.$name.' = '.$value.'; ?>';
+        return $parseStr;
+    }
+
+    /**
+     * defineTag resolution
+     * Constants defined in the template Support variable assignment
+     * Format: <define name="" value="" />
+     * @access public
+     * @param string $attr Tag attributes
+     * @param string $content  Tag contents
+     * @return string
+     */
+    public function _define($attr,$content) {
+        $tag        =   $this->parseXmlAttr($attr,'define');
+        $name       =   '\''.$tag['name']. '\'';
+        if('$'==substr($tag['value'],0,1)) {
+            $value  =   $this->autoBuildVar(substr($tag['value'],1));
+        }else{
+            $value  =   '\''.$tag['value']. '\'';
+        }
+        $parseStr   =   '<?php define('.$name.', '.$value.'); ?>';
+        return $parseStr;
+    }
+    
+    /**
+     * forTag resolution
+     * Format: <for start="" end="" comparison="" step="" name="" />
+     * @access public
+     * @param string $attr Tag attributes
+     * @param string $content  Tag contents
+     * @return string
+     */
+    public function _for($attr, $content){
+        //Set Default
+        $start 		= 0;
+        $end   		= 0;
+        $step 		= 1;
+        $comparison = 'lt';
+        $name		= 'i';
+        $rand       = rand(); //Adding random number to prevent conflicts nested variable
+        //Get Properties
+        foreach ($this->parseXmlAttr($attr, 'for') as $key => $value){
+            $value = trim($value);
+            if(':'==substr($value,0,1))
+                $value = substr($value,1);
+            elseif('$'==substr($value,0,1))
+                $value = $this->autoBuildVar(substr($value,1));
+            switch ($key){
+                case 'start':   
+                    $start      = $value; break;
+                case 'end' :    
+                    $end        = $value; break;
+                case 'step':    
+                    $step       = $value; break;
+                case 'comparison':
+                    $comparison = $value; break;
+                case 'name':
+                    $name       = $value; break;
+            }
+        }
+        
+        $parseStr   = '<?php $__FOR_START_'.$rand.'__='.$start.';$__FOR_END_'.$rand.'__='.$end.';';
+        $parseStr  .= 'for($'.$name.'=$__FOR_START_'.$rand.'__;'.$this->parseCondition('$'.$name.' '.$comparison.' $__FOR_END_'.$rand.'__').';$'.$name.'+='.$step.'){ ?>';
+        $parseStr  .= $content;
+        $parseStr  .= '<?php } ?>';
+        return $parseStr;
+    }
+
+    }

+ 688 - 0
php-senthot/Senthot/Lib/Template/SenTemplate.class.php

@@ -0,0 +1,688 @@
+<?php
+// +--------------------------------------------------------------------------
+// | Senthot [ DEVELOPED BY ME ]
+// +--------------------------------------------------------------------------
+// | Copyright (c) 2005-2013 http://www.senthot.com All rights reserved.
+// | License ( http://www.apache.org/licenses/LICENSE-2.0 )
+// | Author: ms134n ( [email protected] )
+// +--------------------------------------------------------------------------
+
+/**
+ * Senthot built-in template engine class
+ * SupportXML tag and generic tag template parsing
+ * Compiled template engine Support dynamic cache
+ * @category	Sen
+ * @package		Sen
+ * @subpackage  Template
+ * @author		ms134n <[email protected]>
+ */
+class  SenTemplate {
+
+    // Template page tag library introduced in the list
+    protected   $tagLib          =   array();
+    // Current template file
+    protected   $templateFile    =   '';
+    // Template Variables
+    public      $tVar            =   array();
+    public      $config          =   array();
+    private     $literal         =   array();
+    private     $block           =   array();
+
+    /**
+     * Architecture function
+     * @access public
+     */
+    public function __construct(){
+        $this->config['cache_path']         =   C('CACHE_PATH');
+        $this->config['template_suffix']    =   C('TMPL_TEMPLATE_SUFFIX');
+        $this->config['cache_suffix']       =   C('TMPL_CACHFILE_SUFFIX');
+        $this->config['tmpl_cache']         =   C('TMPL_CACHE_ON');
+        $this->config['cache_time']         =   C('TMPL_CACHE_TIME');
+        $this->config['taglib_begin']       =   $this->stripPreg(C('TAGLIB_BEGIN'));
+        $this->config['taglib_end']         =   $this->stripPreg(C('TAGLIB_END'));
+        $this->config['tmpl_begin']         =   $this->stripPreg(C('TMPL_L_DELIM'));
+        $this->config['tmpl_end']           =   $this->stripPreg(C('TMPL_R_DELIM'));
+        $this->config['default_tmpl']       =   C('TEMPLATE_NAME');
+        $this->config['layout_item']        =   C('TMPL_LAYOUT_ITEM');
+    }
+
+    private function stripPreg($str) {
+        return str_replace(
+            array('{','}','(',')','|','[',']','-','+','*','.','^','?'),
+            array('\{','\}','\(','\)','\|','\[','\]','\-','\+','\*','\.','\^','\?'),
+            $str);        
+    }
+
+    // Get and set template variables
+    public function get($name) {
+        if(isset($this->tVar[$name]))
+            return $this->tVar[$name];
+        else
+            return false;
+    }
+
+    public function set($name,$value) {
+        $this->tVar[$name]= $value;
+    }
+
+    /**
+     * Load Template
+     * @access public
+     * @param string $tmplTemplateFile Template File
+     * @param array  $templateVar Template Variables
+     * @param string $prefix Template identifying prefix
+     * @return void
+     */
+    public function fetch($templateFile,$templateVar,$prefix='') {
+        $this->tVar         =   $templateVar;
+        $templateCacheFile  =   $this->loadTemplate($templateFile,$prefix);
+        // Template array variable decomposed into independent variable
+        extract($templateVar, EXTR_OVERWRITE);
+        //Load template cache files
+        include $templateCacheFile;
+    }
+
+    /**
+     * Loaded and cached master template
+     * @access public
+     * @param string $tmplTemplateFile Template File
+     * @param string $prefix Template identifying prefix
+     * @return string
+     * @throws SenExecption
+     */
+    public function loadTemplate ($tmplTemplateFile,$prefix='') {
+        if(is_file($tmplTemplateFile)) {
+            $this->templateFile    =  $tmplTemplateFile;
+            // Read the contents of the template file
+            $tmplContent =  file_get_contents($tmplTemplateFile);
+        }else{
+            $tmplContent =  $tmplTemplateFile;
+        }
+         // According to the template file name to locate the cache file
+        $tmplCacheFile = $this->config['cache_path'].$prefix.md5($tmplTemplateFile).$this->config['cache_suffix'];
+
+        // Determine whether to enable layout
+        if(C('LAYOUT_ON')) {
+            if(false !== strpos($tmplContent,'{__NOLAYOUT__}')) { // Do not use the layout can be individually defined
+                $tmplContent = str_replace('{__NOLAYOUT__}','',$tmplContent);
+            }else{ // Replace the layout of the main content
+                $layoutFile  =  THEME_PATH.C('LAYOUT_NAME').$this->config['template_suffix'];
+                $tmplContent = str_replace($this->config['layout_item'],$tmplContent,file_get_contents($layoutFile));
+            }
+        }
+        // Compiled template content
+        $tmplContent =  $this->compiler($tmplContent);
+        // Detection template directory
+        $dir         =  dirname($tmplCacheFile);
+        if(!is_dir($dir))
+            mkdir($dir,0755,true);
+        //Rewrite Cache Files
+        if( false === file_put_contents($tmplCacheFile,trim($tmplContent)))
+            throw_exception(L('_CACHE_WRITE_ERROR_').':'.$tmplCacheFile);
+        return $tmplCacheFile;
+    }
+
+    /**
+     * Compile the template file contents
+     * @access protected
+     * @param mixed $tmplContent Template content
+     * @return string
+     */
+    protected function compiler($tmplContent) {
+        //Template parsing
+        $tmplContent =  $this->parse($tmplContent);
+        // Restore is replaced Literal tags
+        $tmplContent =  preg_replace('/<!--###literal(\d+)###-->/eis',"\$this->restoreLiteral('\\1')",$tmplContent);
+        // Add Security Code
+        $tmplContent =  '<?php if (!defined(\'SEN_PATH\')) exit();?>'.$tmplContent;
+        if(C('TMPL_STRIP_SPACE')) {
+            /* Strip html whitespace and newline */
+            $find           = array('~>\s+<~','~>(\s+\n|\r)~');
+            $replace        = array('><','>');
+            $tmplContent    = preg_replace($find, $replace, $tmplContent);
+        }
+        // Optimize the generated php code
+        $tmplContent = str_replace('?><?php','',$tmplContent);
+        return strip_whitespace($tmplContent);
+    }
+
+    /**
+     * Template parsing entrance
+     * Support Common tags and TagLib resolution Support custom tag library
+     * @access public
+     * @param string $content To parse the template content
+     * @return string
+     */
+    public function parse($content) {
+        // Content is empty does not resolve
+        if(empty($content)) return '';
+        $begin      =   $this->config['taglib_begin'];
+        $end        =   $this->config['taglib_end'];
+        // Check the include syntax
+        $content    =   $this->parseInclude($content);
+        // Check the PHP syntax
+        $content    =   $this->parsePhp($content);
+        // Replaced first literalTag contents
+        $content    =   preg_replace('/'.$begin.'literal'.$end.'(.*?)'.$begin.'\/literal'.$end.'/eis',"\$this->parseLiteral('\\1')",$content);
+
+        // Gets the list of tag libraries that need to introduce
+        // Only need to define a tag library, allow the introduction of more
+        // General in the top of the file
+        // Format:<taglib name="html,mytag..." />
+        // When TAGLIB_LOAD is configured to true only when testing
+        if(C('TAGLIB_LOAD')) {
+            $this->getIncludeTagLib($content);
+            if(!empty($this->tagLib)) {
+                // Import TagLib parsing
+                foreach($this->tagLib as $tagLibName) {
+                    $this->parseTagLib($tagLibName,$content);
+                }
+            }
+        }
+        // Preload the tag library Do not need to use taglib in each template tag loading But you must use the tag library XML prefix
+        if(C('TAGLIB_PRE_LOAD')) {
+            $tagLibs =  explode(',',C('TAGLIB_PRE_LOAD'));
+            foreach ($tagLibs as $tag){
+                $this->parseTagLib($tag,$content);
+            }
+        }
+        // Built-in tag library Import without using taglib tags you can use And you don't need to use the tag library XML prefix
+        $tagLibs =  explode(',',C('TAGLIB_BUILD_IN'));
+        foreach ($tagLibs as $tag){
+            $this->parseTagLib($tag,$content,true);
+        }
+        //Resolve common template tags {tagName}
+        $content = preg_replace('/('.$this->config['tmpl_begin'].')([^\d\s'.$this->config['tmpl_begin'].$this->config['tmpl_end'].'].+?)('.$this->config['tmpl_end'].')/eis',"\$this->parseTag('\\2')",$content);
+        return $content;
+    }
+
+    // Check the PHP syntax
+    protected function parsePhp($content) {
+        if(ini_get('short_open_tag')){
+            // Open short tag to be<? Tags echo output Otherwise normal output XML ID
+            $content = preg_replace('/(<\?(?!php|=|$))/i', '<?php echo \'\\1\'; ?>'."\n", $content );
+        }
+        // PHP syntax check
+        if(C('TMPL_DENY_PHP') && false !== strpos($content,'<?php')) {
+            throw_exception(L('_NOT_ALLOW_PHP_'));
+        }
+        return $content;
+    }
+
+    // Parsing template layout of tags
+    protected function parseLayout($content) {
+        // Reading layout in the template tags
+        $find = preg_match('/'.$this->config['taglib_begin'].'layout\s(.+?)\s*?\/'.$this->config['taglib_end'].'/is',$content,$matches);
+        if($find) {
+            //Replaces the Layout tag
+            $content    =   str_replace($matches[0],'',$content);
+            //Resolution Layout tags
+            $array      =   $this->parseXmlAttrs($matches[1]);
+            if(!C('LAYOUT_ON') || C('LAYOUT_NAME') !=$array['name'] ) {
+                // Reading layout template
+                $layoutFile =   THEME_PATH.$array['name'].$this->config['template_suffix'];
+                $replace    =   isset($array['replace'])?$array['replace']:$this->config['layout_item'];
+                // Replace the layout of the main content
+                $content    =   str_replace($replace,$content,file_get_contents($layoutFile));
+            }
+        }else{
+            $content = str_replace('{__NOLAYOUT__}','',$content);
+        }
+        return $content;
+    }
+
+    // Include parsing template tags
+    protected function parseInclude($content) {
+        // Resolving inheritance
+        $content    =   $this->parseAddons($content);
+        // Analysis of layout
+        $content    =   $this->parseLayout($content);
+        // Read template include tags
+        $find       =   preg_match_all('/'.$this->config['taglib_begin'].'include\s(.+?)\s*?\/'.$this->config['taglib_end'].'/is',$content,$matches);
+        if($find) {
+            for($i=0;$i<$find;$i++) {
+                $include    =   $matches[1][$i];
+                $array      =   $this->parseXmlAttrs($include);
+                $file       =   $array['file'];
+                unset($array['file']);
+                $content    =   str_replace($matches[0][$i],$this->parseIncludeItem($file,$array),$content);
+            }
+        }
+        return $content;
+    }
+
+    // Addons parsing template tags
+    protected function parseAddons($content) {
+        $begin      =   $this->config['taglib_begin'];
+        $end        =   $this->config['taglib_end'];        
+        // Read inheritance in a template tags
+        $find       =   preg_match('/'.$begin.'addons\s(.+?)\s*?\/'.$end.'/is',$content,$matches);
+        if($find) {
+            //Replace addons tag
+            $content    =   str_replace($matches[0],'',$content);
+            // Block tag records page
+            preg_replace('/'.$begin.'block\sname=(.+?)\s*?'.$end.'(.*?)'.$begin.'\/block'.$end.'/eis',"\$this->parseBlock('\\1','\\2')",$content);
+            // Read inherited template
+            $array      =   $this->parseXmlAttrs($matches[1]);
+            $content    =   $this->parseTemplateName($array['name']);
+            // Replace block tags
+            $content    =   preg_replace('/'.$begin.'block\sname=(.+?)\s*?'.$end.'(.*?)'.$begin.'\/block'.$end.'/eis',"\$this->replaceBlock('\\1','\\2')",$content);
+        }else{
+            $content    =   preg_replace('/'.$begin.'block\sname=(.+?)\s*?'.$end.'(.*?)'.$begin.'\/block'.$end.'/eis',"stripslashes('\\2')",$content);            
+        }
+        return $content;
+    }
+
+    /**
+     * Analysis of XML attributes
+     * @access private
+     * @param string $attrs  XML attribute string
+     * @return array
+     */
+    private function parseXmlAttrs($attrs) {
+        $xml        =   '<tpl><tag '.$attrs.' /></tpl>';
+        $xml        =   simplexml_load_string($xml);
+        if(!$xml)
+            throw_exception(L('_XML_TAG_ERROR_'));
+        $xml        =   (array)($xml->tag->attributes());
+        $array      =   array_change_key_case($xml['@attributes']);
+        return $array;
+    }
+
+    /**
+     * Replace literal tag page
+     * @access private
+     * @param string $content  Template content
+     * @return string|false
+     */
+    private function parseLiteral($content) {
+        if(trim($content)=='')  return '';
+        $content            =   stripslashes($content);
+        $i                  =   count($this->literal);
+        $parseStr           =   "<!--###literal{$i}###-->";
+        $this->literal[$i]  =   $content;
+        return $parseStr;
+    }
+
+    /**
+     * Restore has been replacing literal tags
+     * @access private
+     * @param string $tag  Literal tag serial number
+     * @return string|false
+     */
+    private function restoreLiteral($tag) {
+        // Restore literal tags
+        $parseStr   =  $this->literal[$tag];
+        // Destruction of literal records
+        unset($this->literal[$tag]);
+        return $parseStr;
+    }
+
+    /**
+     * Block tag records in the current page
+     * @access private
+     * @param string $name Block name
+     * @param string $content  Template content
+     * @return string
+     */
+    private function parseBlock($name,$content) {
+        $this->block[$name]  =   $content;
+        return '';
+    }
+
+    /**
+     * Replacing the inherited template block tag
+     * @access private
+     * @param string $name  Block name
+     * @param string $content  Template content
+     * @return string
+     */
+    private function replaceBlock($name,$content) {
+        // Replace block tags Do not redefine the original
+        $replace   =  isset($this->block[$name])?   $this->block[$name]   :   $content;
+        return stripslashes($replace);
+    }
+
+    /**
+     * Search template page containing the TagLib library
+     * And return to the list
+     * @access public
+     * @param string $content  Template content
+     * @return string|false
+     */
+    public function getIncludeTagLib(& $content) {
+        //Search for TagLib tag
+        $find = preg_match('/'.$this->config['taglib_begin'].'taglib\s(.+?)(\s*?)\/'.$this->config['taglib_end'].'\W/is',$content,$matches);
+        if($find) {
+            //Replace TagLib tag
+            $content        = str_replace($matches[0],'',$content);
+            //Resolving TagLib tag
+            $array          =   $this->parseXmlAttrs($matches[1]);
+            $this->tagLib   = explode(',',$array['name']);
+        }
+        return;
+    }
+
+    /**
+     * TagLib library parsing
+     * @access public
+     * @param string $tagLib To parse the tag library
+     * @param string $content To parse the template content
+     * @param boolen $hide Whether to hide tag library prefix
+     * @return string
+     */
+    public function parseTagLib($tagLib,&$content,$hide=false) {
+        $begin      =   $this->config['taglib_begin'];
+        $end        =   $this->config['taglib_end'];
+        $className  =   'TagLib'.ucwords($tagLib);
+        $tLib       =   Sen::instance($className);
+        foreach ($tLib->getTags() as $name=>$val){
+            $tags = array($name);
+            if(isset($val['alias'])) {// Alias settings
+                $tags       = explode(',',$val['alias']);
+                $tags[]     =  $name;
+            }
+            $level      =   isset($val['level'])?$val['level']:1;
+            $closeTag   =   isset($val['close'])?$val['close']:true;
+            foreach ($tags as $tag){
+                $parseTag = !$hide? $tagLib.':'.$tag: $tag;// Actual tag name to be resolved
+                if(!method_exists($tLib,'_'.$tag)) {
+                    // Analytical method may need to define an alias
+                    $tag  =  $name;
+                }
+                $n1 = empty($val['attr'])?'(\s*?)':'\s([^'.$end.']*)';
+                if (!$closeTag){
+                    $patterns       = '/'.$begin.$parseTag.$n1.'\/(\s*?)'.$end.'/eis';
+                    $replacement    = "\$this->parseXmlTag('$tagLib','$tag','$1','')";
+                    $content        = preg_replace($patterns, $replacement,$content);
+                }else{
+                    $patterns       = '/'.$begin.$parseTag.$n1.$end.'(.*?)'.$begin.'\/'.$parseTag.'(\s*?)'.$end.'/eis';
+                    $replacement    = "\$this->parseXmlTag('$tagLib','$tag','$1','$2')";
+                    for($i=0;$i<$level;$i++) 
+                        $content=preg_replace($patterns,$replacement,$content);
+                }
+            }
+        }
+    }
+
+    /**
+     * Resolution tab library
+     * Need to call the corresponding tag library file parsing class
+     * @access public
+     * @param string $tagLib  Tag library name
+     * @param string $tag  Tag names
+     * @param string $attr  Tag attributes
+     * @param string $content  Tag contents
+     * @return string|false
+     */
+    public function parseXmlTag($tagLib,$tag,$attr,$content) {
+        //if (MAGIC_QUOTES_GPC) {
+            $attr   = stripslashes($attr);
+            $content= stripslashes($content);
+        //}
+        if(ini_get('magic_quotes_sybase'))
+            $attr   =  str_replace('\"','\'',$attr);
+        $tLib       =  Sen::instance('TagLib'.ucwords(strtolower($tagLib)));
+        $parse      = '_'.$tag;
+        $content    = trim($content);
+        return $tLib->$parse($attr,$content);
+    }
+
+    /**
+     * Template Tag resolution
+     * Format: {TagName:args [|content] }
+     * @access public
+     * @param string $tagStr Tag contents
+     * @return string
+     */
+    public function parseTag($tagStr){
+        //if (MAGIC_QUOTES_GPC) {
+            $tagStr = stripslashes($tagStr);
+        //}
+        //Reducing non-template tag
+        if(preg_match('/^[\s|\d]/is',$tagStr))
+            //Filtering tags beginning with numbers and spaces
+            return C('TMPL_L_DELIM') . $tagStr .C('TMPL_R_DELIM');
+        $flag   =  substr($tagStr,0,1);
+        $flag2  =  substr($tagStr,1,1);
+        $name   = substr($tagStr,1);
+        if('$' == $flag && '.' != $flag2 && '(' != $flag2){ //Parsing template variables Format {$varName}
+            return $this->parseVar($name);
+        }elseif('-' == $flag || '+'== $flag){ // Output calculation
+            return  '<?php echo '.$flag.$name.';?>';
+        }elseif(':' == $flag){ // Output the result of a function
+            return  '<?php echo '.$name.';?>';
+        }elseif('~' == $flag){ // Perform a function
+            return  '<?php '.$name.';?>';
+        }elseif(substr($tagStr,0,2)=='//' || (substr($tagStr,0,2)=='/*' && substr($tagStr,-2)=='*/')){
+            //Comment tags
+            return '';
+        }
+        // Identification tags are not returned directly
+        return C('TMPL_L_DELIM') . $tagStr .C('TMPL_R_DELIM');
+    }
+
+    /**
+     * Template variable resolution, Support use the function
+     * Format: {$varname|function1|function2=arg1,arg2}
+     * @access public
+     * @param string $varStr Variable data
+     * @return string
+     */
+    public function parseVar($varStr){
+        $varStr     =   trim($varStr);
+        static $_varParseList = array();
+        //If the variable is a string that has been parsed, the direct return variable value
+        if(isset($_varParseList[$varStr])) return $_varParseList[$varStr];
+        $parseStr   =   '';
+        $varExists  =   true;
+        if(!empty($varStr)){
+            $varArray = explode('|',$varStr);
+            //Get the variable name
+            $var = array_shift($varArray);
+            if('Sen.' == substr($var,0,4)){
+                // All to Sen. Variables beginning with a special treat Templates can be exported without assignment
+                $name = $this->parseSenVar($var);
+            }elseif( false !== strpos($var,'.')) {
+                //Support {$var.property}
+                $vars = explode('.',$var);
+                $var  =  array_shift($vars);
+                switch(strtolower(C('TMPL_VAR_IDENTIFY'))) {
+                    case 'array': // Identified as an array
+                        $name = '$'.$var;
+                        foreach ($vars as $key=>$val)
+                            $name .= '["'.$val.'"]';
+                        break;
+                    case 'obj':  // Identifying the object
+                        $name = '$'.$var;
+                        foreach ($vars as $key=>$val)
+                            $name .= '->'.$val;
+                        break;
+                    default:  // Automatically determine the array or object Support only two-dimensional
+                        $name = 'is_array($'.$var.')?$'.$var.'["'.$vars[0].'"]:$'.$var.'->'.$vars[0];
+                }
+            }elseif(false !== strpos($var,'[')) {
+                //Support {$var['key']} Mode output array
+                $name = "$".$var;
+                preg_match('/(.+?)\[(.+?)\]/is',$var,$match);
+                $var = $match[1];
+            }elseif(false !==strpos($var,':') && false ===strpos($var,'::') && false ===strpos($var,'?')){
+                //Support {$var:property} Output the object's properties
+                $vars = explode(':',$var);
+                $var  =  str_replace(':','->',$var);
+                $name = "$".$var;
+                $var  = $vars[0];
+            }else {
+                $name = "$$var";
+            }
+            //The variable using the function
+            if(count($varArray)>0)
+                $name = $this->parseVarFunction($name,$varArray);
+            $parseStr = '<?php echo ('.$name.'); ?>';
+        }
+        $_varParseList[$varStr] = $parseStr;
+        return $parseStr;
+    }
+
+    /**
+     * Use the template variable function
+     * Format {$varname|function1|function2=arg1,arg2}
+     * @access public
+     * @param string $name Variable name
+     * @param array $varArray  Function List
+     * @return string
+     */
+    public function parseVarFunction($name,$varArray){
+        //The variable using the function
+        $length = count($varArray);
+        //Prohibit the use of a template to obtain a list of functions
+        $template_deny_funs = explode(',',C('TMPL_DENY_FUNC_LIST'));
+        for($i=0;$i<$length ;$i++ ){
+            $args = explode('=',$varArray[$i],2);
+            //Template function filter
+            $fun = strtolower(trim($args[0]));
+            switch($fun) {
+            case 'default':  // Special template function
+                $name   = '('.$name.')?('.$name.'):'.$args[1];
+                break;
+            default:  // Universal template function
+                if(!in_array($fun,$template_deny_funs)){
+                    if(isset($args[1])){
+                        if(strstr($args[1],'###')){
+                            $args[1] = str_replace('###',$name,$args[1]);
+                            $name = "$fun($args[1])";
+                        }else{
+                            $name = "$fun($name,$args[1])";
+                        }
+                    }else if(!empty($args[0])){
+                        $name = "$fun($name)";
+                    }
+                }
+            }
+        }
+        return $name;
+    }
+
+    /**
+     * Special template variable resolution
+     * Format $Sen. Heading variable is a special template variables
+     * @access public
+     * @param string $varStr  Variable string
+     * @return string
+     */
+    public function parseSenVar($varStr){
+        $vars = explode('.',$varStr);
+        $vars[1] = strtoupper(trim($vars[1]));
+        $parseStr = '';
+        if(count($vars)>=3){
+            $vars[2] = trim($vars[2]);
+            switch($vars[1]){
+                case 'SERVER':
+                    $parseStr = '$_SERVER[\''.strtoupper($vars[2]).'\']';break;
+                case 'GET':
+                    $parseStr = '$_GET[\''.$vars[2].'\']';break;
+                case 'POST':
+                    $parseStr = '$_POST[\''.$vars[2].'\']';break;
+                case 'COOKIE':
+                    if(isset($vars[3])) {
+                        $parseStr = '$_COOKIE[\''.$vars[2].'\'][\''.$vars[3].'\']';
+                    }else{
+                        $parseStr = 'cookie(\''.$vars[2].'\')';
+                    }
+                    break;
+                case 'SESSION':
+                    if(isset($vars[3])) {
+                        $parseStr = '$_SESSION[\''.$vars[2].'\'][\''.$vars[3].'\']';
+                    }else{
+                        $parseStr = 'session(\''.$vars[2].'\')';
+                    }
+                    break;
+                case 'ENV':
+                    $parseStr = '$_ENV[\''.strtoupper($vars[2]).'\']';break;
+                case 'REQUEST':
+                    $parseStr = '$_REQUEST[\''.$vars[2].'\']';break;
+                case 'CONST':
+                    $parseStr = strtoupper($vars[2]);break;
+                case 'LANG':
+                    $parseStr = 'L("'.$vars[2].'")';break;
+                case 'CONFIG':
+                    if(isset($vars[3])) {
+                        $vars[2] .= '.'.$vars[3];
+                    }
+                    $parseStr = 'C("'.$vars[2].'")';break;
+                default:break;
+            }
+        }else if(count($vars)==2){
+            switch($vars[1]){
+                case 'NOW':
+                    $parseStr = "date('Y-m-d g:i a',time())";
+                    break;
+                case 'VERSION':
+                    $parseStr = 'SEN_VERSION';
+                    break;
+                case 'TEMPLATE':
+                    $parseStr = "'".$this->templateFile."'";//'C("TEMPLATE_NAME")';
+                    break;
+                case 'LDELIM':
+                    $parseStr = 'C("TMPL_L_DELIM")';
+                    break;
+                case 'RDELIM':
+                    $parseStr = 'C("TMPL_R_DELIM")';
+                    break;
+                default:
+                    if(defined($vars[1]))
+                        $parseStr = $vars[1];
+            }
+        }
+        return $parseStr;
+    }
+
+    /**
+     * Common template loaded and cached and the current template in the same path, or use a relative path
+     * @access private
+     * @param string $tmplPublicName  Public template file name
+     * @param array $vars  The list of variables to be passed
+     * @return string
+     */
+    private function parseIncludeItem($tmplPublicName,$vars=array()){
+        // Analyze and read the contents of the template file name
+        $parseStr = $this->parseTemplateName($tmplPublicName);
+        // Substitution variables
+        foreach ($vars as $key=>$val) {
+            $parseStr = str_replace('['.$key.']',$val,$parseStr);
+        }
+        // Template that contains the file again analyzed
+        return $this->parseInclude($parseStr);
+    }
+
+    /**
+     * Analysis of the loaded template file and read the contents Support multiple template file read
+     * @access private
+     * @param string $tmplPublicName  Template file name
+     * @return string
+     */    
+    private function parseTemplateName($templateName){
+        if(substr($templateName,0,1)=='$')
+            //Support load variable file name
+            $templateName = $this->get(substr($templateName,1));
+        $array  =   explode(',',$templateName);
+        $parseStr   =   '';
+        foreach ($array as $templateName){
+            if(false === strpos($templateName,$this->config['template_suffix'])) {
+                // Parsing rules Template Theme:Module:Operating Not Support Cross-project and cross-grouping called
+                $path   =  explode(':',$templateName);
+                $action = array_pop($path);
+                $module = !empty($path)?array_pop($path):MODULE_NAME;
+                if(!empty($path) && THEME_NAME) {// Set Template Theme
+                    $path = dirname(THEME_PATH).'/'.array_pop($path).'/';
+                }else{
+                    $path = THEME_PATH;
+                }
+                $templateName  =  $path.$module.C('TMPL_FILE_DEPR').$action.$this->config['template_suffix'];
+            }
+            // Get the template file contents
+            $parseStr .= file_get_contents($templateName);
+        }
+        return $parseStr;
+    }    
+}

+ 229 - 0
php-senthot/Senthot/Lib/Template/TagLib.class.php

@@ -0,0 +1,229 @@
+<?php
+// +--------------------------------------------------------------------------
+// | Senthot [ DEVELOPED BY ME ]
+// +--------------------------------------------------------------------------
+// | Copyright (c) 2005-2013 http://www.senthot.com All rights reserved.
+// | License ( http://www.apache.org/licenses/LICENSE-2.0 )
+// | Author: ms134n ( [email protected] )
+// +--------------------------------------------------------------------------
+
+/**
+ * Senthot TagLib parsing a tag library base class
+ * @category	Sen
+ * @package		Sen
+ * @subpackage  Template
+ * @author		ms134n <[email protected]>
+ */
+class TagLib {
+
+    /**
+     * Tag library definition XML file
+     * @var string
+     * @access protected
+     */
+    protected $xml      = '';
+    protected $tags     = array();// Tag definition
+    /**
+     * Tag library name
+     * @var string
+     * @access protected
+     */
+    protected $tagLib   ='';
+
+    /**
+     * Tag Library Tag List
+     * @var string
+     * @access protected
+     */
+    protected $tagList  = array();
+
+    /**
+     * Analysis of the array tag library
+     * @var string
+     * @access protected
+     */
+    protected $parse    = array();
+
+    /**
+     * Tag library is valid
+     * @var string
+     * @access protected
+     */
+    protected $valid    = false;
+
+    /**
+     * Current template object
+     * @var object
+     * @access protected
+     */
+    protected $tpl;
+
+    protected $comparison = array(' nheq '=>' !== ',' heq '=>' === ',' neq '=>' != ',' eq '=>' == ',' egt '=>' >= ',' gt '=>' > ',' elt '=>' <= ',' lt '=>' < ');
+
+    /**
+     * Architecture function
+     * @access public
+     */
+    public function __construct() {
+        $this->tagLib  = strtolower(substr(get_class($this),4));
+        $this->tpl     = Sen::instance('SenTemplate');
+    }
+
+    /**
+     * TagLibTag attributes analysis Back Tag attributes array
+     * @access public
+     * @param string $tagStr Tag contents
+     * @return array
+     */
+    public function parseXmlAttr($attr,$tag) {
+        //XML parsing security filtering
+        $attr   =   str_replace('&','___', $attr);
+        $xml    =   '<tpl><tag '.$attr.' /></tpl>';
+        $xml    =   simplexml_load_string($xml);
+        if(!$xml) {
+            throw_exception(L('_XML_TAG_ERROR_').' : '.$attr);
+        }
+        $xml    =   (array)($xml->tag->attributes());
+        $array  =   array_change_key_case($xml['@attributes']);
+        if($array) {
+            $attrs  = explode(',',$this->tags[strtolower($tag)]['attr']);
+            if(isset($this->tags[strtolower($tag)]['must'])){
+                $must   =   explode(',',$this->tags[strtolower($tag)]['must']);
+            }else{
+                $must   =   array();
+            }
+            foreach($attrs as $name) {
+                if( isset($array[$name])) {
+                    $array[$name] = str_replace('___','&',$array[$name]);
+                }elseif(false !== array_search($name,$must)){
+                    throw_exception(L('_PARAM_ERROR_').':'.$name);
+                }
+            }
+            return $array;
+        }
+    }
+
+    /**
+     * Analytical conditional expression
+     * @access public
+     * @param string $condition Expressions Tag contents
+     * @return array
+     */
+    public function parseCondition($condition) {
+        $condition = str_ireplace(array_keys($this->comparison),array_values($this->comparison),$condition);
+        $condition = preg_replace('/\$(\w+):(\w+)\s/is','$\\1->\\2 ',$condition);
+        switch(strtolower(C('TMPL_VAR_IDENTIFY'))) {
+            case 'array': // Identified as an array
+                $condition  =   preg_replace('/\$(\w+)\.(\w+)\s/is','$\\1["\\2"] ',$condition);
+                break;
+            case 'obj':  // Identifying the object
+                $condition  =   preg_replace('/\$(\w+)\.(\w+)\s/is','$\\1->\\2 ',$condition);
+                break;
+            default:  // Automatically determine the array or object Support only two-dimensional
+                $condition  =   preg_replace('/\$(\w+)\.(\w+)\s/is','(is_array($\\1)?$\\1["\\2"]:$\\1->\\2) ',$condition);
+        }
+        if(false !== strpos($condition, '$Sen'))
+            $condition      =   preg_replace('/(\$Sen.*?)\s/ies',"\$this->parseSenVar('\\1');" , $condition);        
+        return $condition;
+    }
+
+    /**
+     * Automatic recognition of construction variables
+     * @access public
+     * @param string $name Variable description
+     * @return string
+     */
+    public function autoBuildVar($name) {
+        if('Sen.' == substr($name,0,4)){
+            // Special variable
+            return $this->parseSenVar($name);
+        }elseif(strpos($name,'.')) {
+            $vars = explode('.',$name);
+            $var  =  array_shift($vars);
+            switch(strtolower(C('TMPL_VAR_IDENTIFY'))) {
+                case 'array': // Identified as an array
+                    $name = '$'.$var;
+                    foreach ($vars as $key=>$val){
+                        if(0===strpos($val,'$')) {
+                            $name .= '["{'.$val.'}"]';
+                        }else{
+                            $name .= '["'.$val.'"]';
+                        }
+                    }
+                    break;
+                case 'obj':  // Identifying the object
+                    $name = '$'.$var;
+                    foreach ($vars as $key=>$val)
+                        $name .= '->'.$val;
+                    break;
+                default:  // Automatically determine the array or object Support only two-dimensional
+                    $name = 'is_array($'.$var.')?$'.$var.'["'.$vars[0].'"]:$'.$var.'->'.$vars[0];
+            }
+        }elseif(strpos($name,':')){
+            // Additional object Support
+            $name   =   '$'.str_replace(':','->',$name);
+        }elseif(!defined($name)) {
+            $name = '$'.$name;
+        }
+        return $name;
+    }
+
+    /**
+     * For Tag attributes inside the special template variable resolution
+     * Format Sen. Heading variable is a special template variables
+     * @access public
+     * @param string $varStr  Variable string
+     * @return string
+     */
+    public function parseSenVar($varStr){
+        $vars       = explode('.',$varStr);
+        $vars[1]    = strtoupper(trim($vars[1]));
+        $parseStr   = '';
+        if(count($vars)>=3){
+            $vars[2] = trim($vars[2]);
+            switch($vars[1]){
+                case 'SERVER':    $parseStr = '$_SERVER[\''.$vars[2].'\']';break;
+                case 'GET':         $parseStr = '$_GET[\''.$vars[2].'\']';break;
+                case 'POST':       $parseStr = '$_POST[\''.$vars[2].'\']';break;
+                case 'COOKIE':
+                    if(isset($vars[3])) {
+                        $parseStr = '$_COOKIE[\''.$vars[2].'\'][\''.$vars[3].'\']';
+                    }elseif(C('COOKIE_PREFIX')){
+                        $parseStr = '$_COOKIE[\''.C('COOKIE_PREFIX').$vars[2].'\']';
+                    }else{
+                        $parseStr = '$_COOKIE[\''.$vars[2].'\']';
+                    }
+                    break;
+                case 'SESSION':
+                    if(isset($vars[3])) {
+                        $parseStr = '$_SESSION[\''.$vars[2].'\'][\''.$vars[3].'\']';
+                    }elseif(C('SESSION_PREFIX')){
+                        $parseStr = '$_SESSION[\''.C('SESSION_PREFIX').'\'][\''.$vars[2].'\']';
+                    }else{
+                        $parseStr = '$_SESSION[\''.$vars[2].'\']';
+                    }
+                    break;
+                case 'ENV':         $parseStr = '$_ENV[\''.$vars[2].'\']';break;
+                case 'REQUEST':  $parseStr = '$_REQUEST[\''.$vars[2].'\']';break;
+                case 'CONST':     $parseStr = strtoupper($vars[2]);break;
+                case 'LANG':       $parseStr = 'L("'.$vars[2].'")';break;
+                case 'CONFIG':    $parseStr = 'C("'.$vars[2].'")';break;
+            }
+        }else if(count($vars)==2){
+            switch($vars[1]){
+                case 'NOW':       $parseStr = "date('Y-m-d g:i a',time())";break;
+                case 'VERSION':  $parseStr = 'SEN_VERSION';break;
+                case 'TEMPLATE':$parseStr = 'C("TEMPLATE_NAME")';break;
+                case 'LDELIM':    $parseStr = 'C("TMPL_L_DELIM")';break;
+                case 'RDELIM':    $parseStr = 'C("TMPL_R_DELIM")';break;
+                default:  if(defined($vars[1])) $parseStr = $vars[1];
+            }
+        }
+        return $parseStr;
+    }
+
+    // Get Tag definition
+    public function getTags(){
+        return $this->tags;
+    }
+}

+ 123 - 0
php-senthot/Senthot/README.txt

@@ -0,0 +1,123 @@
+
+	Senthot [ DEVELOPED BY ME ]
+	Thank you for using the Senthot Framework	:)
+
++---------------------------------------------------------------
+| Version : Senthot 2.2.2 Release 2013/8/17                 
++---------------------------------------------------------------
+| Copyright(c) 2005-2013 http://senthot.com All rights reserved.
++---------------------------------------------------------------
+
+[ Introduction ]
+Senthot is a free PHP Framework, opensource, as a framework development PHP oriented simple object, 
+easy and fast for developing Web application and also simplify the developing entreprise application.
+
+Principle Architecture and Design: (Slim. Small. Smart. Slick. and Secure.)
+Architecture Senthot Framework developed following the principle simple design and practical, 
+resulting core system smaller, but has an ability agile, and with the simplify expected to easily on monitor the security, 
+both in all injection or SSX, because security must be keep still persued.
+
+Senthot since it's inception has been adhering to the principles of simple and practical design, while maintaining the excellent
+and the simplicity of the code at the same time, also focused on ease of use. And has many original features and characteristics,
+constantly in ease of use, Scalebility and performance will always enhanced and optimalized to make sure stability in developing 
+application level portal dan commercial.
+
+After 8 years of accumulation and refactoring, 2.* version in terms of customization and extension at the bottom of the frame is complete,
+application scope of development and needs to be expanded to suit different levels of developer
+demand. And introduce a new CBD (Core+Behavior+Driven) schema Mode, designed to create a framework for DIY
+and AOP programming experience, so that Senthot can in different ways to quickly meet the needs of projects and applications,
+and the official introduction of Cloud, REST and Mongo support.
+
+[ Agreement ]
+Senthot follow the Apache2 open source licenses issued, meaning that you can use for free Senthot,
+even allows commercial closed-source application using your Senthot publishing.
+Specific reference to LICENSE.txt contents 
+
+[ Features ]
+CBD framework: Senthot2.2 version introduces brand new CBD (core+Behavior+Driven) schema Mode,
+Build DIY custom at the bottom and the framework class AOP programming experience. Take advantage of this new feature, developers can
+easy Mode Expansion for their own tailored for your own or enterprise development framework.
+Compile mechanism: original project compilation mechanisms, effectively reduce the performance overhead of OOP development file loading.
+Improved project compilation mechanisms can Support compile-load files directly as a portal, and constant support
+external load, conducive to product release.
+
+Class library import: based on imported namespaces and class library class library class library import looks more
+add simple and clear, but also Support automatic loading and import alias. In order to facilitate cross-platform porting project,
+Loaded System can also check the size of the file to write.
+
+Routing and URL: System support normal Mode, and PATHINFOMode, and REWRITEMode and Compatibility Mode
+URL, Support different deployment server and the Mode of operation, with the URL routing features, let your heart
+SEO optimized URL address and construction needs. Support flexible rules route road
+and redirect Routing Support, developers are more convenient and flexible URL optimization experience.
+
+Debug Mode: Debug Mode can provide the framework easy to Use for different stages of the development process, including development,
+testing and demonstrations of any kind, including the requirements of different Mode can be configured independent of the project profile is applied.
+Just a small sacrifice will be able to meet the performance of debug logging and analysis of needs in the development process, and to ensure that future
+deployed smoothly once switch to the deployment Mode you can quickly increase performance.
+
+ORM : Simple and lightweight ORM implementation, combined with simple CURD and ARMode, development efficiency are everywhere.
+
+Database Support including Mysql, Sqlite, Pgsql, Oracle, SqlServer, Mongo and other databases,
+and built in Distributed databases and separate functions to read and write Support. System support multiple database connections and dynamic switch
+mechanism, a cutting edge enterprise development, cross-database applications and DistributedSupport worry-free.
+
+Query language: built-in rich query mechanism, including combination queries, fast, complex queries, the query interval
+positioning query, statistical inquiries, queries, multiple-table query, subquery, dynamic and native queries, you
+simple and efficient data queries.
+
+Dynamic model: there is no need to create any model that corresponds to the class easily CURD operation is completed, Support a variety of models
+dynamic switching, give you a data manipulation is very nice and the best possible experience.
+
+Extended model: provides a rich extension model, including the following: Serialization Support, read-only field, text field,
+delayed write, optimistic locking, data tables and advanced features such as advanced modeling; easy to dynamically create
+database view models Support correlation model of associated actions; SupportMongo Mongo of the database model
+and so on, are easy to use.
+
+Group modules: don't worry about the big project Division of coordination and deployment issues, 
+grouped to help you overcome the challenges across projects,
+second-level domain name of the Support Group the deployment Support.
+
+Template engine: System built in a remarkable piece of compiled template engine for XML-based, Support two types of
+template tags, integration of Smarty and JSP tag library, and a built-in layout templates and tag library extension
+support. Through drive can also be Support Smarty, TemplateLite, others, such as Smart
+Third-party templating engine.
+
+AJAXSupport: built-in methods and client-independent AJAX data returned, SupportJSON, EVAL and XML types
+return to the client, and can be extended to return the data format, System does not bind any AJAX libraries, free
+familiarize yourself with the operation of the AJAX Library.
+
+Cloud engines Support: provides a powerful platform and Cloud Platform Support, "across" and "smoothness", localized Support
+development and debugging, and deploying switch lets you easily transition to build a new development experience.
+
+RESTFul support:RESTMode provides RESTFul support, for you to design and build a new URL access experience,
+also provides Support for application interfaces.
+
+Multiple language Support:System support language pack features, projects and groups can have a separate language packs and can be
+automatic detection of browser language is automatically loaded the corresponding language pack.
+
+Mode Expansion: in addition to the standard Mode, it also provides the AMF, PHPRpc, Lite, Thin and CliMode Expansion.
+For different levels of core provides the best application development framework, you can also customize Mode Expansion.
+
+Automatically verify and complete: auto complete form data validation and filtering, the new version of IP is added validity and validation testing
+more authentication methods such as card, combined with auto-completion can build secure data objects.
+
+Field type detection: the System will automatically cache the field type and field information, Support illegal field filters and fields classes
+type casting to ensure that writes data to and query the safer.
+
+Caching: System support include file method, APC, Db, Memcache, Shmop, and Sqlite, and Redis and the
+Eaccelerator and Xcache cache type, as well as customizable static caching rules and
+provides a quick way to access operations.
+
+Extension mechanism: System support including Mode Expansion, Behavior extension, Library Expansion, Drive Expansion, Model extensions, 
+controller Powerful and flexible extension, Extension, Widget extension mechanism, so that you will no longer be limited to the core under
+and at a loss, free DIY your own framework and extend the application, meet the needs of enterprise in the development of a more complex project. 
+
+[ Requirement ]
+Senthot 2.2 requires PHP5.2.0 or later support. 
+
+[ Install ]
+Senthot do not need to install, download the core Senthot package or after full version, copy the unzipped directory to
+or the WEB directory of your WEB server. 
+
+[ Support ]
+More content and support, please visit Senthot Official Website http://senthot.com/

+ 29 - 0
php-senthot/Senthot/Senthot.php

@@ -0,0 +1,29 @@
+<?php
+// +--------------------------------------------------------------------------
+// | Senthot [ DEVELOPED BY ME ]
+// +--------------------------------------------------------------------------
+// | Copyright (c) 2005-2013 http://www.senthot.com All rights reserved.
+// | License ( http://www.apache.org/licenses/LICENSE-2.0 )
+// | Author: ms134n ( [email protected] )
+// +--------------------------------------------------------------------------
+
+// Senthot Import documents
+//Recording start running time
+$GLOBALS['_beginTime'] = microtime(TRUE);
+// Record the initial memory use
+define('MEMORY_LIMIT_ON',function_exists('memory_get_usage'));
+if(MEMORY_LIMIT_ON) $GLOBALS['_startUseMems'] = memory_get_usage();
+defined('APP_PATH') 	or define('APP_PATH', dirname($_SERVER['SCRIPT_FILENAME']).'/');
+defined('RUNTIME_PATH') or define('RUNTIME_PATH',APP_PATH.'Runtime/');
+defined('APP_DEBUG') 	or define('APP_DEBUG',false); // Whether Debug Mode
+$runtime = defined('MODE_NAME')?'~'.strtolower(MODE_NAME).'_runtime.php':'~runtime.php';
+defined('RUNTIME_FILE') or define('RUNTIME_FILE',RUNTIME_PATH.$runtime);
+if(!APP_DEBUG && is_file(RUNTIME_FILE)) {
+    // Deployment Mode to run the cache directly load
+    require RUNTIME_FILE;
+}else{
+    // System directory definition
+    defined('SEN_PATH') or define('SEN_PATH', dirname(__FILE__).'/');
+    // Loaded runtime files
+    require SEN_PATH.'Common/runtime.php';
+}

+ 7 - 0
php-senthot/Senthot/Tpl/default_index.tpl

@@ -0,0 +1,7 @@
+<?php
+// This class automatically generated by the System, for testing purposes
+class IndexAction extends Action {
+    public function index(){
+	$this->show('<style type="text/css">*{ padding: 0; margin: 0; } div{ padding: 4px 48px;} body{ background: #fff; font-family: "Tahoma"; color: #333;} h1{ font-size: 100px; font-weight: normal; margin-bottom: 12px; } p{ line-height: 1.8em; font-size: 36px }</style><div style="padding: 24px 48px;"> <h1>:)</h1><p>Welcome <b>Senthot</b>!</p></div>','utf-8');
+    }
+}

+ 44 - 0
php-senthot/Senthot/Tpl/dispatch_jump.tpl

@@ -0,0 +1,44 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<title>Jumplines</title>
+<style type="text/css">
+*{ padding: 0; margin: 0; }
+body{ background: #fff; font-family: 'Arial'; color: #333; font-size: 16px; }
+.system-message{ padding: 24px 48px; }
+.system-message h1{ font-size: 100px; font-weight: normal; line-height: 120px; margin-bottom: 12px; }
+.system-message .jump{ padding-top: 10px}
+.system-message .jump a{ color: #333;}
+.system-message .success,.system-message .error{ line-height: 1.8em; font-size: 36px }
+.system-message .detail{ font-size: 12px; line-height: 20px; margin-top: 12px; display:none}
+</style>
+</head>
+<body>
+<div class="system-message">
+<present name="message">
+<h1>:)</h1>
+<p class="success"><?php echo($message); ?></p>
+<else/>
+<h1>:(</h1>
+<p class="error"><?php echo($error); ?></p>
+</present>
+<p class="detail"></p>
+<p class="jump">
+Pages automatically <a id="href" href="<?php echo($jumpUrl); ?>">Jump</a> Waiting time : <b id="wait"><?php echo($waitSecond); ?></b>
+</p>
+</div>
+<script type="text/javascript">
+(function(){
+var wait = document.getElementById('wait'),href = document.getElementById('href').href;
+var interval = setInterval(function(){
+	var time = --wait.innerHTML;
+	if(time == 0) {
+		location.href = href;
+		clearInterval(interval);
+	};
+}, 1000);
+})();
+</script>
+</body>
+</html>

+ 67 - 0
php-senthot/Senthot/Tpl/page_trace.tpl

@@ -0,0 +1,67 @@
+<div id="sen_page_trace" style="position: fixed;bottom:0;right:0;font-size:14px;width:100%;z-index: 999999;color: #000;text-align:left;font-family:'Arial';">
+<div id="sen_page_trace_tab" style="display: none;background:white;margin:0;height: 250px;">
+<div id="sen_page_trace_tab_tit" style="height:30px;padding: 6px 12px 0;border-bottom:1px solid #ececec;border-top:1px solid #ececec;font-size:16px">
+	<?php foreach($trace as $key => $value){ ?>
+    <span style="color:#000;padding-right:12px;height:30px;line-height: 30px;display:inline-block;margin-right:3px;cursor: pointer;font-weight:700"><?php echo $key ?></span>
+    <?php } ?>
+</div>
+<div id="sen_page_trace_tab_cont" style="overflow:auto;height:212px;padding: 0; line-height: 24px">
+		<?php foreach($trace as $info) { ?>
+    <div style="display:none;">
+    <ol style="padding: 0; margin:0">
+	<?php 
+	if(is_array($info)){
+		foreach ($info as $k=>$val){
+		echo '<li style="border-bottom:1px solid #EEE;font-size:14px;padding:0 12px">' . (is_numeric($k) ? '' : $k.' : ') . htmlentities($val,ENT_COMPAT,'utf-8') .'</li>';
+	    }
+	}
+    ?>
+    </ol>
+    </div>
+    <?php } ?>
+</div>
+</div>
+<div id="sen_page_trace_close" style="display:none;text-align:right;height:15px;position:absolute;top:10px;right:12px;cursor: pointer;"><img style="vertical-align:top;" src="data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAA8AAAAPAgMAAABGuH3ZAAAACVBMVEUAAAADAwP///9QXGhCAAAANUlEQVR4XiWMSQoAIAwD81zpi6RnKXZeaYmXIWRTwFHCVsFS01dEDTIHFYOLlb2fuueFt355by4lFTSvayUAAAAASUVORK5CYII=" /></div>
+</div>
+<div id="sen_page_trace_open" style="height:30px;float:right;text-align: right;overflow:hidden;position:fixed;bottom:0;right:0;color:#000;line-height:30px;cursor:pointer;"><div style="background:#232323;color:#FFF;padding:0 6px;float:right;line-height:30px;font-size:14px"><?php echo G('beginTime','viewEndTime').'s ';?></div><img width="30" style="" title="ShowPageTrace" src="data:image/png;base64,<?php echo App::logo() ?>"></div>
+<script type="text/javascript">
+(function(){
+var tab_tit  = document.getElementById('sen_page_trace_tab_tit').getElementsByTagName('span');
+var tab_cont = document.getElementById('sen_page_trace_tab_cont').getElementsByTagName('div');
+var open     = document.getElementById('sen_page_trace_open');
+var close    = document.getElementById('sen_page_trace_close').childNodes[0];
+var trace    = document.getElementById('sen_page_trace_tab');
+var cookie   = document.cookie.match(/senthot_show_page_trace=(\d\|\d)/);
+var history  = (cookie && typeof cookie[1] != 'undefined' && cookie[1].split('|')) || [0,0];
+open.onclick = function(){
+	trace.style.display = 'block';
+	this.style.display = 'none';
+	close.parentNode.style.display = 'block';
+	history[0] = 1;
+	document.cookie = 'senthot_show_page_trace='+history.join('|')
+}
+close.onclick = function(){
+	trace.style.display = 'none';
+this.parentNode.style.display = 'none';
+	open.style.display = 'block';
+	history[0] = 0;
+	document.cookie = 'senthot_show_page_trace='+history.join('|')
+}
+for(var i = 0; i < tab_tit.length; i++){
+	tab_tit[i].onclick = (function(i){
+		return function(){
+			for(var j = 0; j < tab_cont.length; j++){
+				tab_cont[j].style.display = 'none';
+				tab_tit[j].style.color = '#999';
+			}
+			tab_cont[i].style.display = 'block';
+			tab_tit[i].style.color = '#000';
+			history[1] = i;
+			document.cookie = 'senthot_show_page_trace='+history.join('|')
+		}
+	})(i)
+}
+parseInt(history[0]) && open.click();
+tab_tit[history[1]].click();
+})();
+</script>

+ 55 - 0
php-senthot/Senthot/Tpl/sen_exception.tpl

@@ -0,0 +1,55 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml"><head>
+<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
+<title>System error occurred</title>
+<style type="text/css">
+*{ padding: 0; margin: 0; }
+html{ overflow-y: scroll; }
+body{ background: #fff; font-family: 'Arial'; color: #333; font-size: 16px; }
+img{ border: 0; }
+sup{ font-size: 12px;}
+.error{ padding: 24px 48px; }
+.face, h1 {font-family: 'Tahoma';}
+.face{ font-size: 100px; font-weight: normal; line-height: 120px; margin-bottom: 12px; }
+h1{ font-size: 32px; line-height: 48px; }
+.error .content{ padding-top: 10px}
+.error .info{ margin-bottom: 12px; }
+.error .info .title{ margin-bottom: 3px; }
+.error .info .title h3{ color: #000; font-weight: 700; font-size: 16px; }
+.error .info .text{ line-height: 24px; }
+.copyright{ padding: 12px 48px; color: #999; }
+.copyright a{ color: #000; text-decoration: none; }
+</style>
+</head>
+<body>
+<div class="error">
+<p class="face">:(</p>
+<h1><?php echo strip_tags($e['message']);?></h1>
+<div class="content">
+<?php if(isset($e['file'])) {?>
+	<div class="info">
+		<div class="title">
+			<h3>Wrong location</h3>
+		</div>
+		<div class="text">
+			<p>FILE: <?php echo $e['file'] ;?> &#12288;LINE: <?php echo $e['line'];?></p>
+		</div>
+	</div>
+<?php }?>
+<?php if(isset($e['trace'])) {?>
+	<div class="info">
+		<div class="title">
+			<h3>TRACE</h3>
+		</div>
+		<div class="text">
+			<p><?php echo nl2br($e['trace']);?></p>
+		</div>
+	</div>
+<?php }?>
+</div>
+</div>
+<div class="copyright">
+<p><a title="Official Website" href="http://www.senthot.com">Senthot</a> <sup><?php echo SEN_VERSION ?></sup> { Slim. Small. Smart. Slick. and Secure. }</p>
+</div>
+</body>
+</html>

BIN
php-senthot/Senthot/logo.png


+ 0 - 0
php-senthot/__init__.py


+ 6 - 0
php-senthot/app/.htaccess

@@ -0,0 +1,6 @@
+<IfModule mod_rewrite.c>
+RewriteEngine on
+RewriteCond %{REQUEST_FILENAME} !-d
+RewriteCond %{REQUEST_FILENAME} !-f
+RewriteRule ^(.*)$ index.php/$1 [QSA,PT,L]
+</IfModule>

+ 12 - 0
php-senthot/app/Conf/config.php

@@ -0,0 +1,12 @@
+<?php
+return array(
+   //'Configuration item'=>'Configuration values'
+   'DB_TYPE' => 'mysql', // tipe database
+   'DB_HOST' => 'localhost', // alamat server
+   'DB_NAME' => 'hello_world', // nama database
+   'DB_USER' => 'benchmarkdbuser', // nama pengguna
+   'DB_PWD'  => 'benchmarkdbpass', // password
+   'DB_PORT' => 3306, // port
+   'DB_PREFIX' => '', // prefix
+);
+?>

+ 36 - 0
php-senthot/app/Lib/Action/BenchAction.class.php

@@ -0,0 +1,36 @@
+<?php
+// This class automatically generated by the System, for testing purposes
+class BenchAction extends Action {
+
+   public function rawjson() {
+      header('Content-type: application/json');
+      die(json_encode(array('message' => 'Hello World!')));
+   }
+   public function rawdb() {
+      $query_count = (int) $this->_request('queries');
+
+      if (0 >= $query_count) {
+         $query_count = 1;
+      } elseif (500 < $query_count) {
+         $query_count = 500;
+      }
+
+      $arr = array();
+      $World = M('World');
+
+      while (0 < $query_count--) {
+         $id = mt_rand(1, 10000);
+         $d = $World->find($id);
+         $arr[] = $d;
+      }
+
+      header('Content-type: application/json');
+      die(json_encode($arr));
+
+   }
+   public function rawfortunes() {
+      $Fortunes = M('Fortune');
+      $this->data = $Fortunes->select();
+      $this->display();
+   }
+}

+ 9 - 0
php-senthot/app/Lib/Action/IndexAction.class.php

@@ -0,0 +1,9 @@
+<?php
+class IndexAction extends Action {
+   public function index() {
+      die ( 'index' );
+   }
+   public function no() {
+     die('no');
+   }
+}

+ 14 - 0
php-senthot/app/Tpl/bench/rawfortunes.html

@@ -0,0 +1,14 @@
+<!DOCTYPE html><html><head><title>Fortunes</title></head><body><table>
+  <tr>
+    <th>id</th>
+    <th>message</th>
+  </tr>
+  <volist name="data" id="vo">
+    <tr>
+      <td>{$vo.id|htmlspecialchars}</td>
+      <td>{$vo.message|htmlspecialchars}</td>
+    </tr>
+   </volist>
+  </table></body></html>
+
+

+ 3 - 0
php-senthot/app/index.php

@@ -0,0 +1,3 @@
+<?php
+define('APP_DEBUG', false); // Mengaktifkan mode debug
+require( "../Senthot/Senthot.php"); //Memanggil Framework

+ 14 - 0
php-senthot/benchmark_config

@@ -0,0 +1,14 @@
+{
+  "framework": "senthot",
+  "tests": [{
+    "raw": {
+      "setup_file": "setup",
+      "json_url": "/bench/rawjson",
+      "db_url": "/bench/rawdb",
+      "query_url": "/bench/rawdb?queries=",
+      "fortune_url": "/bench/rawfortunes",
+      "port": 80,
+      "sort": 200
+    }
+  }]
+}

+ 43 - 0
php-senthot/deploy/nginx.conf

@@ -0,0 +1,43 @@
+worker_processes  8;
+
+events {
+    worker_connections  1024;
+}
+
+http {
+    include       /usr/local/nginx/conf/mime.types;
+    default_type  application/octet-stream;
+    sendfile      on;
+    keepalive_timeout  65;
+
+    upstream fastcgi_backend {
+        server 127.0.0.1:9001;
+        keepalive 32;
+    }
+
+    server {
+        listen       80;
+        server_name  localhost;
+
+        root /home/ubuntu/FrameworkBenchmarks/php-senthot/app/;
+        index  index.php;
+
+        location / {
+            try_files $uri /index.php?$args;
+
+            if (-f $request_filename) {
+                expires max;
+                break;
+            }
+        }
+
+        location ~ \.php$ {
+            try_files $uri =404;
+            fastcgi_pass   fastcgi_backend;
+            fastcgi_keep_conn on;
+            fastcgi_index  index.php;
+            include        /usr/local/nginx/conf/fastcgi_params;
+            fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
+        }
+    }
+}

+ 27 - 0
php-senthot/setup.py

@@ -0,0 +1,27 @@
+import subprocess
+import sys
+import setup_util
+from os.path import expanduser
+
+home = expanduser("~")
+
+def start(args):
+  setup_util.replace_text("php-senthot/app/conf/application.ini", "'DB_HOST' => 'localhost'", "'DB_HOST' => '" + args.database_host +"'")
+  setup_util.replace_text("php-senthot/deploy/nginx.conf", "root .*\/FrameworkBenchmarks", "root " + home + "/FrameworkBenchmarks")
+
+  try:
+    subprocess.check_call("sudo chown -R www-data:www-data php-senthot", shell=True)
+    subprocess.check_call("sudo php-fpm --fpm-config config/php-fpm.conf -g " + home + "/FrameworkBenchmarks/php-senthot/deploy/php-fpm.pid", shell=True)
+    subprocess.check_call("sudo /usr/local/nginx/sbin/nginx -c " + home + "/FrameworkBenchmarks/php-senthot/deploy/nginx.conf", shell=True)
+    return 0
+  except subprocess.CalledProcessError:
+    return 1
+
+def stop():
+  try:
+    subprocess.call("sudo /usr/local/nginx/sbin/nginx -s stop", shell=True)
+    subprocess.call("sudo kill -QUIT $( cat php-senthot/deploy/php-fpm.pid )", shell=True)
+    subprocess.check_call("sudo chown -R $USER:$USER php-senthot", shell=True)
+    return 0
+  except subprocess.CalledProcessError:
+    return 1