├── .gitignore ├── Example ├── .htaccess ├── Application │ ├── Common │ │ ├── Common │ │ │ └── index.html │ │ ├── Conf │ │ │ ├── config.php │ │ │ └── index.html │ │ └── index.html │ ├── Home │ │ ├── Common │ │ │ └── index.html │ │ ├── Conf │ │ │ ├── config.php │ │ │ └── index.html │ │ ├── Controller │ │ │ ├── IndexController.class.php │ │ │ ├── OtherController.class.php │ │ │ └── index.html │ │ ├── Model │ │ │ └── index.html │ │ ├── View │ │ │ └── index.html │ │ └── index.html │ ├── README.md │ ├── Test │ │ ├── Conf │ │ │ ├── config.php │ │ │ └── index.html │ │ ├── Controller │ │ │ ├── IndexController.class.php │ │ │ ├── OtherController.class.php │ │ │ ├── aa.php │ │ │ └── index.html │ │ ├── Model │ │ │ └── index.html │ │ ├── View │ │ │ └── index.html │ │ └── index.html │ └── index.html ├── Public │ └── README.md ├── ThinkPHP │ ├── Common │ │ └── functions.php │ ├── Conf │ │ ├── convention.php │ │ └── debug.php │ ├── LICENSE.txt │ ├── Lang │ │ ├── en-us.php │ │ ├── pt-br.php │ │ ├── zh-cn.php │ │ └── zh-tw.php │ ├── Library │ │ ├── Behavior │ │ │ ├── BuildLiteBehavior.class.php │ │ │ ├── CheckLangBehavior.class.php │ │ │ ├── ContentReplaceBehavior.class.php │ │ │ ├── ParseTemplateBehavior.class.php │ │ │ ├── ReadHtmlCacheBehavior.class.php │ │ │ ├── ShowPageTraceBehavior.class.php │ │ │ ├── ShowRuntimeBehavior.class.php │ │ │ ├── TokenBuildBehavior.class.php │ │ │ └── WriteHtmlCacheBehavior.class.php │ │ ├── Think │ │ │ ├── App.class.php │ │ │ ├── Build.class.php │ │ │ ├── Cache.class.php │ │ │ ├── Cache │ │ │ │ └── Driver │ │ │ │ │ ├── File.class.php │ │ │ │ │ └── Memcachesae.class.php │ │ │ ├── Controller.class.php │ │ │ ├── Db.class.php │ │ │ ├── Db │ │ │ │ ├── Driver.class.php │ │ │ │ ├── Driver │ │ │ │ │ └── Mysql.class.php │ │ │ │ └── Lite.class.php │ │ │ ├── Dispatcher.class.php │ │ │ ├── Exception.class.php │ │ │ ├── Hook.class.php │ │ │ ├── Log.class.php │ │ │ ├── Log │ │ │ │ └── Driver │ │ │ │ │ ├── File.class.php │ │ │ │ │ └── Sae.class.php │ │ │ ├── Model.class.php │ │ │ ├── Route.class.php │ │ │ ├── Storage.class.php │ │ │ ├── Storage │ │ │ │ └── Driver │ │ │ │ │ ├── File.class.php │ │ │ │ │ └── Sae.class.php │ │ │ ├── Template.class.php │ │ │ ├── Template │ │ │ │ ├── TagLib.class.php │ │ │ │ └── TagLib │ │ │ │ │ └── Cx.class.php │ │ │ ├── Think.class.php │ │ │ └── View.class.php │ │ └── Vendor │ │ │ └── README.txt │ ├── Mode │ │ ├── Sae │ │ │ └── convention.php │ │ ├── common.php │ │ └── sae.php │ ├── ThinkPHP.php │ ├── Tpl │ │ ├── dispatch_jump.tpl │ │ ├── page_trace.tpl │ │ └── think_exception.tpl │ └── logo.png └── index.php ├── README.md ├── composer.json ├── composer.lock ├── result-screenshot.png ├── src └── T │ └── UnitTest.php └── vendor ├── autoload.php └── composer ├── ClassLoader.php ├── LICENSE ├── autoload_classmap.php ├── autoload_namespaces.php ├── autoload_psr4.php ├── autoload_real.php ├── autoload_static.php └── installed.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear on external disk 35 | .Spotlight-V100 36 | .Trashes 37 | 38 | # Directories potentially created on remote AFP share 39 | .AppleDB 40 | .AppleDesktop 41 | Network Trash Folder 42 | Temporary Items 43 | .apdisk 44 | 45 | # PHPStorm ide create files 46 | *.idea 47 | Runtime -------------------------------------------------------------------------------- /Example/.htaccess: -------------------------------------------------------------------------------- 1 | 2 | Options +FollowSymlinks 3 | RewriteEngine On 4 | 5 | RewriteCond %{REQUEST_FILENAME} !-d 6 | RewriteCond %{REQUEST_FILENAME} !-f 7 | RewriteRule ^(.*)$ index.php/$1 [QSA,PT,L] 8 | -------------------------------------------------------------------------------- /Example/Application/Common/Common/index.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Example/Application/Common/Conf/config.php: -------------------------------------------------------------------------------- 1 | '配置值' 4 | ); -------------------------------------------------------------------------------- /Example/Application/Common/Conf/index.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Example/Application/Common/index.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Example/Application/Home/Common/index.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Example/Application/Home/Conf/config.php: -------------------------------------------------------------------------------- 1 | '配置值' 4 | ); -------------------------------------------------------------------------------- /Example/Application/Home/Conf/index.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Example/Application/Home/Controller/IndexController.class.php: -------------------------------------------------------------------------------- 1 | show('

:)

欢迎使用 ThinkPHP


版本 V{$Think.version}
','utf-8'); 7 | } 8 | 9 | public function getTrue(){ 10 | return true; 11 | } 12 | 13 | public function getFalse(){ 14 | return false; 15 | } 16 | 17 | public function getEmptyArray(){ 18 | return array(); 19 | } 20 | 21 | public function getUnEmptyArray(){ 22 | return array(1,2); 23 | } 24 | 25 | } -------------------------------------------------------------------------------- /Example/Application/Home/Controller/OtherController.class.php: -------------------------------------------------------------------------------- 1 | '配置值' 4 | ); -------------------------------------------------------------------------------- /Example/Application/Test/Conf/index.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Example/Application/Test/Controller/IndexController.class.php: -------------------------------------------------------------------------------- 1 | run(true); 10 | } 11 | 12 | function index2(){ 13 | //通过设置测试类的方式执行测试 14 | $this->setController( array(__CLASS__) ); 15 | $this->run(); 16 | } 17 | 18 | function testAssert(){ 19 | //设置一些测试变量 20 | $empty = 0; 21 | $notEmpty = 1; 22 | $emptyArray = array(); 23 | $array = array(1 , 'a'=>'a' ); 24 | $indexController = new IndexController(); 25 | $jsonString = '{"obj":"object"}'; 26 | $regex = '/^\{.+\}$/'; 27 | 28 | //测试断言方法 29 | $this->assertArrayHasKey( 'a' , $array , 'Some Message!'); 30 | $this->assertNotArrayHasKey('b' , $array , 'Some Message!'); 31 | 32 | $this->assertCount(2 , $array); 33 | $this->assertNotCount(3 , $array); 34 | 35 | $this->assertEmpty($empty); 36 | $this->assertEmpty($emptyArray); 37 | $this->assertNotEmpty($array); 38 | $this->assertNotEmpty($notEmpty); 39 | 40 | $this->assertEquals($empty , false); 41 | $this->assertNotEquals($emptyArray , $array); 42 | 43 | $this->assertSame( $empty , $empty); 44 | $this->assertNotSame($empty , '0'); 45 | 46 | $this->assertTrue(true); 47 | $this->assertFalse(false); 48 | 49 | $this->assertFileExists(__FILE__); 50 | $this->assertNotFileExists(__FILE__ . 'XXX'); 51 | 52 | $this->assertGreater( 0 , $notEmpty); 53 | $this->assertGreaterOrEquals( 0 , $empty); 54 | $this->assertLess( 1 , $empty); 55 | $this->assertLessOrEquals( 1 , $notEmpty ); 56 | 57 | $this->assertInstanceOf(__CLASS__ , $indexController); 58 | $this->assertNotInstanceOf(__CLASS__.'XXX' , $indexController); 59 | 60 | $this->assertJson($jsonString ); 61 | $this->assertNotJson($jsonString."XXX"); 62 | 63 | $this->assertRegex( $regex , $jsonString); 64 | $this->assertNotRegex($regex , $jsonString."XXX" ); 65 | 66 | } 67 | 68 | function testHome_IndexController(){ 69 | $indexController = new \Home\Controller\IndexController(); 70 | $this->assertTrue( $indexController->getTrue() ); 71 | $this->assertFalse( $indexController->getFalse() ); 72 | $this->assertNotEmpty( $indexController->getUnEmptyArray() ); 73 | $this->assertEmpty( $indexController->getEmptyArray() ); 74 | } 75 | } -------------------------------------------------------------------------------- /Example/Application/Test/Controller/OtherController.class.php: -------------------------------------------------------------------------------- 1 | '1'), 10 | array('key'=>'2'), 11 | array('key'=>'3') 12 | ); 13 | $controller = new \Home\Controller\OtherController(); 14 | $this->assertSame( 6 , $controller->sum( $testArray , 'key' ) ); 15 | $this->assertSame( 0 , $controller->sum( array() , 'key' ) ); 16 | } 17 | 18 | function testF(){ 19 | $key = 'test'; 20 | $val = 'val'; 21 | 22 | $this->assertFalse( F($key) ); //读取$key 23 | $this->assertNull( F($key , $val) );//设置$key 24 | $this->assertSame( $val , F($key) ); //读取$key 25 | $this->assertTrue( F($key , null) );//删除$key 26 | $this->assertFalse( F($key) ); //读取$key 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Example/Application/Test/Controller/aa.php: -------------------------------------------------------------------------------- 1 | 10 | // +---------------------------------------------------------------------- 11 | 12 | /** 13 | * ThinkPHP惯例配置文件 14 | * 该文件请不要修改,如果要覆盖惯例配置的值,可在应用配置文件中设定和惯例不符的配置项 15 | * 配置名称大小写任意,系统会统一转换成小写 16 | * 所有配置参数都可以在生效前动态改变 17 | */ 18 | defined('THINK_PATH') or exit(); 19 | return array( 20 | /* 应用设定 */ 21 | 'APP_USE_NAMESPACE' => true, // 应用类库是否使用命名空间 22 | 'APP_SUB_DOMAIN_DEPLOY' => false, // 是否开启子域名部署 23 | 'APP_SUB_DOMAIN_RULES' => array(), // 子域名部署规则 24 | 'APP_DOMAIN_SUFFIX' => '', // 域名后缀 如果是com.cn net.cn 之类的后缀必须设置 25 | 'ACTION_SUFFIX' => '', // 操作方法后缀 26 | 'MULTI_MODULE' => true, // 是否允许多模块 如果为false 则必须设置 DEFAULT_MODULE 27 | 'MODULE_DENY_LIST' => array('Common','Runtime'), 28 | 'CONTROLLER_LEVEL' => 1, 29 | 'APP_AUTOLOAD_LAYER' => 'Controller,Model', // 自动加载的应用类库层 关闭APP_USE_NAMESPACE后有效 30 | 'APP_AUTOLOAD_PATH' => '', // 自动加载的路径 关闭APP_USE_NAMESPACE后有效 31 | 32 | /* Cookie设置 */ 33 | 'COOKIE_EXPIRE' => 0, // Cookie有效期 34 | 'COOKIE_DOMAIN' => '', // Cookie有效域名 35 | 'COOKIE_PATH' => '/', // Cookie路径 36 | 'COOKIE_PREFIX' => '', // Cookie前缀 避免冲突 37 | 'COOKIE_SECURE' => false, // Cookie安全传输 38 | 'COOKIE_HTTPONLY' => '', // Cookie httponly设置 39 | 40 | /* 默认设定 */ 41 | 'DEFAULT_M_LAYER' => 'Model', // 默认的模型层名称 42 | 'DEFAULT_C_LAYER' => 'Controller', // 默认的控制器层名称 43 | 'DEFAULT_V_LAYER' => 'View', // 默认的视图层名称 44 | 'DEFAULT_LANG' => 'zh-cn', // 默认语言 45 | 'DEFAULT_THEME' => '', // 默认模板主题名称 46 | 'DEFAULT_MODULE' => 'Home', // 默认模块 47 | 'DEFAULT_CONTROLLER' => 'Index', // 默认控制器名称 48 | 'DEFAULT_ACTION' => 'index', // 默认操作名称 49 | 'DEFAULT_CHARSET' => 'utf-8', // 默认输出编码 50 | 'DEFAULT_TIMEZONE' => 'PRC', // 默认时区 51 | 'DEFAULT_AJAX_RETURN' => 'JSON', // 默认AJAX 数据返回格式,可选JSON XML ... 52 | 'DEFAULT_JSONP_HANDLER' => 'jsonpReturn', // 默认JSONP格式返回的处理方法 53 | 'DEFAULT_FILTER' => 'htmlspecialchars', // 默认参数过滤方法 用于I函数... 54 | 55 | /* 数据库设置 */ 56 | 'DB_TYPE' => '', // 数据库类型 57 | 'DB_HOST' => '', // 服务器地址 58 | 'DB_NAME' => '', // 数据库名 59 | 'DB_USER' => '', // 用户名 60 | 'DB_PWD' => '', // 密码 61 | 'DB_PORT' => '', // 端口 62 | 'DB_PREFIX' => '', // 数据库表前缀 63 | 'DB_PARAMS' => array(), // 数据库连接参数 64 | 'DB_DEBUG' => TRUE, // 数据库调试模式 开启后可以记录SQL日志 65 | 'DB_FIELDS_CACHE' => true, // 启用字段缓存 66 | 'DB_CHARSET' => 'utf8', // 数据库编码默认采用utf8 67 | 'DB_DEPLOY_TYPE' => 0, // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器) 68 | 'DB_RW_SEPARATE' => false, // 数据库读写是否分离 主从式有效 69 | 'DB_MASTER_NUM' => 1, // 读写分离后 主服务器数量 70 | 'DB_SLAVE_NO' => '', // 指定从服务器序号 71 | 72 | /* 数据缓存设置 */ 73 | 'DATA_CACHE_TIME' => 0, // 数据缓存有效期 0表示永久缓存 74 | 'DATA_CACHE_COMPRESS' => false, // 数据缓存是否压缩缓存 75 | 'DATA_CACHE_CHECK' => false, // 数据缓存是否校验缓存 76 | 'DATA_CACHE_PREFIX' => '', // 缓存前缀 77 | 'DATA_CACHE_TYPE' => 'File', // 数据缓存类型,支持:File|Db|Apc|Memcache|Shmop|Sqlite|Xcache|Apachenote|Eaccelerator 78 | 'DATA_CACHE_PATH' => TEMP_PATH,// 缓存路径设置 (仅对File方式缓存有效) 79 | 'DATA_CACHE_KEY' => '', // 缓存文件KEY (仅对File方式缓存有效) 80 | 'DATA_CACHE_SUBDIR' => false, // 使用子目录缓存 (自动根据缓存标识的哈希创建子目录) 81 | 'DATA_PATH_LEVEL' => 1, // 子目录缓存级别 82 | 83 | /* 错误设置 */ 84 | 'ERROR_MESSAGE' => '页面错误!请稍后再试~',//错误显示信息,非调试模式有效 85 | 'ERROR_PAGE' => '', // 错误定向页面 86 | 'SHOW_ERROR_MSG' => false, // 显示错误信息 87 | 'TRACE_MAX_RECORD' => 100, // 每个级别的错误信息 最大记录数 88 | 89 | /* 日志设置 */ 90 | 'LOG_RECORD' => false, // 默认不记录日志 91 | 'LOG_TYPE' => 'File', // 日志记录类型 默认为文件方式 92 | 'LOG_LEVEL' => 'EMERG,ALERT,CRIT,ERR',// 允许记录的日志级别 93 | 'LOG_FILE_SIZE' => 2097152, // 日志文件大小限制 94 | 'LOG_EXCEPTION_RECORD' => false, // 是否记录异常信息日志 95 | 96 | /* SESSION设置 */ 97 | 'SESSION_AUTO_START' => true, // 是否自动开启Session 98 | 'SESSION_OPTIONS' => array(), // session 配置数组 支持type name id path expire domain 等参数 99 | 'SESSION_TYPE' => '', // session hander类型 默认无需设置 除非扩展了session hander驱动 100 | 'SESSION_PREFIX' => '', // session 前缀 101 | //'VAR_SESSION_ID' => 'session_id', //sessionID的提交变量 102 | 103 | /* 模板引擎设置 */ 104 | 'TMPL_CONTENT_TYPE' => 'text/html', // 默认模板输出类型 105 | 'TMPL_ACTION_ERROR' => THINK_PATH.'Tpl/dispatch_jump.tpl', // 默认错误跳转对应的模板文件 106 | 'TMPL_ACTION_SUCCESS' => THINK_PATH.'Tpl/dispatch_jump.tpl', // 默认成功跳转对应的模板文件 107 | 'TMPL_EXCEPTION_FILE' => THINK_PATH.'Tpl/think_exception.tpl',// 异常页面的模板文件 108 | 'TMPL_DETECT_THEME' => false, // 自动侦测模板主题 109 | 'TMPL_TEMPLATE_SUFFIX' => '.html', // 默认模板文件后缀 110 | 'TMPL_FILE_DEPR' => '/', //模板文件CONTROLLER_NAME与ACTION_NAME之间的分割符 111 | // 布局设置 112 | 'TMPL_ENGINE_TYPE' => 'Think', // 默认模板引擎 以下设置仅对使用Think模板引擎有效 113 | 'TMPL_CACHFILE_SUFFIX' => '.php', // 默认模板缓存后缀 114 | 'TMPL_DENY_FUNC_LIST' => 'echo,exit', // 模板引擎禁用函数 115 | 'TMPL_DENY_PHP' => false, // 默认模板引擎是否禁用PHP原生代码 116 | 'TMPL_L_DELIM' => '{', // 模板引擎普通标签开始标记 117 | 'TMPL_R_DELIM' => '}', // 模板引擎普通标签结束标记 118 | 'TMPL_VAR_IDENTIFY' => 'array', // 模板变量识别。留空自动判断,参数为'obj'则表示对象 119 | 'TMPL_STRIP_SPACE' => true, // 是否去除模板文件里面的html空格与换行 120 | 'TMPL_CACHE_ON' => true, // 是否开启模板编译缓存,设为false则每次都会重新编译 121 | 'TMPL_CACHE_PREFIX' => '', // 模板缓存前缀标识,可以动态改变 122 | 'TMPL_CACHE_TIME' => 0, // 模板缓存有效期 0 为永久,(以数字为值,单位:秒) 123 | 'TMPL_LAYOUT_ITEM' => '{__CONTENT__}', // 布局模板的内容替换标识 124 | 'LAYOUT_ON' => false, // 是否启用布局 125 | 'LAYOUT_NAME' => 'layout', // 当前布局名称 默认为layout 126 | 127 | // Think模板引擎标签库相关设定 128 | 'TAGLIB_BEGIN' => '<', // 标签库标签开始标记 129 | 'TAGLIB_END' => '>', // 标签库标签结束标记 130 | 'TAGLIB_LOAD' => true, // 是否使用内置标签库之外的其它标签库,默认自动检测 131 | 'TAGLIB_BUILD_IN' => 'cx', // 内置标签库名称(标签使用不必指定标签库名称),以逗号分隔 注意解析顺序 132 | 'TAGLIB_PRE_LOAD' => '', // 需要额外加载的标签库(须指定标签库名称),多个以逗号分隔 133 | 134 | /* URL设置 */ 135 | 'URL_CASE_INSENSITIVE' => true, // 默认false 表示URL区分大小写 true则表示不区分大小写 136 | 'URL_MODEL' => 1, // URL访问模式,可选参数0、1、2、3,代表以下四种模式: 137 | // 0 (普通模式); 1 (PATHINFO 模式); 2 (REWRITE 模式); 3 (兼容模式) 默认为PATHINFO 模式 138 | 'URL_PATHINFO_DEPR' => '/', // PATHINFO模式下,各参数之间的分割符号 139 | 'URL_PATHINFO_FETCH' => 'ORIG_PATH_INFO,REDIRECT_PATH_INFO,REDIRECT_URL', // 用于兼容判断PATH_INFO 参数的SERVER替代变量列表 140 | 'URL_REQUEST_URI' => 'REQUEST_URI', // 获取当前页面地址的系统变量 默认为REQUEST_URI 141 | 'URL_HTML_SUFFIX' => 'html', // URL伪静态后缀设置 142 | 'URL_DENY_SUFFIX' => 'ico|png|gif|jpg', // URL禁止访问的后缀设置 143 | 'URL_PARAMS_BIND' => true, // URL变量绑定到Action方法参数 144 | 'URL_PARAMS_BIND_TYPE' => 0, // URL变量绑定的类型 0 按变量名绑定 1 按变量顺序绑定 145 | 'URL_PARAMS_FILTER' => false, // URL变量绑定过滤 146 | 'URL_PARAMS_FILTER_TYPE'=> '', // URL变量绑定过滤方法 如果为空 调用DEFAULT_FILTER 147 | 'URL_ROUTER_ON' => false, // 是否开启URL路由 148 | 'URL_ROUTE_RULES' => array(), // 默认路由规则 针对模块 149 | 'URL_MAP_RULES' => array(), // URL映射定义规则 150 | 151 | /* 系统变量名称设置 */ 152 | 'VAR_MODULE' => 'm', // 默认模块获取变量 153 | 'VAR_ADDON' => 'addon', // 默认的插件控制器命名空间变量 154 | 'VAR_CONTROLLER' => 'c', // 默认控制器获取变量 155 | 'VAR_ACTION' => 'a', // 默认操作获取变量 156 | 'VAR_AJAX_SUBMIT' => 'ajax', // 默认的AJAX提交变量 157 | 'VAR_JSONP_HANDLER' => 'callback', 158 | 'VAR_PATHINFO' => 's', // 兼容模式PATHINFO获取变量例如 ?s=/module/action/id/1 后面的参数取决于URL_PATHINFO_DEPR 159 | 'VAR_TEMPLATE' => 't', // 默认模板切换变量 160 | 'VAR_AUTO_STRING' => false, // 输入变量是否自动强制转换为字符串 如果开启则数组变量需要手动传入变量修饰符获取变量 161 | 162 | 'HTTP_CACHE_CONTROL' => 'private', // 网页缓存控制 163 | 'CHECK_APP_DIR' => true, // 是否检查应用目录是否创建 164 | 'FILE_UPLOAD_TYPE' => 'Local', // 文件上传方式 165 | 'DATA_CRYPT_TYPE' => 'Think', // 数据加密方式 166 | 167 | ); 168 | -------------------------------------------------------------------------------- /Example/ThinkPHP/Conf/debug.php: -------------------------------------------------------------------------------- 1 | 10 | // +---------------------------------------------------------------------- 11 | 12 | /** 13 | * ThinkPHP 默认的调试模式配置文件 14 | */ 15 | defined('THINK_PATH') or exit(); 16 | // 调试模式下面默认设置 可以在应用配置目录下重新定义 debug.php 覆盖 17 | return array( 18 | 'LOG_RECORD' => true, // 进行日志记录 19 | 'LOG_EXCEPTION_RECORD' => true, // 是否记录异常信息日志 20 | 'LOG_LEVEL' => 'EMERG,ALERT,CRIT,ERR,WARN,NOTIC,INFO,DEBUG,SQL', // 允许记录的日志级别 21 | 'DB_FIELDS_CACHE' => false, // 字段缓存信息 22 | 'DB_DEBUG' => true, // 开启调试模式 记录SQL日志 23 | 'TMPL_CACHE_ON' => false, // 是否开启模板编译缓存,设为false则每次都会重新编译 24 | 'TMPL_STRIP_SPACE' => false, // 是否去除模板文件里面的html空格与换行 25 | 'SHOW_ERROR_MSG' => true, // 显示错误信息 26 | 'URL_CASE_INSENSITIVE' => false, // URL区分大小写 27 | ); -------------------------------------------------------------------------------- /Example/ThinkPHP/LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | ThinkPHP遵循Apache2开源协议发布,并提供免费使用。 3 | 版权所有Copyright © 2006-2014 by ThinkPHP (http://thinkphp.cn) 4 | All rights reserved。 5 | ThinkPHP® 商标和著作权所有者为上海顶想信息科技有限公司。 6 | 7 | Apache Licence是著名的非盈利开源组织Apache采用的协议。 8 | 该协议和BSD类似,鼓励代码共享和尊重原作者的著作权, 9 | 允许代码修改,再作为开源或商业软件发布。需要满足 10 | 的条件: 11 | 1. 需要给代码的用户一份Apache Licence ; 12 | 2. 如果你修改了代码,需要在被修改的文件中说明; 13 | 3. 在延伸的代码中(修改和有源代码衍生的代码中)需要 14 | 带有原来代码中的协议,商标,专利声明和其他原来作者规 15 | 定需要包含的说明; 16 | 4. 如果再发布的产品中包含一个Notice文件,则在Notice文 17 | 件中需要带有本协议内容。你可以在Notice中增加自己的 18 | 许可,但不可以表现为对Apache Licence构成更改。 19 | 具体的协议参考:http://www.apache.org/licenses/LICENSE-2.0 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 | COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 29 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 31 | ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 | POSSIBILITY OF SUCH DAMAGE. 33 | -------------------------------------------------------------------------------- /Example/ThinkPHP/Lang/en-us.php: -------------------------------------------------------------------------------- 1 | 10 | // +---------------------------------------------------------------------- 11 | 12 | /** 13 | * ThinkPHP English language package 14 | */ 15 | return array( 16 | /* core language package */ 17 | '_MODULE_NOT_EXIST_' => "Module can't be loaded", 18 | '_CONTROLLER_NOT_EXIST_' => "Controller can't be loaded", 19 | '_ERROR_ACTION_' => 'Illegal Action', 20 | '_LANGUAGE_NOT_LOAD_' => "Can't load language package", 21 | '_TEMPLATE_NOT_EXIST_' => "Template doesn't exist", 22 | '_MODULE_' => 'Module', 23 | '_ACTION_' => 'Action', 24 | '_MODEL_NOT_EXIST_' => "Model can't be loaded", 25 | '_VALID_ACCESS_' => 'No access', 26 | '_XML_TAG_ERROR_' => 'XML tag syntax errors', 27 | '_DATA_TYPE_INVALID_' => 'Illegal data objects!', 28 | '_OPERATION_WRONG_' => 'Operation error occurs', 29 | '_NOT_LOAD_DB_' => 'Unable to load the database', 30 | '_NO_DB_DRIVER_' => 'Unable to load database driver', 31 | '_NOT_SUPPORT_DB_' => 'The system is temporarily not support database', 32 | '_NO_DB_CONFIG_' => 'Not define the database configuration', 33 | '_NOT_SUPPORT_' => 'The system does not support', 34 | '_CACHE_TYPE_INVALID_' => 'Unable to load the cache type', 35 | '_FILE_NOT_WRITABLE_' => 'Directory (file) is not writable', 36 | '_METHOD_NOT_EXIST_' => 'The method you requested does not exist!', 37 | '_CLASS_NOT_EXIST_' => 'Instantiating a class does not exist!', 38 | '_CLASS_CONFLICT_' => 'Class name conflicts', 39 | '_TEMPLATE_ERROR_' => 'Template Engine errors', 40 | '_CACHE_WRITE_ERROR_' => 'Cache file write failed!', 41 | '_TAGLIB_NOT_EXIST_' => 'Tag library is not defined', 42 | '_OPERATION_FAIL_' => 'Operation failed!', 43 | '_OPERATION_SUCCESS_' => 'Operation succeed!', 44 | '_SELECT_NOT_EXIST_' => 'Record does not exist!', 45 | '_EXPRESS_ERROR_' => 'Expression errors', 46 | '_TOKEN_ERROR_' => "Form's token errors", 47 | '_RECORD_HAS_UPDATE_' => 'Record has been updated', 48 | '_NOT_ALLOW_PHP_' => 'PHP codes are not allowed in the template', 49 | '_PARAM_ERROR_' => 'Parameter error or undefined', 50 | '_ERROR_QUERY_EXPRESS_' => 'Query express error', 51 | ); 52 | -------------------------------------------------------------------------------- /Example/ThinkPHP/Lang/pt-br.php: -------------------------------------------------------------------------------- 1 | 10 | // +---------------------------------------------------------------------- 11 | 12 | /** 13 | * ThinkPHP Portuguese language package 14 | */ 15 | return array( 16 | /* core language package */ 17 | '_MODULE_NOT_EXIST_' => "Módulo não pode ser carregado", 18 | '_CONTROLLER_NOT_EXIST_' => "Controller não pode ser carregado", 19 | '_ERROR_ACTION_' => 'Ação ilegal', 20 | '_LANGUAGE_NOT_LOAD_' => "Não é possível carregar pacote da linguagem", 21 | '_TEMPLATE_NOT_EXIST_' => "Template não existe", 22 | '_MODULE_' => 'Módulo', 23 | '_ACTION_' => 'Ação', 24 | '_MODEL_NOT_EXIST_' => "Modelo não pode ser carregado", 25 | '_VALID_ACCESS_' => 'Sem acesso', 26 | '_XML_TAG_ERROR_' => 'Erro de sintaxe - XML tag', 27 | '_DATA_TYPE_INVALID_' => 'Tipos de dados ilegais!', 28 | '_OPERATION_WRONG_' => 'Erro na operação', 29 | '_NOT_LOAD_DB_' => 'Impossível carregar banco de dados', 30 | '_NO_DB_DRIVER_' => 'Impossível carregar driver do bando de dados', 31 | '_NOT_SUPPORT_DB_' => 'Temporariamente sem suporte ao banco', 32 | '_NO_DB_CONFIG_' => 'Não define a configuração do banco', 33 | '_NOT_SUPPORT_' => 'O sistema não suporta', 34 | '_CACHE_TYPE_INVALID_' => 'Impossível carregar o tipo de cache', 35 | '_FILE_NOT_WRITABLE_' => 'Diretório (arquivo) não pode ser escrito', 36 | '_METHOD_NOT_EXIST_' => 'O método solicitado não existe!', 37 | '_CLASS_NOT_EXIST_' => 'Não existe instância da classe', 38 | '_CLASS_CONFLICT_' => 'Conflitos com nome da classe', 39 | '_TEMPLATE_ERROR_' => 'Erros na contrução do template', 40 | '_CACHE_WRITE_ERROR_' => 'Escrita do arquivo de cache falhou!', 41 | '_TAGLIB_NOT_EXIST_' => 'Biblioteca da tag não foi definida', 42 | '_OPERATION_FAIL_' => 'Operação falhou!', 43 | '_OPERATION_SUCCESS_' => 'Operação bem sucessida!', 44 | '_SELECT_NOT_EXIST_' => 'Gravação não existe!', 45 | '_EXPRESS_ERROR_' => 'Erros de expressão', 46 | '_TOKEN_ERROR_' => 'Erro no token do formulário', 47 | '_RECORD_HAS_UPDATE_' => 'Gravação não foi atualizada', 48 | '_NOT_ALLOW_PHP_' => 'Código PHP não é permitido no template', 49 | '_PARAM_ERROR_' => 'Parâmetro errado ou indefinido', 50 | '_ERROR_QUERY_EXPRESS_' => 'Erros na expressão da query', 51 | ); 52 | -------------------------------------------------------------------------------- /Example/ThinkPHP/Lang/zh-cn.php: -------------------------------------------------------------------------------- 1 | 10 | // +---------------------------------------------------------------------- 11 | 12 | /** 13 | * ThinkPHP 简体中文语言包 14 | */ 15 | return array( 16 | /* 核心语言变量 */ 17 | '_MODULE_NOT_EXIST_' => '无法加载模块', 18 | '_CONTROLLER_NOT_EXIST_' => '无法加载控制器', 19 | '_ERROR_ACTION_' => '非法操作', 20 | '_LANGUAGE_NOT_LOAD_' => '无法加载语言包', 21 | '_TEMPLATE_NOT_EXIST_' => '模板不存在', 22 | '_MODULE_' => '模块', 23 | '_ACTION_' => '操作', 24 | '_MODEL_NOT_EXIST_' => '模型不存在或者没有定义', 25 | '_VALID_ACCESS_' => '没有权限', 26 | '_XML_TAG_ERROR_' => 'XML标签语法错误', 27 | '_DATA_TYPE_INVALID_' => '非法数据对象!', 28 | '_OPERATION_WRONG_' => '操作出现错误', 29 | '_NOT_LOAD_DB_' => '无法加载数据库', 30 | '_NO_DB_DRIVER_' => '无法加载数据库驱动', 31 | '_NOT_SUPPORT_DB_' => '系统暂时不支持数据库', 32 | '_NO_DB_CONFIG_' => '没有定义数据库配置', 33 | '_NOT_SUPPORT_' => '系统不支持', 34 | '_CACHE_TYPE_INVALID_' => '无法加载缓存类型', 35 | '_FILE_NOT_WRITABLE_' => '目录(文件)不可写', 36 | '_METHOD_NOT_EXIST_' => '方法不存在!', 37 | '_CLASS_NOT_EXIST_' => '实例化一个不存在的类!', 38 | '_CLASS_CONFLICT_' => '类名冲突', 39 | '_TEMPLATE_ERROR_' => '模板引擎错误', 40 | '_CACHE_WRITE_ERROR_' => '缓存文件写入失败!', 41 | '_TAGLIB_NOT_EXIST_' => '标签库未定义', 42 | '_OPERATION_FAIL_' => '操作失败!', 43 | '_OPERATION_SUCCESS_' => '操作成功!', 44 | '_SELECT_NOT_EXIST_' => '记录不存在!', 45 | '_EXPRESS_ERROR_' => '表达式错误', 46 | '_TOKEN_ERROR_' => '表单令牌错误', 47 | '_RECORD_HAS_UPDATE_' => '记录已经更新', 48 | '_NOT_ALLOW_PHP_' => '模板禁用PHP代码', 49 | '_PARAM_ERROR_' => '参数错误或者未定义', 50 | '_ERROR_QUERY_EXPRESS_' => '错误的查询条件', 51 | ); 52 | -------------------------------------------------------------------------------- /Example/ThinkPHP/Lang/zh-tw.php: -------------------------------------------------------------------------------- 1 | 10 | // +---------------------------------------------------------------------- 11 | 12 | /** 13 | * ThinkPHP 繁体中文語言包 14 | */ 15 | return array( 16 | /* 核心語言變數 */ 17 | '_MODULE_NOT_EXIST_' => '無法載入模組', 18 | '_CONTROLLER_NOT_EXIST_' => '無法載入控制器', 19 | '_ERROR_ACTION_' => '非法操作', 20 | '_LANGUAGE_NOT_LOAD_' => '無法載入語言包', 21 | '_TEMPLATE_NOT_EXIST_' => '模板不存在', 22 | '_MODULE_' => '模組', 23 | '_ACTION_' => '操作', 24 | '_MODEL_NOT_EXIST_' => '模型不存在或者沒有定義', 25 | '_VALID_ACCESS_' => '沒有權限', 26 | '_XML_TAG_ERROR_' => 'XML標籤語法錯誤', 27 | '_DATA_TYPE_INVALID_' => '非法資料物件!', 28 | '_OPERATION_WRONG_' => '操作出現錯誤', 29 | '_NOT_LOAD_DB_' => '無法載入資料庫', 30 | '_NO_DB_DRIVER_' => '無法載入資料庫驅動', 31 | '_NOT_SUPPORT_DB_' => '系統暫時不支援資料庫', 32 | '_NO_DB_CONFIG_' => '沒有定義資料庫設定', 33 | '_NOT_SUPPORT_' => '系統不支援', 34 | '_CACHE_TYPE_INVALID_' => '無法載入快取類型', 35 | '_FILE_NOT_WRITABLE_' => '目錄(檔案)不可寫', 36 | '_METHOD_NOT_EXIST_' => '方法不存在!', 37 | '_CLASS_NOT_EXIST_' => '實例化一個不存在的類別!', 38 | '_CLASS_CONFLICT_' => '類別名稱衝突', 39 | '_TEMPLATE_ERROR_' => '模板引擎錯誤', 40 | '_CACHE_WRITE_ERROR_' => '快取檔案寫入失敗!', 41 | '_TAGLIB_NOT_EXIST_' => '標籤庫未定義', 42 | '_OPERATION_FAIL_' => '操作失敗!', 43 | '_OPERATION_SUCCESS_' => '操作成功!', 44 | '_SELECT_NOT_EXIST_' => '記錄不存在!', 45 | '_EXPRESS_ERROR_' => '運算式錯誤', 46 | '_TOKEN_ERROR_' => '表單權限錯誤', 47 | '_RECORD_HAS_UPDATE_' => '記錄已經更新', 48 | '_NOT_ALLOW_PHP_' => '模板禁用PHP代碼', 49 | '_PARAM_ERROR_' => '參數錯誤或者未定義', 50 | '_ERROR_QUERY_EXPRESS_' => '錯誤的查詢條件', 51 | ); 52 | -------------------------------------------------------------------------------- /Example/ThinkPHP/Library/Behavior/BuildLiteBehavior.class.php: -------------------------------------------------------------------------------- 1 | 10 | // +---------------------------------------------------------------------- 11 | namespace Behavior; 12 | // 创建Lite运行文件 13 | // 可以替换框架入口文件运行 14 | // 建议绑定位置app_init 15 | class BuildLiteBehavior { 16 | public function run(&$params) { 17 | if(!defined('BUILD_LITE_FILE')) return ; 18 | $litefile = C('RUNTIME_LITE_FILE',null,RUNTIME_PATH.'lite.php'); 19 | if(is_file($litefile)) return; 20 | 21 | $defs = get_defined_constants(TRUE); 22 | $content = 'namespace {$GLOBALS[\'_beginTime\'] = microtime(TRUE);'; 23 | if(MEMORY_LIMIT_ON) { 24 | $content .= '$GLOBALS[\'_startUseMems\'] = memory_get_usage();'; 25 | } 26 | 27 | // 生成数组定义 28 | unset($defs['user']['BUILD_LITE_FILE']); 29 | $content .= $this->buildArrayDefine($defs['user']).'}'; 30 | 31 | // 读取编译列表文件 32 | $filelist = is_file(CONF_PATH.'lite.php')? 33 | include CONF_PATH.'lite.php': 34 | array( 35 | THINK_PATH.'Common/functions.php', 36 | COMMON_PATH.'Common/function.php', 37 | CORE_PATH . 'Think'.EXT, 38 | CORE_PATH . 'Hook'.EXT, 39 | CORE_PATH . 'App'.EXT, 40 | CORE_PATH . 'Dispatcher'.EXT, 41 | CORE_PATH . 'Log'.EXT, 42 | CORE_PATH . 'Log/Driver/File'.EXT, 43 | CORE_PATH . 'Route'.EXT, 44 | CORE_PATH . 'Controller'.EXT, 45 | CORE_PATH . 'View'.EXT, 46 | CORE_PATH . 'Storage'.EXT, 47 | CORE_PATH . 'Storage/Driver/File'.EXT, 48 | CORE_PATH . 'Exception'.EXT, 49 | BEHAVIOR_PATH . 'ParseTemplateBehavior'.EXT, 50 | BEHAVIOR_PATH . 'ContentReplaceBehavior'.EXT, 51 | ); 52 | 53 | // 编译文件 54 | foreach ($filelist as $file){ 55 | if(is_file($file)) { 56 | $content .= compile($file); 57 | } 58 | } 59 | 60 | // 处理Think类的start方法 61 | $content = preg_replace('/\$runtimefile = RUNTIME_PATH(.+?)(if\(APP_STATUS)/','\2',$content,1); 62 | $content .= "\nnamespace { Think\Think::addMap(".var_export(\Think\Think::getMap(),true).");"; 63 | $content .= "\nL(".var_export(L(),true).");\nC(".var_export(C(),true).');Think\Hook::import('.var_export(\Think\Hook::get(),true).');Think\Think::start();}'; 64 | 65 | // 生成运行Lite文件 66 | file_put_contents($litefile,strip_whitespace(' $val) { 73 | $key = strtoupper($key); 74 | $content .= 'defined(\'' . $key . '\') or '; 75 | if (is_int($val) || is_float($val)) { 76 | $content .= "define('" . $key . "'," . $val . ');'; 77 | } elseif (is_bool($val)) { 78 | $val = ($val) ? 'true' : 'false'; 79 | $content .= "define('" . $key . "'," . $val . ');'; 80 | } elseif (is_string($val)) { 81 | $content .= "define('" . $key . "','" . addslashes($val) . "');"; 82 | } 83 | $content .= "\n"; 84 | } 85 | return $content; 86 | } 87 | } -------------------------------------------------------------------------------- /Example/ThinkPHP/Library/Behavior/CheckLangBehavior.class.php: -------------------------------------------------------------------------------- 1 | 10 | // +---------------------------------------------------------------------- 11 | namespace Behavior; 12 | /** 13 | * 语言检测 并自动加载语言包 14 | */ 15 | class CheckLangBehavior { 16 | 17 | // 行为扩展的执行入口必须是run 18 | public function run(&$params){ 19 | // 检测语言 20 | $this->checkLanguage(); 21 | } 22 | 23 | /** 24 | * 语言检查 25 | * 检查浏览器支持语言,并自动加载语言包 26 | * @access private 27 | * @return void 28 | */ 29 | private function checkLanguage() { 30 | // 不开启语言包功能,仅仅加载框架语言文件直接返回 31 | if (!C('LANG_SWITCH_ON',null,false)){ 32 | return; 33 | } 34 | $langSet = C('DEFAULT_LANG'); 35 | $varLang = C('VAR_LANGUAGE',null,'l'); 36 | $langList = C('LANG_LIST',null,'zh-cn'); 37 | // 启用了语言包功能 38 | // 根据是否启用自动侦测设置获取语言选择 39 | if (C('LANG_AUTO_DETECT',null,true)){ 40 | if(isset($_GET[$varLang])){ 41 | $langSet = $_GET[$varLang];// url中设置了语言变量 42 | cookie('think_language',$langSet,3600); 43 | }elseif(cookie('think_language')){// 获取上次用户的选择 44 | $langSet = cookie('think_language'); 45 | }elseif(isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])){// 自动侦测浏览器语言 46 | preg_match('/^([a-z\d\-]+)/i', $_SERVER['HTTP_ACCEPT_LANGUAGE'], $matches); 47 | $langSet = $matches[1]; 48 | cookie('think_language',$langSet,3600); 49 | } 50 | if(false === stripos($langList,$langSet)) { // 非法语言参数 51 | $langSet = C('DEFAULT_LANG'); 52 | } 53 | } 54 | // 定义当前语言 55 | define('LANG_SET',strtolower($langSet)); 56 | 57 | // 读取框架语言包 58 | $file = THINK_PATH.'Lang/'.LANG_SET.'.php'; 59 | if(LANG_SET != C('DEFAULT_LANG') && is_file($file)) 60 | L(include $file); 61 | 62 | // 读取应用公共语言包 63 | $file = LANG_PATH.LANG_SET.'.php'; 64 | if(is_file($file)) 65 | L(include $file); 66 | 67 | // 读取模块语言包 68 | $file = MODULE_PATH.'Lang/'.LANG_SET.'.php'; 69 | if(is_file($file)) 70 | L(include $file); 71 | 72 | // 读取当前控制器语言包 73 | $file = MODULE_PATH.'Lang/'.LANG_SET.'/'.strtolower(CONTROLLER_NAME).'.php'; 74 | if (is_file($file)) 75 | L(include $file); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /Example/ThinkPHP/Library/Behavior/ContentReplaceBehavior.class.php: -------------------------------------------------------------------------------- 1 | 10 | // +---------------------------------------------------------------------- 11 | namespace Behavior; 12 | /** 13 | * 系统行为扩展:模板内容输出替换 14 | */ 15 | class ContentReplaceBehavior { 16 | 17 | // 行为扩展的执行入口必须是run 18 | public function run(&$content){ 19 | $content = $this->templateContentReplace($content); 20 | } 21 | 22 | /** 23 | * 模板内容替换 24 | * @access protected 25 | * @param string $content 模板内容 26 | * @return string 27 | */ 28 | protected function templateContentReplace($content) { 29 | // 系统默认的特殊变量替换 30 | $replace = array( 31 | '__ROOT__' => __ROOT__, // 当前网站地址 32 | '__APP__' => __APP__, // 当前应用地址 33 | '__MODULE__' => __MODULE__, 34 | '__ACTION__' => __ACTION__, // 当前操作地址 35 | '__SELF__' => __SELF__, // 当前页面地址 36 | '__CONTROLLER__'=> __CONTROLLER__, 37 | '__URL__' => __CONTROLLER__, 38 | '__PUBLIC__' => __ROOT__.'/Public',// 站点公共目录 39 | ); 40 | // 允许用户自定义模板的字符串替换 41 | if(is_array(C('TMPL_PARSE_STRING')) ) 42 | $replace = array_merge($replace,C('TMPL_PARSE_STRING')); 43 | $content = str_replace(array_keys($replace),array_values($replace),$content); 44 | return $content; 45 | } 46 | 47 | } -------------------------------------------------------------------------------- /Example/ThinkPHP/Library/Behavior/ParseTemplateBehavior.class.php: -------------------------------------------------------------------------------- 1 | 10 | // +---------------------------------------------------------------------- 11 | namespace Behavior; 12 | use Think\Storage; 13 | use Think\Think; 14 | /** 15 | * 系统行为扩展:模板解析 16 | */ 17 | class ParseTemplateBehavior { 18 | 19 | // 行为扩展的执行入口必须是run 20 | public function run(&$_data){ 21 | $engine = strtolower(C('TMPL_ENGINE_TYPE')); 22 | $_content = empty($_data['content'])?$_data['file']:$_data['content']; 23 | $_data['prefix'] = !empty($_data['prefix'])?$_data['prefix']:C('TMPL_CACHE_PREFIX'); 24 | if('think'==$engine){ // 采用Think模板引擎 25 | if((!empty($_data['content']) && $this->checkContentCache($_data['content'],$_data['prefix'])) 26 | || $this->checkCache($_data['file'],$_data['prefix'])) { // 缓存有效 27 | //载入模版缓存文件 28 | Storage::load(C('CACHE_PATH').$_data['prefix'].md5($_content).C('TMPL_CACHFILE_SUFFIX'),$_data['var']); 29 | }else{ 30 | $tpl = Think::instance('Think\\Template'); 31 | // 编译并加载模板文件 32 | $tpl->fetch($_content,$_data['var'],$_data['prefix']); 33 | } 34 | }else{ 35 | // 调用第三方模板引擎解析和输出 36 | if(strpos($engine,'\\')){ 37 | $class = $engine; 38 | }else{ 39 | $class = 'Think\\Template\\Driver\\'.ucwords($engine); 40 | } 41 | if(class_exists($class)) { 42 | $tpl = new $class; 43 | $tpl->fetch($_content,$_data['var']); 44 | }else { // 类没有定义 45 | E(L('_NOT_SUPPORT_').': ' . $class); 46 | } 47 | } 48 | } 49 | 50 | /** 51 | * 检查缓存文件是否有效 52 | * 如果无效则需要重新编译 53 | * @access public 54 | * @param string $tmplTemplateFile 模板文件名 55 | * @return boolean 56 | */ 57 | protected function checkCache($tmplTemplateFile,$prefix='') { 58 | if (!C('TMPL_CACHE_ON')) // 优先对配置设定检测 59 | return false; 60 | $tmplCacheFile = C('CACHE_PATH').$prefix.md5($tmplTemplateFile).C('TMPL_CACHFILE_SUFFIX'); 61 | if(!Storage::has($tmplCacheFile)){ 62 | return false; 63 | }elseif (filemtime($tmplTemplateFile) > Storage::get($tmplCacheFile,'mtime')) { 64 | // 模板文件如果有更新则缓存需要更新 65 | return false; 66 | }elseif (C('TMPL_CACHE_TIME') != 0 && time() > Storage::get($tmplCacheFile,'mtime')+C('TMPL_CACHE_TIME')) { 67 | // 缓存是否在有效期 68 | return false; 69 | } 70 | // 开启布局模板 71 | if(C('LAYOUT_ON')) { 72 | $layoutFile = THEME_PATH.C('LAYOUT_NAME').C('TMPL_TEMPLATE_SUFFIX'); 73 | if(filemtime($layoutFile) > Storage::get($tmplCacheFile,'mtime')) { 74 | return false; 75 | } 76 | } 77 | // 缓存有效 78 | return true; 79 | } 80 | 81 | /** 82 | * 检查缓存内容是否有效 83 | * 如果无效则需要重新编译 84 | * @access public 85 | * @param string $tmplContent 模板内容 86 | * @return boolean 87 | */ 88 | protected function checkContentCache($tmplContent,$prefix='') { 89 | if(Storage::has(C('CACHE_PATH').$prefix.md5($tmplContent).C('TMPL_CACHFILE_SUFFIX'))){ 90 | return true; 91 | }else{ 92 | return false; 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /Example/ThinkPHP/Library/Behavior/ReadHtmlCacheBehavior.class.php: -------------------------------------------------------------------------------- 1 | 10 | // +---------------------------------------------------------------------- 11 | namespace Behavior; 12 | use Think\Storage; 13 | /** 14 | * 系统行为扩展:静态缓存读取 15 | */ 16 | class ReadHtmlCacheBehavior { 17 | // 行为扩展的执行入口必须是run 18 | public function run(&$params){ 19 | // 开启静态缓存 20 | if(IS_GET && C('HTML_CACHE_ON')) { 21 | $cacheTime = $this->requireHtmlCache(); 22 | if( false !== $cacheTime && $this->checkHTMLCache(HTML_FILE_NAME,$cacheTime)) { //静态页面有效 23 | // 读取静态页面输出 24 | echo Storage::read(HTML_FILE_NAME,'html'); 25 | exit(); 26 | } 27 | } 28 | } 29 | 30 | // 判断是否需要静态缓存 31 | static private function requireHtmlCache() { 32 | // 分析当前的静态规则 33 | $htmls = C('HTML_CACHE_RULES'); // 读取静态规则 34 | if(!empty($htmls)) { 35 | $htmls = array_change_key_case($htmls); 36 | // 静态规则文件定义格式 actionName=>array('静态规则','缓存时间','附加规则') 37 | // 'read'=>array('{id},{name}',60,'md5') 必须保证静态规则的唯一性 和 可判断性 38 | // 检测静态规则 39 | $controllerName = strtolower(CONTROLLER_NAME); 40 | $actionName = strtolower(ACTION_NAME); 41 | if(isset($htmls[$controllerName.':'.$actionName])) { 42 | $html = $htmls[$controllerName.':'.$actionName]; // 某个控制器的操作的静态规则 43 | }elseif(isset($htmls[$controllerName.':'])){// 某个控制器的静态规则 44 | $html = $htmls[$controllerName.':']; 45 | }elseif(isset($htmls[$actionName])){ 46 | $html = $htmls[$actionName]; // 所有操作的静态规则 47 | }elseif(isset($htmls['*'])){ 48 | $html = $htmls['*']; // 全局静态规则 49 | } 50 | if(!empty($html)) { 51 | // 解读静态规则 52 | $rule = is_array($html)?$html[0]:$html; 53 | // 以$_开头的系统变量 54 | $callback = function($match){ 55 | switch($match[1]){ 56 | case '_GET': $var = $_GET[$match[2]]; break; 57 | case '_POST': $var = $_POST[$match[2]]; break; 58 | case '_REQUEST': $var = $_REQUEST[$match[2]]; break; 59 | case '_SERVER': $var = $_SERVER[$match[2]]; break; 60 | case '_SESSION': $var = $_SESSION[$match[2]]; break; 61 | case '_COOKIE': $var = $_COOKIE[$match[2]]; break; 62 | } 63 | return (count($match) == 4) ? $match[3]($var) : $var; 64 | }; 65 | $rule = preg_replace_callback('/{\$(_\w+)\.(\w+)(?:\|(\w+))?}/', $callback, $rule); 66 | // {ID|FUN} GET变量的简写 67 | $rule = preg_replace_callback('/{(\w+)\|(\w+)}/', function($match){return $match[2]($_GET[$match[1]]);}, $rule); 68 | $rule = preg_replace_callback('/{(\w+)}/', function($match){return $_GET[$match[1]];}, $rule); 69 | // 特殊系统变量 70 | $rule = str_ireplace( 71 | array('{:controller}','{:action}','{:module}'), 72 | array(CONTROLLER_NAME,ACTION_NAME,MODULE_NAME), 73 | $rule); 74 | // {|FUN} 单独使用函数 75 | $rule = preg_replace_callback('/{|(\w+)}/', function($match){return $match[1]();},$rule); 76 | $cacheTime = C('HTML_CACHE_TIME',null,60); 77 | if(is_array($html)){ 78 | if(!empty($html[2])) $rule = $html[2]($rule); // 应用附加函数 79 | $cacheTime = isset($html[1])?$html[1]:$cacheTime; // 缓存有效期 80 | }else{ 81 | $cacheTime = $cacheTime; 82 | } 83 | 84 | // 当前缓存文件 85 | define('HTML_FILE_NAME',HTML_PATH . $rule.C('HTML_FILE_SUFFIX',null,'.html')); 86 | return $cacheTime; 87 | } 88 | } 89 | // 无需缓存 90 | return false; 91 | } 92 | 93 | /** 94 | * 检查静态HTML文件是否有效 95 | * 如果无效需要重新更新 96 | * @access public 97 | * @param string $cacheFile 静态文件名 98 | * @param integer $cacheTime 缓存有效期 99 | * @return boolean 100 | */ 101 | static public function checkHTMLCache($cacheFile='',$cacheTime='') { 102 | if(!is_file($cacheFile) && 'sae' != APP_MODE ){ 103 | return false; 104 | }elseif (filemtime(\Think\Think::instance('Think\View')->parseTemplate()) > Storage::get($cacheFile,'mtime','html')) { 105 | // 模板文件如果更新静态文件需要更新 106 | return false; 107 | }elseif(!is_numeric($cacheTime) && function_exists($cacheTime)){ 108 | return $cacheTime($cacheFile); 109 | }elseif ($cacheTime != 0 && NOW_TIME > Storage::get($cacheFile,'mtime','html')+$cacheTime) { 110 | // 文件是否在有效期 111 | return false; 112 | } 113 | //静态文件有效 114 | return true; 115 | } 116 | 117 | } -------------------------------------------------------------------------------- /Example/ThinkPHP/Library/Behavior/ShowPageTraceBehavior.class.php: -------------------------------------------------------------------------------- 1 | 10 | // +---------------------------------------------------------------------- 11 | namespace Behavior; 12 | use Think\Log; 13 | /** 14 | * 系统行为扩展:页面Trace显示输出 15 | */ 16 | class ShowPageTraceBehavior { 17 | protected $tracePageTabs = array('BASE'=>'基本','FILE'=>'文件','INFO'=>'流程','ERR|NOTIC'=>'错误','SQL'=>'SQL','DEBUG'=>'调试'); 18 | 19 | // 行为扩展的执行入口必须是run 20 | public function run(&$params){ 21 | if(!IS_AJAX && !IS_CLI && C('SHOW_PAGE_TRACE')) { 22 | echo $this->showTrace(); 23 | } 24 | } 25 | 26 | /** 27 | * 显示页面Trace信息 28 | * @access private 29 | */ 30 | private function showTrace() { 31 | // 系统默认显示信息 32 | $files = get_included_files(); 33 | $info = array(); 34 | foreach ($files as $key=>$file){ 35 | $info[] = $file.' ( '.number_format(filesize($file)/1024,2).' KB )'; 36 | } 37 | $trace = array(); 38 | $base = array( 39 | '请求信息' => date('Y-m-d H:i:s',$_SERVER['REQUEST_TIME']).' '.$_SERVER['SERVER_PROTOCOL'].' '.$_SERVER['REQUEST_METHOD'].' : '.__SELF__, 40 | '运行时间' => $this->showTime(), 41 | '吞吐率' => number_format(1/G('beginTime','viewEndTime'),2).'req/s', 42 | '内存开销' => MEMORY_LIMIT_ON?number_format((memory_get_usage() - $GLOBALS['_startUseMems'])/1024,2).' kb':'不支持', 43 | '查询信息' => N('db_query').' queries '.N('db_write').' writes ', 44 | '文件加载' => count(get_included_files()), 45 | '缓存信息' => N('cache_read').' gets '.N('cache_write').' writes ', 46 | '配置加载' => count(C()), 47 | '会话信息' => 'SESSION_ID='.session_id(), 48 | ); 49 | // 读取应用定义的Trace文件 50 | $traceFile = COMMON_PATH.'Conf/trace.php'; 51 | if(is_file($traceFile)) { 52 | $base = array_merge($base,include $traceFile); 53 | } 54 | $debug = trace(); 55 | $tabs = C('TRACE_PAGE_TABS',null,$this->tracePageTabs); 56 | foreach ($tabs as $name=>$title){ 57 | switch(strtoupper($name)) { 58 | case 'BASE':// 基本信息 59 | $trace[$title] = $base; 60 | break; 61 | case 'FILE': // 文件信息 62 | $trace[$title] = $info; 63 | break; 64 | default:// 调试信息 65 | $name = strtoupper($name); 66 | if(strpos($name,'|')) {// 多组信息 67 | $names = explode('|',$name); 68 | $result = array(); 69 | foreach($names as $name){ 70 | $result += isset($debug[$name])?$debug[$name]:array(); 71 | } 72 | $trace[$title] = $result; 73 | }else{ 74 | $trace[$title] = isset($debug[$name])?$debug[$name]:''; 75 | } 76 | } 77 | } 78 | if($save = C('PAGE_TRACE_SAVE')) { // 保存页面Trace日志 79 | if(is_array($save)) {// 选择选项卡保存 80 | $tabs = C('TRACE_PAGE_TABS',null,$this->tracePageTabs); 81 | $array = array(); 82 | foreach ($save as $tab){ 83 | $array[] = $tabs[$tab]; 84 | } 85 | } 86 | $content = date('[ c ]').' '.get_client_ip().' '.$_SERVER['REQUEST_URI']."\r\n"; 87 | foreach ($trace as $key=>$val){ 88 | if(!isset($array) || in_array_case($key,$array)) { 89 | $content .= '[ '.$key." ]\r\n"; 90 | if(is_array($val)) { 91 | foreach ($val as $k=>$v){ 92 | $content .= (!is_numeric($k)?$k.':':'').print_r($v,true)."\r\n"; 93 | } 94 | }else{ 95 | $content .= print_r($val,true)."\r\n"; 96 | } 97 | $content .= "\r\n"; 98 | } 99 | } 100 | error_log(str_replace('
',"\r\n",$content), 3,C('LOG_PATH').date('y_m_d').'_trace.log'); 101 | } 102 | unset($files,$info,$base); 103 | // 调用Trace页面模板 104 | ob_start(); 105 | include C('TMPL_TRACE_FILE')?C('TMPL_TRACE_FILE'):THINK_PATH.'Tpl/page_trace.tpl'; 106 | return ob_get_clean(); 107 | } 108 | 109 | /** 110 | * 获取运行时间 111 | */ 112 | private function showTime() { 113 | // 显示运行时间 114 | G('beginTime',$GLOBALS['_beginTime']); 115 | G('viewEndTime'); 116 | // 显示详细运行时间 117 | 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 )'; 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /Example/ThinkPHP/Library/Behavior/ShowRuntimeBehavior.class.php: -------------------------------------------------------------------------------- 1 | 10 | // +---------------------------------------------------------------------- 11 | namespace Behavior; 12 | /** 13 | * 系统行为扩展:运行时间信息显示 14 | */ 15 | class ShowRuntimeBehavior { 16 | 17 | // 行为扩展的执行入口必须是run 18 | public function run(&$content){ 19 | if(C('SHOW_RUN_TIME')){ 20 | if(false !== strpos($content,'{__NORUNTIME__}')) { 21 | $content = str_replace('{__NORUNTIME__}','',$content); 22 | }else{ 23 | $runtime = $this->showTime(); 24 | if(strpos($content,'{__RUNTIME__}')) 25 | $content = str_replace('{__RUNTIME__}',$runtime,$content); 26 | else 27 | $content .= $runtime; 28 | } 29 | }else{ 30 | $content = str_replace(array('{__NORUNTIME__}','{__RUNTIME__}'),'',$content); 31 | } 32 | } 33 | 34 | /** 35 | * 显示运行时间、数据库操作、缓存次数、内存使用信息 36 | * @access private 37 | * @return string 38 | */ 39 | private function showTime() { 40 | // 显示运行时间 41 | G('beginTime',$GLOBALS['_beginTime']); 42 | G('viewEndTime'); 43 | $showTime = 'Process: '.G('beginTime','viewEndTime').'s '; 44 | if(C('SHOW_ADV_TIME')) { 45 | // 显示详细运行时间 46 | $showTime .= '( Load:'.G('beginTime','loadTime').'s Init:'.G('loadTime','initTime').'s Exec:'.G('initTime','viewStartTime').'s Template:'.G('viewStartTime','viewEndTime').'s )'; 47 | } 48 | if(C('SHOW_DB_TIMES') ) { 49 | // 显示数据库操作次数 50 | $showTime .= ' | DB :'.N('db_query').' queries '.N('db_write').' writes '; 51 | } 52 | if(C('SHOW_CACHE_TIMES') ) { 53 | // 显示缓存读写次数 54 | $showTime .= ' | Cache :'.N('cache_read').' gets '.N('cache_write').' writes '; 55 | } 56 | if(MEMORY_LIMIT_ON && C('SHOW_USE_MEM')) { 57 | // 显示内存开销 58 | $showTime .= ' | UseMem:'. number_format((memory_get_usage() - $GLOBALS['_startUseMems'])/1024).' kb'; 59 | } 60 | if(C('SHOW_LOAD_FILE')) { 61 | $showTime .= ' | LoadFile:'.count(get_included_files()); 62 | } 63 | if(C('SHOW_FUN_TIMES')) { 64 | $fun = get_defined_functions(); 65 | $showTime .= ' | CallFun:'.count($fun['user']).','.count($fun['internal']); 66 | } 67 | return $showTime; 68 | } 69 | } -------------------------------------------------------------------------------- /Example/ThinkPHP/Library/Behavior/TokenBuildBehavior.class.php: -------------------------------------------------------------------------------- 1 | 10 | // +---------------------------------------------------------------------- 11 | namespace Behavior; 12 | /** 13 | * 系统行为扩展:表单令牌生成 14 | */ 15 | class TokenBuildBehavior { 16 | 17 | public function run(&$content){ 18 | if(C('TOKEN_ON')) { 19 | list($tokenName,$tokenKey,$tokenValue)=$this->getToken(); 20 | $input_token = ''; 21 | $meta_token = ''; 22 | if(strpos($content,'{__TOKEN__}')) { 23 | // 指定表单令牌隐藏域位置 24 | $content = str_replace('{__TOKEN__}',$input_token,$content); 25 | }elseif(preg_match('/<\/form(\s*)>/is',$content,$match)) { 26 | // 智能生成表单令牌隐藏域 27 | $content = str_replace($match[0],$input_token.$match[0],$content); 28 | } 29 | $content = str_ireplace('',$meta_token.'',$content); 30 | }else{ 31 | $content = str_replace('{__TOKEN__}','',$content); 32 | } 33 | } 34 | 35 | //获得token 36 | private function getToken(){ 37 | $tokenName = C('TOKEN_NAME',null,'__hash__'); 38 | $tokenType = C('TOKEN_TYPE',null,'md5'); 39 | if(!isset($_SESSION[$tokenName])) { 40 | $_SESSION[$tokenName] = array(); 41 | } 42 | // 标识当前页面唯一性 43 | $tokenKey = md5($_SERVER['REQUEST_URI']); 44 | if(isset($_SESSION[$tokenName][$tokenKey])) {// 相同页面不重复生成session 45 | $tokenValue = $_SESSION[$tokenName][$tokenKey]; 46 | }else{ 47 | $tokenValue = is_callable($tokenType) ? $tokenType(microtime(true)) : md5(microtime(true)); 48 | $_SESSION[$tokenName][$tokenKey] = $tokenValue; 49 | if(IS_AJAX && C('TOKEN_RESET',null,true)) 50 | header($tokenName.': '.$tokenKey.'_'.$tokenValue); //ajax需要获得这个header并替换页面中meta中的token值 51 | } 52 | return array($tokenName,$tokenKey,$tokenValue); 53 | } 54 | } -------------------------------------------------------------------------------- /Example/ThinkPHP/Library/Behavior/WriteHtmlCacheBehavior.class.php: -------------------------------------------------------------------------------- 1 | 10 | // +---------------------------------------------------------------------- 11 | namespace Behavior; 12 | use Think\Storage; 13 | /** 14 | * 系统行为扩展:静态缓存写入 15 | */ 16 | class WriteHtmlCacheBehavior { 17 | 18 | // 行为扩展的执行入口必须是run 19 | public function run(&$content) { 20 | //2014-11-28 修改 如果有HTTP 4xx 3xx 5xx 头部,禁止存储 21 | //2014-12-1 修改 对注入的网址 防止生成,例如 /game/lst/SortType/hot/-e8-90-8c-e5-85-94-e7-88-b1-e6-b6-88-e9-99-a4/-e8-bf-9b-e5-87-bb-e7-9a-84-e9-83-a8-e8-90-bd/-e9-a3-8e-e4-ba-91-e5-a4-a9-e4-b8-8b/index.shtml 22 | if (C('HTML_CACHE_ON') && defined('HTML_FILE_NAME') 23 | && !preg_match('/Status.*[345]{1}\d{2}/i', implode(' ', headers_list())) 24 | && !preg_match('/(-[a-z0-9]{2}){3,}/i',HTML_FILE_NAME)) { 25 | //静态文件写入 26 | Storage::put(HTML_FILE_NAME, $content, 'html'); 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /Example/ThinkPHP/Library/Think/Build.class.php: -------------------------------------------------------------------------------- 1 | 10 | // +---------------------------------------------------------------------- 11 | namespace Think; 12 | /** 13 | * 用于ThinkPHP的自动生成 14 | */ 15 | class Build { 16 | 17 | static protected $controller = 'show(\'

:)

欢迎使用 ThinkPHP


版本 V{$Think.version}
\',\'utf-8\'); 23 | } 24 | }'; 25 | 26 | static protected $model = ''配置值'\n);":''); 74 | // 写入模块配置文件 75 | if(!is_file(APP_PATH.$module.'/Conf/config'.CONF_EXT)) 76 | file_put_contents(APP_PATH.$module.'/Conf/config'.CONF_EXT,'.php' == CONF_EXT ? "'配置值'\n);":''); 77 | // 生成模块的测试控制器 78 | if(defined('BUILD_CONTROLLER_LIST')){ 79 | // 自动生成的控制器列表(注意大小写) 80 | $list = explode(',',BUILD_CONTROLLER_LIST); 81 | foreach($list as $controller){ 82 | self::buildController($module,$controller); 83 | } 84 | }else{ 85 | // 生成默认的控制器 86 | self::buildController($module); 87 | } 88 | // 生成模块的模型 89 | if(defined('BUILD_MODEL_LIST')){ 90 | // 自动生成的控制器列表(注意大小写) 91 | $list = explode(',',BUILD_MODEL_LIST); 92 | foreach($list as $model){ 93 | self::buildModel($module,$model); 94 | } 95 | } 96 | }else{ 97 | header('Content-Type:text/html; charset=utf-8'); 98 | exit('应用目录['.APP_PATH.']不可写,目录无法自动生成!
请手动生成项目目录~'); 99 | } 100 | } 101 | 102 | // 检查缓存目录(Runtime) 如果不存在则自动创建 103 | static public function buildRuntime() { 104 | if(!is_dir(RUNTIME_PATH)) { 105 | mkdir(RUNTIME_PATH); 106 | }elseif(!is_writeable(RUNTIME_PATH)) { 107 | header('Content-Type:text/html; charset=utf-8'); 108 | exit('目录 [ '.RUNTIME_PATH.' ] 不可写!'); 109 | } 110 | mkdir(CACHE_PATH); // 模板缓存目录 111 | if(!is_dir(LOG_PATH)) mkdir(LOG_PATH); // 日志目录 112 | if(!is_dir(TEMP_PATH)) mkdir(TEMP_PATH); // 数据缓存目录 113 | if(!is_dir(DATA_PATH)) mkdir(DATA_PATH); // 数据文件目录 114 | return true; 115 | } 116 | 117 | // 创建控制器类 118 | static public function buildController($module,$controller='Index') { 119 | $file = APP_PATH.$module.'/Controller/'.$controller.'Controller'.EXT; 120 | if(!is_file($file)){ 121 | $content = str_replace(array('[MODULE]','[CONTROLLER]'),array($module,$controller),self::$controller); 122 | if(!C('APP_USE_NAMESPACE')){ 123 | $content = preg_replace('/namespace\s(.*?);/','',$content,1); 124 | } 125 | $dir = dirname($file); 126 | if(!is_dir($dir)){ 127 | mkdir($dir, 0755, true); 128 | } 129 | file_put_contents($file,$content); 130 | } 131 | } 132 | 133 | // 创建模型类 134 | static public function buildModel($module,$model) { 135 | $file = APP_PATH.$module.'/Model/'.$model.'Model'.EXT; 136 | if(!is_file($file)){ 137 | $content = str_replace(array('[MODULE]','[MODEL]'),array($module,$model),self::$model); 138 | if(!C('APP_USE_NAMESPACE')){ 139 | $content = preg_replace('/namespace\s(.*?);/','',$content,1); 140 | } 141 | $dir = dirname($file); 142 | if(!is_dir($dir)){ 143 | mkdir($dir, 0755, true); 144 | } 145 | file_put_contents($file,$content); 146 | } 147 | } 148 | 149 | // 生成目录安全文件 150 | static public function buildDirSecure($dirs=array()) { 151 | // 目录安全写入(默认开启) 152 | defined('BUILD_DIR_SECURE') or define('BUILD_DIR_SECURE', true); 153 | if(BUILD_DIR_SECURE) { 154 | defined('DIR_SECURE_FILENAME') or define('DIR_SECURE_FILENAME', 'index.html'); 155 | defined('DIR_SECURE_CONTENT') or define('DIR_SECURE_CONTENT', ' '); 156 | // 自动写入目录安全文件 157 | $content = DIR_SECURE_CONTENT; 158 | $files = explode(',', DIR_SECURE_FILENAME); 159 | foreach ($files as $filename){ 160 | foreach ($dirs as $dir) 161 | file_put_contents($dir.$filename,$content); 162 | } 163 | } 164 | } 165 | } 166 | -------------------------------------------------------------------------------- /Example/ThinkPHP/Library/Think/Cache.class.php: -------------------------------------------------------------------------------- 1 | 10 | // +---------------------------------------------------------------------- 11 | namespace Think; 12 | /** 13 | * 缓存管理类 14 | */ 15 | class Cache { 16 | 17 | /** 18 | * 操作句柄 19 | * @var string 20 | * @access protected 21 | */ 22 | protected $handler ; 23 | 24 | /** 25 | * 缓存连接参数 26 | * @var integer 27 | * @access protected 28 | */ 29 | protected $options = array(); 30 | 31 | /** 32 | * 连接缓存 33 | * @access public 34 | * @param string $type 缓存类型 35 | * @param array $options 配置数组 36 | * @return object 37 | */ 38 | public function connect($type='',$options=array()) { 39 | if(empty($type)) $type = C('DATA_CACHE_TYPE'); 40 | $class = strpos($type,'\\')? $type : 'Think\\Cache\\Driver\\'.ucwords(strtolower($type)); 41 | if(class_exists($class)) 42 | $cache = new $class($options); 43 | else 44 | E(L('_CACHE_TYPE_INVALID_').':'.$type); 45 | return $cache; 46 | } 47 | 48 | /** 49 | * 取得缓存类实例 50 | * @static 51 | * @access public 52 | * @return mixed 53 | */ 54 | static function getInstance($type='',$options=array()) { 55 | static $_instance = array(); 56 | $guid = $type.to_guid_string($options); 57 | if(!isset($_instance[$guid])){ 58 | $obj = new Cache(); 59 | $_instance[$guid] = $obj->connect($type,$options); 60 | } 61 | return $_instance[$guid]; 62 | } 63 | 64 | public function __get($name) { 65 | return $this->get($name); 66 | } 67 | 68 | public function __set($name,$value) { 69 | return $this->set($name,$value); 70 | } 71 | 72 | public function __unset($name) { 73 | $this->rm($name); 74 | } 75 | public function setOptions($name,$value) { 76 | $this->options[$name] = $value; 77 | } 78 | 79 | public function getOptions($name) { 80 | return $this->options[$name]; 81 | } 82 | 83 | /** 84 | * 队列缓存 85 | * @access protected 86 | * @param string $key 队列名 87 | * @return mixed 88 | */ 89 | // 90 | protected function queue($key) { 91 | static $_handler = array( 92 | 'file' => array('F','F'), 93 | 'xcache'=> array('xcache_get','xcache_set'), 94 | 'apc' => array('apc_fetch','apc_store'), 95 | ); 96 | $queue = isset($this->options['queue'])?$this->options['queue']:'file'; 97 | $fun = isset($_handler[$queue])?$_handler[$queue]:$_handler['file']; 98 | $queue_name = isset($this->options['queue_name'])?$this->options['queue_name']:'think_queue'; 99 | $value = $fun[0]($queue_name); 100 | if(!$value) { 101 | $value = array(); 102 | } 103 | // 进列 104 | if(false===array_search($key, $value)) array_push($value,$key); 105 | if(count($value) > $this->options['length']) { 106 | // 出列 107 | $key = array_shift($value); 108 | // 删除缓存 109 | $this->rm($key); 110 | if(APP_DEBUG){ 111 | //调试模式下,记录出列次数 112 | N($queue_name.'_out_times',1); 113 | } 114 | } 115 | return $fun[1]($queue_name,$value); 116 | } 117 | 118 | public function __call($method,$args){ 119 | //调用缓存类型自己的方法 120 | if(method_exists($this->handler, $method)){ 121 | return call_user_func_array(array($this->handler,$method), $args); 122 | }else{ 123 | E(__CLASS__.':'.$method.L('_METHOD_NOT_EXIST_')); 124 | return; 125 | } 126 | } 127 | } -------------------------------------------------------------------------------- /Example/ThinkPHP/Library/Think/Cache/Driver/File.class.php: -------------------------------------------------------------------------------- 1 | 10 | // +---------------------------------------------------------------------- 11 | namespace Think\Cache\Driver; 12 | use Think\Cache; 13 | defined('THINK_PATH') or exit(); 14 | /** 15 | * 文件类型缓存类 16 | */ 17 | class File extends Cache { 18 | 19 | /** 20 | * 架构函数 21 | * @access public 22 | */ 23 | public function __construct($options=array()) { 24 | if(!empty($options)) { 25 | $this->options = $options; 26 | } 27 | $this->options['temp'] = !empty($options['temp'])? $options['temp'] : C('DATA_CACHE_PATH'); 28 | $this->options['prefix'] = isset($options['prefix'])? $options['prefix'] : C('DATA_CACHE_PREFIX'); 29 | $this->options['expire'] = isset($options['expire'])? $options['expire'] : C('DATA_CACHE_TIME'); 30 | $this->options['length'] = isset($options['length'])? $options['length'] : 0; 31 | if(substr($this->options['temp'], -1) != '/') $this->options['temp'] .= '/'; 32 | $this->init(); 33 | } 34 | 35 | /** 36 | * 初始化检查 37 | * @access private 38 | * @return boolean 39 | */ 40 | private function init() { 41 | // 创建应用缓存目录 42 | if (!is_dir($this->options['temp'])) { 43 | mkdir($this->options['temp']); 44 | } 45 | } 46 | 47 | /** 48 | * 取得变量的存储文件名 49 | * @access private 50 | * @param string $name 缓存变量名 51 | * @return string 52 | */ 53 | private function filename($name) { 54 | $name = md5(C('DATA_CACHE_KEY').$name); 55 | if(C('DATA_CACHE_SUBDIR')) { 56 | // 使用子目录 57 | $dir =''; 58 | for($i=0;$ioptions['temp'].$dir)) { 62 | mkdir($this->options['temp'].$dir,0755,true); 63 | } 64 | $filename = $dir.$this->options['prefix'].$name.'.php'; 65 | }else{ 66 | $filename = $this->options['prefix'].$name.'.php'; 67 | } 68 | return $this->options['temp'].$filename; 69 | } 70 | 71 | /** 72 | * 读取缓存 73 | * @access public 74 | * @param string $name 缓存变量名 75 | * @return mixed 76 | */ 77 | public function get($name) { 78 | $filename = $this->filename($name); 79 | if (!is_file($filename)) { 80 | return false; 81 | } 82 | N('cache_read',1); 83 | $content = file_get_contents($filename); 84 | if( false !== $content) { 85 | $expire = (int)substr($content,8, 12); 86 | if($expire != 0 && time() > filemtime($filename) + $expire) { 87 | //缓存过期删除缓存文件 88 | unlink($filename); 89 | return false; 90 | } 91 | if(C('DATA_CACHE_CHECK')) {//开启数据校验 92 | $check = substr($content,20, 32); 93 | $content = substr($content,52, -3); 94 | if($check != md5($content)) {//校验错误 95 | return false; 96 | } 97 | }else { 98 | $content = substr($content,20, -3); 99 | } 100 | if(C('DATA_CACHE_COMPRESS') && function_exists('gzcompress')) { 101 | //启用数据压缩 102 | $content = gzuncompress($content); 103 | } 104 | $content = unserialize($content); 105 | return $content; 106 | } 107 | else { 108 | return false; 109 | } 110 | } 111 | 112 | /** 113 | * 写入缓存 114 | * @access public 115 | * @param string $name 缓存变量名 116 | * @param mixed $value 存储数据 117 | * @param int $expire 有效时间 0为永久 118 | * @return boolean 119 | */ 120 | public function set($name,$value,$expire=null) { 121 | N('cache_write',1); 122 | if(is_null($expire)) { 123 | $expire = $this->options['expire']; 124 | } 125 | $filename = $this->filename($name); 126 | $data = serialize($value); 127 | if( C('DATA_CACHE_COMPRESS') && function_exists('gzcompress')) { 128 | //数据压缩 129 | $data = gzcompress($data,3); 130 | } 131 | if(C('DATA_CACHE_CHECK')) {//开启数据校验 132 | $check = md5($data); 133 | }else { 134 | $check = ''; 135 | } 136 | $data = ""; 137 | $result = file_put_contents($filename,$data); 138 | if($result) { 139 | if($this->options['length']>0) { 140 | // 记录缓存队列 141 | $this->queue($name); 142 | } 143 | clearstatcache(); 144 | return true; 145 | }else { 146 | return false; 147 | } 148 | } 149 | 150 | /** 151 | * 删除缓存 152 | * @access public 153 | * @param string $name 缓存变量名 154 | * @return boolean 155 | */ 156 | public function rm($name) { 157 | return unlink($this->filename($name)); 158 | } 159 | 160 | /** 161 | * 清除缓存 162 | * @access public 163 | * @param string $name 缓存变量名 164 | * @return boolean 165 | */ 166 | public function clear() { 167 | $path = $this->options['temp']; 168 | $files = scandir($path); 169 | if($files){ 170 | foreach($files as $file){ 171 | if ($file != '.' && $file != '..' && is_dir($path.$file) ){ 172 | array_map( 'unlink', glob( $path.$file.'/*.*' ) ); 173 | }elseif(is_file($path.$file)){ 174 | unlink( $path . $file ); 175 | } 176 | } 177 | return true; 178 | } 179 | return false; 180 | } 181 | } -------------------------------------------------------------------------------- /Example/ThinkPHP/Library/Think/Cache/Driver/Memcachesae.class.php: -------------------------------------------------------------------------------- 1 | 10 | // +---------------------------------------------------------------------- 11 | namespace Think\Cache\Driver; 12 | use Think\Cache; 13 | 14 | defined('THINK_PATH') or exit(); 15 | /** 16 | * Memcache缓存驱动 17 | * @category Extend 18 | * @package Extend 19 | * @subpackage Driver.Cache 20 | * @author liu21st 21 | */ 22 | class Memcachesae extends Cache { 23 | 24 | /** 25 | * 架构函数 26 | * @param array $options 缓存参数 27 | * @access public 28 | */ 29 | function __construct($options=array()) { 30 | $options = array_merge(array ( 31 | 'host' => C('MEMCACHE_HOST') ? : '127.0.0.1', 32 | 'port' => C('MEMCACHE_PORT') ? : 11211, 33 | 'timeout' => C('DATA_CACHE_TIMEOUT') ? : false, 34 | 'persistent' => false, 35 | ),$options); 36 | 37 | $this->options = $options; 38 | $this->options['expire'] = isset($options['expire'])? $options['expire'] : C('DATA_CACHE_TIME'); 39 | $this->options['prefix'] = isset($options['prefix'])? $options['prefix'] : C('DATA_CACHE_PREFIX'); 40 | $this->options['length'] = isset($options['length'])? $options['length'] : 0; 41 | $this->handler = memcache_init();//[sae] 下实例化 42 | //[sae] 下不用链接 43 | $this->connected=true; 44 | } 45 | 46 | /** 47 | * 是否连接 48 | * @access private 49 | * @return boolean 50 | */ 51 | private function isConnected() { 52 | return $this->connected; 53 | } 54 | 55 | /** 56 | * 读取缓存 57 | * @access public 58 | * @param string $name 缓存变量名 59 | * @return mixed 60 | */ 61 | public function get($name) { 62 | N('cache_read',1); 63 | return $this->handler->get($_SERVER['HTTP_APPVERSION'].'/'.$this->options['prefix'].$name); 64 | } 65 | 66 | /** 67 | * 写入缓存 68 | * @access public 69 | * @param string $name 缓存变量名 70 | * @param mixed $value 存储数据 71 | * @param integer $expire 有效时间(秒) 72 | * @return boolean 73 | */ 74 | public function set($name, $value, $expire = null) { 75 | N('cache_write',1); 76 | if(is_null($expire)) { 77 | $expire = $this->options['expire']; 78 | } 79 | $name = $this->options['prefix'].$name; 80 | if($this->handler->set($_SERVER['HTTP_APPVERSION'].'/'.$name, $value, 0, $expire)) { 81 | if($this->options['length']>0) { 82 | // 记录缓存队列 83 | $this->queue($name); 84 | } 85 | return true; 86 | } 87 | return false; 88 | } 89 | 90 | /** 91 | * 删除缓存 92 | * @access public 93 | * @param string $name 缓存变量名 94 | * @return boolean 95 | */ 96 | public function rm($name, $ttl = false) { 97 | $name = $_SERVER['HTTP_APPVERSION'].'/'.$this->options['prefix'].$name; 98 | return $ttl === false ? 99 | $this->handler->delete($name) : 100 | $this->handler->delete($name, $ttl); 101 | } 102 | 103 | /** 104 | * 清除缓存 105 | * @access public 106 | * @return boolean 107 | */ 108 | public function clear() { 109 | return $this->handler->flush(); 110 | } 111 | 112 | /** 113 | * 队列缓存 114 | * @access protected 115 | * @param string $key 队列名 116 | * @return mixed 117 | */ 118 | //[sae] 下重写queque队列缓存方法 119 | protected function queue($key) { 120 | $queue_name=isset($this->options['queue_name'])?$this->options['queue_name']:'think_queue'; 121 | $value = F($queue_name); 122 | if(!$value) { 123 | $value = array(); 124 | } 125 | // 进列 126 | if(false===array_search($key, $value)) array_push($value,$key); 127 | if(count($value) > $this->options['length']) { 128 | // 出列 129 | $key = array_shift($value); 130 | // 删除缓存 131 | $this->rm($key); 132 | if (APP_DEBUG) { 133 | //调试模式下记录出队次数 134 | $counter = Think::instance('SaeCounter'); 135 | if ($counter->exists($queue_name.'_out_times')) 136 | $counter->incr($queue_name.'_out_times'); 137 | else 138 | $counter->create($queue_name.'_out_times', 1); 139 | } 140 | } 141 | return F($queue_name,$value); 142 | } 143 | 144 | } 145 | -------------------------------------------------------------------------------- /Example/ThinkPHP/Library/Think/Controller.class.php: -------------------------------------------------------------------------------- 1 | 10 | // +---------------------------------------------------------------------- 11 | namespace Think; 12 | /** 13 | * ThinkPHP 控制器基类 抽象类 14 | */ 15 | abstract class Controller { 16 | 17 | /** 18 | * 视图实例对象 19 | * @var view 20 | * @access protected 21 | */ 22 | protected $view = null; 23 | 24 | /** 25 | * 控制器参数 26 | * @var config 27 | * @access protected 28 | */ 29 | protected $config = array(); 30 | 31 | /** 32 | * 架构函数 取得模板对象实例 33 | * @access public 34 | */ 35 | public function __construct() { 36 | Hook::listen('action_begin',$this->config); 37 | //实例化视图类 38 | $this->view = Think::instance('Think\View'); 39 | //控制器初始化 40 | if(method_exists($this,'_initialize')) 41 | $this->_initialize(); 42 | } 43 | 44 | /** 45 | * 模板显示 调用内置的模板引擎显示方法, 46 | * @access protected 47 | * @param string $templateFile 指定要调用的模板文件 48 | * 默认为空 由系统自动定位模板文件 49 | * @param string $charset 输出编码 50 | * @param string $contentType 输出类型 51 | * @param string $content 输出内容 52 | * @param string $prefix 模板缓存前缀 53 | * @return void 54 | */ 55 | protected function display($templateFile='',$charset='',$contentType='',$content='',$prefix='') { 56 | $this->view->display($templateFile,$charset,$contentType,$content,$prefix); 57 | } 58 | 59 | /** 60 | * 输出内容文本可以包括Html 并支持内容解析 61 | * @access protected 62 | * @param string $content 输出内容 63 | * @param string $charset 模板输出字符集 64 | * @param string $contentType 输出类型 65 | * @param string $prefix 模板缓存前缀 66 | * @return mixed 67 | */ 68 | protected function show($content,$charset='',$contentType='',$prefix='') { 69 | $this->view->display('',$charset,$contentType,$content,$prefix); 70 | } 71 | 72 | /** 73 | * 获取输出页面内容 74 | * 调用内置的模板引擎fetch方法, 75 | * @access protected 76 | * @param string $templateFile 指定要调用的模板文件 77 | * 默认为空 由系统自动定位模板文件 78 | * @param string $content 模板输出内容 79 | * @param string $prefix 模板缓存前缀* 80 | * @return string 81 | */ 82 | protected function fetch($templateFile='',$content='',$prefix='') { 83 | return $this->view->fetch($templateFile,$content,$prefix); 84 | } 85 | 86 | /** 87 | * 创建静态页面 88 | * @access protected 89 | * @htmlfile 生成的静态文件名称 90 | * @htmlpath 生成的静态文件路径 91 | * @param string $templateFile 指定要调用的模板文件 92 | * 默认为空 由系统自动定位模板文件 93 | * @return string 94 | */ 95 | protected function buildHtml($htmlfile='',$htmlpath='',$templateFile='') { 96 | $content = $this->fetch($templateFile); 97 | $htmlpath = !empty($htmlpath)?$htmlpath:HTML_PATH; 98 | $htmlfile = $htmlpath.$htmlfile.C('HTML_FILE_SUFFIX'); 99 | Storage::put($htmlfile,$content,'html'); 100 | return $content; 101 | } 102 | 103 | /** 104 | * 模板主题设置 105 | * @access protected 106 | * @param string $theme 模版主题 107 | * @return Action 108 | */ 109 | protected function theme($theme){ 110 | $this->view->theme($theme); 111 | return $this; 112 | } 113 | 114 | /** 115 | * 模板变量赋值 116 | * @access protected 117 | * @param mixed $name 要显示的模板变量 118 | * @param mixed $value 变量的值 119 | * @return Action 120 | */ 121 | protected function assign($name,$value='') { 122 | $this->view->assign($name,$value); 123 | return $this; 124 | } 125 | 126 | public function __set($name,$value) { 127 | $this->assign($name,$value); 128 | } 129 | 130 | /** 131 | * 取得模板显示变量的值 132 | * @access protected 133 | * @param string $name 模板显示变量 134 | * @return mixed 135 | */ 136 | public function get($name='') { 137 | return $this->view->get($name); 138 | } 139 | 140 | public function __get($name) { 141 | return $this->get($name); 142 | } 143 | 144 | /** 145 | * 检测模板变量的值 146 | * @access public 147 | * @param string $name 名称 148 | * @return boolean 149 | */ 150 | public function __isset($name) { 151 | return $this->get($name); 152 | } 153 | 154 | /** 155 | * 魔术方法 有不存在的操作的时候执行 156 | * @access public 157 | * @param string $method 方法名 158 | * @param array $args 参数 159 | * @return mixed 160 | */ 161 | public function __call($method,$args) { 162 | if( 0 === strcasecmp($method,ACTION_NAME.C('ACTION_SUFFIX'))) { 163 | if(method_exists($this,'_empty')) { 164 | // 如果定义了_empty操作 则调用 165 | $this->_empty($method,$args); 166 | }elseif(file_exists_case($this->view->parseTemplate())){ 167 | // 检查是否存在默认模版 如果有直接输出模版 168 | $this->display(); 169 | }else{ 170 | E(L('_ERROR_ACTION_').':'.ACTION_NAME); 171 | } 172 | }else{ 173 | E(__CLASS__.':'.$method.L('_METHOD_NOT_EXIST_')); 174 | return; 175 | } 176 | } 177 | 178 | /** 179 | * 操作错误跳转的快捷方法 180 | * @access protected 181 | * @param string $message 错误信息 182 | * @param string $jumpUrl 页面跳转地址 183 | * @param mixed $ajax 是否为Ajax方式 当数字时指定跳转时间 184 | * @return void 185 | */ 186 | protected function error($message='',$jumpUrl='',$ajax=false) { 187 | $this->dispatchJump($message,0,$jumpUrl,$ajax); 188 | } 189 | 190 | /** 191 | * 操作成功跳转的快捷方法 192 | * @access protected 193 | * @param string $message 提示信息 194 | * @param string $jumpUrl 页面跳转地址 195 | * @param mixed $ajax 是否为Ajax方式 当数字时指定跳转时间 196 | * @return void 197 | */ 198 | protected function success($message='',$jumpUrl='',$ajax=false) { 199 | $this->dispatchJump($message,1,$jumpUrl,$ajax); 200 | } 201 | 202 | /** 203 | * Ajax方式返回数据到客户端 204 | * @access protected 205 | * @param mixed $data 要返回的数据 206 | * @param String $type AJAX返回数据格式 207 | * @param int $json_option 传递给json_encode的option参数 208 | * @return void 209 | */ 210 | protected function ajaxReturn($data,$type='',$json_option=0) { 211 | if(empty($type)) $type = C('DEFAULT_AJAX_RETURN'); 212 | switch (strtoupper($type)){ 213 | case 'JSON' : 214 | // 返回JSON数据格式到客户端 包含状态信息 215 | header('Content-Type:application/json; charset=utf-8'); 216 | exit(json_encode($data,$json_option)); 217 | case 'XML' : 218 | // 返回xml格式数据 219 | header('Content-Type:text/xml; charset=utf-8'); 220 | exit(xml_encode($data)); 221 | case 'JSONP': 222 | // 返回JSON数据格式到客户端 包含状态信息 223 | header('Content-Type:application/json; charset=utf-8'); 224 | $handler = isset($_GET[C('VAR_JSONP_HANDLER')]) ? $_GET[C('VAR_JSONP_HANDLER')] : C('DEFAULT_JSONP_HANDLER'); 225 | exit($handler.'('.json_encode($data,$json_option).');'); 226 | case 'EVAL' : 227 | // 返回可执行的js脚本 228 | header('Content-Type:text/html; charset=utf-8'); 229 | exit($data); 230 | default : 231 | // 用于扩展其他返回格式数据 232 | Hook::listen('ajax_return',$data); 233 | } 234 | } 235 | 236 | /** 237 | * Action跳转(URL重定向) 支持指定模块和延时跳转 238 | * @access protected 239 | * @param string $url 跳转的URL表达式 240 | * @param array $params 其它URL参数 241 | * @param integer $delay 延时跳转的时间 单位为秒 242 | * @param string $msg 跳转提示信息 243 | * @return void 244 | */ 245 | protected function redirect($url,$params=array(),$delay=0,$msg='') { 246 | $url = U($url,$params); 247 | redirect($url,$delay,$msg); 248 | } 249 | 250 | /** 251 | * 默认跳转操作 支持错误导向和正确跳转 252 | * 调用模板显示 默认为public目录下面的success页面 253 | * 提示页面为可配置 支持模板标签 254 | * @param string $message 提示信息 255 | * @param Boolean $status 状态 256 | * @param string $jumpUrl 页面跳转地址 257 | * @param mixed $ajax 是否为Ajax方式 当数字时指定跳转时间 258 | * @access private 259 | * @return void 260 | */ 261 | private function dispatchJump($message,$status=1,$jumpUrl='',$ajax=false) { 262 | if(true === $ajax || IS_AJAX) {// AJAX提交 263 | $data = is_array($ajax)?$ajax:array(); 264 | $data['info'] = $message; 265 | $data['status'] = $status; 266 | $data['url'] = $jumpUrl; 267 | $this->ajaxReturn($data); 268 | } 269 | if(is_int($ajax)) $this->assign('waitSecond',$ajax); 270 | if(!empty($jumpUrl)) $this->assign('jumpUrl',$jumpUrl); 271 | // 提示标题 272 | $this->assign('msgTitle',$status? L('_OPERATION_SUCCESS_') : L('_OPERATION_FAIL_')); 273 | //如果设置了关闭窗口,则提示完毕后自动关闭窗口 274 | if($this->get('closeWin')) $this->assign('jumpUrl','javascript:window.close();'); 275 | $this->assign('status',$status); // 状态 276 | //保证输出不受静态缓存影响 277 | C('HTML_CACHE_ON',false); 278 | if($status) { //发送成功信息 279 | $this->assign('message',$message);// 提示信息 280 | // 成功操作后默认停留1秒 281 | if(!isset($this->waitSecond)) $this->assign('waitSecond','1'); 282 | // 默认操作成功自动返回操作前页面 283 | if(!isset($this->jumpUrl)) $this->assign("jumpUrl",$_SERVER["HTTP_REFERER"]); 284 | $this->display(C('TMPL_ACTION_SUCCESS')); 285 | }else{ 286 | $this->assign('error',$message);// 提示信息 287 | //发生错误时候默认停留3秒 288 | if(!isset($this->waitSecond)) $this->assign('waitSecond','3'); 289 | // 默认发生错误的话自动返回上页 290 | if(!isset($this->jumpUrl)) $this->assign('jumpUrl',"javascript:history.back(-1);"); 291 | $this->display(C('TMPL_ACTION_ERROR')); 292 | // 中止执行 避免出错后继续执行 293 | exit ; 294 | } 295 | } 296 | 297 | /** 298 | * 析构方法 299 | * @access public 300 | */ 301 | public function __destruct() { 302 | // 执行后续操作 303 | Hook::listen('action_end'); 304 | } 305 | } 306 | // 设置控制器别名 便于升级 307 | class_alias('Think\Controller','Think\Action'); 308 | -------------------------------------------------------------------------------- /Example/ThinkPHP/Library/Think/Db.class.php: -------------------------------------------------------------------------------- 1 | 10 | // +---------------------------------------------------------------------- 11 | 12 | namespace Think; 13 | 14 | /** 15 | * ThinkPHP 数据库中间层实现类 16 | */ 17 | class Db { 18 | 19 | static private $instance = array(); // 数据库连接实例 20 | static private $_instance = null; // 当前数据库连接实例 21 | 22 | /** 23 | * 取得数据库类实例 24 | * @static 25 | * @access public 26 | * @param mixed $config 连接配置 27 | * @return Object 返回数据库驱动类 28 | */ 29 | static public function getInstance($config=array()) { 30 | $md5 = md5(serialize($config)); 31 | if(!isset(self::$instance[$md5])) { 32 | // 解析连接参数 支持数组和字符串 33 | $options = self::parseConfig($config); 34 | // 兼容mysqli 35 | if('mysqli' == $options['type']) $options['type'] = 'mysql'; 36 | // 如果采用lite方式 仅支持原生SQL 包括query和execute方法 37 | $class = $options['lite']? 'Think\Db\Lite' : 'Think\\Db\\Driver\\'.ucwords(strtolower($options['type'])); 38 | if(class_exists($class)){ 39 | self::$instance[$md5] = new $class($options); 40 | }else{ 41 | // 类没有定义 42 | E(L('_NO_DB_DRIVER_').': ' . $class); 43 | } 44 | } 45 | self::$_instance = self::$instance[$md5]; 46 | return self::$_instance; 47 | } 48 | 49 | /** 50 | * 数据库连接参数解析 51 | * @static 52 | * @access private 53 | * @param mixed $config 54 | * @return array 55 | */ 56 | static private function parseConfig($config){ 57 | if(!empty($config)){ 58 | if(is_string($config)) { 59 | return self::parseDsn($config); 60 | } 61 | $config = array_change_key_case($config); 62 | $config = array ( 63 | 'type' => $config['db_type'], 64 | 'username' => $config['db_user'], 65 | 'password' => $config['db_pwd'], 66 | 'hostname' => $config['db_host'], 67 | 'hostport' => $config['db_port'], 68 | 'database' => $config['db_name'], 69 | 'dsn' => isset($config['db_dsn'])?$config['db_dsn']:null, 70 | 'params' => isset($config['db_params'])?$config['db_params']:null, 71 | 'charset' => isset($config['db_charset'])?$config['db_charset']:'utf8', 72 | 'deploy' => isset($config['db_deploy_type'])?$config['db_deploy_type']:0, 73 | 'rw_separate' => isset($config['db_rw_separate'])?$config['db_rw_separate']:false, 74 | 'master_num' => isset($config['db_master_num'])?$config['db_master_num']:1, 75 | 'slave_no' => isset($config['db_slave_no'])?$config['db_slave_no']:'', 76 | 'debug' => isset($config['db_debug'])?$config['db_debug']:APP_DEBUG, 77 | 'lite' => isset($config['db_lite'])?$config['db_lite']:false, 78 | ); 79 | }else { 80 | $config = array ( 81 | 'type' => C('DB_TYPE'), 82 | 'username' => C('DB_USER'), 83 | 'password' => C('DB_PWD'), 84 | 'hostname' => C('DB_HOST'), 85 | 'hostport' => C('DB_PORT'), 86 | 'database' => C('DB_NAME'), 87 | 'dsn' => C('DB_DSN'), 88 | 'params' => C('DB_PARAMS'), 89 | 'charset' => C('DB_CHARSET'), 90 | 'deploy' => C('DB_DEPLOY_TYPE'), 91 | 'rw_separate' => C('DB_RW_SEPARATE'), 92 | 'master_num' => C('DB_MASTER_NUM'), 93 | 'slave_no' => C('DB_SLAVE_NO'), 94 | 'debug' => C('DB_DEBUG',null,APP_DEBUG), 95 | 'lite' => C('DB_LITE'), 96 | ); 97 | } 98 | return $config; 99 | } 100 | 101 | /** 102 | * DSN解析 103 | * 格式: mysql://username:passwd@localhost:3306/DbName?param1=val1¶m2=val2#utf8 104 | * @static 105 | * @access private 106 | * @param string $dsnStr 107 | * @return array 108 | */ 109 | static private function parseDsn($dsnStr) { 110 | if( empty($dsnStr) ){return false;} 111 | $info = parse_url($dsnStr); 112 | if(!$info) { 113 | return false; 114 | } 115 | $dsn = array( 116 | 'type' => $info['scheme'], 117 | 'username' => isset($info['user']) ? $info['user'] : '', 118 | 'password' => isset($info['pass']) ? $info['pass'] : '', 119 | 'hostname' => isset($info['host']) ? $info['host'] : '', 120 | 'hostport' => isset($info['port']) ? $info['port'] : '', 121 | 'database' => isset($info['path']) ? substr($info['path'],1) : '', 122 | 'charset' => isset($info['fragment'])?$info['fragment']:'utf8', 123 | ); 124 | 125 | if(isset($info['query'])) { 126 | parse_str($info['query'],$dsn['params']); 127 | }else{ 128 | $dsn['params'] = array(); 129 | } 130 | return $dsn; 131 | } 132 | 133 | // 调用驱动类的方法 134 | static public function __callStatic($method, $params){ 135 | return call_user_func_array(array(self::$_instance, $method), $params); 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /Example/ThinkPHP/Library/Think/Db/Driver/Mysql.class.php: -------------------------------------------------------------------------------- 1 | 10 | // +---------------------------------------------------------------------- 11 | 12 | namespace Think\Db\Driver; 13 | use Think\Db\Driver; 14 | 15 | /** 16 | * mysql数据库驱动 17 | */ 18 | class Mysql extends Driver{ 19 | 20 | /** 21 | * 解析pdo连接的dsn信息 22 | * @access public 23 | * @param array $config 连接信息 24 | * @return string 25 | */ 26 | protected function parseDsn($config){ 27 | $dsn = 'mysql:dbname='.$config['database'].';host='.$config['hostname']; 28 | if(!empty($config['hostport'])) { 29 | $dsn .= ';port='.$config['hostport']; 30 | }elseif(!empty($config['socket'])){ 31 | $dsn .= ';unix_socket='.$config['socket']; 32 | } 33 | 34 | if(!empty($config['charset'])){ 35 | //为兼容各版本PHP,用两种方式设置编码 36 | $this->options[\PDO::MYSQL_ATTR_INIT_COMMAND] = 'SET NAMES '.$config['charset']; 37 | $dsn .= ';charset='.$config['charset']; 38 | } 39 | return $dsn; 40 | } 41 | 42 | /** 43 | * 取得数据表的字段信息 44 | * @access public 45 | */ 46 | public function getFields($tableName) { 47 | $this->initConnect(true); 48 | list($tableName) = explode(' ', $tableName); 49 | if(strpos($tableName,'.')){ 50 | list($dbName,$tableName) = explode('.',$tableName); 51 | $sql = 'SHOW COLUMNS FROM `'.$dbName.'`.`'.$tableName.'`'; 52 | }else{ 53 | $sql = 'SHOW COLUMNS FROM `'.$tableName.'`'; 54 | } 55 | 56 | $result = $this->query($sql); 57 | $info = array(); 58 | if($result) { 59 | foreach ($result as $key => $val) { 60 | if(\PDO::CASE_LOWER != $this->_linkID->getAttribute(\PDO::ATTR_CASE)){ 61 | $val = array_change_key_case ( $val , CASE_LOWER ); 62 | } 63 | $info[$val['field']] = array( 64 | 'name' => $val['field'], 65 | 'type' => $val['type'], 66 | 'notnull' => (bool) ($val['null'] === ''), // not null is empty, null is yes 67 | 'default' => $val['default'], 68 | 'primary' => (strtolower($val['key']) == 'pri'), 69 | 'autoinc' => (strtolower($val['extra']) == 'auto_increment'), 70 | ); 71 | } 72 | } 73 | return $info; 74 | } 75 | 76 | /** 77 | * 取得数据库的表信息 78 | * @access public 79 | */ 80 | public function getTables($dbName='') { 81 | $sql = !empty($dbName)?'SHOW TABLES FROM '.$dbName:'SHOW TABLES '; 82 | $result = $this->query($sql); 83 | $info = array(); 84 | foreach ($result as $key => $val) { 85 | $info[$key] = current($val); 86 | } 87 | return $info; 88 | } 89 | 90 | /** 91 | * 字段和表名处理 92 | * @access protected 93 | * @param string $key 94 | * @return string 95 | */ 96 | protected function parseKey(&$key) { 97 | $key = trim($key); 98 | if(!is_numeric($key) && !preg_match('/[,\'\"\*\(\)`.\s]/',$key)) { 99 | $key = '`'.$key.'`'; 100 | } 101 | return $key; 102 | } 103 | 104 | /** 105 | * 批量插入记录 106 | * @access public 107 | * @param mixed $dataSet 数据集 108 | * @param array $options 参数表达式 109 | * @param boolean $replace 是否replace 110 | * @return false | integer 111 | */ 112 | public function insertAll($dataSet,$options=array(),$replace=false) { 113 | $values = array(); 114 | $this->model = $options['model']; 115 | if(!is_array($dataSet[0])) return false; 116 | $this->parseBind(!empty($options['bind'])?$options['bind']:array()); 117 | $fields = array_map(array($this,'parseKey'),array_keys($dataSet[0])); 118 | foreach ($dataSet as $data){ 119 | $value = array(); 120 | foreach ($data as $key=>$val){ 121 | if(is_array($val) && 'exp' == $val[0]){ 122 | $value[] = $val[1]; 123 | }elseif(is_scalar($val)){ 124 | if(0===strpos($val,':') && in_array($val,array_keys($this->bind))){ 125 | $value[] = $this->parseValue($val); 126 | }else{ 127 | $name = count($this->bind); 128 | $value[] = ':'.$name; 129 | $this->bindParam($name,$val); 130 | } 131 | } 132 | } 133 | $values[] = '('.implode(',', $value).')'; 134 | } 135 | // 兼容数字传入方式 136 | $replace= (is_numeric($replace) && $replace>0)?true:$replace; 137 | $sql = (true===$replace?'REPLACE':'INSERT').' INTO '.$this->parseTable($options['table']).' ('.implode(',', $fields).') VALUES '.implode(',',$values).$this->parseDuplicate($replace); 138 | $sql .= $this->parseComment(!empty($options['comment'])?$options['comment']:''); 139 | return $this->execute($sql,!empty($options['fetch_sql']) ? true : false); 140 | } 141 | 142 | /** 143 | * ON DUPLICATE KEY UPDATE 分析 144 | * @access protected 145 | * @param mixed $duplicate 146 | * @return string 147 | */ 148 | protected function parseDuplicate($duplicate){ 149 | // 布尔值或空则返回空字符串 150 | if(is_bool($duplicate) || empty($duplicate)) return ''; 151 | 152 | if(is_string($duplicate)){ 153 | // field1,field2 转数组 154 | $duplicate = explode(',', $duplicate); 155 | }elseif(is_object($duplicate)){ 156 | // 对象转数组 157 | $duplicate = get_class_vars($duplicate); 158 | } 159 | $updates = array(); 160 | foreach((array) $duplicate as $key=>$val){ 161 | if(is_numeric($key)){ // array('field1', 'field2', 'field3') 解析为 ON DUPLICATE KEY UPDATE field1=VALUES(field1), field2=VALUES(field2), field3=VALUES(field3) 162 | $updates[] = $this->parseKey($val)."=VALUES(".$this->parseKey($val).")"; 163 | }else{ 164 | if(is_scalar($val)) // 兼容标量传值方式 165 | $val = array('value', $val); 166 | if(!isset($val[1])) continue; 167 | switch($val[0]){ 168 | case 'exp': // 表达式 169 | $updates[] = $this->parseKey($key)."=($val[1])"; 170 | break; 171 | case 'value': // 值 172 | default: 173 | $name = count($this->bind); 174 | $updates[] = $this->parseKey($key)."=:".$name; 175 | $this->bindParam($name, $val[1]); 176 | break; 177 | } 178 | } 179 | } 180 | if(empty($updates)) return ''; 181 | return " ON DUPLICATE KEY UPDATE ".join(', ', $updates); 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /Example/ThinkPHP/Library/Think/Exception.class.php: -------------------------------------------------------------------------------- 1 | 10 | // +---------------------------------------------------------------------- 11 | namespace Think; 12 | /** 13 | * ThinkPHP系统异常基类 14 | */ 15 | class Exception extends \Exception { 16 | } -------------------------------------------------------------------------------- /Example/ThinkPHP/Library/Think/Hook.class.php: -------------------------------------------------------------------------------- 1 | 10 | // +---------------------------------------------------------------------- 11 | namespace Think; 12 | /** 13 | * ThinkPHP系统钩子实现 14 | */ 15 | class Hook { 16 | 17 | static private $tags = array(); 18 | 19 | /** 20 | * 动态添加插件到某个标签 21 | * @param string $tag 标签名称 22 | * @param mixed $name 插件名称 23 | * @return void 24 | */ 25 | static public function add($tag,$name) { 26 | if(!isset(self::$tags[$tag])){ 27 | self::$tags[$tag] = array(); 28 | } 29 | if(is_array($name)){ 30 | self::$tags[$tag] = array_merge(self::$tags[$tag],$name); 31 | }else{ 32 | self::$tags[$tag][] = $name; 33 | } 34 | } 35 | 36 | /** 37 | * 批量导入插件 38 | * @param array $data 插件信息 39 | * @param boolean $recursive 是否递归合并 40 | * @return void 41 | */ 42 | static public function import($data,$recursive=true) { 43 | if(!$recursive){ // 覆盖导入 44 | self::$tags = array_merge(self::$tags,$data); 45 | }else{ // 合并导入 46 | foreach ($data as $tag=>$val){ 47 | if(!isset(self::$tags[$tag])) 48 | self::$tags[$tag] = array(); 49 | if(!empty($val['_overlay'])){ 50 | // 可以针对某个标签指定覆盖模式 51 | unset($val['_overlay']); 52 | self::$tags[$tag] = $val; 53 | }else{ 54 | // 合并模式 55 | self::$tags[$tag] = array_merge(self::$tags[$tag],$val); 56 | } 57 | } 58 | } 59 | } 60 | 61 | /** 62 | * 获取插件信息 63 | * @param string $tag 插件位置 留空获取全部 64 | * @return array 65 | */ 66 | static public function get($tag='') { 67 | if(empty($tag)){ 68 | // 获取全部的插件信息 69 | return self::$tags; 70 | }else{ 71 | return self::$tags[$tag]; 72 | } 73 | } 74 | 75 | /** 76 | * 监听标签的插件 77 | * @param string $tag 标签名称 78 | * @param mixed $params 传入参数 79 | * @return void 80 | */ 81 | static public function listen($tag, &$params=NULL) { 82 | if(isset(self::$tags[$tag])) { 83 | if(APP_DEBUG) { 84 | G($tag.'Start'); 85 | trace('[ '.$tag.' ] --START--','','INFO'); 86 | } 87 | foreach (self::$tags[$tag] as $name) { 88 | APP_DEBUG && G($name.'_start'); 89 | $result = self::exec($name, $tag,$params); 90 | if(APP_DEBUG){ 91 | G($name.'_end'); 92 | trace('Run '.$name.' [ RunTime:'.G($name.'_start',$name.'_end',6).'s ]','','INFO'); 93 | } 94 | if(false === $result) { 95 | // 如果返回false 则中断插件执行 96 | return ; 97 | } 98 | } 99 | if(APP_DEBUG) { // 记录行为的执行日志 100 | trace('[ '.$tag.' ] --END-- [ RunTime:'.G($tag.'Start',$tag.'End',6).'s ]','','INFO'); 101 | } 102 | } 103 | return; 104 | } 105 | 106 | /** 107 | * 执行某个插件 108 | * @param string $name 插件名称 109 | * @param string $tag 方法名(标签名) 110 | * @param Mixed $params 传入的参数 111 | * @return void 112 | */ 113 | static public function exec($name, $tag,&$params=NULL) { 114 | if('Behavior' == substr($name,-8) ){ 115 | // 行为扩展必须用run入口方法 116 | $tag = 'run'; 117 | } 118 | $addon = new $name(); 119 | return $addon->$tag($params); 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /Example/ThinkPHP/Library/Think/Log.class.php: -------------------------------------------------------------------------------- 1 | 10 | // +---------------------------------------------------------------------- 11 | namespace Think; 12 | /** 13 | * 日志处理类 14 | */ 15 | class Log { 16 | 17 | // 日志级别 从上到下,由低到高 18 | const EMERG = 'EMERG'; // 严重错误: 导致系统崩溃无法使用 19 | const ALERT = 'ALERT'; // 警戒性错误: 必须被立即修改的错误 20 | const CRIT = 'CRIT'; // 临界值错误: 超过临界值的错误,例如一天24小时,而输入的是25小时这样 21 | const ERR = 'ERR'; // 一般错误: 一般性错误 22 | const WARN = 'WARN'; // 警告性错误: 需要发出警告的错误 23 | const NOTICE = 'NOTIC'; // 通知: 程序可以运行但是还不够完美的错误 24 | const INFO = 'INFO'; // 信息: 程序输出信息 25 | const DEBUG = 'DEBUG'; // 调试: 调试信息 26 | const SQL = 'SQL'; // SQL:SQL语句 注意只在调试模式开启时有效 27 | 28 | // 日志信息 29 | static protected $log = array(); 30 | 31 | // 日志存储 32 | static protected $storage = null; 33 | 34 | // 日志初始化 35 | static public function init($config=array()){ 36 | $type = isset($config['type'])?$config['type']:'File'; 37 | $class = strpos($type,'\\')? $type: 'Think\\Log\\Driver\\'. ucwords(strtolower($type)); 38 | unset($config['type']); 39 | self::$storage = new $class($config); 40 | } 41 | 42 | /** 43 | * 记录日志 并且会过滤未经设置的级别 44 | * @static 45 | * @access public 46 | * @param string $message 日志信息 47 | * @param string $level 日志级别 48 | * @param boolean $record 是否强制记录 49 | * @return void 50 | */ 51 | static function record($message,$level=self::ERR,$record=false) { 52 | if($record || false !== strpos(C('LOG_LEVEL'),$level)) { 53 | self::$log[] = "{$level}: {$message}\r\n"; 54 | } 55 | } 56 | 57 | /** 58 | * 日志保存 59 | * @static 60 | * @access public 61 | * @param integer $type 日志记录方式 62 | * @param string $destination 写入目标 63 | * @return void 64 | */ 65 | static function save($type='',$destination='') { 66 | if(empty(self::$log)) return ; 67 | 68 | if(empty($destination)) 69 | $destination = C('LOG_PATH').date('y_m_d').'.log'; 70 | if(!self::$storage){ 71 | $type = $type?:C('LOG_TYPE'); 72 | $class = 'Think\\Log\\Driver\\'. ucwords($type); 73 | self::$storage = new $class(); 74 | } 75 | $message = implode('',self::$log); 76 | self::$storage->write($message,$destination); 77 | // 保存后清空日志缓存 78 | self::$log = array(); 79 | } 80 | 81 | /** 82 | * 日志直接写入 83 | * @static 84 | * @access public 85 | * @param string $message 日志信息 86 | * @param string $level 日志级别 87 | * @param integer $type 日志记录方式 88 | * @param string $destination 写入目标 89 | * @return void 90 | */ 91 | static function write($message,$level=self::ERR,$type='',$destination='') { 92 | if(!self::$storage){ 93 | $type = $type?:C('LOG_TYPE'); 94 | $class = 'Think\\Log\\Driver\\'. ucwords($type); 95 | self::$storage = new $class(); 96 | } 97 | if(empty($destination)) 98 | $destination = C('LOG_PATH').date('y_m_d').'.log'; 99 | self::$storage->write("{$level}: {$message}", $destination); 100 | } 101 | } -------------------------------------------------------------------------------- /Example/ThinkPHP/Library/Think/Log/Driver/File.class.php: -------------------------------------------------------------------------------- 1 | 10 | // +---------------------------------------------------------------------- 11 | 12 | namespace Think\Log\Driver; 13 | 14 | class File { 15 | 16 | protected $config = array( 17 | 'log_time_format' => ' c ', 18 | 'log_file_size' => 2097152, 19 | 'log_path' => '', 20 | ); 21 | 22 | // 实例化并传入参数 23 | public function __construct($config=array()){ 24 | $this->config = array_merge($this->config,$config); 25 | } 26 | 27 | /** 28 | * 日志写入接口 29 | * @access public 30 | * @param string $log 日志信息 31 | * @param string $destination 写入目标 32 | * @return void 33 | */ 34 | public function write($log,$destination='') { 35 | $now = date($this->config['log_time_format']); 36 | if(empty($destination)) 37 | $destination = $this->config['log_path'].date('y_m_d').'.log'; 38 | // 自动创建日志目录 39 | $log_dir = dirname($destination); 40 | if (!is_dir($log_dir)) { 41 | mkdir($log_dir, 0755, true); 42 | } 43 | //检测日志文件大小,超过配置大小则备份日志文件重新生成 44 | if(is_file($destination) && floor($this->config['log_file_size']) <= filesize($destination) ) 45 | rename($destination,dirname($destination).'/'.time().'-'.basename($destination)); 46 | error_log("[{$now}] ".$_SERVER['REMOTE_ADDR'].' '.$_SERVER['REQUEST_URI']."\r\n{$log}\r\n", 3,$destination); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Example/ThinkPHP/Library/Think/Log/Driver/Sae.class.php: -------------------------------------------------------------------------------- 1 | 10 | // +---------------------------------------------------------------------- 11 | 12 | namespace Think\Log\Driver; 13 | 14 | class Sae { 15 | 16 | protected $config = array( 17 | 'log_time_format' => ' c ', 18 | ); 19 | 20 | // 实例化并传入参数 21 | public function __construct($config=array()){ 22 | $this->config = array_merge($this->config,$config); 23 | } 24 | 25 | /** 26 | * 日志写入接口 27 | * @access public 28 | * @param string $log 日志信息 29 | * @param string $destination 写入目标 30 | * @return void 31 | */ 32 | public function write($log,$destination='') { 33 | static $is_debug=null; 34 | $now = date($this->config['log_time_format']); 35 | $logstr="[{$now}] ".$_SERVER['REMOTE_ADDR'].' '.$_SERVER['REQUEST_URI']."\r\n{$log}\r\n"; 36 | if(is_null($is_debug)){ 37 | preg_replace('@(\w+)\=([^;]*)@e', '$appSettings[\'\\1\']="\\2";', $_SERVER['HTTP_APPCOOKIE']); 38 | $is_debug = in_array($_SERVER['HTTP_APPVERSION'], explode(',', $appSettings['debug'])) ? true : false; 39 | } 40 | if($is_debug) 41 | sae_set_display_errors(false);//记录日志不将日志打印出来 42 | sae_debug($logstr); 43 | if($is_debug) 44 | sae_set_display_errors(true); 45 | 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Example/ThinkPHP/Library/Think/Route.class.php: -------------------------------------------------------------------------------- 1 | 10 | // +---------------------------------------------------------------------- 11 | namespace Think; 12 | /** 13 | * ThinkPHP路由解析类 14 | */ 15 | class Route { 16 | 17 | // 路由检测 18 | public static function check(){ 19 | $depr = C('URL_PATHINFO_DEPR'); 20 | $regx = preg_replace('/\.'.__EXT__.'$/i','',trim($_SERVER['PATH_INFO'],$depr)); 21 | // 分隔符替换 确保路由定义使用统一的分隔符 22 | if('/' != $depr){ 23 | $regx = str_replace($depr,'/',$regx); 24 | } 25 | // URL映射定义(静态路由) 26 | $maps = C('URL_MAP_RULES'); 27 | if(isset($maps[$regx])) { 28 | $var = self::parseUrl($maps[$regx]); 29 | $_GET = array_merge($var, $_GET); 30 | return true; 31 | } 32 | // 动态路由处理 33 | $routes = C('URL_ROUTE_RULES'); 34 | if(!empty($routes)) { 35 | foreach ($routes as $rule=>$route){ 36 | if(is_numeric($rule)){ 37 | // 支持 array('rule','adddress',...) 定义路由 38 | $rule = array_shift($route); 39 | } 40 | if(is_array($route) && isset($route[2])){ 41 | // 路由参数 42 | $options = $route[2]; 43 | if(isset($options['ext']) && __EXT__ != $options['ext']){ 44 | // URL后缀检测 45 | continue; 46 | } 47 | if(isset($options['method']) && REQUEST_METHOD != strtoupper($options['method'])){ 48 | // 请求类型检测 49 | continue; 50 | } 51 | // 自定义检测 52 | if(!empty($options['callback']) && is_callable($options['callback'])) { 53 | if(false === call_user_func($options['callback'])) { 54 | continue; 55 | } 56 | } 57 | } 58 | if(0===strpos($rule,'/') && preg_match($rule,$regx,$matches)) { // 正则路由 59 | if($route instanceof \Closure) { 60 | // 执行闭包 61 | $result = self::invokeRegx($route, $matches); 62 | // 如果返回布尔值 则继续执行 63 | return is_bool($result) ? $result : exit; 64 | }else{ 65 | return self::parseRegex($matches,$route,$regx); 66 | } 67 | }else{ // 规则路由 68 | $len1 = substr_count($regx,'/'); 69 | $len2 = substr_count($rule,'/'); 70 | if($len1>=$len2 || strpos($rule,'[')) { 71 | if('$' == substr($rule,-1,1)) {// 完整匹配 72 | if($len1 != $len2) { 73 | continue; 74 | }else{ 75 | $rule = substr($rule,0,-1); 76 | } 77 | } 78 | $match = self::checkUrlMatch($regx,$rule); 79 | if(false !== $match) { 80 | if($route instanceof \Closure) { 81 | // 执行闭包 82 | $result = self::invokeRule($route, $match); 83 | // 如果返回布尔值 则继续执行 84 | return is_bool($result) ? $result : exit; 85 | }else{ 86 | return self::parseRule($rule,$route,$regx); 87 | } 88 | } 89 | } 90 | } 91 | } 92 | } 93 | return false; 94 | } 95 | 96 | // 检测URL和规则路由是否匹配 97 | private static function checkUrlMatch($regx,$rule) { 98 | $m1 = explode('/',$regx); 99 | $m2 = explode('/',$rule); 100 | $var = array(); 101 | foreach ($m2 as $key=>$val){ 102 | if(0 === strpos($val,'[:')){ 103 | $val = substr($val,1,-1); 104 | } 105 | 106 | if(':' == substr($val,0,1)) {// 动态变量 107 | if($pos = strpos($val,'|')){ 108 | // 使用函数过滤 109 | $val = substr($val,1,$pos-1); 110 | } 111 | if(strpos($val,'\\')) { 112 | $type = substr($val,-1); 113 | if('d'==$type) { 114 | if(isset($m1[$key]) && !is_numeric($m1[$key])) 115 | return false; 116 | } 117 | $name = substr($val, 1, -2); 118 | }elseif($pos = strpos($val,'^')){ 119 | $array = explode('-',substr(strstr($val,'^'),1)); 120 | if(in_array($m1[$key],$array)) { 121 | return false; 122 | } 123 | $name = substr($val, 1, $pos - 1); 124 | }else{ 125 | $name = substr($val, 1); 126 | } 127 | $var[$name] = isset($m1[$key])?$m1[$key]:''; 128 | }elseif(0 !== strcasecmp($val,$m1[$key])){ 129 | return false; 130 | } 131 | } 132 | // 成功匹配后返回URL中的动态变量数组 133 | return $var; 134 | } 135 | 136 | // 解析规范的路由地址 137 | // 地址格式 [控制器/操作?]参数1=值1&参数2=值2... 138 | private static function parseUrl($url) { 139 | $var = array(); 140 | if(false !== strpos($url,'?')) { // [控制器/操作?]参数1=值1&参数2=值2... 141 | $info = parse_url($url); 142 | $path = explode('/',$info['path']); 143 | parse_str($info['query'],$var); 144 | }elseif(strpos($url,'/')){ // [控制器/操作] 145 | $path = explode('/',$url); 146 | }else{ // 参数1=值1&参数2=值2... 147 | parse_str($url,$var); 148 | } 149 | if(isset($path)) { 150 | $var[C('VAR_ACTION')] = array_pop($path); 151 | if(!empty($path)) { 152 | $var[C('VAR_CONTROLLER')] = array_pop($path); 153 | } 154 | if(!empty($path)) { 155 | $var[C('VAR_MODULE')] = array_pop($path); 156 | } 157 | } 158 | return $var; 159 | } 160 | 161 | // 解析规则路由 162 | // '路由规则'=>'[控制器/操作]?额外参数1=值1&额外参数2=值2...' 163 | // '路由规则'=>array('[控制器/操作]','额外参数1=值1&额外参数2=值2...') 164 | // '路由规则'=>'外部地址' 165 | // '路由规则'=>array('外部地址','重定向代码') 166 | // 路由规则中 :开头 表示动态变量 167 | // 外部地址中可以用动态变量 采用 :1 :2 的方式 168 | // 'news/:month/:day/:id'=>array('News/read?cate=1','status=1'), 169 | // 'new/:id'=>array('/new.php?id=:1',301), 重定向 170 | private static function parseRule($rule,$route,$regx) { 171 | // 获取路由地址规则 172 | $url = is_array($route)?$route[0]:$route; 173 | // 获取URL地址中的参数 174 | $paths = explode('/',$regx); 175 | // 解析路由规则 176 | $matches = array(); 177 | $rule = explode('/',$rule); 178 | foreach ($rule as $item){ 179 | $fun = ''; 180 | if(0 === strpos($item,'[:')){ 181 | $item = substr($item,1,-1); 182 | } 183 | if(0===strpos($item,':')) { // 动态变量获取 184 | if($pos = strpos($item,'|')){ 185 | // 支持函数过滤 186 | $fun = substr($item,$pos+1); 187 | $item = substr($item,0,$pos); 188 | } 189 | if($pos = strpos($item,'^') ) { 190 | $var = substr($item,1,$pos-1); 191 | }elseif(strpos($item,'\\')){ 192 | $var = substr($item,1,-2); 193 | }else{ 194 | $var = substr($item,1); 195 | } 196 | $matches[$var] = !empty($fun)? $fun(array_shift($paths)) : array_shift($paths); 197 | }else{ // 过滤URL中的静态变量 198 | array_shift($paths); 199 | } 200 | } 201 | 202 | if(0=== strpos($url,'/') || 0===strpos($url,'http')) { // 路由重定向跳转 203 | if(strpos($url,':')) { // 传递动态参数 204 | $values = array_values($matches); 205 | $url = preg_replace_callback('/:(\d+)/', function($match) use($values){ return $values[$match[1] - 1]; }, $url); 206 | } 207 | header("Location: $url", true,(is_array($route) && isset($route[1]))?$route[1]:301); 208 | exit; 209 | }else{ 210 | // 解析路由地址 211 | $var = self::parseUrl($url); 212 | // 解析路由地址里面的动态参数 213 | $values = array_values($matches); 214 | foreach ($var as $key=>$val){ 215 | if(0===strpos($val,':')) { 216 | $var[$key] = $values[substr($val,1)-1]; 217 | } 218 | } 219 | $var = array_merge($matches,$var); 220 | // 解析剩余的URL参数 221 | if(!empty($paths)) { 222 | preg_replace_callback('/(\w+)\/([^\/]+)/', function($match) use(&$var){ $var[strtolower($match[1])]=strip_tags($match[2]);}, implode('/',$paths)); 223 | } 224 | // 解析路由自动传入参数 225 | if(is_array($route) && isset($route[1])) { 226 | if(is_array($route[1])){ 227 | $params = $route[1]; 228 | }else{ 229 | parse_str($route[1],$params); 230 | } 231 | $var = array_merge($var,$params); 232 | } 233 | $_GET = array_merge($var,$_GET); 234 | } 235 | return true; 236 | } 237 | 238 | // 解析正则路由 239 | // '路由正则'=>'[控制器/操作]?参数1=值1&参数2=值2...' 240 | // '路由正则'=>array('[控制器/操作]?参数1=值1&参数2=值2...','额外参数1=值1&额外参数2=值2...') 241 | // '路由正则'=>'外部地址' 242 | // '路由正则'=>array('外部地址','重定向代码') 243 | // 参数值和外部地址中可以用动态变量 采用 :1 :2 的方式 244 | // '/new\/(\d+)\/(\d+)/'=>array('News/read?id=:1&page=:2&cate=1','status=1'), 245 | // '/new\/(\d+)/'=>array('/new.php?id=:1&page=:2&status=1','301'), 重定向 246 | private static function parseRegex($matches,$route,$regx) { 247 | // 获取路由地址规则 248 | $url = is_array($route)?$route[0]:$route; 249 | $url = preg_replace_callback('/:(\d+)/', function($match) use($matches){return $matches[$match[1]];}, $url); 250 | if(0=== strpos($url,'/') || 0===strpos($url,'http')) { // 路由重定向跳转 251 | header("Location: $url", true,(is_array($route) && isset($route[1]))?$route[1]:301); 252 | exit; 253 | }else{ 254 | // 解析路由地址 255 | $var = self::parseUrl($url); 256 | // 处理函数 257 | foreach($var as $key=>$val){ 258 | if(strpos($val,'|')){ 259 | list($val,$fun) = explode('|',$val); 260 | $var[$key] = $fun($val); 261 | } 262 | } 263 | // 解析剩余的URL参数 264 | $regx = substr_replace($regx,'',0,strlen($matches[0])); 265 | if($regx) { 266 | preg_replace_callback('/(\w+)\/([^\/]+)/', function($match) use(&$var){ 267 | $var[strtolower($match[1])] = strip_tags($match[2]); 268 | }, $regx); 269 | } 270 | // 解析路由自动传入参数 271 | if(is_array($route) && isset($route[1])) { 272 | if(is_array($route[1])){ 273 | $params = $route[1]; 274 | }else{ 275 | parse_str($route[1],$params); 276 | } 277 | $var = array_merge($var,$params); 278 | } 279 | $_GET = array_merge($var,$_GET); 280 | } 281 | return true; 282 | } 283 | 284 | // 执行正则匹配下的闭包方法 支持参数调用 285 | static private function invokeRegx($closure, $var = array()) { 286 | $reflect = new \ReflectionFunction($closure); 287 | $params = $reflect->getParameters(); 288 | $args = array(); 289 | array_shift($var); 290 | foreach ($params as $param){ 291 | if(!empty($var)) { 292 | $args[] = array_shift($var); 293 | }elseif($param->isDefaultValueAvailable()){ 294 | $args[] = $param->getDefaultValue(); 295 | } 296 | } 297 | return $reflect->invokeArgs($args); 298 | } 299 | 300 | // 执行规则匹配下的闭包方法 支持参数调用 301 | static private function invokeRule($closure, $var = array()) { 302 | $reflect = new \ReflectionFunction($closure); 303 | $params = $reflect->getParameters(); 304 | $args = array(); 305 | foreach ($params as $param){ 306 | $name = $param->getName(); 307 | if(isset($var[$name])) { 308 | $args[] = $var[$name]; 309 | }elseif($param->isDefaultValueAvailable()){ 310 | $args[] = $param->getDefaultValue(); 311 | } 312 | } 313 | return $reflect->invokeArgs($args); 314 | } 315 | 316 | } -------------------------------------------------------------------------------- /Example/ThinkPHP/Library/Think/Storage.class.php: -------------------------------------------------------------------------------- 1 | 10 | // +---------------------------------------------------------------------- 11 | namespace Think; 12 | // 分布式文件存储类 13 | class Storage { 14 | 15 | /** 16 | * 操作句柄 17 | * @var string 18 | * @access protected 19 | */ 20 | static protected $handler ; 21 | 22 | /** 23 | * 连接分布式文件系统 24 | * @access public 25 | * @param string $type 文件类型 26 | * @param array $options 配置数组 27 | * @return void 28 | */ 29 | static public function connect($type='File',$options=array()) { 30 | $class = 'Think\\Storage\\Driver\\'.ucwords($type); 31 | self::$handler = new $class($options); 32 | } 33 | 34 | static public function __callstatic($method,$args){ 35 | //调用缓存驱动的方法 36 | if(method_exists(self::$handler, $method)){ 37 | return call_user_func_array(array(self::$handler,$method), $args); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Example/ThinkPHP/Library/Think/Storage/Driver/File.class.php: -------------------------------------------------------------------------------- 1 | 10 | // +---------------------------------------------------------------------- 11 | namespace Think\Storage\Driver; 12 | use Think\Storage; 13 | // 本地文件写入存储类 14 | class File extends Storage{ 15 | 16 | private $contents=array(); 17 | 18 | /** 19 | * 架构函数 20 | * @access public 21 | */ 22 | public function __construct() { 23 | } 24 | 25 | /** 26 | * 文件内容读取 27 | * @access public 28 | * @param string $filename 文件名 29 | * @return string 30 | */ 31 | public function read($filename,$type=''){ 32 | return $this->get($filename,'content',$type); 33 | } 34 | 35 | /** 36 | * 文件写入 37 | * @access public 38 | * @param string $filename 文件名 39 | * @param string $content 文件内容 40 | * @return boolean 41 | */ 42 | public function put($filename,$content,$type=''){ 43 | $dir = dirname($filename); 44 | if(!is_dir($dir)){ 45 | mkdir($dir,0777,true); 46 | } 47 | if(false === file_put_contents($filename,$content)){ 48 | E(L('_STORAGE_WRITE_ERROR_').':'.$filename); 49 | }else{ 50 | $this->contents[$filename]=$content; 51 | return true; 52 | } 53 | } 54 | 55 | /** 56 | * 文件追加写入 57 | * @access public 58 | * @param string $filename 文件名 59 | * @param string $content 追加的文件内容 60 | * @return boolean 61 | */ 62 | public function append($filename,$content,$type=''){ 63 | if(is_file($filename)){ 64 | $content = $this->read($filename,$type).$content; 65 | } 66 | return $this->put($filename,$content,$type); 67 | } 68 | 69 | /** 70 | * 加载文件 71 | * @access public 72 | * @param string $filename 文件名 73 | * @param array $vars 传入变量 74 | * @return void 75 | */ 76 | public function load($_filename,$vars=null){ 77 | if(!is_null($vars)){ 78 | extract($vars, EXTR_OVERWRITE); 79 | } 80 | include $_filename; 81 | } 82 | 83 | /** 84 | * 文件是否存在 85 | * @access public 86 | * @param string $filename 文件名 87 | * @return boolean 88 | */ 89 | public function has($filename,$type=''){ 90 | return is_file($filename); 91 | } 92 | 93 | /** 94 | * 文件删除 95 | * @access public 96 | * @param string $filename 文件名 97 | * @return boolean 98 | */ 99 | public function unlink($filename,$type=''){ 100 | unset($this->contents[$filename]); 101 | return is_file($filename) ? unlink($filename) : false; 102 | } 103 | 104 | /** 105 | * 读取文件信息 106 | * @access public 107 | * @param string $filename 文件名 108 | * @param string $name 信息名 mtime或者content 109 | * @return boolean 110 | */ 111 | public function get($filename,$name,$type=''){ 112 | if(!isset($this->contents[$filename])){ 113 | if(!is_file($filename)) return false; 114 | $this->contents[$filename]=file_get_contents($filename); 115 | } 116 | $content=$this->contents[$filename]; 117 | $info = array( 118 | 'mtime' => filemtime($filename), 119 | 'content' => $content 120 | ); 121 | return $info[$name]; 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /Example/ThinkPHP/Library/Think/Storage/Driver/Sae.class.php: -------------------------------------------------------------------------------- 1 | 10 | // +---------------------------------------------------------------------- 11 | namespace Think\Storage\Driver; 12 | use Think\Storage; 13 | // SAE环境文件写入存储类 14 | class Sae extends Storage{ 15 | 16 | /** 17 | * 架构函数 18 | * @access public 19 | */ 20 | private $mc; 21 | private $kvs = array(); 22 | private $htmls = array(); 23 | private $contents = array(); 24 | public function __construct() { 25 | if(!function_exists('memcache_init')){ 26 | header('Content-Type:text/html;charset=utf-8'); 27 | exit('请在SAE平台上运行代码。'); 28 | } 29 | $this->mc = @memcache_init(); 30 | if(!$this->mc){ 31 | header('Content-Type:text/html;charset=utf-8'); 32 | exit('您未开通Memcache服务,请在SAE管理平台初始化Memcache服务'); 33 | } 34 | } 35 | 36 | /** 37 | * 获得SaeKv对象 38 | */ 39 | private function getKv(){ 40 | static $kv; 41 | if(!$kv){ 42 | $kv = new \SaeKV(); 43 | if(!$kv->init()) 44 | E('您没有初始化KVDB,请在SAE管理平台初始化KVDB服务'); 45 | } 46 | return $kv; 47 | } 48 | 49 | 50 | /** 51 | * 文件内容读取 52 | * @access public 53 | * @param string $filename 文件名 54 | * @return string 55 | */ 56 | public function read($filename,$type=''){ 57 | switch(strtolower($type)){ 58 | case 'f': 59 | $kv = $this->getKv(); 60 | if(!isset($this->kvs[$filename])){ 61 | $this->kvs[$filename]=$kv->get($filename); 62 | } 63 | return $this->kvs[$filename]; 64 | default: 65 | return $this->get($filename,'content',$type); 66 | } 67 | } 68 | 69 | /** 70 | * 文件写入 71 | * @access public 72 | * @param string $filename 文件名 73 | * @param string $content 文件内容 74 | * @return boolean 75 | */ 76 | public function put($filename,$content,$type=''){ 77 | switch(strtolower($type)){ 78 | case 'f': 79 | $kv = $this->getKv(); 80 | $this->kvs[$filename] = $content; 81 | return $kv->set($filename,$content); 82 | case 'html': 83 | $kv = $this->getKv(); 84 | $content = time().$content; 85 | $this->htmls[$filename] = $content; 86 | return $kv->set($filename,$content); 87 | default: 88 | $content = time().$content; 89 | if(!$this->mc->set($filename,$content,MEMCACHE_COMPRESSED,0)){ 90 | E(L('_STORAGE_WRITE_ERROR_').':'.$filename); 91 | }else{ 92 | $this->contents[$filename] = $content; 93 | return true; 94 | } 95 | } 96 | } 97 | 98 | /** 99 | * 文件追加写入 100 | * @access public 101 | * @param string $filename 文件名 102 | * @param string $content 追加的文件内容 103 | * @return boolean 104 | */ 105 | public function append($filename,$content,$type=''){ 106 | if($old_content = $this->read($filename,$type)){ 107 | $content = $old_content.$content; 108 | } 109 | return $this->put($filename,$content,$type); 110 | } 111 | 112 | /** 113 | * 加载文件 114 | * @access public 115 | * @param string $_filename 文件名 116 | * @param array $vars 传入变量 117 | * @return void 118 | */ 119 | public function load($_filename,$vars=null){ 120 | if(!is_null($vars)) 121 | extract($vars, EXTR_OVERWRITE); 122 | eval('?>'.$this->read($_filename)); 123 | } 124 | 125 | /** 126 | * 文件是否存在 127 | * @access public 128 | * @param string $filename 文件名 129 | * @return boolean 130 | */ 131 | public function has($filename,$type=''){ 132 | if($this->read($filename,$type)){ 133 | return true; 134 | }else{ 135 | return false; 136 | } 137 | } 138 | 139 | /** 140 | * 文件删除 141 | * @access public 142 | * @param string $filename 文件名 143 | * @return boolean 144 | */ 145 | public function unlink($filename,$type=''){ 146 | switch(strtolower($type)){ 147 | case 'f': 148 | $kv = $this->getKv(); 149 | unset($this->kvs[$filename]); 150 | return $kv->delete($filename); 151 | case 'html': 152 | $kv = $this->getKv(); 153 | unset($this->htmls[$filename]); 154 | return $kv->delete($filename); 155 | default: 156 | unset($this->contents[$filename]); 157 | return $this->mc->delete($filename); 158 | } 159 | } 160 | 161 | /** 162 | * 读取文件信息 163 | * @access public 164 | * @param string $filename 文件名 165 | * @param string $name 信息名 mtime或者content 166 | * @return boolean 167 | */ 168 | public function get($filename,$name,$type=''){ 169 | switch(strtolower($type)){ 170 | case 'html': 171 | if(!isset($this->htmls[$filename])){ 172 | $kv = $this->getKv(); 173 | $this->htmls[$filename] = $kv->get($filename); 174 | } 175 | $content = $this->htmls[$filename]; 176 | break; 177 | default: 178 | if(!isset($this->contents[$filename])){ 179 | $this->contents[$filename] = $this->mc->get($filename); 180 | } 181 | $content = $this->contents[$filename]; 182 | } 183 | if(false===$content){ 184 | return false; 185 | } 186 | $info = array( 187 | 'mtime' => substr($content,0,10), 188 | 'content' => substr($content,10) 189 | ); 190 | return $info[$name]; 191 | } 192 | 193 | } -------------------------------------------------------------------------------- /Example/ThinkPHP/Library/Think/Template/TagLib.class.php: -------------------------------------------------------------------------------- 1 | 10 | // +---------------------------------------------------------------------- 11 | namespace Think\Template; 12 | /** 13 | * ThinkPHP标签库TagLib解析基类 14 | */ 15 | class TagLib { 16 | 17 | /** 18 | * 标签库定义XML文件 19 | * @var string 20 | * @access protected 21 | */ 22 | protected $xml = ''; 23 | protected $tags = array();// 标签定义 24 | /** 25 | * 标签库名称 26 | * @var string 27 | * @access protected 28 | */ 29 | protected $tagLib =''; 30 | 31 | /** 32 | * 标签库标签列表 33 | * @var string 34 | * @access protected 35 | */ 36 | protected $tagList = array(); 37 | 38 | /** 39 | * 标签库分析数组 40 | * @var string 41 | * @access protected 42 | */ 43 | protected $parse = array(); 44 | 45 | /** 46 | * 标签库是否有效 47 | * @var string 48 | * @access protected 49 | */ 50 | protected $valid = false; 51 | 52 | /** 53 | * 当前模板对象 54 | * @var object 55 | * @access protected 56 | */ 57 | protected $tpl; 58 | 59 | protected $comparison = array(' nheq '=>' !== ',' heq '=>' === ',' neq '=>' != ',' eq '=>' == ',' egt '=>' >= ',' gt '=>' > ',' elt '=>' <= ',' lt '=>' < '); 60 | 61 | /** 62 | * 架构函数 63 | * @access public 64 | */ 65 | public function __construct() { 66 | $this->tagLib = strtolower(substr(get_class($this),6)); 67 | $this->tpl = \Think\Think::instance('Think\\Template'); 68 | } 69 | 70 | /** 71 | * TagLib标签属性分析 返回标签属性数组 72 | * @access public 73 | * @param string $tagStr 标签内容 74 | * @return array 75 | */ 76 | public function parseXmlAttr($attr,$tag) { 77 | //XML解析安全过滤 78 | $attr = str_replace('&','___', $attr); 79 | $xml = ''; 80 | $xml = simplexml_load_string($xml); 81 | if(!$xml) { 82 | E(L('_XML_TAG_ERROR_').' : '.$attr); 83 | } 84 | $xml = (array)($xml->tag->attributes()); 85 | if(isset($xml['@attributes'])){ 86 | $array = array_change_key_case($xml['@attributes']); 87 | if($array) { 88 | $tag = strtolower($tag); 89 | if(!isset($this->tags[$tag])){ 90 | // 检测是否存在别名定义 91 | foreach($this->tags as $key=>$val){ 92 | if(isset($val['alias']) && in_array($tag,explode(',',$val['alias']))){ 93 | $item = $val; 94 | break; 95 | } 96 | } 97 | }else{ 98 | $item = $this->tags[$tag]; 99 | } 100 | $attrs = explode(',',$item['attr']); 101 | if(isset($item['must'])){ 102 | $must = explode(',',$item['must']); 103 | }else{ 104 | $must = array(); 105 | } 106 | foreach($attrs as $name) { 107 | if( isset($array[$name])) { 108 | $array[$name] = str_replace('___','&',$array[$name]); 109 | }elseif(false !== array_search($name,$must)){ 110 | E(L('_PARAM_ERROR_').':'.$name); 111 | } 112 | } 113 | return $array; 114 | } 115 | }else{ 116 | return array(); 117 | } 118 | } 119 | 120 | /** 121 | * 解析条件表达式 122 | * @access public 123 | * @param string $condition 表达式标签内容 124 | * @return array 125 | */ 126 | public function parseCondition($condition) { 127 | $condition = str_ireplace(array_keys($this->comparison),array_values($this->comparison),$condition); 128 | $condition = preg_replace('/\$(\w+):(\w+)\s/is','$\\1->\\2 ',$condition); 129 | switch(strtolower(C('TMPL_VAR_IDENTIFY'))) { 130 | case 'array': // 识别为数组 131 | $condition = preg_replace('/\$(\w+)\.(\w+)\s/is','$\\1["\\2"] ',$condition); 132 | break; 133 | case 'obj': // 识别为对象 134 | $condition = preg_replace('/\$(\w+)\.(\w+)\s/is','$\\1->\\2 ',$condition); 135 | break; 136 | default: // 自动判断数组或对象 只支持二维 137 | $condition = preg_replace('/\$(\w+)\.(\w+)\s/is','(is_array($\\1)?$\\1["\\2"]:$\\1->\\2) ',$condition); 138 | } 139 | if(false !== strpos($condition, '$Think')) 140 | $condition = preg_replace_callback('/(\$Think.*?)\s/is', array($this, 'parseThinkVar'), $condition); 141 | return $condition; 142 | } 143 | 144 | /** 145 | * 自动识别构建变量 146 | * @access public 147 | * @param string $name 变量描述 148 | * @return string 149 | */ 150 | public function autoBuildVar($name) { 151 | if('Think.' == substr($name,0,6)){ 152 | // 特殊变量 153 | return $this->parseThinkVar($name); 154 | }elseif(strpos($name,'.')) { 155 | $vars = explode('.',$name); 156 | $var = array_shift($vars); 157 | switch(strtolower(C('TMPL_VAR_IDENTIFY'))) { 158 | case 'array': // 识别为数组 159 | $name = '$'.$var; 160 | foreach ($vars as $key=>$val){ 161 | if(0===strpos($val,'$')) { 162 | $name .= '["{'.$val.'}"]'; 163 | }else{ 164 | $name .= '["'.$val.'"]'; 165 | } 166 | } 167 | break; 168 | case 'obj': // 识别为对象 169 | $name = '$'.$var; 170 | foreach ($vars as $key=>$val) 171 | $name .= '->'.$val; 172 | break; 173 | default: // 自动判断数组或对象 只支持二维 174 | $name = 'is_array($'.$var.')?$'.$var.'["'.$vars[0].'"]:$'.$var.'->'.$vars[0]; 175 | } 176 | }elseif(strpos($name,':')){ 177 | // 额外的对象方式支持 178 | $name = '$'.str_replace(':','->',$name); 179 | }elseif(!defined($name)) { 180 | $name = '$'.$name; 181 | } 182 | return $name; 183 | } 184 | 185 | /** 186 | * 用于标签属性里面的特殊模板变量解析 187 | * 格式 以 Think. 打头的变量属于特殊模板变量 188 | * @access public 189 | * @param string $varStr 变量字符串 190 | * @return string 191 | */ 192 | public function parseThinkVar($varStr){ 193 | if(is_array($varStr)){//用于正则替换回调函数 194 | $varStr = $varStr[1]; 195 | } 196 | $vars = explode('.',$varStr); 197 | $vars[1] = strtoupper(trim($vars[1])); 198 | $parseStr = ''; 199 | if(count($vars)>=3){ 200 | $vars[2] = trim($vars[2]); 201 | switch($vars[1]){ 202 | case 'SERVER': $parseStr = '$_SERVER[\''.$vars[2].'\']';break; 203 | case 'GET': $parseStr = '$_GET[\''.$vars[2].'\']';break; 204 | case 'POST': $parseStr = '$_POST[\''.$vars[2].'\']';break; 205 | case 'COOKIE': 206 | if(isset($vars[3])) { 207 | $parseStr = '$_COOKIE[\''.$vars[2].'\'][\''.$vars[3].'\']'; 208 | }elseif(C('COOKIE_PREFIX')){ 209 | $parseStr = '$_COOKIE[\''.C('COOKIE_PREFIX').$vars[2].'\']'; 210 | }else{ 211 | $parseStr = '$_COOKIE[\''.$vars[2].'\']'; 212 | } 213 | break; 214 | case 'SESSION': 215 | if(isset($vars[3])) { 216 | $parseStr = '$_SESSION[\''.$vars[2].'\'][\''.$vars[3].'\']'; 217 | }elseif(C('SESSION_PREFIX')){ 218 | $parseStr = '$_SESSION[\''.C('SESSION_PREFIX').'\'][\''.$vars[2].'\']'; 219 | }else{ 220 | $parseStr = '$_SESSION[\''.$vars[2].'\']'; 221 | } 222 | break; 223 | case 'ENV': $parseStr = '$_ENV[\''.$vars[2].'\']';break; 224 | case 'REQUEST': $parseStr = '$_REQUEST[\''.$vars[2].'\']';break; 225 | case 'CONST': $parseStr = strtoupper($vars[2]);break; 226 | case 'LANG': $parseStr = 'L("'.$vars[2].'")';break; 227 | case 'CONFIG': $parseStr = 'C("'.$vars[2].'")';break; 228 | } 229 | }else if(count($vars)==2){ 230 | switch($vars[1]){ 231 | case 'NOW': $parseStr = "date('Y-m-d g:i a',time())";break; 232 | case 'VERSION': $parseStr = 'THINK_VERSION';break; 233 | case 'TEMPLATE':$parseStr = 'C("TEMPLATE_NAME")';break; 234 | case 'LDELIM': $parseStr = 'C("TMPL_L_DELIM")';break; 235 | case 'RDELIM': $parseStr = 'C("TMPL_R_DELIM")';break; 236 | default: if(defined($vars[1])) $parseStr = $vars[1]; 237 | } 238 | } 239 | return $parseStr; 240 | } 241 | 242 | // 获取标签定义 243 | public function getTags(){ 244 | return $this->tags; 245 | } 246 | } -------------------------------------------------------------------------------- /Example/ThinkPHP/Library/Think/Think.class.php: -------------------------------------------------------------------------------- 1 | 10 | // +---------------------------------------------------------------------- 11 | 12 | namespace Think; 13 | /** 14 | * ThinkPHP 引导类 15 | */ 16 | class Think { 17 | 18 | // 类映射 19 | private static $_map = array(); 20 | 21 | // 实例化对象 22 | private static $_instance = array(); 23 | 24 | /** 25 | * 应用程序初始化 26 | * @access public 27 | * @return void 28 | */ 29 | static public function start() { 30 | // 注册AUTOLOAD方法 31 | spl_autoload_register('Think\Think::autoload'); 32 | // 设定错误和异常处理 33 | register_shutdown_function('Think\Think::fatalError'); 34 | set_error_handler('Think\Think::appError'); 35 | set_exception_handler('Think\Think::appException'); 36 | 37 | // 初始化文件存储方式 38 | Storage::connect(STORAGE_TYPE); 39 | 40 | $runtimefile = RUNTIME_PATH.APP_MODE.'~runtime.php'; 41 | if(!APP_DEBUG && Storage::has($runtimefile)){ 42 | Storage::load($runtimefile); 43 | }else{ 44 | if(Storage::has($runtimefile)) 45 | Storage::unlink($runtimefile); 46 | $content = ''; 47 | // 读取应用模式 48 | $mode = include is_file(CONF_PATH.'core.php')?CONF_PATH.'core.php':MODE_PATH.APP_MODE.'.php'; 49 | // 加载核心文件 50 | foreach ($mode['core'] as $file){ 51 | if(is_file($file)) { 52 | include $file; 53 | if(!APP_DEBUG) $content .= compile($file); 54 | } 55 | } 56 | 57 | // 加载应用模式配置文件 58 | foreach ($mode['config'] as $key=>$file){ 59 | is_numeric($key)?C(load_config($file)):C($key,load_config($file)); 60 | } 61 | 62 | // 读取当前应用模式对应的配置文件 63 | if('common' != APP_MODE && is_file(CONF_PATH.'config_'.APP_MODE.CONF_EXT)) 64 | C(load_config(CONF_PATH.'config_'.APP_MODE.CONF_EXT)); 65 | 66 | // 加载模式别名定义 67 | if(isset($mode['alias'])){ 68 | self::addMap(is_array($mode['alias'])?$mode['alias']:include $mode['alias']); 69 | } 70 | 71 | // 加载应用别名定义文件 72 | if(is_file(CONF_PATH.'alias.php')) 73 | self::addMap(include CONF_PATH.'alias.php'); 74 | 75 | // 加载模式行为定义 76 | if(isset($mode['tags'])) { 77 | Hook::import(is_array($mode['tags'])?$mode['tags']:include $mode['tags']); 78 | } 79 | 80 | // 加载应用行为定义 81 | if(is_file(CONF_PATH.'tags.php')) 82 | // 允许应用增加开发模式配置定义 83 | Hook::import(include CONF_PATH.'tags.php'); 84 | 85 | // 加载框架底层语言包 86 | L(include THINK_PATH.'Lang/'.strtolower(C('DEFAULT_LANG')).'.php'); 87 | 88 | if(!APP_DEBUG){ 89 | $content .= "\nnamespace { Think\\Think::addMap(".var_export(self::$_map,true).");"; 90 | $content .= "\nL(".var_export(L(),true).");\nC(".var_export(C(),true).');Think\Hook::import('.var_export(Hook::get(),true).');}'; 91 | Storage::put($runtimefile,strip_whitespace('getMessage(); 218 | $trace = $e->getTrace(); 219 | if('E'==$trace[0]['function']) { 220 | $error['file'] = $trace[0]['file']; 221 | $error['line'] = $trace[0]['line']; 222 | }else{ 223 | $error['file'] = $e->getFile(); 224 | $error['line'] = $e->getLine(); 225 | } 226 | $error['trace'] = $e->getTraceAsString(); 227 | Log::record($error['message'],Log::ERR); 228 | // 发送404信息 229 | header('HTTP/1.1 404 Not Found'); 230 | header('Status:404 Not Found'); 231 | self::halt($error); 232 | } 233 | 234 | /** 235 | * 自定义错误处理 236 | * @access public 237 | * @param int $errno 错误类型 238 | * @param string $errstr 错误信息 239 | * @param string $errfile 错误文件 240 | * @param int $errline 错误行数 241 | * @return void 242 | */ 243 | static public function appError($errno, $errstr, $errfile, $errline) { 244 | switch ($errno) { 245 | case E_ERROR: 246 | case E_PARSE: 247 | case E_CORE_ERROR: 248 | case E_COMPILE_ERROR: 249 | case E_USER_ERROR: 250 | ob_end_clean(); 251 | $errorStr = "$errstr ".$errfile." 第 $errline 行."; 252 | if(C('LOG_RECORD')) Log::write("[$errno] ".$errorStr,Log::ERR); 253 | self::halt($errorStr); 254 | break; 255 | default: 256 | $errorStr = "[$errno] $errstr ".$errfile." 第 $errline 行."; 257 | self::trace($errorStr,'','NOTIC'); 258 | break; 259 | } 260 | } 261 | 262 | // 致命错误捕获 263 | static public function fatalError() { 264 | Log::save(); 265 | if ($e = error_get_last()) { 266 | switch($e['type']){ 267 | case E_ERROR: 268 | case E_PARSE: 269 | case E_CORE_ERROR: 270 | case E_COMPILE_ERROR: 271 | case E_USER_ERROR: 272 | ob_end_clean(); 273 | self::halt($e); 274 | break; 275 | } 276 | } 277 | } 278 | 279 | /** 280 | * 错误输出 281 | * @param mixed $error 错误 282 | * @return void 283 | */ 284 | static public function halt($error) { 285 | $e = array(); 286 | if (APP_DEBUG || IS_CLI) { 287 | //调试模式下输出错误信息 288 | if (!is_array($error)) { 289 | $trace = debug_backtrace(); 290 | $e['message'] = $error; 291 | $e['file'] = $trace[0]['file']; 292 | $e['line'] = $trace[0]['line']; 293 | ob_start(); 294 | debug_print_backtrace(); 295 | $e['trace'] = ob_get_clean(); 296 | } else { 297 | $e = $error; 298 | } 299 | if(IS_CLI){ 300 | exit(iconv('UTF-8','gbk',$e['message']).PHP_EOL.'FILE: '.$e['file'].'('.$e['line'].')'.PHP_EOL.$e['trace']); 301 | } 302 | } else { 303 | //否则定向到错误页面 304 | $error_page = C('ERROR_PAGE'); 305 | if (!empty($error_page)) { 306 | redirect($error_page); 307 | } else { 308 | $message = is_array($error) ? $error['message'] : $error; 309 | $e['message'] = C('SHOW_ERROR_MSG')? $message : C('ERROR_MESSAGE'); 310 | } 311 | } 312 | // 包含异常页面模板 313 | $exceptionFile = C('TMPL_EXCEPTION_FILE',null,THINK_PATH.'Tpl/think_exception.tpl'); 314 | include $exceptionFile; 315 | exit; 316 | } 317 | 318 | /** 319 | * 添加和获取页面Trace记录 320 | * @param string $value 变量 321 | * @param string $label 标签 322 | * @param string $level 日志级别(或者页面Trace的选项卡) 323 | * @param boolean $record 是否记录日志 324 | * @return void|array 325 | */ 326 | static public function trace($value='[think]',$label='',$level='DEBUG',$record=false) { 327 | static $_trace = array(); 328 | if('[think]' === $value){ // 获取trace信息 329 | return $_trace; 330 | }else{ 331 | $info = ($label?$label.':':'').print_r($value,true); 332 | $level = strtoupper($level); 333 | 334 | if((defined('IS_AJAX') && IS_AJAX) || !C('SHOW_PAGE_TRACE') || $record) { 335 | Log::record($info,$level,$record); 336 | }else{ 337 | if(!isset($_trace[$level]) || count($_trace[$level])>C('TRACE_MAX_RECORD')) { 338 | $_trace[$level] = array(); 339 | } 340 | $_trace[$level][] = $info; 341 | } 342 | } 343 | } 344 | } 345 | -------------------------------------------------------------------------------- /Example/ThinkPHP/Library/Think/View.class.php: -------------------------------------------------------------------------------- 1 | 10 | // +---------------------------------------------------------------------- 11 | namespace Think; 12 | /** 13 | * ThinkPHP 视图类 14 | */ 15 | class View { 16 | /** 17 | * 模板输出变量 18 | * @var tVar 19 | * @access protected 20 | */ 21 | protected $tVar = array(); 22 | 23 | /** 24 | * 模板主题 25 | * @var theme 26 | * @access protected 27 | */ 28 | protected $theme = ''; 29 | 30 | /** 31 | * 模板变量赋值 32 | * @access public 33 | * @param mixed $name 34 | * @param mixed $value 35 | */ 36 | public function assign($name,$value=''){ 37 | if(is_array($name)) { 38 | $this->tVar = array_merge($this->tVar,$name); 39 | }else { 40 | $this->tVar[$name] = $value; 41 | } 42 | } 43 | 44 | /** 45 | * 取得模板变量的值 46 | * @access public 47 | * @param string $name 48 | * @return mixed 49 | */ 50 | public function get($name=''){ 51 | if('' === $name) { 52 | return $this->tVar; 53 | } 54 | return isset($this->tVar[$name])?$this->tVar[$name]:false; 55 | } 56 | 57 | /** 58 | * 加载模板和页面输出 可以返回输出内容 59 | * @access public 60 | * @param string $templateFile 模板文件名 61 | * @param string $charset 模板输出字符集 62 | * @param string $contentType 输出类型 63 | * @param string $content 模板输出内容 64 | * @param string $prefix 模板缓存前缀 65 | * @return mixed 66 | */ 67 | public function display($templateFile='',$charset='',$contentType='',$content='',$prefix='') { 68 | G('viewStartTime'); 69 | // 视图开始标签 70 | Hook::listen('view_begin',$templateFile); 71 | // 解析并获取模板内容 72 | $content = $this->fetch($templateFile,$content,$prefix); 73 | // 输出模板内容 74 | $this->render($content,$charset,$contentType); 75 | // 视图结束标签 76 | Hook::listen('view_end'); 77 | } 78 | 79 | /** 80 | * 输出内容文本可以包括Html 81 | * @access private 82 | * @param string $content 输出内容 83 | * @param string $charset 模板输出字符集 84 | * @param string $contentType 输出类型 85 | * @return mixed 86 | */ 87 | private function render($content,$charset='',$contentType=''){ 88 | if(empty($charset)) $charset = C('DEFAULT_CHARSET'); 89 | if(empty($contentType)) $contentType = C('TMPL_CONTENT_TYPE'); 90 | // 网页字符编码 91 | header('Content-Type:'.$contentType.'; charset='.$charset); 92 | header('Cache-control: '.C('HTTP_CACHE_CONTROL')); // 页面缓存控制 93 | header('X-Powered-By:ThinkPHP'); 94 | // 输出模板文件 95 | echo $content; 96 | } 97 | 98 | /** 99 | * 解析和获取模板内容 用于输出 100 | * @access public 101 | * @param string $templateFile 模板文件名 102 | * @param string $content 模板输出内容 103 | * @param string $prefix 模板缓存前缀 104 | * @return string 105 | */ 106 | public function fetch($templateFile='',$content='',$prefix='') { 107 | if(empty($content)) { 108 | $templateFile = $this->parseTemplate($templateFile); 109 | // 模板文件不存在直接返回 110 | if(!is_file($templateFile)) E(L('_TEMPLATE_NOT_EXIST_').':'.$templateFile); 111 | }else{ 112 | defined('THEME_PATH') or define('THEME_PATH', $this->getThemePath()); 113 | } 114 | // 页面缓存 115 | ob_start(); 116 | ob_implicit_flush(0); 117 | if('php' == strtolower(C('TMPL_ENGINE_TYPE'))) { // 使用PHP原生模板 118 | $_content = $content; 119 | // 模板阵列变量分解成为独立变量 120 | extract($this->tVar, EXTR_OVERWRITE); 121 | // 直接载入PHP模板 122 | empty($_content)?include $templateFile:eval('?>'.$_content); 123 | }else{ 124 | // 视图解析标签 125 | $params = array('var'=>$this->tVar,'file'=>$templateFile,'content'=>$content,'prefix'=>$prefix); 126 | Hook::listen('view_parse',$params); 127 | } 128 | // 获取并清空缓存 129 | $content = ob_get_clean(); 130 | // 内容过滤标签 131 | Hook::listen('view_filter',$content); 132 | // 输出模板文件 133 | return $content; 134 | } 135 | 136 | /** 137 | * 自动定位模板文件 138 | * @access protected 139 | * @param string $template 模板文件规则 140 | * @return string 141 | */ 142 | public function parseTemplate($template='') { 143 | if(is_file($template)) { 144 | return $template; 145 | } 146 | $depr = C('TMPL_FILE_DEPR'); 147 | $template = str_replace(':', $depr, $template); 148 | 149 | // 获取当前模块 150 | $module = MODULE_NAME; 151 | if(strpos($template,'@')){ // 跨模块调用模版文件 152 | list($module,$template) = explode('@',$template); 153 | } 154 | // 获取当前主题的模版路径 155 | defined('THEME_PATH') or define('THEME_PATH', $this->getThemePath($module)); 156 | 157 | // 分析模板文件规则 158 | if('' == $template) { 159 | // 如果模板文件名为空 按照默认规则定位 160 | $template = CONTROLLER_NAME . $depr . ACTION_NAME; 161 | }elseif(false === strpos($template, $depr)){ 162 | $template = CONTROLLER_NAME . $depr . $template; 163 | } 164 | $file = THEME_PATH.$template.C('TMPL_TEMPLATE_SUFFIX'); 165 | if(C('TMPL_LOAD_DEFAULTTHEME') && THEME_NAME != C('DEFAULT_THEME') && !is_file($file)){ 166 | // 找不到当前主题模板的时候定位默认主题中的模板 167 | $file = dirname(THEME_PATH).'/'.C('DEFAULT_THEME').'/'.$template.C('TMPL_TEMPLATE_SUFFIX'); 168 | } 169 | return $file; 170 | } 171 | 172 | /** 173 | * 获取当前的模板路径 174 | * @access protected 175 | * @param string $module 模块名 176 | * @return string 177 | */ 178 | protected function getThemePath($module=MODULE_NAME){ 179 | // 获取当前主题名称 180 | $theme = $this->getTemplateTheme(); 181 | // 获取当前主题的模版路径 182 | $tmplPath = C('VIEW_PATH'); // 模块设置独立的视图目录 183 | if(!$tmplPath){ 184 | // 定义TMPL_PATH 则改变全局的视图目录到模块之外 185 | $tmplPath = defined('TMPL_PATH')? TMPL_PATH.$module.'/' : APP_PATH.$module.'/'.C('DEFAULT_V_LAYER').'/'; 186 | } 187 | return $tmplPath.$theme; 188 | } 189 | 190 | /** 191 | * 设置当前输出的模板主题 192 | * @access public 193 | * @param mixed $theme 主题名称 194 | * @return View 195 | */ 196 | public function theme($theme){ 197 | $this->theme = $theme; 198 | return $this; 199 | } 200 | 201 | /** 202 | * 获取当前的模板主题 203 | * @access private 204 | * @return string 205 | */ 206 | private function getTemplateTheme() { 207 | if($this->theme) { // 指定模板主题 208 | $theme = $this->theme; 209 | }else{ 210 | /* 获取模板主题名称 */ 211 | $theme = C('DEFAULT_THEME'); 212 | if(C('TMPL_DETECT_THEME')) {// 自动侦测模板主题 213 | $t = C('VAR_TEMPLATE'); 214 | if (isset($_GET[$t])){ 215 | $theme = $_GET[$t]; 216 | }elseif(cookie('think_template')){ 217 | $theme = cookie('think_template'); 218 | } 219 | if(!in_array($theme,explode(',',C('THEME_LIST')))){ 220 | $theme = C('DEFAULT_THEME'); 221 | } 222 | cookie('think_template',$theme,864000); 223 | } 224 | } 225 | defined('THEME_NAME') || define('THEME_NAME', $theme); // 当前模板主题名称 226 | return $theme?$theme . '/':''; 227 | } 228 | 229 | } -------------------------------------------------------------------------------- /Example/ThinkPHP/Library/Vendor/README.txt: -------------------------------------------------------------------------------- 1 | 第三方类库包目录 -------------------------------------------------------------------------------- /Example/ThinkPHP/Mode/Sae/convention.php: -------------------------------------------------------------------------------- 1 | 10 | // +---------------------------------------------------------------------- 11 | 12 | /** 13 | * SAE模式惯例配置文件 14 | * 该文件请不要修改,如果要覆盖惯例配置的值,可在应用配置文件中设定和惯例不符的配置项 15 | * 配置名称大小写任意,系统会统一转换成小写 16 | * 所有配置参数都可以在生效前动态改变 17 | */ 18 | defined('THINK_PATH') or exit(); 19 | $st = new SaeStorage(); 20 | return array( 21 | //SAE下固定mysql配置 22 | 'DB_TYPE' => 'mysql', // 数据库类型 23 | 'DB_DEPLOY_TYPE' => 1, 24 | 'DB_RW_SEPARATE' => true, 25 | 'DB_HOST' => SAE_MYSQL_HOST_M.','.SAE_MYSQL_HOST_S, // 服务器地址 26 | 'DB_NAME' => SAE_MYSQL_DB, // 数据库名 27 | 'DB_USER' => SAE_MYSQL_USER, // 用户名 28 | 'DB_PWD' => SAE_MYSQL_PASS, // 密码 29 | 'DB_PORT' => SAE_MYSQL_PORT, // 端口 30 | //更改模板替换变量,让普通能在所有平台下显示 31 | 'TMPL_PARSE_STRING' => array( 32 | // __PUBLIC__/upload --> /Public/upload -->http://appname-public.stor.sinaapp.com/upload 33 | '/Public/upload' => $st->getUrl('public','upload') 34 | ), 35 | 'LOG_TYPE' => 'Sae', 36 | 'DATA_CACHE_TYPE' => 'Memcachesae', 37 | 'CHECK_APP_DIR' => false, 38 | 'FILE_UPLOAD_TYPE' => 'Sae', 39 | ); 40 | -------------------------------------------------------------------------------- /Example/ThinkPHP/Mode/common.php: -------------------------------------------------------------------------------- 1 | 10 | // +---------------------------------------------------------------------- 11 | 12 | /** 13 | * ThinkPHP 普通模式定义 14 | */ 15 | return array( 16 | // 配置文件 17 | 'config' => array( 18 | THINK_PATH.'Conf/convention.php', // 系统惯例配置 19 | CONF_PATH.'config'.CONF_EXT, // 应用公共配置 20 | ), 21 | 22 | // 别名定义 23 | 'alias' => array( 24 | 'Think\Log' => CORE_PATH . 'Log'.EXT, 25 | 'Think\Log\Driver\File' => CORE_PATH . 'Log/Driver/File'.EXT, 26 | 'Think\Exception' => CORE_PATH . 'Exception'.EXT, 27 | 'Think\Model' => CORE_PATH . 'Model'.EXT, 28 | 'Think\Db' => CORE_PATH . 'Db'.EXT, 29 | 'Think\Template' => CORE_PATH . 'Template'.EXT, 30 | 'Think\Cache' => CORE_PATH . 'Cache'.EXT, 31 | 'Think\Cache\Driver\File' => CORE_PATH . 'Cache/Driver/File'.EXT, 32 | 'Think\Storage' => CORE_PATH . 'Storage'.EXT, 33 | ), 34 | 35 | // 函数和类文件 36 | 'core' => array( 37 | THINK_PATH.'Common/functions.php', 38 | COMMON_PATH.'Common/function.php', 39 | CORE_PATH . 'Hook'.EXT, 40 | CORE_PATH . 'App'.EXT, 41 | CORE_PATH . 'Dispatcher'.EXT, 42 | //CORE_PATH . 'Log'.EXT, 43 | CORE_PATH . 'Route'.EXT, 44 | CORE_PATH . 'Controller'.EXT, 45 | CORE_PATH . 'View'.EXT, 46 | BEHAVIOR_PATH . 'BuildLiteBehavior'.EXT, 47 | BEHAVIOR_PATH . 'ParseTemplateBehavior'.EXT, 48 | BEHAVIOR_PATH . 'ContentReplaceBehavior'.EXT, 49 | ), 50 | // 行为扩展定义 51 | 'tags' => array( 52 | 'app_init' => array( 53 | 'Behavior\BuildLiteBehavior', // 生成运行Lite文件 54 | ), 55 | 'app_begin' => array( 56 | 'Behavior\ReadHtmlCacheBehavior', // 读取静态缓存 57 | ), 58 | 'app_end' => array( 59 | 'Behavior\ShowPageTraceBehavior', // 页面Trace显示 60 | ), 61 | 'view_parse' => array( 62 | 'Behavior\ParseTemplateBehavior', // 模板解析 支持PHP、内置模板引擎和第三方模板引擎 63 | ), 64 | 'template_filter'=> array( 65 | 'Behavior\ContentReplaceBehavior', // 模板输出替换 66 | ), 67 | 'view_filter' => array( 68 | 'Behavior\WriteHtmlCacheBehavior', // 写入静态缓存 69 | ), 70 | ), 71 | ); 72 | -------------------------------------------------------------------------------- /Example/ThinkPHP/Mode/sae.php: -------------------------------------------------------------------------------- 1 | 10 | // +---------------------------------------------------------------------- 11 | 12 | /** 13 | * ThinkPHP SAE应用模式定义文件 14 | */ 15 | return array( 16 | // 配置文件 17 | 'config' => array( 18 | THINK_PATH.'Conf/convention.php', // 系统惯例配置 19 | CONF_PATH.'config'.CONF_EXT, // 应用公共配置 20 | MODE_PATH.'Sae/convention.php',//[sae] sae的惯例配置 21 | ), 22 | 23 | // 别名定义 24 | 'alias' => array( 25 | 'Think\Log' => CORE_PATH . 'Log'.EXT, 26 | 'Think\Log\Driver\File' => CORE_PATH . 'Log/Driver/File'.EXT, 27 | 'Think\Exception' => CORE_PATH . 'Exception'.EXT, 28 | 'Think\Model' => CORE_PATH . 'Model'.EXT, 29 | 'Think\Db' => CORE_PATH . 'Db'.EXT, 30 | 'Think\Template' => CORE_PATH . 'Template'.EXT, 31 | 'Think\Cache' => CORE_PATH . 'Cache'.EXT, 32 | 'Think\Cache\Driver\File' => CORE_PATH . 'Cache/Driver/File'.EXT, 33 | 'Think\Storage' => CORE_PATH . 'Storage'.EXT, 34 | ), 35 | 36 | // 函数和类文件 37 | 'core' => array( 38 | THINK_PATH.'Common/functions.php', 39 | COMMON_PATH.'Common/function.php', 40 | CORE_PATH . 'Hook'.EXT, 41 | CORE_PATH . 'App'.EXT, 42 | CORE_PATH . 'Dispatcher'.EXT, 43 | //CORE_PATH . 'Log'.EXT, 44 | CORE_PATH . 'Route'.EXT, 45 | CORE_PATH . 'Controller'.EXT, 46 | CORE_PATH . 'View'.EXT, 47 | BEHAVIOR_PATH . 'ParseTemplateBehavior'.EXT, 48 | BEHAVIOR_PATH . 'ContentReplaceBehavior'.EXT, 49 | ), 50 | // 行为扩展定义 51 | 'tags' => array( 52 | 'app_begin' => array( 53 | 'Behavior\ReadHtmlCacheBehavior', // 读取静态缓存 54 | ), 55 | 'app_end' => array( 56 | 'Behavior\ShowPageTraceBehavior', // 页面Trace显示 57 | ), 58 | 'view_parse' => array( 59 | 'Behavior\ParseTemplateBehavior', // 模板解析 支持PHP、内置模板引擎和第三方模板引擎 60 | ), 61 | 'template_filter'=> array( 62 | 'Behavior\ContentReplaceBehavior', // 模板输出替换 63 | ), 64 | 'view_filter' => array( 65 | 'Behavior\WriteHtmlCacheBehavior', // 写入静态缓存 66 | ), 67 | ), 68 | ); 69 | -------------------------------------------------------------------------------- /Example/ThinkPHP/ThinkPHP.php: -------------------------------------------------------------------------------- 1 | 10 | // +---------------------------------------------------------------------- 11 | 12 | //---------------------------------- 13 | // ThinkPHP公共入口文件 14 | //---------------------------------- 15 | 16 | // 记录开始运行时间 17 | $GLOBALS['_beginTime'] = microtime(TRUE); 18 | // 记录内存初始使用 19 | define('MEMORY_LIMIT_ON',function_exists('memory_get_usage')); 20 | if(MEMORY_LIMIT_ON) $GLOBALS['_startUseMems'] = memory_get_usage(); 21 | 22 | // 版本信息 23 | const THINK_VERSION = '3.2.3'; 24 | 25 | // URL 模式定义 26 | const URL_COMMON = 0; //普通模式 27 | const URL_PATHINFO = 1; //PATHINFO模式 28 | const URL_REWRITE = 2; //REWRITE模式 29 | const URL_COMPAT = 3; // 兼容模式 30 | 31 | // 类文件后缀 32 | const EXT = '.class.php'; 33 | 34 | // 系统常量定义 35 | defined('THINK_PATH') or define('THINK_PATH', __DIR__.'/'); 36 | defined('APP_PATH') or define('APP_PATH', dirname($_SERVER['SCRIPT_FILENAME']).'/'); 37 | defined('APP_STATUS') or define('APP_STATUS', ''); // 应用状态 加载对应的配置文件 38 | defined('APP_DEBUG') or define('APP_DEBUG', false); // 是否调试模式 39 | 40 | if(function_exists('saeAutoLoader')){// 自动识别SAE环境 41 | defined('APP_MODE') or define('APP_MODE', 'sae'); 42 | defined('STORAGE_TYPE') or define('STORAGE_TYPE', 'Sae'); 43 | }else{ 44 | defined('APP_MODE') or define('APP_MODE', 'common'); // 应用模式 默认为普通模式 45 | defined('STORAGE_TYPE') or define('STORAGE_TYPE', 'File'); // 存储类型 默认为File 46 | } 47 | 48 | defined('RUNTIME_PATH') or define('RUNTIME_PATH', APP_PATH.'Runtime/'); // 系统运行时目录 49 | defined('LIB_PATH') or define('LIB_PATH', realpath(THINK_PATH.'Library').'/'); // 系统核心类库目录 50 | defined('CORE_PATH') or define('CORE_PATH', LIB_PATH.'Think/'); // Think类库目录 51 | defined('BEHAVIOR_PATH')or define('BEHAVIOR_PATH', LIB_PATH.'Behavior/'); // 行为类库目录 52 | defined('MODE_PATH') or define('MODE_PATH', THINK_PATH.'Mode/'); // 系统应用模式目录 53 | defined('VENDOR_PATH') or define('VENDOR_PATH', LIB_PATH.'Vendor/'); // 第三方类库目录 54 | defined('COMMON_PATH') or define('COMMON_PATH', APP_PATH.'Common/'); // 应用公共目录 55 | defined('CONF_PATH') or define('CONF_PATH', COMMON_PATH.'Conf/'); // 应用配置目录 56 | defined('LANG_PATH') or define('LANG_PATH', COMMON_PATH.'Lang/'); // 应用语言目录 57 | defined('HTML_PATH') or define('HTML_PATH', APP_PATH.'Html/'); // 应用静态目录 58 | defined('LOG_PATH') or define('LOG_PATH', RUNTIME_PATH.'Logs/'); // 应用日志目录 59 | defined('TEMP_PATH') or define('TEMP_PATH', RUNTIME_PATH.'Temp/'); // 应用缓存目录 60 | defined('DATA_PATH') or define('DATA_PATH', RUNTIME_PATH.'Data/'); // 应用数据目录 61 | defined('CACHE_PATH') or define('CACHE_PATH', RUNTIME_PATH.'Cache/'); // 应用模板缓存目录 62 | defined('CONF_EXT') or define('CONF_EXT', '.php'); // 配置文件后缀 63 | defined('CONF_PARSE') or define('CONF_PARSE', ''); // 配置文件解析方法 64 | defined('ADDON_PATH') or define('ADDON_PATH', APP_PATH.'Addon'); 65 | 66 | // 系统信息 67 | if(version_compare(PHP_VERSION,'5.4.0','<')) { 68 | ini_set('magic_quotes_runtime',0); 69 | define('MAGIC_QUOTES_GPC',get_magic_quotes_gpc()? true : false); 70 | }else{ 71 | define('MAGIC_QUOTES_GPC',false); 72 | } 73 | define('IS_CGI',(0 === strpos(PHP_SAPI,'cgi') || false !== strpos(PHP_SAPI,'fcgi')) ? 1 : 0 ); 74 | define('IS_WIN',strstr(PHP_OS, 'WIN') ? 1 : 0 ); 75 | define('IS_CLI',PHP_SAPI=='cli'? 1 : 0); 76 | 77 | if(!IS_CLI) { 78 | // 当前文件名 79 | if(!defined('_PHP_FILE_')) { 80 | if(IS_CGI) { 81 | //CGI/FASTCGI模式下 82 | $_temp = explode('.php',$_SERVER['PHP_SELF']); 83 | define('_PHP_FILE_', rtrim(str_replace($_SERVER['HTTP_HOST'],'',$_temp[0].'.php'),'/')); 84 | }else { 85 | define('_PHP_FILE_', rtrim($_SERVER['SCRIPT_NAME'],'/')); 86 | } 87 | } 88 | if(!defined('__ROOT__')) { 89 | $_root = rtrim(dirname(_PHP_FILE_),'/'); 90 | define('__ROOT__', (($_root=='/' || $_root=='\\')?'':$_root)); 91 | } 92 | } 93 | 94 | // 加载核心Think类 95 | require CORE_PATH.'Think'.EXT; 96 | // 应用初始化 97 | Think\Think::start(); -------------------------------------------------------------------------------- /Example/ThinkPHP/Tpl/dispatch_jump.tpl: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 9 | 10 | 跳转提示 11 | 21 | 22 | 23 |
24 | 25 |

:)

26 |

27 | 28 |

:(

29 |

30 | 31 |

32 |

33 | 页面自动 跳转 等待时间: 34 |

35 |
36 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /Example/ThinkPHP/Tpl/page_trace.tpl: -------------------------------------------------------------------------------- 1 |
2 | 24 | 25 |
26 |
27 | 68 | -------------------------------------------------------------------------------- /Example/ThinkPHP/Tpl/think_exception.tpl: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 9 | 系统发生错误 10 | 26 | 27 | 28 |
29 |

:(

30 |

31 |
32 | 33 |
34 |
35 |

错误位置

36 |
37 |
38 |

FILE:  LINE:

39 |
40 |
41 | 42 | 43 |
44 |
45 |

TRACE

46 |
47 |
48 |

49 |
50 |
51 | 52 |
53 |
54 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /Example/ThinkPHP/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hizt/ThinkPHPUnit/8be6cedcc2598fcadf3108c1416a85c65e22b907/Example/ThinkPHP/logo.png -------------------------------------------------------------------------------- /Example/index.php: -------------------------------------------------------------------------------- 1 | 10 | // +---------------------------------------------------------------------- 11 | 12 | // 应用入口文件 13 | 14 | // 检测PHP环境 15 | if(version_compare(PHP_VERSION,'5.3.0','<')) die('require PHP > 5.3.0 !'); 16 | 17 | // 开启调试模式 建议开发阶段开启 部署阶段注释或者设为false 18 | define('APP_DEBUG',True); 19 | 20 | // 定义应用目录 21 | define('APP_PATH','./Application/'); 22 | 23 | // 引入ThinkPHP入口文件 24 | 25 | require '../vendor/autoload.php'; 26 | require './ThinkPHP/ThinkPHP.php'; 27 | 28 | // 亲^_^ 后面不需要任何代码了 就是如此简单 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ThinkPHPUnit v0.95 2 | 一个为ThinkPHP打造的的UnitTest,简单易用、高效便捷。
3 | 4 |
5 | 6 | 7 | ##How To Use 8 | ### 详细使用介绍查看项目`example`,下面列出一个简单的使用介绍 9 | * 在`Application`目录下创建`Test/Controller`,编写测试Controller。 10 | * 以编写 IndexController为例: 11 | ```PHP 12 | namespace \Test\Controller; 13 | class IndexController extends UnitTest{ 14 | 15 | /** 16 | * 调用方法: 17 | * 1. http://localhost/PROJECT_NAME/index.php?m=Test 自动执行全部测试文件 18 | * 2. http://localhost/PROJECT_NAME/index.php?m=Test&controller=XXX 自动执行参数crontroller指定的文件 19 | */ 20 | function index(){ 21 | $this->run(true); //测试方式1 : 通过自动遍历测试文件的方式执行测试 22 | 23 | } 24 | 25 | function index2(){ 26 | $this->setController( array(__CLASS__ ,'\OtherClassName') ); //测试方式2 :设置将要执行的测试类 27 | $this->run(); //执行测试代码 28 | 29 | } 30 | 31 | function testExample1(){ //该方法将自动被测试 32 | $this->assertTrue(true); 33 | $this->assertFalse(false); 34 | } 35 | 36 | function testExample2(){ //该方法将自动被测试 37 | $this->assertEmpty(null); 38 | $this->assertNotEmpty(true); 39 | } 40 | } 41 | ``` 42 | * 到浏览器运行 `http://localhost/PROJECT_PATH/index.php?m=Test` 43 | * 运行结果 44 | ![IMG](https://raw.githubusercontent.com/hizt/ThinkPHPUnit/master/result-screenshot.png) 45 | 46 | 47 |
48 | 49 | 50 | ##Bug && Contact Author 51 | * bug提交:[https://github.com/hizt/ThinkPHPUnit/issues](https://github.com/hizt/ThinkPHPUnit/issues) 52 | * 作者:[zthi@qq.com](mailto:zthi@qq.com) -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "zt/unit-test", 3 | "version":"1.2", 4 | "type": "library", 5 | "description": "Thinkphp Unit Test", 6 | "keywords": ["ThinkPHP","UnitTest"], 7 | "homepage": "https://github.com/hizt/ThinkPHPUnit", 8 | "license": "MIT", 9 | "authors": [ 10 | { 11 | "name": "ZT", 12 | "email": "hizt@qq.com", 13 | "role": "Developer" 14 | } 15 | ], 16 | "require": { 17 | "php": ">=5.3.0" 18 | }, 19 | "autoload": { 20 | "psr-4": {"":"src"} 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", 5 | "This file is @generated automatically" 6 | ], 7 | "hash": "0bd73487ec194ccbc990d7e2e19030c0", 8 | "content-hash": "254c82a94243a76448004dd46260d9d3", 9 | "packages": [], 10 | "packages-dev": [], 11 | "aliases": [], 12 | "minimum-stability": "stable", 13 | "stability-flags": [], 14 | "prefer-stable": false, 15 | "prefer-lowest": false, 16 | "platform": { 17 | "php": ">=5.3.0" 18 | }, 19 | "platform-dev": [] 20 | } 21 | -------------------------------------------------------------------------------- /result-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hizt/ThinkPHPUnit/8be6cedcc2598fcadf3108c1416a85c65e22b907/result-screenshot.png -------------------------------------------------------------------------------- /vendor/autoload.php: -------------------------------------------------------------------------------- 1 | array($baseDir . '/src'), 10 | ); 11 | -------------------------------------------------------------------------------- /vendor/composer/autoload_real.php: -------------------------------------------------------------------------------- 1 | = 50600 && !defined('HHVM_VERSION'); 27 | if ($useStaticLoader) { 28 | require_once __DIR__ . '/autoload_static.php'; 29 | 30 | call_user_func(\Composer\Autoload\ComposerStaticInitb221e74a9793533f8fba052277fb1c99::getInitializer($loader)); 31 | } else { 32 | $map = require __DIR__ . '/autoload_namespaces.php'; 33 | foreach ($map as $namespace => $path) { 34 | $loader->set($namespace, $path); 35 | } 36 | 37 | $map = require __DIR__ . '/autoload_psr4.php'; 38 | foreach ($map as $namespace => $path) { 39 | $loader->setPsr4($namespace, $path); 40 | } 41 | 42 | $classMap = require __DIR__ . '/autoload_classmap.php'; 43 | if ($classMap) { 44 | $loader->addClassMap($classMap); 45 | } 46 | } 47 | 48 | $loader->register(true); 49 | 50 | return $loader; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /vendor/composer/autoload_static.php: -------------------------------------------------------------------------------- 1 | __DIR__ . '/../..' . '/src', 11 | ); 12 | 13 | public static function getInitializer(ClassLoader $loader) 14 | { 15 | return \Closure::bind(function () use ($loader) { 16 | $loader->fallbackDirsPsr4 = ComposerStaticInitb221e74a9793533f8fba052277fb1c99::$fallbackDirsPsr4; 17 | 18 | }, null, ClassLoader::class); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /vendor/composer/installed.json: -------------------------------------------------------------------------------- 1 | [] 2 | --------------------------------------------------------------------------------