From 1fe13d0106078aec79be0a5578734bcdeec5dea9 Mon Sep 17 00:00:00 2001 From: ThinkPHP Date: Wed, 18 Dec 2013 12:40:11 +0800 Subject: [PATCH 001/562] =?UTF-8?q?3.2=E7=89=88=E6=9C=AC=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Application/README.md | 1 + Application/index.html | 1 + Public/README.md | 1 + ThinkPHP/Common/build.php | 102 + ThinkPHP/Common/common.php | 757 ---- ThinkPHP/Common/functions.php | 875 +++-- ThinkPHP/Common/runtime.php | 242 -- ThinkPHP/Conf/Mode/common.php | 78 + ThinkPHP/Conf/Mode/sae.php | 80 + ThinkPHP/Conf/alias.php | 23 - ThinkPHP/Conf/convention.php | 199 +- ThinkPHP/Conf/convention_sae.php | 38 + ThinkPHP/Conf/debug.php | 27 +- ThinkPHP/Conf/tags.php | 39 - ThinkPHP/Extend/README.txt | 24 - ThinkPHP/Lang/en-us.php | 72 +- ThinkPHP/Lang/zh-cn.php | 72 +- ThinkPHP/Lib/Core/Dispatcher.class.php | 271 -- ThinkPHP/Lib/Core/Think.class.php | 316 -- ThinkPHP/Lib/Core/Widget.class.php | 107 - .../Behavior/AgentCheckBehavior.class.php | 33 + .../Behavior/BrowserCheckBehavior.class.php | 43 + .../CheckActionRouteBehavior.class.php} | 100 +- .../Behavior/CheckLangBehavior.class.php | 88 + .../ChromeShowPageTraceBehavior.class.php | 616 ++++ .../Behavior/ContentReplaceBehavior.class.php | 18 +- .../Behavior/CronRunBehavior.class.php | 74 + .../FireShowPageTraceBehavior.class.php | 2094 +++++++++++ .../Behavior/ParseTemplateBehavior.class.php | 39 +- .../Behavior/ReadHtmlCacheBehavior.class.php | 53 +- .../Behavior/RobotCheckBehavior.class.php | 46 + .../Behavior/ShowPageTraceBehavior.class.php | 14 +- .../Behavior/ShowRuntimeBehavior.class.php | 9 +- .../Behavior/TokenBuildBehavior.class.php | 26 +- .../Behavior/UpgradeNoticeBehavior.class.php | 129 + .../Behavior/WriteHtmlCacheBehavior.class.php | 17 +- .../{Lib/Core => Library/Think}/App.class.php | 104 +- .../Core => Library/Think}/Behavior.class.php | 8 +- .../Core => Library/Think}/Cache.class.php | 46 +- .../Think/Cache/Driver/Apachenote.class.php | 124 + .../Library/Think/Cache/Driver/Apc.class.php | 86 + .../Library/Think/Cache/Driver/Db.class.php | 138 + .../Think/Cache/Driver/Eaccelerator.class.php | 77 + .../Think/Cache/Driver/File.class.php} | 13 +- .../Think/Cache/Driver/Memcache.class.php | 103 + .../Think/Cache/Driver/Memcachesae.class.php | 153 + .../Think/Cache/Driver/Redis.class.php | 108 + .../Think/Cache/Driver/Shmop.class.php | 186 + .../Think/Cache/Driver/Sqlite.class.php | 119 + .../Think/Cache/Driver/Wincache.class.php | 79 + .../Think/Cache/Driver/Xcache.class.php | 81 + .../Think/Controller.class.php} | 714 ++-- ThinkPHP/Library/Think/Crypt.class.php | 57 + .../Think/Crypt/Driver/Base64.class.php | 74 + .../Think/Crypt/Driver/Crypt.class.php | 83 + .../Library/Think/Crypt/Driver/Des.class.php | 241 ++ .../Think/Crypt/Driver/Think.class.php | 86 + .../Think/Crypt/Driver/Xxtea.class.php | 116 + .../{Lib/Core => Library/Think}/Db.class.php | 1836 +++++----- .../Library/Think/Db/Driver/Ibase.class.php | 335 ++ .../Library/Think/Db/Driver/Mongo.class.php | 753 ++++ .../Library/Think/Db/Driver/Mssql.class.php | 331 ++ .../Think/Db/Driver/Mysql.class.php} | 15 +- .../Think/Db/Driver/Mysqli.class.php} | 15 +- .../Library/Think/Db/Driver/Oracle.class.php | 334 ++ .../Library/Think/Db/Driver/Pdo.class.php | 490 +++ .../Library/Think/Db/Driver/Pgsql.class.php | 297 ++ .../Library/Think/Db/Driver/Sqlite.class.php | 282 ++ .../Library/Think/Db/Driver/Sqlsrv.class.php | 349 ++ ThinkPHP/Library/Think/Dispatcher.class.php | 323 ++ .../Think/Exception.class.php} | 10 +- ThinkPHP/Library/Think/Hook.class.php | 125 + ThinkPHP/Library/Think/Image.class.php | 190 + .../Library/Think/Image/Driver/GIF.class.php | 570 +++ .../Library/Think/Image/Driver/Gd.class.php | 544 +++ .../Think/Image/Driver/Imagick.class.php | 589 +++ .../{Lib/Core => Library/Think}/Log.class.php | 80 +- .../Library/Think/Log/Driver/File.class.php | 43 + .../Library/Think/Log/Driver/Sae.class.php | 47 + .../Core => Library/Think}/Model.class.php | 3151 +++++++++-------- .../Library/Think/Model/AdvModel.class.php | 668 ++++ .../Library/Think/Model/MongoModel.class.php | 310 ++ .../Think/Model/RelationModel.class.php | 393 ++ .../Library/Think/Model/ViewModel.class.php | 246 ++ ThinkPHP/Library/Think/Page.class.php | 144 + ThinkPHP/Library/Think/Route.class.php | 302 ++ .../Library/Think/Session/Driver/Db.class.php | 184 + ThinkPHP/Library/Think/Storage.class.php | 45 + .../Think/Storage/Driver/File.class.php | 121 + .../Think/Storage/Driver/Sae.class.php | 246 ++ .../Think/Template.class.php} | 1399 ++++---- .../Think/Template/Driver/Ease.class.php | 42 + .../Think/Template/Driver/Lite.class.php | 40 + .../Think/Template/Driver/Mobile.class.php | 29 + .../Think/Template/Driver/Smart.class.php | 41 + .../Think/Template/Driver/Smarty.class.php | 42 + .../Think}/Template/TagLib.class.php | 61 +- .../Think/Template/TagLib/Cx.class.php} | 189 +- .../Think/Template/TagLib/Html.class.php | 524 +++ ThinkPHP/Library/Think/Think.class.php | 322 ++ ThinkPHP/Library/Think/Upload.class.php | 374 ++ .../Library/Think/Upload/Driver/Bcs.class.php | 237 ++ .../Think/Upload/Driver/Bcs/bcs.class.php | 1318 +++++++ .../Upload/Driver/Bcs/mimetypes.class.php | 137 + .../Upload/Driver/Bcs/requestcore.class.php | 840 +++++ .../Library/Think/Upload/Driver/Ftp.class.php | 164 + .../Think/Upload/Driver/Local.class.php | 117 + .../Think/Upload/Driver/Qiniu.class.php | 102 + .../Driver/Qiniu/QiniuStorage.class.php | 333 ++ .../Library/Think/Upload/Driver/Sae.class.php | 102 + .../Think/Upload/Driver/Upyun.class.php | 219 ++ ThinkPHP/Library/Think/Verify.class.php | 255 ++ ThinkPHP/Library/Think/Verify/bgs/1.jpg | Bin 0 -> 30428 bytes ThinkPHP/Library/Think/Verify/bgs/2.jpg | Bin 0 -> 29677 bytes ThinkPHP/Library/Think/Verify/bgs/3.jpg | Bin 0 -> 32109 bytes ThinkPHP/Library/Think/Verify/bgs/4.jpg | Bin 0 -> 29081 bytes ThinkPHP/Library/Think/Verify/bgs/5.jpg | Bin 0 -> 27940 bytes ThinkPHP/Library/Think/Verify/bgs/6.jpg | Bin 0 -> 31381 bytes ThinkPHP/Library/Think/Verify/bgs/7.jpg | Bin 0 -> 30234 bytes ThinkPHP/Library/Think/Verify/bgs/8.jpg | Bin 0 -> 30188 bytes ThinkPHP/Library/Think/Verify/ttfs/1.ttf | Bin 0 -> 57520 bytes ThinkPHP/Library/Think/Verify/ttfs/2.ttf | Bin 0 -> 28328 bytes ThinkPHP/Library/Think/Verify/ttfs/3.ttf | Bin 0 -> 39308 bytes ThinkPHP/Library/Think/Verify/ttfs/4.ttf | Bin 0 -> 34852 bytes ThinkPHP/Library/Think/Verify/ttfs/5.ttf | Bin 0 -> 32664 bytes ThinkPHP/Library/Think/Verify/ttfs/6.ttf | Bin 0 -> 28036 bytes ThinkPHP/Library/Think/Verify/zhttfs/1.ttf | Bin 0 -> 2183628 bytes .../Core => Library/Think}/View.class.php | 443 ++- ThinkPHP/Library/Vendor/README.txt | 1 + ThinkPHP/README.txt | 6 +- ThinkPHP/ThinkPHP.php | 137 +- ThinkPHP/Tpl/default_index.tpl | 4 +- ThinkPHP/Tpl/page_trace.tpl | 6 +- index.php | 23 + 134 files changed, 23918 insertions(+), 6477 deletions(-) create mode 100644 Application/README.md create mode 100644 Application/index.html create mode 100644 Public/README.md create mode 100644 ThinkPHP/Common/build.php delete mode 100644 ThinkPHP/Common/common.php delete mode 100644 ThinkPHP/Common/runtime.php create mode 100644 ThinkPHP/Conf/Mode/common.php create mode 100644 ThinkPHP/Conf/Mode/sae.php delete mode 100644 ThinkPHP/Conf/alias.php create mode 100644 ThinkPHP/Conf/convention_sae.php delete mode 100644 ThinkPHP/Conf/tags.php delete mode 100644 ThinkPHP/Extend/README.txt delete mode 100644 ThinkPHP/Lib/Core/Dispatcher.class.php delete mode 100644 ThinkPHP/Lib/Core/Think.class.php delete mode 100644 ThinkPHP/Lib/Core/Widget.class.php create mode 100644 ThinkPHP/Library/Behavior/AgentCheckBehavior.class.php create mode 100644 ThinkPHP/Library/Behavior/BrowserCheckBehavior.class.php rename ThinkPHP/{Lib/Behavior/CheckRouteBehavior.class.php => Library/Behavior/CheckActionRouteBehavior.class.php} (70%) create mode 100644 ThinkPHP/Library/Behavior/CheckLangBehavior.class.php create mode 100644 ThinkPHP/Library/Behavior/ChromeShowPageTraceBehavior.class.php rename ThinkPHP/{Lib => Library}/Behavior/ContentReplaceBehavior.class.php (78%) create mode 100644 ThinkPHP/Library/Behavior/CronRunBehavior.class.php create mode 100644 ThinkPHP/Library/Behavior/FireShowPageTraceBehavior.class.php rename ThinkPHP/{Lib => Library}/Behavior/ParseTemplateBehavior.class.php (81%) rename ThinkPHP/{Lib => Library}/Behavior/ReadHtmlCacheBehavior.class.php (68%) create mode 100644 ThinkPHP/Library/Behavior/RobotCheckBehavior.class.php rename ThinkPHP/{Lib => Library}/Behavior/ShowPageTraceBehavior.class.php (95%) rename ThinkPHP/{Lib => Library}/Behavior/ShowRuntimeBehavior.class.php (95%) rename ThinkPHP/{Lib => Library}/Behavior/TokenBuildBehavior.class.php (68%) create mode 100644 ThinkPHP/Library/Behavior/UpgradeNoticeBehavior.class.php rename ThinkPHP/{Lib => Library}/Behavior/WriteHtmlCacheBehavior.class.php (60%) rename ThinkPHP/{Lib/Core => Library/Think}/App.class.php (78%) rename ThinkPHP/{Lib/Core => Library/Think}/Behavior.class.php (90%) rename ThinkPHP/{Lib/Core => Library/Think}/Cache.class.php (82%) create mode 100644 ThinkPHP/Library/Think/Cache/Driver/Apachenote.class.php create mode 100644 ThinkPHP/Library/Think/Cache/Driver/Apc.class.php create mode 100644 ThinkPHP/Library/Think/Cache/Driver/Db.class.php create mode 100644 ThinkPHP/Library/Think/Cache/Driver/Eaccelerator.class.php rename ThinkPHP/{Lib/Driver/Cache/CacheFile.class.php => Library/Think/Cache/Driver/File.class.php} (95%) create mode 100644 ThinkPHP/Library/Think/Cache/Driver/Memcache.class.php create mode 100644 ThinkPHP/Library/Think/Cache/Driver/Memcachesae.class.php create mode 100644 ThinkPHP/Library/Think/Cache/Driver/Redis.class.php create mode 100644 ThinkPHP/Library/Think/Cache/Driver/Shmop.class.php create mode 100644 ThinkPHP/Library/Think/Cache/Driver/Sqlite.class.php create mode 100644 ThinkPHP/Library/Think/Cache/Driver/Wincache.class.php create mode 100644 ThinkPHP/Library/Think/Cache/Driver/Xcache.class.php rename ThinkPHP/{Lib/Core/Action.class.php => Library/Think/Controller.class.php} (64%) create mode 100644 ThinkPHP/Library/Think/Crypt.class.php create mode 100644 ThinkPHP/Library/Think/Crypt/Driver/Base64.class.php create mode 100644 ThinkPHP/Library/Think/Crypt/Driver/Crypt.class.php create mode 100644 ThinkPHP/Library/Think/Crypt/Driver/Des.class.php create mode 100644 ThinkPHP/Library/Think/Crypt/Driver/Think.class.php create mode 100644 ThinkPHP/Library/Think/Crypt/Driver/Xxtea.class.php rename ThinkPHP/{Lib/Core => Library/Think}/Db.class.php (92%) create mode 100644 ThinkPHP/Library/Think/Db/Driver/Ibase.class.php create mode 100644 ThinkPHP/Library/Think/Db/Driver/Mongo.class.php create mode 100644 ThinkPHP/Library/Think/Db/Driver/Mssql.class.php rename ThinkPHP/{Lib/Driver/Db/DbMysql.class.php => Library/Think/Db/Driver/Mysql.class.php} (97%) rename ThinkPHP/{Lib/Driver/Db/DbMysqli.class.php => Library/Think/Db/Driver/Mysqli.class.php} (95%) create mode 100644 ThinkPHP/Library/Think/Db/Driver/Oracle.class.php create mode 100644 ThinkPHP/Library/Think/Db/Driver/Pdo.class.php create mode 100644 ThinkPHP/Library/Think/Db/Driver/Pgsql.class.php create mode 100644 ThinkPHP/Library/Think/Db/Driver/Sqlite.class.php create mode 100644 ThinkPHP/Library/Think/Db/Driver/Sqlsrv.class.php create mode 100644 ThinkPHP/Library/Think/Dispatcher.class.php rename ThinkPHP/{Lib/Core/ThinkException.class.php => Library/Think/Exception.class.php} (73%) create mode 100644 ThinkPHP/Library/Think/Hook.class.php create mode 100644 ThinkPHP/Library/Think/Image.class.php create mode 100644 ThinkPHP/Library/Think/Image/Driver/GIF.class.php create mode 100644 ThinkPHP/Library/Think/Image/Driver/Gd.class.php create mode 100644 ThinkPHP/Library/Think/Image/Driver/Imagick.class.php rename ThinkPHP/{Lib/Core => Library/Think}/Log.class.php (54%) create mode 100644 ThinkPHP/Library/Think/Log/Driver/File.class.php create mode 100644 ThinkPHP/Library/Think/Log/Driver/Sae.class.php rename ThinkPHP/{Lib/Core => Library/Think}/Model.class.php (90%) create mode 100644 ThinkPHP/Library/Think/Model/AdvModel.class.php create mode 100644 ThinkPHP/Library/Think/Model/MongoModel.class.php create mode 100644 ThinkPHP/Library/Think/Model/RelationModel.class.php create mode 100644 ThinkPHP/Library/Think/Model/ViewModel.class.php create mode 100644 ThinkPHP/Library/Think/Page.class.php create mode 100644 ThinkPHP/Library/Think/Route.class.php create mode 100644 ThinkPHP/Library/Think/Session/Driver/Db.class.php create mode 100644 ThinkPHP/Library/Think/Storage.class.php create mode 100644 ThinkPHP/Library/Think/Storage/Driver/File.class.php create mode 100644 ThinkPHP/Library/Think/Storage/Driver/Sae.class.php rename ThinkPHP/{Lib/Template/ThinkTemplate.class.php => Library/Think/Template.class.php} (80%) create mode 100644 ThinkPHP/Library/Think/Template/Driver/Ease.class.php create mode 100644 ThinkPHP/Library/Think/Template/Driver/Lite.class.php create mode 100644 ThinkPHP/Library/Think/Template/Driver/Mobile.class.php create mode 100644 ThinkPHP/Library/Think/Template/Driver/Smart.class.php create mode 100644 ThinkPHP/Library/Think/Template/Driver/Smarty.class.php rename ThinkPHP/{Lib => Library/Think}/Template/TagLib.class.php (81%) rename ThinkPHP/{Lib/Driver/TagLib/TagLibCx.class.php => Library/Think/Template/TagLib/Cx.class.php} (78%) create mode 100644 ThinkPHP/Library/Think/Template/TagLib/Html.class.php create mode 100644 ThinkPHP/Library/Think/Think.class.php create mode 100644 ThinkPHP/Library/Think/Upload.class.php create mode 100644 ThinkPHP/Library/Think/Upload/Driver/Bcs.class.php create mode 100644 ThinkPHP/Library/Think/Upload/Driver/Bcs/bcs.class.php create mode 100644 ThinkPHP/Library/Think/Upload/Driver/Bcs/mimetypes.class.php create mode 100644 ThinkPHP/Library/Think/Upload/Driver/Bcs/requestcore.class.php create mode 100644 ThinkPHP/Library/Think/Upload/Driver/Ftp.class.php create mode 100644 ThinkPHP/Library/Think/Upload/Driver/Local.class.php create mode 100644 ThinkPHP/Library/Think/Upload/Driver/Qiniu.class.php create mode 100644 ThinkPHP/Library/Think/Upload/Driver/Qiniu/QiniuStorage.class.php create mode 100644 ThinkPHP/Library/Think/Upload/Driver/Sae.class.php create mode 100644 ThinkPHP/Library/Think/Upload/Driver/Upyun.class.php create mode 100644 ThinkPHP/Library/Think/Verify.class.php create mode 100644 ThinkPHP/Library/Think/Verify/bgs/1.jpg create mode 100644 ThinkPHP/Library/Think/Verify/bgs/2.jpg create mode 100644 ThinkPHP/Library/Think/Verify/bgs/3.jpg create mode 100644 ThinkPHP/Library/Think/Verify/bgs/4.jpg create mode 100644 ThinkPHP/Library/Think/Verify/bgs/5.jpg create mode 100644 ThinkPHP/Library/Think/Verify/bgs/6.jpg create mode 100644 ThinkPHP/Library/Think/Verify/bgs/7.jpg create mode 100644 ThinkPHP/Library/Think/Verify/bgs/8.jpg create mode 100644 ThinkPHP/Library/Think/Verify/ttfs/1.ttf create mode 100644 ThinkPHP/Library/Think/Verify/ttfs/2.ttf create mode 100644 ThinkPHP/Library/Think/Verify/ttfs/3.ttf create mode 100644 ThinkPHP/Library/Think/Verify/ttfs/4.ttf create mode 100644 ThinkPHP/Library/Think/Verify/ttfs/5.ttf create mode 100644 ThinkPHP/Library/Think/Verify/ttfs/6.ttf create mode 100644 ThinkPHP/Library/Think/Verify/zhttfs/1.ttf rename ThinkPHP/{Lib/Core => Library/Think}/View.class.php (69%) create mode 100644 ThinkPHP/Library/Vendor/README.txt create mode 100644 index.php diff --git a/Application/README.md b/Application/README.md new file mode 100644 index 000000000..5bc1d44fe --- /dev/null +++ b/Application/README.md @@ -0,0 +1 @@ +项目目录 \ No newline at end of file diff --git a/Application/index.html b/Application/index.html new file mode 100644 index 000000000..0519ecba6 --- /dev/null +++ b/Application/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Public/README.md b/Public/README.md new file mode 100644 index 000000000..40f011ace --- /dev/null +++ b/Public/README.md @@ -0,0 +1 @@ +资源文件目录 \ No newline at end of file diff --git a/ThinkPHP/Common/build.php b/ThinkPHP/Common/build.php new file mode 100644 index 000000000..2c98336c0 --- /dev/null +++ b/ThinkPHP/Common/build.php @@ -0,0 +1,102 @@ + +// +---------------------------------------------------------------------- + +/** + * ThinkPHP 目录创建和初始化 + */ +defined('THINK_PATH') or exit(); + +// 检查应用目录结构 如果不存在则自动创建 +if(!is_dir(COMMON_PATH)) { + // 创建目录结构 + build_app_dir(); +}elseif(!is_dir(LOG_PATH)){ + // 检查缓存目录 + check_runtime(); +} + +// 检查缓存目录(Runtime) 如果不存在则自动创建 +function check_runtime() { + if(!is_dir(RUNTIME_PATH)) { + mkdir(RUNTIME_PATH); + }elseif(!is_writeable(RUNTIME_PATH)) { + header('Content-Type:text/html; charset=utf-8'); + exit('目录 [ '.RUNTIME_PATH.' ] 不可写!'); + } + mkdir(CACHE_PATH); // 模板缓存目录 + if(!is_dir(LOG_PATH)) mkdir(LOG_PATH); // 日志目录 + if(!is_dir(TEMP_PATH)) mkdir(TEMP_PATH); // 数据缓存目录 + if(!is_dir(DATA_PATH)) mkdir(DATA_PATH); // 数据文件目录 + return true; +} + +// 创建应用目录结构 +function build_app_dir() { + // 没有创建的话自动创建 + if(!is_dir(APP_PATH)) mkdir(APP_PATH,0755,true); + if(is_writeable(APP_PATH)) { + $dirs = array( + COMMON_PATH, + COMMON_PATH.'Common/', + COMMON_PATH.'Conf/', + APP_PATH.C('DEFAULT_MODULE').'/', + APP_PATH.C('DEFAULT_MODULE').'/Common/', + APP_PATH.C('DEFAULT_MODULE').'/Controller/', + APP_PATH.C('DEFAULT_MODULE').'/Model/', + APP_PATH.C('DEFAULT_MODULE').'/Conf/', + APP_PATH.C('DEFAULT_MODULE').'/View/', + RUNTIME_PATH, + CACHE_PATH, + LOG_PATH, + TEMP_PATH, + DATA_PATH, + ); + foreach ($dirs as $dir){ + if(!is_dir($dir)) mkdir($dir,0755,true); + } + // 写入目录安全文件 + build_dir_secure($dirs); + // 写入初始配置文件 + if(!is_file(COMMON_PATH.'Conf/config.php')) + file_put_contents(COMMON_PATH.'Conf/config.php',"'配置值'\n);"); + // 写入测试Action + build_first_action(); + }else{ + header('Content-Type:text/html; charset=utf-8'); + exit('应用目录['.APP_PATH.']不可写,目录无法自动生成!
请手动生成项目目录~'); + } +} + +// 创建测试Action +function build_first_action() { + $file = APP_PATH.C('DEFAULT_MODULE').'/Controller/IndexController'.EXT; + if(!is_file($file)){ + $content = file_get_contents(THINK_PATH.'Tpl/default_index.tpl'); + file_put_contents($file,$content); + } +} + +// 生成目录安全文件 +function build_dir_secure($dirs=array()) { + // 目录安全写入(默认开启) + defined('BUILD_DIR_SECURE') or define('BUILD_DIR_SECURE', true); + if(BUILD_DIR_SECURE) { + defined('DIR_SECURE_FILENAME') or define('DIR_SECURE_FILENAME', 'index.html'); + defined('DIR_SECURE_CONTENT') or define('DIR_SECURE_CONTENT', ' '); + // 自动写入目录安全文件 + $content = DIR_SECURE_CONTENT; + $files = explode(',', DIR_SECURE_FILENAME); + foreach ($files as $filename){ + foreach ($dirs as $dir) + file_put_contents($dir.$filename,$content); + } + } +} \ No newline at end of file diff --git a/ThinkPHP/Common/common.php b/ThinkPHP/Common/common.php deleted file mode 100644 index e060546f7..000000000 --- a/ThinkPHP/Common/common.php +++ /dev/null @@ -1,757 +0,0 @@ - -// +---------------------------------------------------------------------- - -/** - * Think 基础函数库 - * @category Think - * @package Common - * @author liu21st - */ - -/** - * 获取模版文件 格式 项目://分组@主题/模块/操作 - * @param string $name 模版资源地址 - * @param string $layer 视图层(目录)名称 - * @return string - */ -function T($template='',$layer=''){ - if(is_file($template)) { - return $template; - } - // 解析模版资源地址 - if(false === strpos($template,'://')){ - $template = APP_NAME.'://'.str_replace(':', '/',$template); - } - $info = parse_url($template); - $file = $info['host'].(isset($info['path'])?$info['path']:''); - $group = isset($info['user'])?$info['user'].'/':(defined('GROUP_NAME')?GROUP_NAME.'/':''); - $app = $info['scheme']; - $layer = $layer?$layer:C('DEFAULT_V_LAYER'); - - // 获取当前主题的模版路径 - if(($list = C('EXTEND_GROUP_LIST')) && isset($list[$app])){ // 扩展分组 - $baseUrl = $list[$app].'/'.$group.$layer.'/'; - }elseif(1==C('APP_GROUP_MODE')){ // 独立分组模式 - $baseUrl = dirname(BASE_LIB_PATH).'/'.$group.$layer.'/'; - }else{ - $baseUrl = TMPL_PATH.$group; - } - $depr = C('TMPL_FILE_DEPR'); - // 分析模板文件规则 - if('' == $file) { - // 如果模板文件名为空 按照默认规则定位 - $file = MODULE_NAME . $depr . ACTION_NAME; - }elseif(false === strpos($file, $depr)){ - $file = MODULE_NAME . $depr . $file; - } - return $baseUrl.$file.C('TMPL_TEMPLATE_SUFFIX'); -} - -/** - * 获取输入参数 支持过滤和默认值 - * 使用方法: - * - * I('id',0); 获取id参数 自动判断get或者post - * I('post.name','','htmlspecialchars'); 获取$_POST['name'] - * I('get.'); 获取$_GET - * - * @param string $name 变量的名称 支持指定类型 - * @param mixed $default 不存在的时候默认值 - * @param mixed $filter 参数过滤方法 - * @return mixed - */ -function I($name,$default='',$filter=null) { - if(strpos($name,'.')) { // 指定参数来源 - list($method,$name) = explode('.',$name,2); - }else{ // 默认为自动判断 - $method = 'param'; - } - switch(strtolower($method)) { - case 'get' : $input =& $_GET;break; - case 'post' : $input =& $_POST;break; - case 'put' : parse_str(file_get_contents('php://input'), $input);break; - case 'param' : - switch($_SERVER['REQUEST_METHOD']) { - case 'POST': - $input = $_POST; - break; - case 'PUT': - parse_str(file_get_contents('php://input'), $input); - break; - default: - $input = $_GET; - } - if(C('VAR_URL_PARAMS') && isset($_GET[C('VAR_URL_PARAMS')])){ - $input = array_merge($input,$_GET[C('VAR_URL_PARAMS')]); - } - break; - case 'request' : $input =& $_REQUEST; break; - case 'session' : $input =& $_SESSION; break; - case 'cookie' : $input =& $_COOKIE; break; - case 'server' : $input =& $_SERVER; break; - case 'globals' : $input =& $GLOBALS; break; - default: - return NULL; - } - // 全局过滤 - // array_walk_recursive($input,'filter_exp'); - if(C('VAR_FILTERS')) { - $_filters = explode(',',C('VAR_FILTERS')); - foreach($_filters as $_filter){ - // 全局参数过滤 - array_walk_recursive($input,$_filter); - } - } - if(empty($name)) { // 获取全部变量 - $data = $input; - $filters = isset($filter)?$filter:C('DEFAULT_FILTER'); - if($filters) { - $filters = explode(',',$filters); - foreach($filters as $filter){ - $data = array_map($filter,$data); // 参数过滤 - } - } - }elseif(isset($input[$name])) { // 取值操作 - $data = $input[$name]; - $filters = isset($filter)?$filter:C('DEFAULT_FILTER'); - if($filters) { - $filters = explode(',',$filters); - foreach($filters as $filter){ - if(function_exists($filter)) { - $data = is_array($data)?array_map($filter,$data):$filter($data); // 参数过滤 - }else{ - $data = filter_var($data,is_int($filter)?$filter:filter_id($filter)); - if(false === $data) { - return isset($default)?$default:NULL; - } - } - } - } - }else{ // 变量默认值 - $data = isset($default)?$default:NULL; - } - return $data; -} - -/** - * 记录和统计时间(微秒)和内存使用情况 - * 使用方法: - * - * G('begin'); // 记录开始标记位 - * // ... 区间运行代码 - * G('end'); // 记录结束标签位 - * echo G('begin','end',6); // 统计区间运行时间 精确到小数后6位 - * echo G('begin','end','m'); // 统计区间内存使用情况 - * 如果end标记位没有定义,则会自动以当前作为标记位 - * 其中统计内存使用需要 MEMORY_LIMIT_ON 常量为true才有效 - * - * @param string $start 开始标签 - * @param string $end 结束标签 - * @param integer|string $dec 小数位或者m - * @return mixed - */ -function G($start,$end='',$dec=4) { - static $_info = array(); - static $_mem = array(); - if(is_float($end)) { // 记录时间 - $_info[$start] = $end; - }elseif(!empty($end)){ // 统计时间和内存使用 - if(!isset($_info[$end])) $_info[$end] = microtime(TRUE); - if(MEMORY_LIMIT_ON && $dec=='m'){ - if(!isset($_mem[$end])) $_mem[$end] = memory_get_usage(); - return number_format(($_mem[$end]-$_mem[$start])/1024); - }else{ - return number_format(($_info[$end]-$_info[$start]),$dec); - } - - }else{ // 记录时间和内存使用 - $_info[$start] = microtime(TRUE); - if(MEMORY_LIMIT_ON) $_mem[$start] = memory_get_usage(); - } -} - -/** - * 设置和获取统计数据 - * 使用方法: - * - * N('db',1); // 记录数据库操作次数 - * N('read',1); // 记录读取次数 - * echo N('db'); // 获取当前页面数据库的所有操作次数 - * echo N('read'); // 获取当前页面读取次数 - * - * @param string $key 标识位置 - * @param integer $step 步进值 - * @return mixed - */ -function N($key, $step=0,$save=false) { - static $_num = array(); - if (!isset($_num[$key])) { - $_num[$key] = (false !== $save)? S('N_'.$key) : 0; - } - if (empty($step)) - return $_num[$key]; - else - $_num[$key] = $_num[$key] + (int) $step; - if(false !== $save){ // 保存结果 - S('N_'.$key,$_num[$key],$save); - } -} - -/** - * 字符串命名风格转换 - * type 0 将Java风格转换为C的风格 1 将C风格转换为Java的风格 - * @param string $name 字符串 - * @param integer $type 转换类型 - * @return string - */ -function parse_name($name, $type=0) { - if ($type) { - return ucfirst(preg_replace("/_([a-zA-Z])/e", "strtoupper('\\1')", $name)); - } else { - return strtolower(trim(preg_replace("/[A-Z]/", "_\\0", $name), "_")); - } -} - -/** - * 优化的require_once - * @param string $filename 文件地址 - * @return boolean - */ -function require_cache($filename) { - static $_importFiles = array(); - if (!isset($_importFiles[$filename])) { - if (file_exists_case($filename)) { - require $filename; - $_importFiles[$filename] = true; - } else { - $_importFiles[$filename] = false; - } - } - return $_importFiles[$filename]; -} - -/** - * 批量导入文件 成功则返回 - * @param array $array 文件数组 - * @param boolean $return 加载成功后是否返回 - * @return boolean - */ -function require_array($array,$return=false){ - foreach ($array as $file){ - if (require_cache($file) && $return) return true; - } - if($return) return false; -} - -/** - * 区分大小写的文件存在判断 - * @param string $filename 文件地址 - * @return boolean - */ -function file_exists_case($filename) { - if (is_file($filename)) { - if (IS_WIN && C('APP_FILE_CASE')) { - if (basename(realpath($filename)) != basename($filename)) - return false; - } - return true; - } - return false; -} - -/** - * 导入所需的类库 同java的Import 本函数有缓存功能 - * @param string $class 类库命名空间字符串 - * @param string $baseUrl 起始路径 - * @param string $ext 导入的文件扩展名 - * @return boolean - */ -function import($class, $baseUrl = '', $ext='.class.php') { - static $_file = array(); - $class = str_replace(array('.', '#'), array('/', '.'), $class); - if ('' === $baseUrl && false === strpos($class, '/')) { - // 检查别名导入 - return alias_import($class); - } - if (isset($_file[$class . $baseUrl])) - return true; - else - $_file[$class . $baseUrl] = true; - $class_strut = explode('/', $class); - if (empty($baseUrl)) { - $libPath = defined('BASE_LIB_PATH')?BASE_LIB_PATH:LIB_PATH; - if ('@' == $class_strut[0] || APP_NAME == $class_strut[0]) { - //加载当前项目应用类库 - $baseUrl = dirname($libPath); - $class = substr_replace($class, basename($libPath).'/', 0, strlen($class_strut[0]) + 1); - }elseif ('think' == strtolower($class_strut[0])){ // think 官方基类库 - $baseUrl = CORE_PATH; - $class = substr($class,6); - }elseif (in_array(strtolower($class_strut[0]), array('org', 'com'))) { - // org 第三方公共类库 com 企业公共类库 - $baseUrl = LIBRARY_PATH; - }else { // 加载其他项目应用类库 - $class = substr_replace($class, '', 0, strlen($class_strut[0]) + 1); - $baseUrl = APP_PATH . '../' . $class_strut[0] . '/'.basename($libPath).'/'; - } - } - if (substr($baseUrl, -1) != '/') - $baseUrl .= '/'; - $classfile = $baseUrl . $class . $ext; - if (!class_exists(basename($class),false)) { - // 如果类不存在 则导入类库文件 - return require_cache($classfile); - } -} - -/** - * 基于命名空间方式导入函数库 - * load('@.Util.Array') - * @param string $name 函数库命名空间字符串 - * @param string $baseUrl 起始路径 - * @param string $ext 导入的文件扩展名 - * @return void - */ -function load($name, $baseUrl='', $ext='.php') { - $name = str_replace(array('.', '#'), array('/', '.'), $name); - if (empty($baseUrl)) { - if (0 === strpos($name, '@/')) { - //加载当前项目函数库 - $baseUrl = COMMON_PATH; - $name = substr($name, 2); - } else { - //加载ThinkPHP 系统函数库 - $baseUrl = EXTEND_PATH . 'Function/'; - } - } - if (substr($baseUrl, -1) != '/') - $baseUrl .= '/'; - require_cache($baseUrl . $name . $ext); -} - -/** - * 快速导入第三方框架类库 所有第三方框架的类库文件统一放到 系统的Vendor目录下面 - * @param string $class 类库 - * @param string $baseUrl 基础目录 - * @param string $ext 类库后缀 - * @return boolean - */ -function vendor($class, $baseUrl = '', $ext='.php') { - if (empty($baseUrl)) - $baseUrl = VENDOR_PATH; - return import($class, $baseUrl, $ext); -} - -/** - * 快速定义和导入别名 支持批量定义 - * @param string|array $alias 类库别名 - * @param string $classfile 对应类库 - * @return boolean - */ -function alias_import($alias, $classfile='') { - static $_alias = array(); - if (is_string($alias)) { - if(isset($_alias[$alias])) { - return require_cache($_alias[$alias]); - }elseif ('' !== $classfile) { - // 定义别名导入 - $_alias[$alias] = $classfile; - return; - } - }elseif (is_array($alias)) { - $_alias = array_merge($_alias,$alias); - return; - } - return false; -} - -/** - * D函数用于实例化Model 格式 项目://分组/模块 - * @param string $name Model资源地址 - * @param string $layer 业务层名称 - * @return Model - */ -function D($name='',$layer='') { - if(empty($name)) return new Model; - static $_model = array(); - $layer = $layer?$layer:C('DEFAULT_M_LAYER'); - if(strpos($name,'://')) {// 指定项目 - list($app) = explode('://',$name); - $name = str_replace('://','/'.$layer.'/',$name); - }else{ - $app = C('DEFAULT_APP'); - $name = $app.'/'.$layer.'/'.$name; - } - if(isset($_model[$name])) return $_model[$name]; - $path = explode('/',$name); - if($list = C('EXTEND_GROUP_LIST') && isset($list[$app])){ // 扩展分组 - $baseUrl = $list[$app]; - import($path[2].'/'.$path[1].'/'.$path[3].$layer,$baseUrl); - }elseif(count($path)>3 && 1 == C('APP_GROUP_MODE')) { // 独立分组 - $baseUrl = $path[0]== '@' ? dirname(BASE_LIB_PATH) : APP_PATH.'../'.$path[0].'/'.C('APP_GROUP_PATH').'/'; - import($path[2].'/'.$path[1].'/'.$path[3].$layer,$baseUrl); - }else{ - import($name.$layer); - } - $class = basename($name.$layer); - if(class_exists($class)) { - $model = new $class(basename($name)); - }else { - $model = new Model(basename($name)); - } - $_model[$name] = $model; - return $model; -} - -/** - * M函数用于实例化一个没有模型文件的Model - * @param string $name Model名称 支持指定基础模型 例如 MongoModel:User - * @param string $tablePrefix 表前缀 - * @param mixed $connection 数据库连接信息 - * @return Model - */ -function M($name='', $tablePrefix='',$connection='') { - static $_model = array(); - if(strpos($name,':')) { - list($class,$name) = explode(':',$name); - }else{ - $class = 'Model'; - } - $guid = $tablePrefix . $name . '_' . $class; - if (!isset($_model[$guid])) - $_model[$guid] = new $class($name,$tablePrefix,$connection); - return $_model[$guid]; -} - -/** - * A函数用于实例化Action 格式:[项目://][分组/]模块 - * @param string $name Action资源地址 - * @param string $layer 控制层名称 - * @param boolean $common 是否公共目录 - * @return Action|false - */ -function A($name,$layer='',$common=false) { - static $_action = array(); - $layer = $layer?$layer:C('DEFAULT_C_LAYER'); - if(strpos($name,'://')) {// 指定项目 - list($app) = explode('://',$name); - $name = str_replace('://','/'.$layer.'/',$name); - }else{ - $app = '@'; - $name = '@/'.$layer.'/'.$name; - } - if(isset($_action[$name])) return $_action[$name]; - $path = explode('/',$name); - if($list = C('EXTEND_GROUP_LIST') && isset($list[$app])){ // 扩展分组 - $baseUrl = $list[$app]; - import($path[2].'/'.$path[1].'/'.$path[3].$layer,$baseUrl); - }elseif(count($path)>3 && 1 == C('APP_GROUP_MODE')) { // 独立分组 - $baseUrl = $path[0]== '@' ? dirname(BASE_LIB_PATH) : APP_PATH.'../'.$path[0].'/'.C('APP_GROUP_PATH').'/'; - import($path[2].'/'.$path[1].'/'.$path[3].$layer,$baseUrl); - }elseif($common) { // 加载公共类库目录 - import(str_replace('@/','',$name).$layer,LIB_PATH); - }else{ - import($name.$layer); - } - $class = basename($name.$layer); - if(class_exists($class,false)) { - $action = new $class(); - $_action[$name] = $action; - return $action; - }else { - return false; - } -} - -/** - * 远程调用模块的操作方法 URL 参数格式 [项目://][分组/]模块/操作 - * @param string $url 调用地址 - * @param string|array $vars 调用参数 支持字符串和数组 - * @param string $layer 要调用的控制层名称 - * @return mixed - */ -function R($url,$vars=array(),$layer='') { - $info = pathinfo($url); - $action = $info['basename']; - $module = $info['dirname']; - $class = A($module,$layer); - if($class){ - if(is_string($vars)) { - parse_str($vars,$vars); - } - return call_user_func_array(array(&$class,$action.C('ACTION_SUFFIX')),$vars); - }else{ - return false; - } -} - -/** - * 获取和设置语言定义(不区分大小写) - * @param string|array $name 语言变量 - * @param string $value 语言值 - * @return mixed - */ -function L($name=null, $value=null) { - static $_lang = array(); - // 空参数返回所有定义 - if (empty($name)) - return $_lang; - // 判断语言获取(或设置) - // 若不存在,直接返回全大写$name - if (is_string($name)) { - $name = strtoupper($name); - if (is_null($value)) - return isset($_lang[$name]) ? $_lang[$name] : $name; - $_lang[$name] = $value; // 语言定义 - return; - } - // 批量定义 - if (is_array($name)) - $_lang = array_merge($_lang, array_change_key_case($name, CASE_UPPER)); - return; -} - -/** - * 获取和设置配置参数 支持批量定义 - * @param string|array $name 配置变量 - * @param mixed $value 配置值 - * @return mixed - */ -function C($name=null, $value=null) { - static $_config = array(); - // 无参数时获取所有 - if (empty($name)) { - if(!empty($value) && $array = S('c_'.$value)) { - $_config = array_merge($_config, array_change_key_case($array)); - } - return $_config; - } - // 优先执行设置获取或赋值 - if (is_string($name)) { - if (!strpos($name, '.')) { - $name = strtolower($name); - if (is_null($value)) - return isset($_config[$name]) ? $_config[$name] : null; - $_config[$name] = $value; - return; - } - // 二维数组设置和获取支持 - $name = explode('.', $name); - $name[0] = strtolower($name[0]); - if (is_null($value)) - return isset($_config[$name[0]][$name[1]]) ? $_config[$name[0]][$name[1]] : null; - $_config[$name[0]][$name[1]] = $value; - return; - } - // 批量设置 - if (is_array($name)){ - $_config = array_merge($_config, array_change_key_case($name)); - if(!empty($value)) {// 保存配置值 - S('c_'.$value,$_config); - } - return; - } - return null; // 避免非法参数 -} - -/** - * 处理标签扩展 - * @param string $tag 标签名称 - * @param mixed $params 传入参数 - * @return mixed - */ -function tag($tag, &$params=NULL) { - // 系统标签扩展 - $extends = C('extends.' . $tag); - // 应用标签扩展 - $tags = C('tags.' . $tag); - if (!empty($tags)) { - if(empty($tags['_overlay']) && !empty($extends)) { // 合并扩展 - $tags = array_unique(array_merge($extends,$tags)); - }elseif(isset($tags['_overlay'])){ // 通过设置 '_overlay'=>1 覆盖系统标签 - unset($tags['_overlay']); - } - }elseif(!empty($extends)) { - $tags = $extends; - } - if($tags) { - if(APP_DEBUG) { - G($tag.'Start'); - trace('[ '.$tag.' ] --START--','','INFO'); - } - // 执行扩展 - foreach ($tags as $key=>$name) { - if(!is_int($key)) { // 指定行为类的完整路径 用于模式扩展 - $name = $key; - } - B($name, $params); - } - if(APP_DEBUG) { // 记录行为的执行日志 - trace('[ '.$tag.' ] --END-- [ RunTime:'.G($tag.'Start',$tag.'End',6).'s ]','','INFO'); - } - }else{ // 未执行任何行为 返回false - return false; - } -} - -/** - * 动态添加行为扩展到某个标签 - * @param string $tag 标签名称 - * @param string $behavior 行为名称 - * @param string $path 行为路径 - * @return void - */ -function add_tag_behavior($tag,$behavior,$path='') { - $array = C('tags.'.$tag); - if(!$array) { - $array = array(); - } - if($path) { - $array[$behavior] = $path; - }else{ - $array[] = $behavior; - } - C('tags.'.$tag,$array); -} - -/** - * 执行某个行为 - * @param string $name 行为名称 - * @param Mixed $params 传入的参数 - * @return void - */ -function B($name, &$params=NULL) { - if(strpos($name,'/')){ - list($name,$method) = explode('/',$name); - }else{ - $method = 'run'; - } - $class = $name.'Behavior'; - if(APP_DEBUG) { - G('behaviorStart'); - } - $behavior = new $class(); - $behavior->$method($params); - if(APP_DEBUG) { // 记录行为的执行日志 - G('behaviorEnd'); - trace($name.' Behavior ::'.$method.' [ RunTime:'.G('behaviorStart','behaviorEnd',6).'s ]','','INFO'); - } -} - -/** - * 去除代码中的空白和注释 - * @param string $content 代码内容 - * @return string - */ -function strip_whitespace($content) { - $stripStr = ''; - //分析php源码 - $tokens = token_get_all($content); - $last_space = false; - for ($i = 0, $j = count($tokens); $i < $j; $i++) { - if (is_string($tokens[$i])) { - $last_space = false; - $stripStr .= $tokens[$i]; - } else { - switch ($tokens[$i][0]) { - //过滤各种PHP注释 - case T_COMMENT: - case T_DOC_COMMENT: - break; - //过滤空格 - case T_WHITESPACE: - if (!$last_space) { - $stripStr .= ' '; - $last_space = true; - } - break; - case T_START_HEREDOC: - $stripStr .= "<<' == substr($content, -2)) - $content = substr($content, 0, -2); - return $content; -} - -// 根据数组生成常量定义 -function array_define($array,$check=true) { - $content = "\n"; - foreach ($array as $key => $val) { - $key = strtoupper($key); - if($check) $content .= 'defined(\'' . $key . '\') or '; - if (is_int($val) || is_float($val)) { - $content .= "define('" . $key . "'," . $val . ');'; - } elseif (is_bool($val)) { - $val = ($val) ? 'true' : 'false'; - $content .= "define('" . $key . "'," . $val . ');'; - } elseif (is_string($val)) { - $content .= "define('" . $key . "','" . addslashes($val) . "');"; - } - $content .= "\n"; - } - return $content; -} -//[/RUNTIME] - -/** - * 添加和获取页面Trace记录 - * @param string $value 变量 - * @param string $label 标签 - * @param string $level 日志级别 - * @param boolean $record 是否记录日志 - * @return void - */ -function trace($value='[think]',$label='',$level='DEBUG',$record=false) { - static $_trace = array(); - if('[think]' === $value){ // 获取trace信息 - return $_trace; - }else{ - $info = ($label?$label.':':'').print_r($value,true); - if('ERR' == $level && C('TRACE_EXCEPTION')) {// 抛出异常 - throw_exception($info); - } - $level = strtoupper($level); - if(!isset($_trace[$level])) { - $_trace[$level] = array(); - } - $_trace[$level][] = $info; - if((defined('IS_AJAX') && IS_AJAX) || !C('SHOW_PAGE_TRACE') || $record) { - Log::record($info,$level,$record); - } - } -} \ No newline at end of file diff --git a/ThinkPHP/Common/functions.php b/ThinkPHP/Common/functions.php index dcfb35c50..b4563aa0a 100644 --- a/ThinkPHP/Common/functions.php +++ b/ThinkPHP/Common/functions.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK IT ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006-2013 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -10,61 +10,608 @@ // +---------------------------------------------------------------------- /** - * Think 标准模式公共函数库 - * @category Think - * @package Common - * @author liu21st + * Think 函数库 */ /** - * 错误输出 - * @param mixed $error 错误 + * 抛出异常处理 + * @param string $msg 异常消息 + * @param integer $code 异常代码 默认为0 * @return void */ -function halt($error) { - $e = array(); - if (APP_DEBUG) { - //调试模式下输出错误信息 - if (!is_array($error)) { - $trace = debug_backtrace(); - $e['message'] = $error; - $e['file'] = $trace[0]['file']; - $e['line'] = $trace[0]['line']; - ob_start(); - debug_print_backtrace(); - $e['trace'] = ob_get_clean(); - } else { - $e = $error; +function E($msg, $code=0) { + throw new Think\Exception($msg, $code); +} + +/** + * 记录和统计时间(微秒)和内存使用情况 + * 使用方法: + * + * G('begin'); // 记录开始标记位 + * // ... 区间运行代码 + * G('end'); // 记录结束标签位 + * echo G('begin','end',6); // 统计区间运行时间 精确到小数后6位 + * echo G('begin','end','m'); // 统计区间内存使用情况 + * 如果end标记位没有定义,则会自动以当前作为标记位 + * 其中统计内存使用需要 MEMORY_LIMIT_ON 常量为true才有效 + * + * @param string $start 开始标签 + * @param string $end 结束标签 + * @param integer|string $dec 小数位或者m + * @return mixed + */ +function G($start,$end='',$dec=4) { + static $_info = array(); + static $_mem = array(); + if(is_float($end)) { // 记录时间 + $_info[$start] = $end; + }elseif(!empty($end)){ // 统计时间和内存使用 + if(!isset($_info[$end])) $_info[$end] = microtime(TRUE); + if(MEMORY_LIMIT_ON && $dec=='m'){ + if(!isset($_mem[$end])) $_mem[$end] = memory_get_usage(); + return number_format(($_mem[$end]-$_mem[$start])/1024); + }else{ + return number_format(($_info[$end]-$_info[$start]),$dec); + } + + }else{ // 记录时间和内存使用 + $_info[$start] = microtime(TRUE); + if(MEMORY_LIMIT_ON) $_mem[$start] = memory_get_usage(); + } +} + +/** + * 获取和设置语言定义(不区分大小写) + * @param string|array $name 语言变量 + * @param string $value 语言值 + * @return mixed + */ +function L($name=null, $value=null) { + static $_lang = array(); + // 空参数返回所有定义 + if (empty($name)) + return $_lang; + // 判断语言获取(或设置) + // 若不存在,直接返回全大写$name + if (is_string($name)) { + $name = strtoupper($name); + if (is_null($value)) + return isset($_lang[$name]) ? $_lang[$name] : $name; + $_lang[$name] = $value; // 语言定义 + return; + } + // 批量定义 + if (is_array($name)) + $_lang = array_merge($_lang, array_change_key_case($name, CASE_UPPER)); + return; +} + +/** + * 添加和获取页面Trace记录 + * @param string $value 变量 + * @param string $label 标签 + * @param string $level 日志级别 + * @param boolean $record 是否记录日志 + * @return void + */ +function trace($value='[think]',$label='',$level='DEBUG',$record=false) { + return Think\Think::trace($value,$label,$level,$record); +} + +/** + * 编译文件 + * @param string $filename 文件名 + * @return string + */ +function compile($filename) { + $content = php_strip_whitespace($filename); + $content = trim(substr($content, 5)); + // 替换预编译指令 + $content = preg_replace('/\/\/\[RUNTIME\](.*?)\/\/\[\/RUNTIME\]/s', '', $content); + if(0===strpos($content,'namespace')){ + $content = preg_replace('/namespace\s(.*?);/','namespace \\1{',$content); + }else{ + $content = 'namespace {'.$content; + } + if ('?>' == substr($content, -2)) + $content = substr($content, 0, -2); + return $content.'}'; +} + +/** + * 获取模版文件 格式 资源://模块@主题/控制器/操作 + * @param string $name 模版资源地址 + * @param string $layer 视图层(目录)名称 + * @return string + */ +function T($template='',$layer=''){ + + // 解析模版资源地址 + if(false === strpos($template,'://')){ + $template = 'http://'.str_replace(':', '/',$template); + } + $info = parse_url($template); + $file = $info['host'].(isset($info['path'])?$info['path']:''); + $module = isset($info['user'])?$info['user'].'/':MODULE_NAME.'/'; + $extend = $info['scheme']; + $layer = $layer?$layer:C('DEFAULT_V_LAYER'); + + // 获取当前主题的模版路径 + $auto = C('AUTOLOAD_NAMESPACE'); + if($auto && isset($auto[$extend])){ // 扩展资源 + $baseUrl = $auto[$extend].$module.$layer.'/'; + }elseif(C('VIEW_PATH')){ // 指定视图目录 + $baseUrl = C('VIEW_PATH').$module.'/'; + }else{ + $baseUrl = APP_PATH.$module.$layer.'/'; + } + + // 获取主题 + $theme = substr_count($file,'/')<2 ? C('DEFAULT_THEME') : ''; + + // 分析模板文件规则 + $depr = C('TMPL_FILE_DEPR'); + if('' == $file) { + // 如果模板文件名为空 按照默认规则定位 + $file = CONTROLLER_NAME . $depr . ACTION_NAME; + }elseif(false === strpos($file, '/')){ + $file = CONTROLLER_NAME . $depr . $file; + }elseif('/' != $depr){ + if(substr_count($file,'/')>1){ + $file = substr_replace($file,$depr,strrpos($file,'/'),1); + }else{ + $file = str_replace('/', $depr, $file); + } + } + return $baseUrl.($theme?$theme.'/':'').$file.C('TMPL_TEMPLATE_SUFFIX'); +} + +/** + * 获取输入参数 支持过滤和默认值 + * 使用方法: + * + * I('id',0); 获取id参数 自动判断get或者post + * I('post.name','','htmlspecialchars'); 获取$_POST['name'] + * I('get.'); 获取$_GET + * + * @param string $name 变量的名称 支持指定类型 + * @param mixed $default 不存在的时候默认值 + * @param mixed $filter 参数过滤方法 + * @return mixed + */ +function I($name,$default='',$filter=null) { + if(strpos($name,'.')) { // 指定参数来源 + list($method,$name) = explode('.',$name,2); + }else{ // 默认为自动判断 + $method = 'param'; + } + switch(strtolower($method)) { + case 'get' : $input =& $_GET;break; + case 'post' : $input =& $_POST;break; + case 'put' : parse_str(file_get_contents('php://input'), $input);break; + case 'param' : + switch($_SERVER['REQUEST_METHOD']) { + case 'POST': + $input = $_POST; + break; + case 'PUT': + parse_str(file_get_contents('php://input'), $input); + break; + default: + $input = $_GET; + } + break; + case 'request' : $input =& $_REQUEST; break; + case 'session' : $input =& $_SESSION; break; + case 'cookie' : $input =& $_COOKIE; break; + case 'server' : $input =& $_SERVER; break; + case 'globals' : $input =& $GLOBALS; break; + default: + return NULL; + } + if(empty($name)) { // 获取全部变量 + $data = $input; + array_walk_recursive($data,'filter_exp'); + $filters = isset($filter)?$filter:C('DEFAULT_FILTER'); + if($filters) { + $filters = explode(',',$filters); + foreach($filters as $filter){ + $data = array_map_recursive($filter,$data); // 参数过滤 + } + } + }elseif(isset($input[$name])) { // 取值操作 + $data = $input[$name]; + is_array($data) && array_walk_recursive($data,'filter_exp'); + $filters = isset($filter)?$filter:C('DEFAULT_FILTER'); + if($filters) { + $filters = explode(',',$filters); + foreach($filters as $filter){ + if(function_exists($filter)) { + $data = is_array($data)?array_map_recursive($filter,$data):$filter($data); // 参数过滤 + }else{ + $data = filter_var($data,is_int($filter)?$filter:filter_id($filter)); + if(false === $data) { + return isset($default)?$default:NULL; + } + } + } } + }else{ // 变量默认值 + $data = isset($default)?$default:NULL; + } + return $data; +} + +function array_map_recursive($filter, $data) { + $result = array(); + foreach ($data as $key => $val) { + $result[$key] = is_array($val) + ? array_map_recursive($filter, $val) + : call_user_func($filter, $val); + } + return $result; + } + +/** + * 设置和获取统计数据 + * 使用方法: + * + * N('db',1); // 记录数据库操作次数 + * N('read',1); // 记录读取次数 + * echo N('db'); // 获取当前页面数据库的所有操作次数 + * echo N('read'); // 获取当前页面读取次数 + * + * @param string $key 标识位置 + * @param integer $step 步进值 + * @return mixed + */ +function N($key, $step=0,$save=false) { + static $_num = array(); + if (!isset($_num[$key])) { + $_num[$key] = (false !== $save)? S('N_'.$key) : 0; + } + if (empty($step)) + return $_num[$key]; + else + $_num[$key] = $_num[$key] + (int) $step; + if(false !== $save){ // 保存结果 + S('N_'.$key,$_num[$key],$save); + } +} + +/** + * 字符串命名风格转换 + * type 0 将Java风格转换为C的风格 1 将C风格转换为Java的风格 + * @param string $name 字符串 + * @param integer $type 转换类型 + * @return string + */ +function parse_name($name, $type=0) { + if ($type) { + return ucfirst(preg_replace_callback('/_([a-zA-Z])/', function($match){return strtoupper($match[1]);}, $name)); } else { - //否则定向到错误页面 - $error_page = C('ERROR_PAGE'); - if (!empty($error_page)) { - redirect($error_page); + return strtolower(trim(preg_replace("/[A-Z]/", "_\\0", $name), "_")); + } +} + +/** + * 优化的require_once + * @param string $filename 文件地址 + * @return boolean + */ +function require_cache($filename) { + static $_importFiles = array(); + if (!isset($_importFiles[$filename])) { + if (file_exists_case($filename)) { + require $filename; + $_importFiles[$filename] = true; + } else { + $_importFiles[$filename] = false; + } + } + return $_importFiles[$filename]; +} + +/** + * 区分大小写的文件存在判断 + * @param string $filename 文件地址 + * @return boolean + */ +function file_exists_case($filename) { + if (is_file($filename)) { + if (IS_WIN && C('APP_FILE_CASE')) { + if (basename(realpath($filename)) != basename($filename)) + return false; + } + return true; + } + return false; +} + +/** + * 导入所需的类库 同java的Import 本函数有缓存功能 + * @param string $class 类库命名空间字符串 + * @param string $baseUrl 起始路径 + * @param string $ext 导入的文件扩展名 + * @return boolean + */ +function import($class, $baseUrl = '', $ext=EXT) { + static $_file = array(); + $class = str_replace(array('.', '#'), array('/', '.'), $class); + if (isset($_file[$class . $baseUrl])) + return true; + else + $_file[$class . $baseUrl] = true; + $class_strut = explode('/', $class); + if (empty($baseUrl)) { + if ('@' == $class_strut[0] || MODULE_NAME == $class_strut[0]) { + //加载当前模块的类库 + $baseUrl = MODULE_PATH; + $class = substr_replace($class, '', 0, strlen($class_strut[0]) + 1); + }elseif (in_array($class_strut[0],array('Think','Org','Behavior','Com','Vendor')) || is_dir(LIB_PATH.$class_strut[0])) { + // 系统类库包和第三方类库包 + $baseUrl = LIB_PATH; + }else { // 加载其他模块的类库 + $baseUrl = APP_PATH; + } + } + if (substr($baseUrl, -1) != '/') + $baseUrl .= '/'; + $classfile = $baseUrl . $class . $ext; + if (!class_exists(basename($class),false)) { + // 如果类不存在 则导入类库文件 + return require_cache($classfile); + } +} + +/** + * 基于命名空间方式导入函数库 + * load('@.Util.Array') + * @param string $name 函数库命名空间字符串 + * @param string $baseUrl 起始路径 + * @param string $ext 导入的文件扩展名 + * @return void + */ +function load($name, $baseUrl='', $ext='.php') { + $name = str_replace(array('.', '#'), array('/', '.'), $name); + if (empty($baseUrl)) { + if (0 === strpos($name, '@/')) {//加载当前模块函数库 + $baseUrl = MODULE_PATH.'Common/'; + $name = substr($name, 2); + } else { //加载其他模块函数库 + $array = explode('/', $name); + $baseUrl = APP_PATH . array_shift($array).'/Common/'; + $name = implode('/',$array); + } + } + if (substr($baseUrl, -1) != '/') + $baseUrl .= '/'; + require_cache($baseUrl . $name . $ext); +} + +/** + * 快速导入第三方框架类库 所有第三方框架的类库文件统一放到 系统的Vendor目录下面 + * @param string $class 类库 + * @param string $baseUrl 基础目录 + * @param string $ext 类库后缀 + * @return boolean + */ +function vendor($class, $baseUrl = '', $ext='.php') { + if (empty($baseUrl)) + $baseUrl = VENDOR_PATH; + return import($class, $baseUrl, $ext); +} + +/** + * D函数用于实例化模型类 格式 [资源://][模块/]模型 + * @param string $name 资源地址 + * @param string $layer 模型层名称 + * @return Model + */ +function D($name='',$layer='') { + if(empty($name)) return new Think\Model; + static $_model = array(); + $layer = $layer? $layer : C('DEFAULT_M_LAYER'); + if(isset($_model[$name.$layer])) + return $_model[$name.$layer]; + $class = parse_res_name($name,$layer); + if(class_exists($class)) { + $model = new $class(basename($name)); + }elseif(false === strpos($name,'/')){ + // 自动加载公共模块下面的模型 + $class = '\\Common\\'.$layer.'\\'.$name.$layer; + $model = class_exists($class)? new $class($name) : new Think\Model($name); + }else { + Think\Log::record('D方法实例化没找到模型类'.$class,Think\Log::NOTICE); + $model = new Think\Model(basename($name)); + } + $_model[$name.$layer] = $model; + return $model; +} + +/** + * M函数用于实例化一个没有模型文件的Model + * @param string $name Model名称 支持指定基础模型 例如 MongoModel:User + * @param string $tablePrefix 表前缀 + * @param mixed $connection 数据库连接信息 + * @return Model + */ +function M($name='', $tablePrefix='',$connection='') { + static $_model = array(); + if(strpos($name,':')) { + list($class,$name) = explode(':',$name); + }else{ + $class = 'Think\\Model'; + } + $guid = (is_array($connection)?implode('',$connection):$connection).$tablePrefix . $name . '_' . $class; + if (!isset($_model[$guid])) + $_model[$guid] = new $class($name,$tablePrefix,$connection); + return $_model[$guid]; +} + +/** + * 解析资源地址并导入类库文件 + * 例如 module/controller addon://module/behavior + * @param string $name 资源地址 格式:[扩展://][模块/]资源名 + * @param string $layer 分层名称 + * @return string + */ +function parse_res_name($name,$layer,$level=1){ + if(strpos($name,'://')) {// 指定扩展资源 + list($extend,$name) = explode('://',$name); + }else{ + $extend = ''; + } + if(strpos($name,'/') && substr_count($name, '/')>=$level){ // 指定模块 + list($module,$name) = explode('/',$name,2); + }else{ + $module = MODULE_NAME; + } + $array = explode('/',$name); + $class = $module.'\\'.$layer; + foreach($array as $name){ + $class .= '\\'.parse_name($name, 1); + } + // 导入资源类库 + if($extend){ // 扩展资源 + $class = $extend.'\\'.$class; + } + return $class.$layer; +} + +/** + * A函数用于实例化控制器 格式:[资源://][模块/]控制器 + * @param string $name 资源地址 + * @param string $layer 控制层名称 + * @param integer $level 控制器层次 + * @return Controller|false + */ +function A($name,$layer='',$level='') { + static $_action = array(); + $layer = $layer? $layer : C('DEFAULT_C_LAYER'); + $level = $level? $level : ($layer == C('DEFAULT_C_LAYER')?C('CONTROLLER_LEVEL'):1); + if(isset($_action[$name.$layer])) + return $_action[$name.$layer]; + $class = parse_res_name($name,$layer,$level); + if(class_exists($class)) { + $action = new $class(); + $_action[$name.$layer] = $action; + return $action; + }else { + return false; + } +} + +/** + * 远程调用控制器的操作方法 URL 参数格式 [资源://][模块/]控制器/操作 + * @param string $url 调用地址 + * @param string|array $vars 调用参数 支持字符串和数组 + * @param string $layer 要调用的控制层名称 + * @return mixed + */ +function R($url,$vars=array(),$layer='') { + $info = pathinfo($url); + $action = $info['basename']; + $module = $info['dirname']; + $class = A($module,$layer); + if($class){ + if(is_string($vars)) { + parse_str($vars,$vars); + } + return call_user_func_array(array(&$class,$action.C('ACTION_SUFFIX')),$vars); + }else{ + return false; + } +} + +/** + * 处理标签扩展 + * @param string $tag 标签名称 + * @param mixed $params 传入参数 + * @return mixed + */ +function tag($tag, &$params=NULL) { + return \Think\Hook::listen($tag,$params); +} + +/** + * 执行某个行为 + * @param string $name 行为名称 + * @param Mixed $params 传入的参数 + * @return void + */ +function B($name, &$params=NULL) { + if(strpos($name,'/')){ + list($name,$tag) = explode('/',$name); + }else{ + $tag = 'run'; + } + return \Think\Hook::exec($name,$tag,$params); +} + +/** + * 去除代码中的空白和注释 + * @param string $content 代码内容 + * @return string + */ +function strip_whitespace($content) { + $stripStr = ''; + //分析php源码 + $tokens = token_get_all($content); + $last_space = false; + for ($i = 0, $j = count($tokens); $i < $j; $i++) { + if (is_string($tokens[$i])) { + $last_space = false; + $stripStr .= $tokens[$i]; } else { - if (C('SHOW_ERROR_MSG')) - $e['message'] = is_array($error) ? $error['message'] : $error; - else - $e['message'] = C('ERROR_MESSAGE'); + switch ($tokens[$i][0]) { + //过滤各种PHP注释 + case T_COMMENT: + case T_DOC_COMMENT: + break; + //过滤空格 + case T_WHITESPACE: + if (!$last_space) { + $stripStr .= ' '; + $last_space = true; + } + break; + case T_START_HEREDOC: + $stripStr .= "<<array('项目[/分组]'); + // '子域名'=>array('模块[/控制器]'); foreach (C('APP_SUB_DOMAIN_RULES') as $key => $rule) { - if(false === strpos($key,'*') && 0=== strpos($url,$rule[0])) { + $rule = is_array($rule)?$rule[0]:$rule; + if(false === strpos($key,'*') && 0=== strpos($url,$rule)) { $domain = $key.strstr($domain,'.'); // 生成对应子域名 - $url = substr_replace($url,'',0,strlen($rule[0])); + $url = substr_replace($url,'',0,strlen($rule)); break; } } @@ -205,55 +730,70 @@ function U($url='',$vars='',$suffix=true,$redirect=false,$domain=false) { if('/' != $depr) { // 安全替换 $url = str_replace('/',$depr,$url); } - // 解析分组、模块和操作 + // 解析模块、控制器和操作 $url = trim($url,$depr); $path = explode($depr,$url); $var = array(); $var[C('VAR_ACTION')] = !empty($path)?array_pop($path):ACTION_NAME; - $var[C('VAR_MODULE')] = !empty($path)?array_pop($path):MODULE_NAME; + $var[C('VAR_CONTROLLER')] = !empty($path)?array_pop($path):CONTROLLER_NAME; if($maps = C('URL_ACTION_MAP')) { - if(isset($maps[strtolower($var[C('VAR_MODULE')])])) { - $maps = $maps[strtolower($var[C('VAR_MODULE')])]; + if(isset($maps[strtolower($var[C('VAR_CONTROLLER')])])) { + $maps = $maps[strtolower($var[C('VAR_CONTROLLER')])]; if($action = array_search(strtolower($var[C('VAR_ACTION')]),$maps)){ $var[C('VAR_ACTION')] = $action; } } } - if($maps = C('URL_MODULE_MAP')) { - if($module = array_search(strtolower($var[C('VAR_MODULE')]),$maps)){ - $var[C('VAR_MODULE')] = $module; + if($maps = C('URL_CONTROLLER_MAP')) { + if($controller = array_search(strtolower($var[C('VAR_CONTROLLER')]),$maps)){ + $var[C('VAR_CONTROLLER')] = $controller; } - } + } if(C('URL_CASE_INSENSITIVE')) { - $var[C('VAR_MODULE')] = parse_name($var[C('VAR_MODULE')]); + $var[C('VAR_CONTROLLER')] = parse_name($var[C('VAR_CONTROLLER')]); } - if(!C('APP_SUB_DOMAIN_DEPLOY') && C('APP_GROUP_LIST')) { - if(!empty($path)) { - $group = array_pop($path); - $var[C('VAR_GROUP')] = $group; - }else{ - if(GROUP_NAME != C('DEFAULT_GROUP')) { - $var[C('VAR_GROUP')]= GROUP_NAME; + $module = ''; + + if(!empty($path)) { + $var[C('VAR_MODULE')] = array_pop($path); + }else{ + if(C('MULTI_MODULE')) { + if(MODULE_NAME != C('DEFAULT_MODULE') || !C('MODULE_ALLOW_LIST')){ + $var[C('VAR_MODULE')]= MODULE_NAME; } } - if(C('URL_CASE_INSENSITIVE') && isset($var[C('VAR_GROUP')])) { - $var[C('VAR_GROUP')] = strtolower($var[C('VAR_GROUP')]); + } + if($maps = C('URL_MODULE_MAP')) { + if($_module = array_search(strtolower($var[C('VAR_MODULE')]),$maps)){ + $var[C('VAR_MODULE')] = $_module; } } + if(isset($var[C('VAR_MODULE')])){ + $module = $var[C('VAR_MODULE')]; + unset($var[C('VAR_MODULE')]); + } + } } if(C('URL_MODEL') == 0) { // 普通模式URL转换 - $url = __APP__.'?'.http_build_query(array_reverse($var)); + $url = __APP__.'?'.C('VAR_MODULE')."={$module}&".http_build_query(array_reverse($var)); + if(C('URL_CASE_INSENSITIVE')){ + $url = strtolower($url); + } if(!empty($vars)) { - $vars = urldecode(http_build_query($vars)); + $vars = http_build_query($vars); $url .= '&'.$vars; } }else{ // PATHINFO模式或者兼容URL模式 + $module = defined('BIND_MODULE') ? '' : $module; if(isset($route)) { - $url = __APP__.'/'.rtrim($url,$depr); + $url = __APP__.'/'.($module?$module.MODULE_PATHINFO_DEPR:'').rtrim($url,$depr); }else{ - $url = __APP__.'/'.implode($depr,array_reverse($var)); + $url = __APP__.'/'.($module?$module.MODULE_PATHINFO_DEPR:'').implode($depr,array_reverse($var)); + } + if(C('URL_CASE_INSENSITIVE')){ + $url = strtolower($url); } if(!empty($vars)) { // 添加参数 foreach ($vars as $var => $val){ @@ -276,45 +816,17 @@ function U($url='',$vars='',$suffix=true,$redirect=false,$domain=false) { if($domain) { $url = (is_ssl()?'https://':'http://').$domain.$url; } - if($redirect) // 直接跳转URL - redirect($url); - else - return $url; + return $url; } /** * 渲染输出Widget * @param string $name Widget名称 * @param array $data 传入的参数 - * @param boolean $return 是否返回内容 - * @param string $path Widget所在路径 - * @return void - */ -function W($name, $data=array(), $return=false,$path='') { - $class = $name . 'Widget'; - $path = empty($path) ? BASE_LIB_PATH : $path; - require_cache($path . 'Widget/' . $class . '.class.php'); - if (!class_exists($class)) - throw_exception(L('_CLASS_NOT_EXIST_') . ':' . $class); - $widget = Think::instance($class); - $content = $widget->render($data); - if ($return) - return $content; - else - echo $content; -} - -/** - * 过滤器方法 引用传值 - * @param string $name 过滤器名称 - * @param string $content 要过滤的内容 * @return void */ -function filter($name, &$content) { - $class = $name . 'Filter'; - require_cache(BASE_LIB_PATH . 'Filter/' . $class . '.class.php'); - $filter = new $class(); - $content = $filter->run($content); +function W($name, $data=array()) { + return R($name,$data,'Widget'); } /** @@ -371,13 +883,13 @@ function S($name,$value='',$options=null) { if(is_array($options) && empty($cache)){ // 缓存操作的同时初始化 $type = isset($options['type'])?$options['type']:''; - $cache = Cache::getInstance($type,$options); + $cache = Think\Cache::getInstance($type,$options); }elseif(is_array($name)) { // 缓存初始化 $type = isset($name['type'])?$name['type']:''; - $cache = Cache::getInstance($type,$name); + $cache = Think\Cache::getInstance($type,$name); return $cache; }elseif(empty($cache)) { // 自动初始化 - $cache = Cache::getInstance(); + $cache = Think\Cache::getInstance(); } if(''=== $value){ // 获取缓存 return $cache->get($name); @@ -392,10 +904,6 @@ function S($name,$value='',$options=null) { return $cache->set($name, $value, $expire); } } -// S方法的别名 已经废除 不再建议使用 -function cache($name,$value='',$options=null){ - return S($name,$value,$options); -} /** * 快速文件数据读取和保存 针对简单类型数据 字符串、数组 @@ -405,27 +913,29 @@ function cache($name,$value='',$options=null){ * @return mixed */ function F($name, $value='', $path=DATA_PATH) { - static $_cache = array(); - $filename = $path . $name . '.php'; + static $_cache = array(); + $filename = $path . $name . '.php'; if ('' !== $value) { if (is_null($value)) { // 删除缓存 - return false !== strpos($name,'*')?array_map("unlink", glob($filename)):unlink($filename); + if(false !== strpos($name,'*')){ + return false; // TODO + }else{ + unset($_cache[$name]); + return Think\Storage::unlink($filename,'F'); + } } else { + Think\Storage::put($filename,serialize($value),'F'); // 缓存数据 - $dir = dirname($filename); - // 目录不存在则创建 - if (!is_dir($dir)) - mkdir($dir,0755,true); $_cache[$name] = $value; - return file_put_contents($filename, strip_whitespace("")); + return ; } } + // 获取缓存数据 if (isset($_cache[$name])) return $_cache[$name]; - // 获取缓存数据 - if (is_file($filename)) { - $value = include $filename; + if (Think\Storage::has($filename,'F')){ + $value = unserialize(Think\Storage::read($filename,'F')); $_cache[$name] = $value; } else { $value = false; @@ -433,42 +943,13 @@ function F($name, $value='', $path=DATA_PATH) { return $value; } -/** - * 取得对象实例 支持调用类的静态方法 - * @param string $name 类名 - * @param string $method 方法名,如果为空则返回实例化对象 - * @param array $args 调用参数 - * @return object - */ -function get_instance_of($name, $method='', $args=array()) { - static $_instance = array(); - $identify = empty($args) ? $name . $method : $name . $method . to_guid_string($args); - if (!isset($_instance[$identify])) { - if (class_exists($name)) { - $o = new $name(); - if (method_exists($o, $method)) { - if (!empty($args)) { - $_instance[$identify] = call_user_func_array(array(&$o, $method), $args); - } else { - $_instance[$identify] = $o->$method(); - } - } - else - $_instance[$identify] = $o; - } - else - halt(L('_CLASS_NOT_EXIST_') . ':' . $name); - } - return $_instance[$identify]; -} - /** * 根据PHP各种类型变量生成唯一标识号 * @param mixed $mix 变量 * @return string */ function to_guid_string($mix) { - if (is_object($mix) && function_exists('spl_object_hash')) { + if (is_object($mix)) { return spl_object_hash($mix); } elseif (is_resource($mix)) { $mix = get_resource_type($mix) . strval($mix); @@ -541,7 +1022,9 @@ function session($name,$value='') { }elseif(isset($name['id'])) { session_id($name['id']); } - ini_set('session.auto_start', 0); + if('common' != APP_MODE){ // 其它模式可能不支持 + ini_set('session.auto_start', 0); + } if(isset($name['name'])) session_name($name['name']); if(isset($name['path'])) session_save_path($name['path']); if(isset($name['domain'])) ini_set('session.cookie_domain', $name['domain']); @@ -552,15 +1035,9 @@ function session($name,$value='') { if(isset($name['cache_expire'])) session_cache_expire($name['cache_expire']); if(isset($name['type'])) C('SESSION_TYPE',$name['type']); if(C('SESSION_TYPE')) { // 读取session驱动 - $class = 'Session'. ucwords(strtolower(C('SESSION_TYPE'))); - // 检查驱动类 - if(require_cache(EXTEND_PATH.'Driver/Session/'.$class.'.class.php')) { - $hander = new $class(); - $hander->execute(); - }else { - // 类没有定义 - throw_exception(L('_CLASS_NOT_EXIST_').': ' . $class); - } + $class = 'Think\\Session\\Driver\\'. ucwords(strtolower(C('SESSION_TYPE'))); + $hander = new $class(); + $hander->execute(); } // 启动session if(C('SESSION_AUTO_START')) session_start(); @@ -696,12 +1173,12 @@ function cookie($name, $value='', $option=null) { * 加载动态扩展文件 * @return void */ -function load_ext_file() { +function load_ext_file($path) { // 加载自定义外部文件 if(C('LOAD_EXT_FILE')) { $files = explode(',',C('LOAD_EXT_FILE')); foreach ($files as $file){ - $file = COMMON_PATH.$file.'.php'; + $file = $path.'Common/'.$file.'.php'; if(is_file($file)) include $file; } } @@ -710,7 +1187,7 @@ function load_ext_file() { $configs = C('LOAD_EXT_CONFIG'); if(is_string($configs)) $configs = explode(',',$configs); foreach ($configs as $key=>$config){ - $file = CONF_PATH.$config.'.php'; + $file = $path.'Conf/'.$config.'.php'; if(is_file($file)) { is_numeric($key)?C(include $file):C($key,include $file); } @@ -724,7 +1201,7 @@ function load_ext_file() { * @return mixed */ function get_client_ip($type = 0) { - $type = $type ? 1 : 0; + $type = $type ? 1 : 0; static $ip = NULL; if ($ip !== NULL) return $ip[$type]; if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) { @@ -750,53 +1227,18 @@ function get_client_ip($type = 0) { */ function send_http_status($code) { static $_status = array( - // Informational 1xx - 100 => 'Continue', - 101 => 'Switching Protocols', // Success 2xx 200 => 'OK', - 201 => 'Created', - 202 => 'Accepted', - 203 => 'Non-Authoritative Information', - 204 => 'No Content', - 205 => 'Reset Content', - 206 => 'Partial Content', // Redirection 3xx - 300 => 'Multiple Choices', 301 => 'Moved Permanently', - 302 => 'Moved Temporarily ', // 1.1 - 303 => 'See Other', - 304 => 'Not Modified', - 305 => 'Use Proxy', - // 306 is deprecated but reserved - 307 => 'Temporary Redirect', + 302 => 'Moved Temporarily ', // 1.1 // Client Error 4xx 400 => 'Bad Request', - 401 => 'Unauthorized', - 402 => 'Payment Required', 403 => 'Forbidden', 404 => 'Not Found', - 405 => 'Method Not Allowed', - 406 => 'Not Acceptable', - 407 => 'Proxy Authentication Required', - 408 => 'Request Timeout', - 409 => 'Conflict', - 410 => 'Gone', - 411 => 'Length Required', - 412 => 'Precondition Failed', - 413 => 'Request Entity Too Large', - 414 => 'Request-URI Too Long', - 415 => 'Unsupported Media Type', - 416 => 'Requested Range Not Satisfiable', - 417 => 'Expectation Failed', // Server Error 5xx 500 => 'Internal Server Error', - 501 => 'Not Implemented', - 502 => 'Bad Gateway', 503 => 'Service Unavailable', - 504 => 'Gateway Timeout', - 505 => 'HTTP Version Not Supported', - 509 => 'Bandwidth Limit Exceeded' ); if(isset($_status[$code])) { header('HTTP/1.1 '.$code.' '.$_status[$code]); @@ -811,3 +1253,8 @@ function filter_exp(&$value){ $value .= ' '; } } + +// 不区分大小写的in_array实现 +function in_array_case($value,$array){ + return in_array(strtolower($value),array_map('strtolower',$array)); +} diff --git a/ThinkPHP/Common/runtime.php b/ThinkPHP/Common/runtime.php deleted file mode 100644 index 19399197b..000000000 --- a/ThinkPHP/Common/runtime.php +++ /dev/null @@ -1,242 +0,0 @@ - -// +---------------------------------------------------------------------- - -/** - * ThinkPHP 运行时文件 编译后不再加载 - * @category Think - * @package Common - * @author liu21st - */ -defined('THINK_PATH') or exit(); -if(version_compare(PHP_VERSION,'5.2.0','<')) die('require PHP > 5.2.0 !'); - -// 版本信息 -define('THINK_VERSION', '3.1.3'); - -// 系统信息 -if(version_compare(PHP_VERSION,'5.4.0','<')) { - ini_set('magic_quotes_runtime',0); - define('MAGIC_QUOTES_GPC',get_magic_quotes_gpc()?True:False); -}else{ - define('MAGIC_QUOTES_GPC',false); -} -define('IS_CGI',substr(PHP_SAPI, 0,3)=='cgi' ? 1 : 0 ); -define('IS_WIN',strstr(PHP_OS, 'WIN') ? 1 : 0 ); -define('IS_CLI',PHP_SAPI=='cli'? 1 : 0); - -// 项目名称 -defined('APP_NAME') or define('APP_NAME', basename(dirname($_SERVER['SCRIPT_FILENAME']))); - -if(!IS_CLI) { - // 当前文件名 - if(!defined('_PHP_FILE_')) { - if(IS_CGI) { - //CGI/FASTCGI模式下 - $_temp = explode('.php',$_SERVER['PHP_SELF']); - define('_PHP_FILE_', rtrim(str_replace($_SERVER['HTTP_HOST'],'',$_temp[0].'.php'),'/')); - }else { - define('_PHP_FILE_', rtrim($_SERVER['SCRIPT_NAME'],'/')); - } - } - if(!defined('__ROOT__')) { - // 网站URL根目录 - if( strtoupper(APP_NAME) == strtoupper(basename(dirname(_PHP_FILE_))) ) { - $_root = dirname(dirname(_PHP_FILE_)); - }else { - $_root = dirname(_PHP_FILE_); - } - define('__ROOT__', (($_root=='/' || $_root=='\\')?'':$_root)); - } - - //支持的URL模式 - define('URL_COMMON', 0); //普通模式 - define('URL_PATHINFO', 1); //PATHINFO模式 - define('URL_REWRITE', 2); //REWRITE模式 - define('URL_COMPAT', 3); // 兼容模式 -} - -// 路径设置 可在入口文件中重新定义 所有路径常量都必须以/ 结尾 -defined('CORE_PATH') or define('CORE_PATH', THINK_PATH.'Lib/'); // 系统核心类库目录 -defined('EXTEND_PATH') or define('EXTEND_PATH', THINK_PATH.'Extend/'); // 系统扩展目录 -defined('MODE_PATH') or define('MODE_PATH', EXTEND_PATH.'Mode/'); // 模式扩展目录 -defined('ENGINE_PATH') or define('ENGINE_PATH', EXTEND_PATH.'Engine/'); // 引擎扩展目录 -defined('VENDOR_PATH') or define('VENDOR_PATH', EXTEND_PATH.'Vendor/'); // 第三方类库目录 -defined('LIBRARY_PATH') or define('LIBRARY_PATH', EXTEND_PATH.'Library/'); // 扩展类库目录 -defined('COMMON_PATH') or define('COMMON_PATH', APP_PATH.'Common/'); // 项目公共目录 -defined('LIB_PATH') or define('LIB_PATH', APP_PATH.'Lib/'); // 项目类库目录 -defined('CONF_PATH') or define('CONF_PATH', APP_PATH.'Conf/'); // 项目配置目录 -defined('LANG_PATH') or define('LANG_PATH', APP_PATH.'Lang/'); // 项目语言包目录 -defined('TMPL_PATH') or define('TMPL_PATH', APP_PATH.'Tpl/'); // 项目模板目录 -defined('HTML_PATH') or define('HTML_PATH', APP_PATH.'Html/'); // 项目静态目录 -defined('LOG_PATH') or define('LOG_PATH', RUNTIME_PATH.'Logs/'); // 项目日志目录 -defined('TEMP_PATH') or define('TEMP_PATH', RUNTIME_PATH.'Temp/'); // 项目缓存目录 -defined('DATA_PATH') or define('DATA_PATH', RUNTIME_PATH.'Data/'); // 项目数据目录 -defined('CACHE_PATH') or define('CACHE_PATH', RUNTIME_PATH.'Cache/'); // 项目模板缓存目录 - -// 为了方便导入第三方类库 设置Vendor目录到include_path -set_include_path(get_include_path() . PATH_SEPARATOR . VENDOR_PATH); - -// 加载运行时所需要的文件 并负责自动目录生成 -function load_runtime_file() { - // 加载系统基础函数库 - require THINK_PATH.'Common/common.php'; - // 读取核心文件列表 - $list = array( - CORE_PATH.'Core/Think.class.php', - CORE_PATH.'Core/ThinkException.class.php', // 异常处理类 - CORE_PATH.'Core/Behavior.class.php', - ); - // 加载模式文件列表 - foreach ($list as $key=>$file){ - if(is_file($file)) require_cache($file); - } - // 加载系统类库别名定义 - alias_import(include THINK_PATH.'Conf/alias.php'); - - // 检查项目目录结构 如果不存在则自动创建 - if(!is_dir(LIB_PATH)) { - // 创建项目目录结构 - build_app_dir(); - }elseif(!is_dir(CACHE_PATH)){ - // 检查缓存目录 - check_runtime(); - }elseif(APP_DEBUG){ - // 调试模式切换删除编译缓存 - if(is_file(RUNTIME_FILE)) unlink(RUNTIME_FILE); - } -} - -// 检查缓存目录(Runtime) 如果不存在则自动创建 -function check_runtime() { - if(!is_dir(RUNTIME_PATH)) { - mkdir(RUNTIME_PATH); - }elseif(!is_writeable(RUNTIME_PATH)) { - header('Content-Type:text/html; charset=utf-8'); - exit('目录 [ '.RUNTIME_PATH.' ] 不可写!'); - } - mkdir(CACHE_PATH); // 模板缓存目录 - if(!is_dir(LOG_PATH)) mkdir(LOG_PATH); // 日志目录 - if(!is_dir(TEMP_PATH)) mkdir(TEMP_PATH); // 数据缓存目录 - if(!is_dir(DATA_PATH)) mkdir(DATA_PATH); // 数据文件目录 - return true; -} - -// 创建编译缓存 -function build_runtime_cache($append='') { - // 生成编译文件 - $defs = get_defined_constants(TRUE); - $content = '$GLOBALS[\'_beginTime\'] = microtime(TRUE);'; - if(defined('RUNTIME_DEF_FILE')) { // 编译后的常量文件外部引入 - file_put_contents(RUNTIME_DEF_FILE,'$item){ - foreach ($item as $key=>$name) { - $content .= is_int($key)?compile(CORE_PATH.'Behavior/'.$name.'Behavior.class.php'):compile($name); - } - } - return $content; -} - -// 创建项目目录结构 -function build_app_dir() { - // 没有创建项目目录的话自动创建 - if(!is_dir(APP_PATH)) mkdir(APP_PATH,0755,true); - if(is_writeable(APP_PATH)) { - $dirs = array( - LIB_PATH, - RUNTIME_PATH, - CONF_PATH, - COMMON_PATH, - LANG_PATH, - CACHE_PATH, - TMPL_PATH, - TMPL_PATH.C('DEFAULT_THEME').'/', - LOG_PATH, - TEMP_PATH, - DATA_PATH, - LIB_PATH.'Model/', - LIB_PATH.'Action/', - LIB_PATH.'Behavior/', - LIB_PATH.'Widget/', - ); - foreach ($dirs as $dir){ - if(!is_dir($dir)) mkdir($dir,0755,true); - } - // 写入目录安全文件 - build_dir_secure($dirs); - // 写入初始配置文件 - if(!is_file(CONF_PATH.'config.php')) - file_put_contents(CONF_PATH.'config.php',"'配置值'\n);\n?>"); - // 写入测试Action - if(!is_file(LIB_PATH.'Action/IndexAction.class.php')) - build_first_action(); - }else{ - header('Content-Type:text/html; charset=utf-8'); - exit('项目目录不可写,目录无法自动生成!
请使用项目生成器或者手动生成项目目录~'); - } -} - -// 创建测试Action -function build_first_action() { - $content = file_get_contents(THINK_PATH.'Tpl/default_index.tpl'); - file_put_contents(LIB_PATH.'Action/IndexAction.class.php',$content); -} - -// 生成目录安全文件 -function build_dir_secure($dirs=array()) { - // 目录安全写入 - if(defined('BUILD_DIR_SECURE') && BUILD_DIR_SECURE) { - defined('DIR_SECURE_FILENAME') or define('DIR_SECURE_FILENAME', 'index.html'); - defined('DIR_SECURE_CONTENT') or define('DIR_SECURE_CONTENT', ' '); - // 自动写入目录安全文件 - $content = DIR_SECURE_CONTENT; - $files = explode(',', DIR_SECURE_FILENAME); - foreach ($files as $filename){ - foreach ($dirs as $dir) - file_put_contents($dir.$filename,$content); - } - } -} - -// 加载运行时所需文件 -load_runtime_file(); -// 记录加载文件时间 -G('loadTime'); -// 执行入口 -Think::Start(); \ No newline at end of file diff --git a/ThinkPHP/Conf/Mode/common.php b/ThinkPHP/Conf/Mode/common.php new file mode 100644 index 000000000..62119b3de --- /dev/null +++ b/ThinkPHP/Conf/Mode/common.php @@ -0,0 +1,78 @@ + +// +---------------------------------------------------------------------- + +/** + * ThinkPHP 普通模式定义 + */ +return array( + // 配置文件 + 'config' => array( + THINK_PATH.'Conf/convention.php', // 系统惯例配置 + COMMON_PATH.'Conf/config.php', // 应用公共配置 + ), + + // 别名定义 + 'alias' => array( + 'Think\Log' => CORE_PATH . 'Log'.EXT, + 'Think\Log\Driver\File' => CORE_PATH . 'Log/Driver/File'.EXT, + 'Think\Exception' => CORE_PATH . 'Exception'.EXT, + 'Think\Model' => CORE_PATH . 'Model'.EXT, + 'Think\Db' => CORE_PATH . 'Db'.EXT, + 'Think\Template' => CORE_PATH . 'Template'.EXT, + 'Think\Cache' => CORE_PATH . 'Cache'.EXT, + 'Think\Cache\Driver\File' => CORE_PATH . 'Cache/Driver/File'.EXT, + 'Think\Storage' => CORE_PATH . 'Storage'.EXT, + ), + + // 函数和类文件 + 'core' => array( + THINK_PATH.'Common/functions.php', + COMMON_PATH.'Common/function.php', + CORE_PATH . 'Hook'.EXT, + CORE_PATH . 'App'.EXT, + CORE_PATH . 'Dispatcher'.EXT, + //CORE_PATH . 'Log'.EXT, + CORE_PATH . 'Route'.EXT, + CORE_PATH . 'Controller'.EXT, + CORE_PATH . 'View'.EXT, + CORE_PATH . 'Behavior'.EXT, + BEHAVIOR_PATH . 'ReadHtmlCacheBehavior'.EXT, + BEHAVIOR_PATH . 'ShowPageTraceBehavior'.EXT, + BEHAVIOR_PATH . 'ParseTemplateBehavior'.EXT, + BEHAVIOR_PATH . 'ContentReplaceBehavior'.EXT, + BEHAVIOR_PATH . 'WriteHtmlCacheBehavior'.EXT, + ), + // 行为扩展定义 + 'tags' => array( + 'app_init' => array( + ), + 'app_begin' => array( + 'Behavior\ReadHtmlCache', // 读取静态缓存 + ), + 'app_end' => array( + 'Behavior\ShowPageTrace', // 页面Trace显示 + ), + 'path_info' => array(), + 'action_begin' => array(), + 'action_end' => array(), + 'view_begin' => array(), + 'view_parse' => array( + 'Behavior\ParseTemplate', // 模板解析 支持PHP、内置模板引擎和第三方模板引擎 + ), + 'template_filter'=> array( + 'Behavior\ContentReplace', // 模板输出替换 + ), + 'view_filter' => array( + 'Behavior\WriteHtmlCache', // 写入静态缓存 + ), + 'view_end' => array(), + ), +); diff --git a/ThinkPHP/Conf/Mode/sae.php b/ThinkPHP/Conf/Mode/sae.php new file mode 100644 index 000000000..6723df7a1 --- /dev/null +++ b/ThinkPHP/Conf/Mode/sae.php @@ -0,0 +1,80 @@ + +// +---------------------------------------------------------------------- + +/** + * ThinkPHP SAE应用模式定义文件 + */ +return array( + // 配置文件 + 'config' => array( + THINK_PATH.'Conf/convention.php', // 系统惯例配置 + COMMON_PATH.'Conf/config.php', // 应用公共配置 + THINK_PATH.'Conf/convention_sae.php',//[sae] sae的惯例配置 + COMMON_PATH.'Conf/config_sae.php', // sae应用公共配置 + ), + + // 别名定义 + 'alias' => array( + 'Think\Log' => CORE_PATH . 'Log'.EXT, + 'Think\Log\Driver\File' => CORE_PATH . 'Log/Driver/File'.EXT, + 'Think\Exception' => CORE_PATH . 'Exception'.EXT, + 'Think\Model' => CORE_PATH . 'Model'.EXT, + 'Think\Db' => CORE_PATH . 'Db'.EXT, + 'Think\Template' => CORE_PATH . 'Template'.EXT, + 'Think\Cache' => CORE_PATH . 'Cache'.EXT, + 'Think\Cache\Driver\File' => CORE_PATH . 'Cache/Driver/File'.EXT, + 'Think\Storage' => CORE_PATH . 'Storage'.EXT, + ), + + // 函数和类文件 + 'core' => array( + THINK_PATH.'Common/functions.php', + COMMON_PATH.'Common/function.php', + CORE_PATH . 'Hook'.EXT, + CORE_PATH . 'App'.EXT, + CORE_PATH . 'Dispatcher'.EXT, + //CORE_PATH . 'Log'.EXT, + CORE_PATH . 'Route'.EXT, + CORE_PATH . 'Controller'.EXT, + CORE_PATH . 'View'.EXT, + CORE_PATH . 'Behavior'.EXT, + BEHAVIOR_PATH . 'ReadHtmlCacheBehavior'.EXT, + BEHAVIOR_PATH . 'ShowPageTraceBehavior'.EXT, + BEHAVIOR_PATH . 'ParseTemplateBehavior'.EXT, + BEHAVIOR_PATH . 'ContentReplaceBehavior'.EXT, + BEHAVIOR_PATH . 'WriteHtmlCacheBehavior'.EXT, + ), + // 行为扩展定义 + 'tags' => array( + 'app_init' => array( + ), + 'app_begin' => array( + 'Behavior\ReadHtmlCache', // 读取静态缓存 + ), + 'app_end' => array( + 'Behavior\ShowPageTrace', // 页面Trace显示 + ), + 'path_info' => array(), + 'action_begin' => array(), + 'action_end' => array(), + 'view_begin' => array(), + 'view_parse' => array( + 'Behavior\ParseTemplate', // 模板解析 支持PHP、内置模板引擎和第三方模板引擎 + ), + 'template_filter'=> array( + 'Behavior\ContentReplace', // 模板输出替换 + ), + 'view_filter' => array( + 'Behavior\WriteHtmlCache', // 写入静态缓存 + ), + 'view_end' => array(), + ), +); diff --git a/ThinkPHP/Conf/alias.php b/ThinkPHP/Conf/alias.php deleted file mode 100644 index 466b34fdb..000000000 --- a/ThinkPHP/Conf/alias.php +++ /dev/null @@ -1,23 +0,0 @@ - -// +---------------------------------------------------------------------- - -defined('THINK_PATH') or exit(); -// 系统别名定义文件 -return array( - 'Model' => CORE_PATH.'Core/Model.class.php', - 'Db' => CORE_PATH.'Core/Db.class.php', - 'Log' => CORE_PATH.'Core/Log.class.php', - 'ThinkTemplate' => CORE_PATH.'Template/ThinkTemplate.class.php', - 'TagLib' => CORE_PATH.'Template/TagLib.class.php', - 'Cache' => CORE_PATH.'Core/Cache.class.php', - 'Widget' => CORE_PATH.'Core/Widget.class.php', - 'TagLibCx' => CORE_PATH.'Driver/TagLib/TagLibCx.class.php', -); \ No newline at end of file diff --git a/ThinkPHP/Conf/convention.php b/ThinkPHP/Conf/convention.php index f2a4d23c8..9a8978301 100644 --- a/ThinkPHP/Conf/convention.php +++ b/ThinkPHP/Conf/convention.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK IT ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006-2013 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -11,135 +11,132 @@ /** * ThinkPHP惯例配置文件 - * 该文件请不要修改,如果要覆盖惯例配置的值,可在项目配置文件中设定和惯例不符的配置项 + * 该文件请不要修改,如果要覆盖惯例配置的值,可在应用配置文件中设定和惯例不符的配置项 * 配置名称大小写任意,系统会统一转换成小写 * 所有配置参数都可以在生效前动态改变 - * @category Think - * @package Common - * @author liu21st - * @version $Id: convention.php 3088 2012-07-29 09:12:19Z luofei614@gmail.com $ */ defined('THINK_PATH') or exit(); return array( - /* 项目设定 */ - 'APP_STATUS' => 'debug', // 应用调试模式状态 调试模式开启后有效 默认为debug 可扩展 并自动加载对应的配置文件 - 'APP_FILE_CASE' => false, // 是否检查文件的大小写 对Windows平台有效 - 'APP_AUTOLOAD_PATH' => '',// 自动加载机制的自动搜索路径,注意搜索顺序 - 'APP_TAGS_ON' => true, // 系统标签扩展开关 - 'APP_SUB_DOMAIN_DEPLOY' => false, // 是否开启子域名部署 - 'APP_SUB_DOMAIN_RULES' => array(), // 子域名部署规则 - 'APP_SUB_DOMAIN_DENY' => array(), // 子域名禁用列表 - 'APP_GROUP_LIST' => '', // 项目分组设定,多个组之间用逗号分隔,例如'Home,Admin' - 'APP_GROUP_MODE' => 0, // 分组模式 0 普通分组 1 独立分组 - 'APP_GROUP_PATH' => 'Modules', // 分组目录 独立分组模式下面有效 + /* 应用设定 */ + 'APP_FILE_CASE' => false, // 是否检查文件的大小写 对Windows平台有效 + 'APP_SUB_DOMAIN_DEPLOY' => false, // 是否开启子域名部署 + 'APP_SUB_DOMAIN_RULES' => array(), // 子域名部署规则 + 'APP_DOMAIN_SUFFIX' => '', // 域名后缀 如果是com.cn net.cn 之类的后缀必须设置 'ACTION_SUFFIX' => '', // 操作方法后缀 + 'MULTI_MODULE' => true, // 是否允许多模块 如果为false 则必须设置 DEFAULT_MODULE + 'MODULE_DENY_LIST' => array('Common','Runtime'), + 'CONTROLLER_LEVEL' => 1, /* Cookie设置 */ - 'COOKIE_EXPIRE' => 0, // Coodie有效期 - 'COOKIE_DOMAIN' => '', // Cookie有效域名 - 'COOKIE_PATH' => '/', // Cookie路径 - 'COOKIE_PREFIX' => '', // Cookie前缀 避免冲突 + 'COOKIE_EXPIRE' => 0, // Coodie有效期 + 'COOKIE_DOMAIN' => '', // Cookie有效域名 + 'COOKIE_PATH' => '/', // Cookie路径 + 'COOKIE_PREFIX' => '', // Cookie前缀 避免冲突 /* 默认设定 */ 'DEFAULT_M_LAYER' => 'Model', // 默认的模型层名称 - 'DEFAULT_C_LAYER' => 'Action', // 默认的控制器层名称 - 'DEFAULT_V_LAYER' => 'Tpl', // 默认的视图层名称 - 'DEFAULT_APP' => '@', // 默认项目名称,@表示当前项目 - 'DEFAULT_LANG' => 'zh-cn', // 默认语言 - 'DEFAULT_THEME' => '', // 默认模板主题名称 - 'DEFAULT_GROUP' => 'Home', // 默认分组 - 'DEFAULT_MODULE' => 'Index', // 默认模块名称 - 'DEFAULT_ACTION' => 'index', // 默认操作名称 - 'DEFAULT_CHARSET' => 'utf-8', // 默认输出编码 - 'DEFAULT_TIMEZONE' => 'PRC', // 默认时区 - 'DEFAULT_AJAX_RETURN' => 'JSON', // 默认AJAX 数据返回格式,可选JSON XML ... - 'DEFAULT_JSONP_HANDLER' => 'jsonpReturn', // 默认JSONP格式返回的处理方法 - 'DEFAULT_FILTER' => 'htmlspecialchars', // 默认参数过滤方法 用于 $this->_get('变量名');$this->_post('变量名')... + 'DEFAULT_C_LAYER' => 'Controller', // 默认的控制器层名称 + 'DEFAULT_V_LAYER' => 'View', // 默认的视图层名称 + 'DEFAULT_LANG' => 'zh-cn', // 默认语言 + 'DEFAULT_THEME' => '', // 默认模板主题名称 + 'DEFAULT_MODULE' => 'Home', // 默认模块 + 'DEFAULT_CONTROLLER' => 'Index', // 默认控制器名称 + 'DEFAULT_ACTION' => 'index', // 默认操作名称 + 'DEFAULT_CHARSET' => 'utf-8', // 默认输出编码 + 'DEFAULT_TIMEZONE' => 'PRC', // 默认时区 + 'DEFAULT_AJAX_RETURN' => 'JSON', // 默认AJAX 数据返回格式,可选JSON XML ... + 'DEFAULT_JSONP_HANDLER' => 'jsonpReturn', // 默认JSONP格式返回的处理方法 + 'DEFAULT_FILTER' => 'htmlspecialchars', // 默认参数过滤方法 用于I函数... /* 数据库设置 */ - 'DB_TYPE' => 'mysql', // 数据库类型 - 'DB_HOST' => 'localhost', // 服务器地址 - 'DB_NAME' => '', // 数据库名 - 'DB_USER' => 'root', // 用户名 - 'DB_PWD' => '', // 密码 - 'DB_PORT' => '', // 端口 - 'DB_PREFIX' => 'think_', // 数据库表前缀 - 'DB_FIELDTYPE_CHECK' => false, // 是否进行字段类型检查 - 'DB_FIELDS_CACHE' => true, // 启用字段缓存 - 'DB_CHARSET' => 'utf8', // 数据库编码默认采用utf8 - 'DB_DEPLOY_TYPE' => 0, // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器) - 'DB_RW_SEPARATE' => false, // 数据库读写是否分离 主从式有效 - 'DB_MASTER_NUM' => 1, // 读写分离后 主服务器数量 - 'DB_SLAVE_NO' => '', // 指定从服务器序号 - 'DB_SQL_BUILD_CACHE' => false, // 数据库查询的SQL创建缓存 - 'DB_SQL_BUILD_QUEUE' => 'file', // SQL缓存队列的缓存方式 支持 file xcache和apc - 'DB_SQL_BUILD_LENGTH' => 20, // SQL缓存的队列长度 - 'DB_SQL_LOG' => false, // SQL执行日志记录 + 'DB_TYPE' => '', // 数据库类型 + 'DB_HOST' => '', // 服务器地址 + 'DB_NAME' => '', // 数据库名 + 'DB_USER' => '', // 用户名 + 'DB_PWD' => '', // 密码 + 'DB_PORT' => '', // 端口 + 'DB_PREFIX' => '', // 数据库表前缀 + 'DB_FIELDTYPE_CHECK' => false, // 是否进行字段类型检查 + 'DB_FIELDS_CACHE' => true, // 启用字段缓存 + 'DB_CHARSET' => 'utf8', // 数据库编码默认采用utf8 + 'DB_DEPLOY_TYPE' => 0, // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器) + 'DB_RW_SEPARATE' => false, // 数据库读写是否分离 主从式有效 + 'DB_MASTER_NUM' => 1, // 读写分离后 主服务器数量 + 'DB_SLAVE_NO' => '', // 指定从服务器序号 + 'DB_SQL_BUILD_CACHE' => false, // 数据库查询的SQL创建缓存 + 'DB_SQL_BUILD_QUEUE' => 'file', // SQL缓存队列的缓存方式 支持 file xcache和apc + 'DB_SQL_BUILD_LENGTH' => 20, // SQL缓存的队列长度 + 'DB_SQL_LOG' => false, // SQL执行日志记录 + 'DB_BIND_PARAM' => false, // 数据库写入数据自动参数绑定 /* 数据缓存设置 */ - 'DATA_CACHE_TIME' => 0, // 数据缓存有效期 0表示永久缓存 - 'DATA_CACHE_COMPRESS' => false, // 数据缓存是否压缩缓存 - 'DATA_CACHE_CHECK' => false, // 数据缓存是否校验缓存 - 'DATA_CACHE_PREFIX' => '', // 缓存前缀 - 'DATA_CACHE_TYPE' => 'File', // 数据缓存类型,支持:File|Db|Apc|Memcache|Shmop|Sqlite|Xcache|Apachenote|Eaccelerator - 'DATA_CACHE_PATH' => TEMP_PATH,// 缓存路径设置 (仅对File方式缓存有效) - 'DATA_CACHE_SUBDIR' => false, // 使用子目录缓存 (自动根据缓存标识的哈希创建子目录) - 'DATA_PATH_LEVEL' => 1, // 子目录缓存级别 + 'DATA_CACHE_TIME' => 0, // 数据缓存有效期 0表示永久缓存 + 'DATA_CACHE_COMPRESS' => false, // 数据缓存是否压缩缓存 + 'DATA_CACHE_CHECK' => false, // 数据缓存是否校验缓存 + 'DATA_CACHE_PREFIX' => '', // 缓存前缀 + 'DATA_CACHE_TYPE' => 'File', // 数据缓存类型,支持:File|Db|Apc|Memcache|Shmop|Sqlite|Xcache|Apachenote|Eaccelerator + 'DATA_CACHE_PATH' => TEMP_PATH,// 缓存路径设置 (仅对File方式缓存有效) + 'DATA_CACHE_SUBDIR' => false, // 使用子目录缓存 (自动根据缓存标识的哈希创建子目录) + 'DATA_PATH_LEVEL' => 1, // 子目录缓存级别 /* 错误设置 */ - 'ERROR_MESSAGE' => '页面错误!请稍后再试~',//错误显示信息,非调试模式有效 - 'ERROR_PAGE' => '', // 错误定向页面 - 'SHOW_ERROR_MSG' => false, // 显示错误信息 - 'TRACE_EXCEPTION' => false, // TRACE错误信息是否抛异常 针对trace方法 + 'ERROR_MESSAGE' => '页面错误!请稍后再试~',//错误显示信息,非调试模式有效 + 'ERROR_PAGE' => '', // 错误定向页面 + 'SHOW_ERROR_MSG' => false, // 显示错误信息 + 'TRACE_EXCEPTION' => false, // TRACE错误信息是否抛异常 针对trace方法 + 'TRACE_MAX_RECORD' => 100, // 每个级别的错误信息 最大记录数 /* 日志设置 */ - 'LOG_RECORD' => false, // 默认不记录日志 - 'LOG_TYPE' => 3, // 日志记录类型 0 系统 1 邮件 3 文件 4 SAPI 默认为文件方式 - 'LOG_DEST' => '', // 日志记录目标 - 'LOG_EXTRA' => '', // 日志记录额外信息 - 'LOG_LEVEL' => 'EMERG,ALERT,CRIT,ERR',// 允许记录的日志级别 - 'LOG_FILE_SIZE' => 2097152, // 日志文件大小限制 - 'LOG_EXCEPTION_RECORD' => false, // 是否记录异常信息日志 + 'LOG_RECORD' => false, // 默认不记录日志 + 'LOG_TYPE' => 'File', // 日志记录类型 默认为文件方式 + 'LOG_LEVEL' => 'EMERG,ALERT,CRIT,ERR',// 允许记录的日志级别 + 'LOG_FILE_SIZE' => 2097152, // 日志文件大小限制 + 'LOG_EXCEPTION_RECORD' => false, // 是否记录异常信息日志 /* SESSION设置 */ - 'SESSION_AUTO_START' => true, // 是否自动开启Session - 'SESSION_OPTIONS' => array(), // session 配置数组 支持type name id path expire domain 等参数 - 'SESSION_TYPE' => '', // session hander类型 默认无需设置 除非扩展了session hander驱动 - 'SESSION_PREFIX' => '', // session 前缀 - //'VAR_SESSION_ID' => 'session_id', //sessionID的提交变量 + 'SESSION_AUTO_START' => true, // 是否自动开启Session + 'SESSION_OPTIONS' => array(), // session 配置数组 支持type name id path expire domain 等参数 + 'SESSION_TYPE' => '', // session hander类型 默认无需设置 除非扩展了session hander驱动 + 'SESSION_PREFIX' => '', // session 前缀 + //'VAR_SESSION_ID' => 'session_id', //sessionID的提交变量 /* 模板引擎设置 */ - 'TMPL_CONTENT_TYPE' => 'text/html', // 默认模板输出类型 - 'TMPL_ACTION_ERROR' => THINK_PATH.'Tpl/dispatch_jump.tpl', // 默认错误跳转对应的模板文件 - 'TMPL_ACTION_SUCCESS' => THINK_PATH.'Tpl/dispatch_jump.tpl', // 默认成功跳转对应的模板文件 - 'TMPL_EXCEPTION_FILE' => THINK_PATH.'Tpl/think_exception.tpl',// 异常页面的模板文件 - 'TMPL_DETECT_THEME' => false, // 自动侦测模板主题 - 'TMPL_TEMPLATE_SUFFIX' => '.html', // 默认模板文件后缀 - 'TMPL_FILE_DEPR' => '/', //模板文件MODULE_NAME与ACTION_NAME之间的分割符 + 'TMPL_CONTENT_TYPE' => 'text/html', // 默认模板输出类型 + 'TMPL_ACTION_ERROR' => THINK_PATH.'Tpl/dispatch_jump.tpl', // 默认错误跳转对应的模板文件 + 'TMPL_ACTION_SUCCESS' => THINK_PATH.'Tpl/dispatch_jump.tpl', // 默认成功跳转对应的模板文件 + 'TMPL_EXCEPTION_FILE' => THINK_PATH.'Tpl/think_exception.tpl',// 异常页面的模板文件 + 'TMPL_DETECT_THEME' => false, // 自动侦测模板主题 + 'TMPL_TEMPLATE_SUFFIX' => '.html', // 默认模板文件后缀 + 'TMPL_FILE_DEPR' => '/', //模板文件CONTROLLER_NAME与ACTION_NAME之间的分割符 /* URL设置 */ - 'URL_CASE_INSENSITIVE' => false, // 默认false 表示URL区分大小写 true则表示不区分大小写 - 'URL_MODEL' => 1, // URL访问模式,可选参数0、1、2、3,代表以下四种模式: - // 0 (普通模式); 1 (PATHINFO 模式); 2 (REWRITE 模式); 3 (兼容模式) 默认为PATHINFO 模式,提供最好的用户体验和SEO支持 - 'URL_PATHINFO_DEPR' => '/', // PATHINFO模式下,各参数之间的分割符号 - 'URL_PATHINFO_FETCH' => 'ORIG_PATH_INFO,REDIRECT_PATH_INFO,REDIRECT_URL', // 用于兼容判断PATH_INFO 参数的SERVER替代变量列表 - 'URL_HTML_SUFFIX' => 'html', // URL伪静态后缀设置 + 'URL_CASE_INSENSITIVE' => false, // 默认false 表示URL区分大小写 true则表示不区分大小写 + 'URL_MODEL' => 1, // URL访问模式,可选参数0、1、2、3,代表以下四种模式: + // 0 (普通模式); 1 (PATHINFO 模式); 2 (REWRITE 模式); 3 (兼容模式) 默认为PATHINFO 模式 + 'URL_PATHINFO_DEPR' => '/', // PATHINFO模式下,各参数之间的分割符号 + 'URL_PATHINFO_FETCH' => 'ORIG_PATH_INFO,REDIRECT_PATH_INFO,REDIRECT_URL', // 用于兼容判断PATH_INFO 参数的SERVER替代变量列表 + 'URL_REQUEST_URI' => 'REQUEST_URI', // 获取当前页面地址的系统变量 默认为REQUEST_URI + 'URL_HTML_SUFFIX' => 'html', // URL伪静态后缀设置 'URL_DENY_SUFFIX' => 'ico|png|gif|jpg', // URL禁止访问的后缀设置 'URL_PARAMS_BIND' => true, // URL变量绑定到Action方法参数 + 'URL_PARAMS_BIND_TYPE' => 0, // URL变量绑定的类型 0 按变量名绑定 1 按变量顺序绑定 'URL_404_REDIRECT' => '', // 404 跳转页面 部署模式有效 + 'URL_ROUTER_ON' => false, // 是否开启URL路由 + 'URL_ROUTE_RULES' => array(), // 默认路由规则 针对模块 + 'URL_MAP_RULES' => array(), // URL映射定义规则 /* 系统变量名称设置 */ - 'VAR_GROUP' => 'g', // 默认分组获取变量 - 'VAR_MODULE' => 'm', // 默认模块获取变量 - 'VAR_ACTION' => 'a', // 默认操作获取变量 - 'VAR_AJAX_SUBMIT' => 'ajax', // 默认的AJAX提交变量 - 'VAR_JSONP_HANDLER' => 'callback', - 'VAR_PATHINFO' => 's', // PATHINFO 兼容模式获取变量例如 ?s=/module/action/id/1 后面的参数取决于URL_PATHINFO_DEPR - 'VAR_URL_PARAMS' => '_URL_', // PATHINFO URL参数变量 - 'VAR_TEMPLATE' => 't', // 默认模板切换变量 + 'VAR_MODULE' => 'm', // 默认模块获取变量 + 'VAR_CONTROLLER' => 'c', // 默认控制器获取变量 + 'VAR_ACTION' => 'a', // 默认操作获取变量 + 'VAR_AJAX_SUBMIT' => 'ajax', // 默认的AJAX提交变量 + 'VAR_JSONP_HANDLER' => 'callback', + 'VAR_PATHINFO' => 's', // 兼容模式PATHINFO获取变量例如 ?s=/module/action/id/1 后面的参数取决于URL_PATHINFO_DEPR + 'VAR_TEMPLATE' => 't', // 默认模板切换变量 'VAR_FILTERS' => 'filter_exp', // 全局系统变量的默认过滤方法 多个用逗号分割 - 'OUTPUT_ENCODE' => false, // 页面压缩输出 - 'HTTP_CACHE_CONTROL' => 'private', // 网页缓存控制 - -); \ No newline at end of file + 'HTTP_CACHE_CONTROL' => 'private', // 网页缓存控制 + 'CHECK_APP_DIR' => true, // 是否检查应用目录是否创建 + 'FILE_UPLOAD_TYPE' => 'Local', // 文件上传方式 + 'DATA_CRYPT_TYPE' => 'Think', // 数据加密方式 +); diff --git a/ThinkPHP/Conf/convention_sae.php b/ThinkPHP/Conf/convention_sae.php new file mode 100644 index 000000000..471f4f6d3 --- /dev/null +++ b/ThinkPHP/Conf/convention_sae.php @@ -0,0 +1,38 @@ + +// +---------------------------------------------------------------------- + +/** + * SAE模式惯例配置文件 + * 该文件请不要修改,如果要覆盖惯例配置的值,可在应用配置文件中设定和惯例不符的配置项 + * 配置名称大小写任意,系统会统一转换成小写 + * 所有配置参数都可以在生效前动态改变 + */ +defined('THINK_PATH') or exit(); +$st = new SaeStorage(); +return array( + //SAE下固定mysql配置 + 'DB_TYPE' => 'mysql', // 数据库类型 + 'DB_DEPLOY_TYPE' => 1, + 'DB_RW_SEPARATE' => true, + 'DB_HOST' => SAE_MYSQL_HOST_M.','.SAE_MYSQL_HOST_S, // 服务器地址 + 'DB_NAME' => SAE_MYSQL_DB, // 数据库名 + 'DB_USER' => SAE_MYSQL_USER, // 用户名 + 'DB_PWD' => SAE_MYSQL_PASS, // 密码 + 'DB_PORT' => SAE_MYSQL_PORT, // 端口 + //更改模板替换变量,让普通能在所有平台下显示 + 'TMPL_PARSE_STRING' => array( + // __PUBLIC__/upload --> /Public/upload -->http://appname-public.stor.sinaapp.com/upload + '/Public/upload' => $st->getUrl('public','upload') + ), + 'LOG_TYPE' => 'Sae', + 'DATA_CACHE_TYPE' => 'Memcachesae', + 'CHECK_APP_DIR' => false +); diff --git a/ThinkPHP/Conf/debug.php b/ThinkPHP/Conf/debug.php index c4b8a5c40..4faf24fcb 100644 --- a/ThinkPHP/Conf/debug.php +++ b/ThinkPHP/Conf/debug.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK IT ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006-2013 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -11,22 +11,17 @@ /** * ThinkPHP 默认的调试模式配置文件 - * 如果项目有定义自己的调试模式配置文件,本文件无效 - * @category Think - * @package Common - * @author liu21st - * @version $Id: debug.php 3071 2012-07-15 07:59:23Z liu21st@gmail.com $ */ defined('THINK_PATH') or exit(); -// 调试模式下面默认设置 可以在项目配置目录下重新定义 debug.php 覆盖 +// 调试模式下面默认设置 可以在应用配置目录下重新定义 debug.php 覆盖 return array( - 'LOG_RECORD' => true, // 进行日志记录 - 'LOG_EXCEPTION_RECORD' => true, // 是否记录异常信息日志 - 'LOG_LEVEL' => 'EMERG,ALERT,CRIT,ERR,WARN,NOTIC,INFO,DEBUG,SQL', // 允许记录的日志级别 - 'DB_FIELDS_CACHE' => false, // 字段缓存信息 - 'DB_SQL_LOG' => true, // 记录SQL信息 - 'APP_FILE_CASE' => true, // 是否检查文件的大小写 对Windows平台有效 - 'TMPL_CACHE_ON' => false, // 是否开启模板编译缓存,设为false则每次都会重新编译 - 'TMPL_STRIP_SPACE' => false, // 是否去除模板文件里面的html空格与换行 - 'SHOW_ERROR_MSG' => true, // 显示错误信息 + 'LOG_RECORD' => true, // 进行日志记录 + 'LOG_EXCEPTION_RECORD' => true, // 是否记录异常信息日志 + 'LOG_LEVEL' => 'EMERG,ALERT,CRIT,ERR,WARN,NOTIC,INFO,DEBUG,SQL', // 允许记录的日志级别 + 'DB_FIELDS_CACHE' => false, // 字段缓存信息 + 'DB_SQL_LOG' => true, // 记录SQL信息 + 'APP_FILE_CASE' => true, // 是否检查文件的大小写 对Windows平台有效 + 'TMPL_CACHE_ON' => false, // 是否开启模板编译缓存,设为false则每次都会重新编译 + 'TMPL_STRIP_SPACE' => false, // 是否去除模板文件里面的html空格与换行 + 'SHOW_ERROR_MSG' => true, // 显示错误信息 ); \ No newline at end of file diff --git a/ThinkPHP/Conf/tags.php b/ThinkPHP/Conf/tags.php deleted file mode 100644 index 701817ad7..000000000 --- a/ThinkPHP/Conf/tags.php +++ /dev/null @@ -1,39 +0,0 @@ - -// +---------------------------------------------------------------------- - -// 系统默认的核心行为扩展列表文件 -return array( - 'app_init' => array( - ), - 'app_begin' => array( - 'ReadHtmlCache', // 读取静态缓存 - ), - 'route_check' => array( - 'CheckRoute', // 路由检测 - ), - 'app_end' => array(), - 'path_info' => array(), - 'action_begin' => array(), - 'action_end' => array(), - 'view_begin' => array(), - 'view_parse' => array( - 'ParseTemplate', // 模板解析 支持PHP、内置模板引擎和第三方模板引擎 - ), - 'view_filter' => array( - 'ContentReplace', // 模板输出替换 - 'TokenBuild', // 表单令牌 - 'WriteHtmlCache', // 写入静态缓存 - 'ShowRuntime', // 运行时间显示 - ), - 'view_end' => array( - 'ShowPageTrace', // 页面Trace显示 - ), -); \ No newline at end of file diff --git a/ThinkPHP/Extend/README.txt b/ThinkPHP/Extend/README.txt deleted file mode 100644 index 1c150dfeb..000000000 --- a/ThinkPHP/Extend/README.txt +++ /dev/null @@ -1,24 +0,0 @@ - -Extend目录为系统扩展目录(核心版不含任何扩展),子目录结构为: - -|-Action 控制器扩展 -|-Behavior 行为扩展 -|-Driver 驱动扩展 -| ├Driver/Cache 缓存驱动 -| ├Driver/Db 数据库驱动 -| ├Driver/Session SESSION驱动 -| ├Driver/TagLib 标签库驱动 -| ├Driver/Template 模板引擎驱动 -| -|-Engine 引擎扩展 -|-Function 函数扩展 -|-Library 类库扩展 -| ├ORG ORG类库包 -| ├COM COM类库包 -| -|-Mode 模式扩展 -|-Model 模型扩展 -|-Tool 其他扩展或工具 -|-Vendor 第三方类库目录 - -关于扩展的详细使用,请参考开发手册的扩展章节。 \ No newline at end of file diff --git a/ThinkPHP/Lang/en-us.php b/ThinkPHP/Lang/en-us.php index cea776583..00c9dc02a 100644 --- a/ThinkPHP/Lang/en-us.php +++ b/ThinkPHP/Lang/en-us.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK IT ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006-2013 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -17,38 +17,38 @@ * @version $Id: zh-cn.php 3034 2012-10-17 21:14:00Z yangweijiester@gmail.com $ */ return array( - // core - '_MODULE_NOT_EXIST_' => 'Module can not been loaded', - '_ERROR_ACTION_' => 'Error action', - '_LANGUAGE_NOT_LOAD_' => 'Can\'t load language package', - '_TEMPLATE_NOT_EXIST_' => 'Template does\'t exist', - '_MODULE_' => 'Module', - '_ACTION_' => 'Action', - '_ACTION_NOT_EXIST_' => 'Action does\'t exist Or not defined', - '_MODEL_NOT_EXIST_' => 'Model does\'t exist Or not defined', - '_VALID_ACCESS_' => 'No access', - '_XML_TAG_ERROR_' => 'XML tag syntax errors', - '_DATA_TYPE_INVALID_' => 'Invlid data type!', - '_OPERATION_WRONG_' => 'Operation error occurs', - '_NOT_LOAD_DB_' => 'Unable to load the database', - '_NO_DB_DRIVER_' => 'Unable to load database driver', - '_NOT_SUPPORT_DB_' => 'The system is temporarily not support database', - '_NO_DB_CONFIG_' => 'Not define the database configuration', - '_NOT_SUPPERT_' => 'The system does not support', - '_CACHE_TYPE_INVALID_' => 'Unable to load the cache type', - '_FILE_NOT_WRITEABLE_' => 'Directory (file) is not writable', - '_METHOD_NOT_EXIST_' => 'The method you requested does not exist!', - '_CLASS_NOT_EXIST_' => 'Instantiating a class does not exist!', - '_CLASS_CONFLICT_' => 'Class name conflicts', - '_TEMPLATE_ERROR_' => 'Template Engine errors', - '_CACHE_WRITE_ERROR_' => 'Cache file write failed!', - '_TAGLIB_NOT_EXIST_' => 'Tag library is not defined', - '_OPERATION_FAIL_' => 'Operation failed!', - '_OPERATION_SUCCESS_' => 'Operation successed!', - '_SELECT_NOT_EXIST_' => 'Record does not exist!', - '_EXPRESS_ERROR_' => 'Expression errors', - '_TOKEN_ERROR_' => 'Form\'s token errors', - '_RECORD_HAS_UPDATE_' => 'Record has been updated', - '_NOT_ALLOW_PHP_' => 'PHP codes are not allowed in the template', - '_PARAM_ERROR_' => 'Parameter error or undefined', -); \ No newline at end of file + /* core language pachage */ + '_MODULE_NOT_EXIST_' => "Module can't been loaded", + '_CONTROLLER_NOT_EXIST_' => "Controler can't been loaded", + '_ERROR_ACTION_' => 'Illegal Action', + '_LANGUAGE_NOT_LOAD_' => "Can't load language package", + '_TEMPLATE_NOT_EXIST_' => "Template does't exist", + '_MODULE_' => 'Module', + '_ACTION_' => 'Action', + '_MODEL_NOT_EXIST_' => "Model can't been loaded", + '_VALID_ACCESS_' => 'No access', + '_XML_TAG_ERROR_' => 'XML tag syntax errors', + '_DATA_TYPE_INVALID_' => 'Illegal data objects!', + '_OPERATION_WRONG_' => 'Operation error occurs', + '_NOT_LOAD_DB_' => 'Unable to load the database', + '_NO_DB_DRIVER_' => 'Unable to load database driver', + '_NOT_SUPPORT_DB_' => 'The system is temporarily not support database', + '_NO_DB_CONFIG_' => 'Not define the database configuration', + '_NOT_SUPPERT_' => 'The system does not support', + '_CACHE_TYPE_INVALID_' => 'Unable to load the cache type', + '_FILE_NOT_WRITEABLE_' => 'Directory (file) is not writable', + '_METHOD_NOT_EXIST_' => 'The method you requested does not exist!', + '_CLASS_NOT_EXIST_' => 'Instantiating a class does not exist!', + '_CLASS_CONFLICT_' => 'Class name conflicts', + '_TEMPLATE_ERROR_' => 'Template Engine errors', + '_CACHE_WRITE_ERROR_' => 'Cache file write failed!', + '_TAGLIB_NOT_EXIST_' => 'Tag library is not defined', + '_OPERATION_FAIL_' => 'Operation failed!', + '_OPERATION_SUCCESS_' => 'Operation successed!', + '_SELECT_NOT_EXIST_' => 'Record does not exist!', + '_EXPRESS_ERROR_' => 'Expression errors', + '_TOKEN_ERROR_' => "Form's token errors", + '_RECORD_HAS_UPDATE_' => 'Record has been updated', + '_NOT_ALLOW_PHP_' => 'PHP codes are not allowed in the template', + '_PARAM_ERROR_' => 'Parameter error or undefined', +); diff --git a/ThinkPHP/Lang/zh-cn.php b/ThinkPHP/Lang/zh-cn.php index dd540c6ae..9478091cc 100644 --- a/ThinkPHP/Lang/zh-cn.php +++ b/ThinkPHP/Lang/zh-cn.php @@ -2,7 +2,7 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK IT ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006-2013 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- @@ -16,38 +16,38 @@ * @author liu21st */ return array( - // 核心 - '_MODULE_NOT_EXIST_' => '无法加载模块', - '_ERROR_ACTION_' => '非法操作', - '_LANGUAGE_NOT_LOAD_' => '无法加载语言包', - '_TEMPLATE_NOT_EXIST_' => '模板不存在', - '_MODULE_' => '模块', - '_ACTION_' => '操作', - '_ACTION_NOT_EXIST_' => '控制器不存在或者没有定义', - '_MODEL_NOT_EXIST_' => '模型不存在或者没有定义', - '_VALID_ACCESS_' => '没有权限', - '_XML_TAG_ERROR_' => 'XML标签语法错误', - '_DATA_TYPE_INVALID_' => '非法数据对象!', - '_OPERATION_WRONG_' => '操作出现错误', - '_NOT_LOAD_DB_' => '无法加载数据库', - '_NO_DB_DRIVER_' => '无法加载数据库驱动', - '_NOT_SUPPORT_DB_' => '系统暂时不支持数据库', - '_NO_DB_CONFIG_' => '没有定义数据库配置', - '_NOT_SUPPERT_' => '系统不支持', - '_CACHE_TYPE_INVALID_' => '无法加载缓存类型', - '_FILE_NOT_WRITEABLE_' => '目录(文件)不可写', - '_METHOD_NOT_EXIST_' => '您所请求的方法不存在!', - '_CLASS_NOT_EXIST_' => '实例化一个不存在的类!', - '_CLASS_CONFLICT_' => '类名冲突', - '_TEMPLATE_ERROR_' => '模板引擎错误', - '_CACHE_WRITE_ERROR_' => '缓存文件写入失败!', - '_TAGLIB_NOT_EXIST_' => '标签库未定义', - '_OPERATION_FAIL_' => '操作失败!', - '_OPERATION_SUCCESS_' => '操作成功!', - '_SELECT_NOT_EXIST_' => '记录不存在!', - '_EXPRESS_ERROR_' => '表达式错误', - '_TOKEN_ERROR_' => '表单令牌错误', - '_RECORD_HAS_UPDATE_' => '记录已经更新', - '_NOT_ALLOW_PHP_' => '模板禁用PHP代码', - '_PARAM_ERROR_' => '参数错误或者未定义', -); \ No newline at end of file + /* 核心语言变量 */ + '_MODULE_NOT_EXIST_' => '无法加载模块', + '_CONTROLLER_NOT_EXIST_' => '无法加载控制器', + '_ERROR_ACTION_' => '非法操作', + '_LANGUAGE_NOT_LOAD_' => '无法加载语言包', + '_TEMPLATE_NOT_EXIST_' => '模板不存在', + '_MODULE_' => '模块', + '_ACTION_' => '操作', + '_MODEL_NOT_EXIST_' => '模型不存在或者没有定义', + '_VALID_ACCESS_' => '没有权限', + '_XML_TAG_ERROR_' => 'XML标签语法错误', + '_DATA_TYPE_INVALID_' => '非法数据对象!', + '_OPERATION_WRONG_' => '操作出现错误', + '_NOT_LOAD_DB_' => '无法加载数据库', + '_NO_DB_DRIVER_' => '无法加载数据库驱动', + '_NOT_SUPPORT_DB_' => '系统暂时不支持数据库', + '_NO_DB_CONFIG_' => '没有定义数据库配置', + '_NOT_SUPPERT_' => '系统不支持', + '_CACHE_TYPE_INVALID_' => '无法加载缓存类型', + '_FILE_NOT_WRITEABLE_' => '目录(文件)不可写', + '_METHOD_NOT_EXIST_' => '您所请求的方法不存在!', + '_CLASS_NOT_EXIST_' => '实例化一个不存在的类!', + '_CLASS_CONFLICT_' => '类名冲突', + '_TEMPLATE_ERROR_' => '模板引擎错误', + '_CACHE_WRITE_ERROR_' => '缓存文件写入失败!', + '_TAGLIB_NOT_EXIST_' => '标签库未定义', + '_OPERATION_FAIL_' => '操作失败!', + '_OPERATION_SUCCESS_' => '操作成功!', + '_SELECT_NOT_EXIST_' => '记录不存在!', + '_EXPRESS_ERROR_' => '表达式错误', + '_TOKEN_ERROR_' => '表单令牌错误', + '_RECORD_HAS_UPDATE_' => '记录已经更新', + '_NOT_ALLOW_PHP_' => '模板禁用PHP代码', + '_PARAM_ERROR_' => '参数错误或者未定义', +); diff --git a/ThinkPHP/Lib/Core/Dispatcher.class.php b/ThinkPHP/Lib/Core/Dispatcher.class.php deleted file mode 100644 index 9da5df0e1..000000000 --- a/ThinkPHP/Lib/Core/Dispatcher.class.php +++ /dev/null @@ -1,271 +0,0 @@ - -// +---------------------------------------------------------------------- - -/** - * ThinkPHP内置的Dispatcher类 - * 完成URL解析、路由和调度 - * @category Think - * @package Think - * @subpackage Core - * @author liu21st - */ -class Dispatcher { - - /** - * URL映射到控制器 - * @access public - * @return void - */ - static public function dispatch() { - $urlMode = C('URL_MODEL'); - if(isset($_GET[C('VAR_PATHINFO')])) { // 判断URL里面是否有兼容模式参数 - $_SERVER['PATH_INFO'] = $_GET[C('VAR_PATHINFO')]; - unset($_GET[C('VAR_PATHINFO')]); - } - if($urlMode == URL_COMPAT ){ - // 兼容模式判断 - define('PHP_FILE',_PHP_FILE_.'?'.C('VAR_PATHINFO').'='); - }elseif($urlMode == URL_REWRITE ) { - //当前项目地址 - $url = dirname(_PHP_FILE_); - if($url == '/' || $url == '\\') - $url = ''; - define('PHP_FILE',$url); - }else { - //当前项目地址 - define('PHP_FILE',_PHP_FILE_); - } - - // 开启子域名部署 - if(C('APP_SUB_DOMAIN_DEPLOY')) { - $rules = C('APP_SUB_DOMAIN_RULES'); - if(isset($rules[$_SERVER['HTTP_HOST']])) { // 完整域名或者IP配置 - $rule = $rules[$_SERVER['HTTP_HOST']]; - }else{ - $subDomain = strtolower(substr($_SERVER['HTTP_HOST'],0,strpos($_SERVER['HTTP_HOST'],'.'))); - define('SUB_DOMAIN',$subDomain); // 二级域名定义 - if($subDomain && isset($rules[$subDomain])) { - $rule = $rules[$subDomain]; - }elseif(isset($rules['*'])){ // 泛域名支持 - if('www' != $subDomain && !in_array($subDomain,C('APP_SUB_DOMAIN_DENY'))) { - $rule = $rules['*']; - } - } - } - - if(!empty($rule)) { - // 子域名部署规则 '子域名'=>array('分组名/[模块名]','var1=a&var2=b'); - $array = explode('/',$rule[0]); - $module = array_pop($array); - if(!empty($module)) { - $_GET[C('VAR_MODULE')] = $module; - $domainModule = true; - } - if(!empty($array)) { - $_GET[C('VAR_GROUP')] = array_pop($array); - $domainGroup = true; - } - if(isset($rule[1])) { // 传入参数 - parse_str($rule[1],$parms); - $_GET = array_merge($_GET,$parms); - } - } - } - // 分析PATHINFO信息 - if(!isset($_SERVER['PATH_INFO'])) { - $types = explode(',',C('URL_PATHINFO_FETCH')); - foreach ($types as $type){ - if(0===strpos($type,':')) {// 支持函数判断 - $_SERVER['PATH_INFO'] = call_user_func(substr($type,1)); - break; - }elseif(!empty($_SERVER[$type])) { - $_SERVER['PATH_INFO'] = (0 === strpos($_SERVER[$type],$_SERVER['SCRIPT_NAME']))? - substr($_SERVER[$type], strlen($_SERVER['SCRIPT_NAME'])) : $_SERVER[$type]; - break; - } - } - } - $depr = C('URL_PATHINFO_DEPR'); - if(!empty($_SERVER['PATH_INFO'])) { - tag('path_info'); - $part = pathinfo($_SERVER['PATH_INFO']); - define('__EXT__', isset($part['extension'])?strtolower($part['extension']):''); - if(__EXT__){ - if(C('URL_DENY_SUFFIX') && preg_match('/\.('.trim(C('URL_DENY_SUFFIX'),'.').')$/i', $_SERVER['PATH_INFO'])){ - send_http_status(404); - exit; - } - if(C('URL_HTML_SUFFIX')) { - $_SERVER['PATH_INFO'] = preg_replace('/\.('.trim(C('URL_HTML_SUFFIX'),'.').')$/i', '', $_SERVER['PATH_INFO']); - }else{ - $_SERVER['PATH_INFO'] = preg_replace('/.'.__EXT__.'$/i','',$_SERVER['PATH_INFO']); - } - } - - if(!self::routerCheck()){ // 检测路由规则 如果没有则按默认规则调度URL - $paths = explode($depr,trim($_SERVER['PATH_INFO'],'/')); - if(C('VAR_URL_PARAMS')) { - // 直接通过$_GET['_URL_'][1] $_GET['_URL_'][2] 获取URL参数 方便不用路由时参数获取 - $_GET[C('VAR_URL_PARAMS')] = $paths; - } - $var = array(); - if (C('APP_GROUP_LIST') && !isset($_GET[C('VAR_GROUP')])){ - $var[C('VAR_GROUP')] = in_array(strtolower($paths[0]),explode(',',strtolower(C('APP_GROUP_LIST'))))? array_shift($paths) : ''; - if(C('APP_GROUP_DENY') && in_array(strtolower($var[C('VAR_GROUP')]),explode(',',strtolower(C('APP_GROUP_DENY'))))) { - // 禁止直接访问分组 - exit; - } - } - if(!isset($_GET[C('VAR_MODULE')])) {// 还没有定义模块名称 - $var[C('VAR_MODULE')] = array_shift($paths); - } - $var[C('VAR_ACTION')] = array_shift($paths); - // 解析剩余的URL参数 - preg_replace('@(\w+)\/([^\/]+)@e', '$var[\'\\1\']=strip_tags(\'\\2\');', implode('/',$paths)); - $_GET = array_merge($var,$_GET); - } - define('__INFO__',$_SERVER['PATH_INFO']); - }else{ - define('__INFO__',''); - } - - // URL常量 - define('__SELF__',strip_tags($_SERVER['REQUEST_URI'])); - // 当前项目地址 - define('__APP__',strip_tags(PHP_FILE)); - - // 获取分组 模块和操作名称 - if (C('APP_GROUP_LIST')) { - define('GROUP_NAME', self::getGroup(C('VAR_GROUP'))); - // 分组URL地址 - define('__GROUP__',(!empty($domainGroup) || strtolower(GROUP_NAME) == strtolower(C('DEFAULT_GROUP')) )?__APP__ : __APP__.'/'.(C('URL_CASE_INSENSITIVE') ? strtolower(GROUP_NAME) : GROUP_NAME)); - } - - // 定义项目基础加载路径 - define('BASE_LIB_PATH', (defined('GROUP_NAME') && C('APP_GROUP_MODE')==1) ? APP_PATH.C('APP_GROUP_PATH').'/'.GROUP_NAME.'/' : LIB_PATH); - if(defined('GROUP_NAME')) { - C('CACHE_PATH',CACHE_PATH.GROUP_NAME.'/'); - if(1 == C('APP_GROUP_MODE')){ // 独立分组模式 - $config_path = BASE_LIB_PATH.'Conf/'; - $common_path = BASE_LIB_PATH.'Common/'; - }else{ // 普通分组模式 - $config_path = CONF_PATH.GROUP_NAME.'/'; - $common_path = COMMON_PATH.GROUP_NAME.'/'; - } - // 加载分组配置文件 - if(is_file($config_path.'config.php')) - C(include $config_path.'config.php'); - // 加载分组别名定义 - if(is_file($config_path.'alias.php')) - alias_import(include $config_path.'alias.php'); - // 加载分组tags文件定义 - if(is_file($config_path.'tags.php')) - C('tags', include $config_path.'tags.php'); - // 加载分组函数文件 - if(is_file($common_path.'function.php')) - include $common_path.'function.php'; - }else{ - C('CACHE_PATH',CACHE_PATH); - } - define('MODULE_NAME',self::getModule(C('VAR_MODULE'))); - define('ACTION_NAME',self::getAction(C('VAR_ACTION'))); - - // 当前模块和分组地址 - $moduleName = defined('MODULE_ALIAS')?MODULE_ALIAS:MODULE_NAME; - if(defined('GROUP_NAME')) { - define('__URL__',!empty($domainModule)?__GROUP__.$depr : __GROUP__.$depr.( C('URL_CASE_INSENSITIVE') ? strtolower($moduleName) : $moduleName ) ); - }else{ - define('__URL__',!empty($domainModule)?__APP__.'/' : __APP__.'/'.( C('URL_CASE_INSENSITIVE') ? strtolower($moduleName) : $moduleName) ); - } - // 当前操作地址 - define('__ACTION__',__URL__.$depr.(defined('ACTION_ALIAS')?ACTION_ALIAS:ACTION_NAME)); - //保证$_REQUEST正常取值 - $_REQUEST = array_merge($_POST,$_GET); - } - - /** - * 路由检测 - * @access public - * @return void - */ - static public function routerCheck() { - $return = false; - // 路由检测标签 - tag('route_check',$return); - return $return; - } - - /** - * 获得实际的模块名称 - * @access private - * @return string - */ - static private function getModule($var) { - $module = (!empty($_GET[$var])? $_GET[$var]:C('DEFAULT_MODULE')); - unset($_GET[$var]); - if($maps = C('URL_MODULE_MAP')) { - if(isset($maps[strtolower($module)])) { - // 记录当前别名 - define('MODULE_ALIAS',strtolower($module)); - // 获取实际的模块名 - return $maps[MODULE_ALIAS]; - }elseif(array_search(strtolower($module),$maps)){ - // 禁止访问原始模块 - return ''; - } - } - if(C('URL_CASE_INSENSITIVE')) { - // URL地址不区分大小写 - // 智能识别方式 index.php/user_type/index/ 识别到 UserTypeAction 模块 - $module = ucfirst(parse_name($module,1)); - } - return strip_tags($module); - } - - /** - * 获得实际的操作名称 - * @access private - * @return string - */ - static private function getAction($var) { - $action = !empty($_POST[$var]) ? - $_POST[$var] : - (!empty($_GET[$var])?$_GET[$var]:C('DEFAULT_ACTION')); - unset($_POST[$var],$_GET[$var]); - if($maps = C('URL_ACTION_MAP')) { - if(isset($maps[strtolower(MODULE_NAME)])) { - $maps = $maps[strtolower(MODULE_NAME)]; - if(isset($maps[strtolower($action)])) { - // 记录当前别名 - define('ACTION_ALIAS',strtolower($action)); - // 获取实际的操作名 - return $maps[ACTION_ALIAS]; - }elseif(array_search(strtolower($action),$maps)){ - // 禁止访问原始操作 - return ''; - } - } - } - return strip_tags(C('URL_CASE_INSENSITIVE')?strtolower($action):$action); - } - - /** - * 获得实际的分组名称 - * @access private - * @return string - */ - static private function getGroup($var) { - $group = (!empty($_GET[$var])?$_GET[$var]:C('DEFAULT_GROUP')); - unset($_GET[$var]); - return strip_tags(C('URL_CASE_INSENSITIVE') ?ucfirst(strtolower($group)):$group); - } - -} diff --git a/ThinkPHP/Lib/Core/Think.class.php b/ThinkPHP/Lib/Core/Think.class.php deleted file mode 100644 index 201461e93..000000000 --- a/ThinkPHP/Lib/Core/Think.class.php +++ /dev/null @@ -1,316 +0,0 @@ - -// +---------------------------------------------------------------------- - -/** - * ThinkPHP Portal类 - * @category Think - * @package Think - * @subpackage Core - * @author liu21st - */ -class Think { - - private static $_instance = array(); - - /** - * 应用程序初始化 - * @access public - * @return void - */ - static public function start() { - // 设定错误和异常处理 - register_shutdown_function(array('Think','fatalError')); - set_error_handler(array('Think','appError')); - set_exception_handler(array('Think','appException')); - // 注册AUTOLOAD方法 - spl_autoload_register(array('Think', 'autoload')); - //[RUNTIME] - Think::buildApp(); // 预编译项目 - //[/RUNTIME] - // 运行应用 - App::run(); - return ; - } - - //[RUNTIME] - /** - * 读取配置信息 编译项目 - * @access private - * @return string - */ - static private function buildApp() { - - // 读取运行模式 - if(defined('MODE_NAME')) { // 读取模式的设置 - $mode = include MODE_PATH.strtolower(MODE_NAME).'.php'; - }else{ - $mode = array(); - } - // 加载核心惯例配置文件 - C(include THINK_PATH.'Conf/convention.php'); - if(isset($mode['config'])) {// 加载模式配置文件 - C( is_array($mode['config'])?$mode['config']:include $mode['config'] ); - } - - // 加载项目配置文件 - if(is_file(CONF_PATH.'config.php')) - C(include CONF_PATH.'config.php'); - - // 加载框架底层语言包 - L(include THINK_PATH.'Lang/'.strtolower(C('DEFAULT_LANG')).'.php'); - - // 加载模式系统行为定义 - if(C('APP_TAGS_ON')) { - if(isset($mode['extends'])) { - C('extends',is_array($mode['extends'])?$mode['extends']:include $mode['extends']); - }else{ // 默认加载系统行为扩展定义 - C('extends', include THINK_PATH.'Conf/tags.php'); - } - } - - // 加载应用行为定义 - if(isset($mode['tags'])) { - C('tags', is_array($mode['tags'])?$mode['tags']:include $mode['tags']); - }elseif(is_file(CONF_PATH.'tags.php')){ - // 默认加载项目配置目录的tags文件定义 - C('tags', include CONF_PATH.'tags.php'); - } - - $compile = ''; - // 读取核心编译文件列表 - if(isset($mode['core'])) { - $list = $mode['core']; - }else{ - $list = array( - THINK_PATH.'Common/functions.php', // 标准模式函数库 - CORE_PATH.'Core/Log.class.php', // 日志处理类 - CORE_PATH.'Core/Dispatcher.class.php', // URL调度类 - CORE_PATH.'Core/App.class.php', // 应用程序类 - CORE_PATH.'Core/Action.class.php', // 控制器类 - CORE_PATH.'Core/View.class.php', // 视图类 - ); - } - // 项目追加核心编译列表文件 - if(is_file(CONF_PATH.'core.php')) { - $list = array_merge($list,include CONF_PATH.'core.php'); - } - foreach ($list as $file){ - if(is_file($file)) { - require_cache($file); - if(!APP_DEBUG) $compile .= compile($file); - } - } - - // 加载项目公共文件 - if(is_file(COMMON_PATH.'common.php')) { - include COMMON_PATH.'common.php'; - // 编译文件 - if(!APP_DEBUG) $compile .= compile(COMMON_PATH.'common.php'); - } - - // 加载模式别名定义 - if(isset($mode['alias'])) { - $alias = is_array($mode['alias'])?$mode['alias']:include $mode['alias']; - alias_import($alias); - if(!APP_DEBUG) $compile .= 'alias_import('.var_export($alias,true).');'; - } - - // 加载项目别名定义 - if(is_file(CONF_PATH.'alias.php')){ - $alias = include CONF_PATH.'alias.php'; - alias_import($alias); - if(!APP_DEBUG) $compile .= 'alias_import('.var_export($alias,true).');'; - } - - if(APP_DEBUG) { - // 调试模式加载系统默认的配置文件 - C(include THINK_PATH.'Conf/debug.php'); - // 读取调试模式的应用状态 - $status = C('APP_STATUS'); - // 加载对应的项目配置文件 - if(is_file(CONF_PATH.$status.'.php')) - // 允许项目增加开发模式配置定义 - C(include CONF_PATH.$status.'.php'); - }else{ - // 部署模式下面生成编译文件 - build_runtime_cache($compile); - } - return ; - } - //[/RUNTIME] - - /** - * 系统自动加载ThinkPHP类库 - * 并且支持配置自动加载路径 - * @param string $class 对象类名 - * @return void - */ - public static function autoload($class) { - // 检查是否存在别名定义 - if(alias_import($class)) return ; - $libPath = defined('BASE_LIB_PATH')?BASE_LIB_PATH:LIB_PATH; - $group = defined('GROUP_NAME') && C('APP_GROUP_MODE')==0 ?GROUP_NAME.'/':''; - $file = $class.'.class.php'; - if(substr($class,-8)=='Behavior') { // 加载行为 - if(require_array(array( - CORE_PATH.'Behavior/'.$file, - EXTEND_PATH.'Behavior/'.$file, - LIB_PATH.'Behavior/'.$file, - $libPath.'Behavior/'.$file),true) - || (defined('MODE_NAME') && require_cache(MODE_PATH.ucwords(MODE_NAME).'/Behavior/'.$file))) { - return ; - } - }elseif(substr($class,-5)=='Model'){ // 加载模型 - if(require_array(array( - LIB_PATH.'Model/'.$group.$file, - $libPath.'Model/'.$file, - EXTEND_PATH.'Model/'.$file),true)) { - return ; - } - }elseif(substr($class,-6)=='Action'){ // 加载控制器 - if(require_array(array( - LIB_PATH.'Action/'.$group.$file, - $libPath.'Action/'.$file, - EXTEND_PATH.'Action/'.$file),true)) { - return ; - } - }elseif(substr($class,0,5)=='Cache'){ // 加载缓存驱动 - if(require_array(array( - EXTEND_PATH.'Driver/Cache/'.$file, - CORE_PATH.'Driver/Cache/'.$file),true)){ - return ; - } - }elseif(substr($class,0,2)=='Db'){ // 加载数据库驱动 - if(require_array(array( - EXTEND_PATH.'Driver/Db/'.$file, - CORE_PATH.'Driver/Db/'.$file),true)){ - return ; - } - }elseif(substr($class,0,8)=='Template'){ // 加载模板引擎驱动 - if(require_array(array( - EXTEND_PATH.'Driver/Template/'.$file, - CORE_PATH.'Driver/Template/'.$file),true)){ - return ; - } - }elseif(substr($class,0,6)=='TagLib'){ // 加载标签库驱动 - if(require_array(array( - EXTEND_PATH.'Driver/TagLib/'.$file, - CORE_PATH.'Driver/TagLib/'.$file),true)) { - return ; - } - } - - // 根据自动加载路径设置进行尝试搜索 - $paths = explode(',',C('APP_AUTOLOAD_PATH')); - foreach ($paths as $path){ - if(import($path.'.'.$class)) - // 如果加载类成功则返回 - return ; - } - } - - /** - * 取得对象实例 支持调用类的静态方法 - * @param string $class 对象类名 - * @param string $method 类的静态方法名 - * @return object - */ - static public function instance($class,$method='') { - $identify = $class.$method; - if(!isset(self::$_instance[$identify])) { - if(class_exists($class)){ - $o = new $class(); - if(!empty($method) && method_exists($o,$method)) - self::$_instance[$identify] = call_user_func_array(array(&$o, $method)); - else - self::$_instance[$identify] = $o; - } - else - halt(L('_CLASS_NOT_EXIST_').':'.$class); - } - return self::$_instance[$identify]; - } - - /** - * 自定义异常处理 - * @access public - * @param mixed $e 异常对象 - */ - static public function appException($e) { - $error = array(); - $error['message'] = $e->getMessage(); - $trace = $e->getTrace(); - if('throw_exception'==$trace[0]['function']) { - $error['file'] = $trace[0]['file']; - $error['line'] = $trace[0]['line']; - }else{ - $error['file'] = $e->getFile(); - $error['line'] = $e->getLine(); - } - Log::record($error['message'],Log::ERR); - halt($error); - } - - /** - * 自定义错误处理 - * @access public - * @param int $errno 错误类型 - * @param string $errstr 错误信息 - * @param string $errfile 错误文件 - * @param int $errline 错误行数 - * @return void - */ - static public function appError($errno, $errstr, $errfile, $errline) { - switch ($errno) { - case E_ERROR: - case E_PARSE: - case E_CORE_ERROR: - case E_COMPILE_ERROR: - case E_USER_ERROR: - ob_end_clean(); - // 页面压缩输出支持 - if(C('OUTPUT_ENCODE')){ - $zlib = ini_get('zlib.output_compression'); - if(empty($zlib)) ob_start('ob_gzhandler'); - } - $errorStr = "$errstr ".$errfile." 第 $errline 行."; - if(C('LOG_RECORD')) Log::write("[$errno] ".$errorStr,Log::ERR); - function_exists('halt')?halt($errorStr):exit('ERROR:'.$errorStr); - break; - case E_STRICT: - case E_USER_WARNING: - case E_USER_NOTICE: - default: - $errorStr = "[$errno] $errstr ".$errfile." 第 $errline 行."; - trace($errorStr,'','NOTIC'); - break; - } - } - - // 致命错误捕获 - static public function fatalError() { - // 保存日志记录 - if(C('LOG_RECORD')) Log::save(); - if ($e = error_get_last()) { - switch($e['type']){ - case E_ERROR: - case E_PARSE: - case E_CORE_ERROR: - case E_COMPILE_ERROR: - case E_USER_ERROR: - ob_end_clean(); - function_exists('halt')?halt($e):exit('ERROR:'.$e['message']. ' in '.$e['file'].' on line '.$e['line'].''); - break; - } - } - } - -} diff --git a/ThinkPHP/Lib/Core/Widget.class.php b/ThinkPHP/Lib/Core/Widget.class.php deleted file mode 100644 index 38cd7c050..000000000 --- a/ThinkPHP/Lib/Core/Widget.class.php +++ /dev/null @@ -1,107 +0,0 @@ - -// +---------------------------------------------------------------------- - -/** - * ThinkPHP Widget类 抽象类 - * @category Think - * @package Think - * @subpackage Core - * @author liu21st - */ -abstract class Widget { - - // 使用的模板引擎 每个Widget可以单独配置不受系统影响 - protected $template = ''; - - /** - * 渲染输出 render方法是Widget唯一的接口 - * 使用字符串返回 不能有任何输出 - * @access public - * @param mixed $data 要渲染的数据 - * @return string - */ - abstract public function render($data); - - /** - * 渲染模板输出 供render方法内部调用 - * @access public - * @param string $templateFile 模板文件 - * @param mixed $var 模板变量 - * @return string - */ - protected function renderFile($templateFile='',$var='') { - ob_start(); - ob_implicit_flush(0); - if(!file_exists_case($templateFile)){ - // 自动定位模板文件 - $name = substr(get_class($this),0,-6); - $filename = empty($templateFile)?$name:$templateFile; - $templateFile = BASE_LIB_PATH.'Widget/'.$name.'/'.$filename.C('TMPL_TEMPLATE_SUFFIX'); - if(!file_exists_case($templateFile)) - throw_exception(L('_TEMPLATE_NOT_EXIST_').'['.$templateFile.']'); - } - $template = strtolower($this->template?$this->template:(C('TMPL_ENGINE_TYPE')?C('TMPL_ENGINE_TYPE'):'php')); - if('php' == $template) { - // 使用PHP模板 - if(!empty($var)) extract($var, EXTR_OVERWRITE); - // 直接载入PHP模板 - include $templateFile; - }elseif('think'==$template){ // 采用Think模板引擎 - if($this->checkCache($templateFile)) { // 缓存有效 - // 分解变量并载入模板缓存 - extract($var, EXTR_OVERWRITE); - //载入模版缓存文件 - include C('CACHE_PATH').md5($templateFile).C('TMPL_CACHFILE_SUFFIX'); - }else{ - $tpl = Think::instance('ThinkTemplate'); - // 编译并加载模板文件 - $tpl->fetch($templateFile,$var); - } - }else{ - $class = 'Template'.ucwords($template); - if(is_file(CORE_PATH.'Driver/Template/'.$class.'.class.php')) { - // 内置驱动 - $path = CORE_PATH; - }else{ // 扩展驱动 - $path = EXTEND_PATH; - } - require_cache($path.'Driver/Template/'.$class.'.class.php'); - $tpl = new $class; - $tpl->fetch($templateFile,$var); - } - $content = ob_get_clean(); - return $content; - } - - /** - * 检查缓存文件是否有效 - * 如果无效则需要重新编译 - * @access public - * @param string $tmplTemplateFile 模板文件名 - * @return boolen - */ - protected function checkCache($tmplTemplateFile) { - if (!C('TMPL_CACHE_ON')) // 优先对配置设定检测 - return false; - $tmplCacheFile = C('CACHE_PATH').md5($tmplTemplateFile).C('TMPL_CACHFILE_SUFFIX'); - if(!is_file($tmplCacheFile)){ - return false; - }elseif (filemtime($tmplTemplateFile) > filemtime($tmplCacheFile)) { - // 模板文件如果有更新则缓存需要更新 - return false; - }elseif (C('TMPL_CACHE_TIME') != 0 && time() > filemtime($tmplCacheFile)+C('TMPL_CACHE_TIME')) { - // 缓存是否在有效期 - return false; - } - // 缓存有效 - return true; - } -} \ No newline at end of file diff --git a/ThinkPHP/Library/Behavior/AgentCheckBehavior.class.php b/ThinkPHP/Library/Behavior/AgentCheckBehavior.class.php new file mode 100644 index 000000000..960677943 --- /dev/null +++ b/ThinkPHP/Library/Behavior/AgentCheckBehavior.class.php @@ -0,0 +1,33 @@ + +// +---------------------------------------------------------------------- +namespace Behavior; +use Think\Behavior; +defined('THINK_PATH') or exit(); +/** + * 行为扩展:代理检测 + * @category Extend + * @package Extend + * @subpackage Behavior + * @author liu21st + */ +class AgentCheckBehavior extends Behavior { + protected $options = array( + 'LIMIT_PROXY_VISIT'=>true, + ); + public function run(&$params) { + // 代理访问检测 + if(C('LIMIT_PROXY_VISIT') && ($_SERVER['HTTP_X_FORWARDED_FOR'] || $_SERVER['HTTP_VIA'] || $_SERVER['HTTP_PROXY_CONNECTION'] || $_SERVER['HTTP_USER_AGENT_VIA'])) { + // 禁止代理访问 + exit('Access Denied'); + } + } +} +?> \ No newline at end of file diff --git a/ThinkPHP/Library/Behavior/BrowserCheckBehavior.class.php b/ThinkPHP/Library/Behavior/BrowserCheckBehavior.class.php new file mode 100644 index 000000000..0668e0ca6 --- /dev/null +++ b/ThinkPHP/Library/Behavior/BrowserCheckBehavior.class.php @@ -0,0 +1,43 @@ + +// +---------------------------------------------------------------------- +namespace Behavior; +use Think\Behavior; +defined('THINK_PATH') or exit(); +/** + * 浏览器防刷新检测 + * @category Extend + * @package Extend + * @subpackage Behavior + * @author liu21st + */ +class BrowserCheckBehavior extends Behavior { + protected $options = array( + // 浏览器防刷新的时间间隔(秒) + 'LIMIT_REFLESH_TIMES' => 10, + ); + + public function run(&$params) { + if($_SERVER['REQUEST_METHOD'] == 'GET') { + // 启用页面防刷新机制 + $guid = md5($_SERVER['PHP_SELF']); + // 检查页面刷新间隔 + if(cookie('_last_visit_time_'.$guid) && cookie('_last_visit_time_'.$guid)>time()-C('LIMIT_REFLESH_TIMES')) { + // 页面刷新读取浏览器缓存 + header('HTTP/1.1 304 Not Modified'); + exit; + }else{ + // 缓存当前地址访问时间 + cookie('_last_visit_time_'.$guid, $_SERVER['REQUEST_TIME']); + //header('Last-Modified:'.(date('D,d M Y H:i:s',$_SERVER['REQUEST_TIME']-C('LIMIT_REFLESH_TIMES'))).' GMT'); + } + } + } +} \ No newline at end of file diff --git a/ThinkPHP/Lib/Behavior/CheckRouteBehavior.class.php b/ThinkPHP/Library/Behavior/CheckActionRouteBehavior.class.php similarity index 70% rename from ThinkPHP/Lib/Behavior/CheckRouteBehavior.class.php rename to ThinkPHP/Library/Behavior/CheckActionRouteBehavior.class.php index be60d55e9..cd770ad01 100644 --- a/ThinkPHP/Lib/Behavior/CheckRouteBehavior.class.php +++ b/ThinkPHP/Library/Behavior/CheckActionRouteBehavior.class.php @@ -8,39 +8,34 @@ // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- - +namespace Behavior; +use Think\Behavior; defined('THINK_PATH') or exit(); /** - * 系统行为扩展:路由检测 + * 系统行为扩展:操作路由检测 * @category Think * @package Think * @subpackage Behavior * @author liu21st */ -class CheckRouteBehavior extends Behavior { - // 行为参数定义(默认值) 可在项目配置中覆盖 - protected $options = array( - 'URL_ROUTER_ON' => false, // 是否开启URL路由 - 'URL_ROUTE_RULES' => array(), // 默认路由规则,注:分组配置无法替代 - ); +class CheckActionRouteBehavior extends Behavior { // 行为扩展的执行入口必须是run - public function run(&$return){ + public function run(&$config){ // 优先检测是否存在PATH_INFO - $regx = trim($_SERVER['PATH_INFO'],'/'); - if(empty($regx)) return $return = true; - // 是否开启路由使用 - if(!C('URL_ROUTER_ON')) return $return = false; + $regx = trim($_SERVER['PATH_INFO'],'/'); + if(empty($regx)) return ; // 路由定义文件优先于config中的配置定义 - $routes = C('URL_ROUTE_RULES'); // 路由处理 + $routes = $config['routes']; if(!empty($routes)) { $depr = C('URL_PATHINFO_DEPR'); // 分隔符替换 确保路由定义使用统一的分隔符 $regx = str_replace($depr,'/',$regx); + $regx = substr_replace($regx,'',0,strlen(__URL__)); foreach ($routes as $rule=>$route){ if(0===strpos($rule,'/') && preg_match($rule,$regx,$matches)) { // 正则路由 - return $return = $this->parseRegex($matches,$route,$regx); + return C('ACTION_NAME',$this->parseRegex($matches,$route,$regx)); }else{ // 规则路由 $len1 = substr_count($regx,'/'); $len2 = substr_count($rule,'/'); @@ -53,19 +48,18 @@ public function run(&$return){ } } $match = $this->checkUrlMatch($regx,$rule); - if($match) return $return = $this->parseRule($rule,$route,$regx); + if($match) return C('ACTION_NAME',$this->parseRule($rule,$route,$regx)); } } } } - $return = false; } // 检测URL和规则路由是否匹配 private function checkUrlMatch($regx,$rule) { - $m1 = explode('/',$regx); - $m2 = explode('/',$rule); - $match = true; // 是否匹配 + $m1 = explode('/',$regx); + $m2 = explode('/',$rule); + $match = true; // 是否匹配 foreach ($m2 as $key=>$val){ if(':' == substr($val,0,1)) {// 动态变量 if(strpos($val,'\\')) { @@ -90,33 +84,23 @@ private function checkUrlMatch($regx,$rule) { } // 解析规范的路由地址 - // 地址格式 [分组/模块/操作?]参数1=值1&参数2=值2... + // 地址格式 操作?参数1=值1&参数2=值2... private function parseUrl($url) { $var = array(); - if(false !== strpos($url,'?')) { // [分组/模块/操作?]参数1=值1&参数2=值2... - $info = parse_url($url); - $path = explode('/',$info['path']); + if(false !== strpos($url,'?')) { // 操作?参数1=值1&参数2=值2... + $info = parse_url($url); + $path = $info['path']; parse_str($info['query'],$var); - }elseif(strpos($url,'/')){ // [分组/模块/操作] - $path = explode('/',$url); - }else{ // 参数1=值1&参数2=值2... - parse_str($url,$var); - } - if(isset($path)) { - $var[C('VAR_ACTION')] = array_pop($path); - if(!empty($path)) { - $var[C('VAR_MODULE')] = array_pop($path); - } - if(!empty($path)) { - $var[C('VAR_GROUP')] = array_pop($path); - } + }else{ // 操作 + $path = $url; } + $var[C('VAR_ACTION')] = $path; return $var; } // 解析规则路由 - // '路由规则'=>'[分组/模块/操作]?额外参数1=值1&额外参数2=值2...' - // '路由规则'=>array('[分组/模块/操作]','额外参数1=值1&额外参数2=值2...') + // '路由规则'=>'操作?额外参数1=值1&额外参数2=值2...' + // '路由规则'=>array('操作','额外参数1=值1&额外参数2=值2...') // '路由规则'=>'外部地址' // '路由规则'=>array('外部地址','重定向代码') // 路由规则中 :开头 表示动态变量 @@ -125,12 +109,12 @@ private function parseUrl($url) { // 'new/:id'=>array('/new.php?id=:1',301), 重定向 private function parseRule($rule,$route,$regx) { // 获取路由地址规则 - $url = is_array($route)?$route[0]:$route; + $url = is_array($route)?$route[0]:$route; // 获取URL地址中的参数 - $paths = explode('/',$regx); + $paths = explode('/',$regx); // 解析路由规则 - $matches = array(); - $rule = explode('/',$rule); + $matches = array(); + $rule = explode('/',$rule); foreach ($rule as $item){ if(0===strpos($item,':')) { // 动态变量获取 if($pos = strpos($item,'^') ) { @@ -147,34 +131,36 @@ private function parseRule($rule,$route,$regx) { } if(0=== strpos($url,'/') || 0===strpos($url,'http')) { // 路由重定向跳转 if(strpos($url,':')) { // 传递动态参数 - $values = array_values($matches); - $url = preg_replace('/:(\d+)/e','$values[\\1-1]',$url); + $values = array_values($matches); + $url = preg_replace('/:(\d+)/e','$values[\\1-1]',$url); } header("Location: $url", true,(is_array($route) && isset($route[1]))?$route[1]:301); exit; }else{ // 解析路由地址 - $var = $this->parseUrl($url); + $var = $this->parseUrl($url); // 解析路由地址里面的动态参数 - $values = array_values($matches); + $values = array_values($matches); foreach ($var as $key=>$val){ if(0===strpos($val,':')) { $var[$key] = $values[substr($val,1)-1]; } } - $var = array_merge($matches,$var); + $var = array_merge($matches,$var); // 解析剩余的URL参数 if($paths) { preg_replace('@(\w+)\/([^\/]+)@e', '$var[strtolower(\'\\1\')]=strip_tags(\'\\2\');', implode('/',$paths)); } - // 解析路由自动传入参数 + // 解析路由自动传人参数 if(is_array($route) && isset($route[1])) { parse_str($route[1],$params); $var = array_merge($var,$params); } - $_GET = array_merge($var,$_GET); + $action = $var[C('VAR_ACTION')]; + unset($var[C('VAR_ACTION')]); + $_GET = array_merge($var,$_GET); + return $action; } - return true; } // 解析正则路由 @@ -194,19 +180,21 @@ private function parseRegex($matches,$route,$regx) { exit; }else{ // 解析路由地址 - $var = $this->parseUrl($url); + $var = $this->parseUrl($url); // 解析剩余的URL参数 - $regx = substr_replace($regx,'',0,strlen($matches[0])); + $regx = substr_replace($regx,'',0,strlen($matches[0])); if($regx) { preg_replace('@(\w+)\/([^,\/]+)@e', '$var[strtolower(\'\\1\')]=strip_tags(\'\\2\');', $regx); } - // 解析路由自动传入参数 + // 解析路由自动传人参数 if(is_array($route) && isset($route[1])) { parse_str($route[1],$params); $var = array_merge($var,$params); } - $_GET = array_merge($var,$_GET); + $action = $var[C('VAR_ACTION')]; + unset($var[C('VAR_ACTION')]); + $_GET = array_merge($var,$_GET); } - return true; + return $action; } } \ No newline at end of file diff --git a/ThinkPHP/Library/Behavior/CheckLangBehavior.class.php b/ThinkPHP/Library/Behavior/CheckLangBehavior.class.php new file mode 100644 index 000000000..bd460424d --- /dev/null +++ b/ThinkPHP/Library/Behavior/CheckLangBehavior.class.php @@ -0,0 +1,88 @@ + +// +---------------------------------------------------------------------- +namespace Behavior; +use Think\Behavior; +defined('THINK_PATH') or exit(); +/** + * 语言检测 并自动加载语言包 + * @category Extend + * @package Extend + * @subpackage Behavior + * @author liu21st + */ +class CheckLangBehavior extends Behavior { + // 行为参数定义(默认值) 可在应用配置中覆盖 + protected $options = array( + 'LANG_SWITCH_ON' => false, // 默认关闭语言包功能 + 'LANG_AUTO_DETECT' => true, // 自动侦测语言 开启多语言功能后有效 + 'LANG_LIST' => 'zh-cn', // 允许切换的语言列表 用逗号分隔 + 'VAR_LANGUAGE' => 'l', // 默认语言切换变量 + ); + + // 行为扩展的执行入口必须是run + public function run(&$params){ + // 检测语言 + $this->checkLanguage(); + } + + /** + * 语言检查 + * 检查浏览器支持语言,并自动加载语言包 + * @access private + * @return void + */ + private function checkLanguage() { + // 不开启语言包功能,仅仅加载框架语言文件直接返回 + if (!C('LANG_SWITCH_ON')){ + return; + } + $langSet = C('DEFAULT_LANG'); + // 启用了语言包功能 + // 根据是否启用自动侦测设置获取语言选择 + if (C('LANG_AUTO_DETECT')){ + if(isset($_GET[C('VAR_LANGUAGE')])){ + $langSet = $_GET[C('VAR_LANGUAGE')];// url中设置了语言变量 + cookie('think_language',$langSet,3600); + }elseif(cookie('think_language')){// 获取上次用户的选择 + $langSet = cookie('think_language'); + }elseif(isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])){// 自动侦测浏览器语言 + preg_match('/^([a-z\d\-]+)/i', $_SERVER['HTTP_ACCEPT_LANGUAGE'], $matches); + $langSet = $matches[1]; + cookie('think_language',$langSet,3600); + } + if(false === stripos(C('LANG_LIST'),$langSet)) { // 非法语言参数 + $langSet = C('DEFAULT_LANG'); + } + } + // 定义当前语言 + define('LANG_SET',strtolower($langSet)); + + // 读取框架语言包 + $file = THINK_PATH.'Lang/'.LANG_SET.'.php'); + if(LANG_SET != C('DEFAULT_LANG') && is_file($file)) + L(include $file); + + // 读取应用公共语言包 + $file = LANG_PATH.LANG_SET.'.php'; + if(is_file($file)) + L(include $file); + + // 读取模块语言包 + $file = MODULE_PATH.'Lang/'.LANG_SET.'.php'; + if(is_file($file)) + L(include $file); + + // 读取当前控制器语言包 + $file = MODULE_PATH.'Lang/'.LANG_SET.'/'.strtolower(CONTROLLER_NAME).'.php'; + if (is_file($file)) + L(include $file); + } +} diff --git a/ThinkPHP/Library/Behavior/ChromeShowPageTraceBehavior.class.php b/ThinkPHP/Library/Behavior/ChromeShowPageTraceBehavior.class.php new file mode 100644 index 000000000..1a302b8d8 --- /dev/null +++ b/ThinkPHP/Library/Behavior/ChromeShowPageTraceBehavior.class.php @@ -0,0 +1,616 @@ + +// +---------------------------------------------------------------------- +// $Id$ + +/** + * 将Trace信息输出到chrome浏览器的控制器,从而不影响ajax效果和页面的布局。 + * 使用前,你需要先安装 chrome log 这个插件: http://craig.is/writing/chrome-logger。 + * 定义应用的tags.php文件 Application/Common/Conf/tags.php, + * + * array( + * 'Behavior\ChromeShowPageTrace' + * ) + * ); + * + * 如果trace信息没有正常输出,请查看您的日志。 + * 这是通过http headers和chrome通信,所以要保证在输出trace信息之前不能有 + * headers输出,你可以在入口文件第一行加入代码 ob_start(); 或者配置output_buffering + * + */ +namespace Behavior; +use Think\Behavior; +use Think\Log; + +defined('THINK_PATH') or exit(); +/** + * 系统行为扩展 页面Trace显示输出 + */ +class ChromeShowPageTraceBehavior extends Behavior { + // 行为参数定义 + protected $options = array( + 'SHOW_PAGE_TRACE'=> false, // 显示页面Trace信息 + 'TRACE_PAGE_TABS' => array('BASE'=>'基本','FILE'=>'文件','INFO'=>'流程','ERR|NOTIC'=>'错误','SQL'=>'SQL','DEBUG'=>'调试'), // 页面Trace可定制的选项卡 + 'PAGE_TRACE_SAVE' => false, + ); + + // 行为扩展的执行入口必须是run + public function run(&$params){ + if(C('SHOW_PAGE_TRACE')) $this->showTrace(); + } + + + /** + * 显示页面Trace信息 + * @access private + */ + private function showTrace() { + // 系统默认显示信息 + $files = get_included_files(); + $info = array(); + foreach ($files as $key=>$file){ + $info[] = $file.' ( '.number_format(filesize($file)/1024,2).' KB )'; + } + $trace = array(); + $base = array( + '请求信息' => date('Y-m-d H:i:s',$_SERVER['REQUEST_TIME']).' '.$_SERVER['SERVER_PROTOCOL'].' '.$_SERVER['REQUEST_METHOD'].' : '.__SELF__, + '运行时间' => $this->showTime(), + '吞吐率' => number_format(1/G('beginTime','viewEndTime'),2).'req/s', + '内存开销' => MEMORY_LIMIT_ON?number_format((memory_get_usage() - $GLOBALS['_startUseMems'])/1024,2).' kb':'不支持', + '查询信息' => N('db_query').' queries '.N('db_write').' writes ', + '文件加载' => count(get_included_files()), + '缓存信息' => N('cache_read').' gets '.N('cache_write').' writes ', + '配置加载' => count(c()), + '会话信息' => 'SESSION_ID='.session_id(), + ); + // 读取应用定义的Trace文件 + $traceFile = COMMON_PATH.'Conf/trace.php'; + if(is_file($traceFile)) { + $base = array_merge($base,include $traceFile); + } + + $debug = trace(); + $tabs = C('TRACE_PAGE_TABS'); + foreach ($tabs as $name=>$title){ + switch(strtoupper($name)) { + case 'BASE':// 基本信息 + $trace[$title] = $base; + break; + case 'FILE': // 文件信息 + $trace[$title] = $info; + break; + default:// 调试信息 + $name = strtoupper($name); + if(strpos($name,'|')) {// 多组信息 + $array = explode('|',$name); + $result = array(); + foreach($array as $name){ + $result += isset($debug[$name])?$debug[$name]:array(); + } + $trace[$title] = $result; + }else{ + $trace[$title] = isset($debug[$name])?$debug[$name]:''; + } + } + } + chrome_debug('TRACE信息:'.__SELF__,'group'); + //输出日志 + foreach($trace as $title=>$log){ + '错误'==$title?chrome_debug($title,'group'):chrome_debug($title,'groupCollapsed'); + foreach($log as $i=>$logstr){ + chrome_debug($i.'.'.$logstr,'log'); + } + chrome_debug('','groupEnd'); + } + chrome_debug('','groupEnd'); + if($save = C('PAGE_TRACE_SAVE')) { // 保存页面Trace日志 + if(is_array($save)) {// 选择选项卡保存 + $tabs = C('TRACE_PAGE_TABS'); + $array = array(); + foreach ($save as $tab){ + $array[] = $tabs[$tab]; + } + } + $content = date('[ c ]').' '.get_client_ip().' '.$_SERVER['REQUEST_URI']."\r\n"; + foreach ($trace as $key=>$val){ + if(!isset($array) || in_array($key,$array)) { + $content .= '[ '.$key." ]\r\n"; + if(is_array($val)) { + foreach ($val as $k=>$v){ + $content .= (!is_numeric($k)?$k.':':'').print_r($v,true)."\r\n"; + } + }else{ + $content .= print_r($val,true)."\r\n"; + } + $content .= "\r\n"; + } + } + error_log(str_replace('
',"\r\n",$content), Log::FILE,LOG_PATH.date('y_m_d').'_trace.log'); + } + unset($files,$info,$base); + } + + /** + * 获取运行时间 + */ + private function showTime() { + // 显示运行时间 + G('beginTime',$GLOBALS['_beginTime']); + G('viewEndTime'); + // 显示详细运行时间 + 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 )'; + } +} +if(!function_exists('chrome_debug')){ +//ChromePhp 输出trace的函数 +function chrome_debug($msg,$type='trace',$trace_level=1){ + if('trace'==$type){ + ChromePhp::groupCollapsed($msg); + $traces=debug_backtrace(false); + $traces=array_reverse($traces); + $max=count($traces)-$trace_level; + for($i=0;$i<$max;$i++){ + $trace=$traces[$i]; + $fun=isset($trace['class'])?$trace['class'].'::'.$trace['function']:$trace['function']; + $file=isset($trace['file'])?$trace['file']:'unknown file'; + $line=isset($trace['line'])?$trace['line']:'unknown line'; + $trace_msg='#'.$i.' '.$fun.' called at ['.$file.':'.$line.']'; + if(!empty($trace['args'])){ + ChromePhp::groupCollapsed($trace_msg); + ChromePhp::log($trace['args']); + ChromePhp::groupEnd(); + }else{ + ChromePhp::log($trace_msg); + } + } + ChromePhp::groupEnd(); + }else{ + if(method_exists('Behavior\ChromePhp',$type)){ + //支持type trace,warn,log,error,group, groupCollapsed, groupEnd等 + call_user_func(array('Behavior\ChromePhp',$type),$msg); + }else{ + //如果type不为trace,warn,log等,则为log的标签 + call_user_func_array(array('Behavior\ChromePhp','log'),func_get_args()); + } + } +} + + + +/** + * Server Side Chrome PHP debugger class + * + * @package ChromePhp + * @author Craig Campbell + */ +class ChromePhp{ + /** + * @var string + */ + const VERSION = '4.1.0'; + + /** + * @var string + */ + const HEADER_NAME = 'X-ChromeLogger-Data'; + + /** + * @var string + */ + const BACKTRACE_LEVEL = 'backtrace_level'; + + /** + * @var string + */ + const LOG = 'log'; + + /** + * @var string + */ + const WARN = 'warn'; + + /** + * @var string + */ + const ERROR = 'error'; + + /** + * @var string + */ + const GROUP = 'group'; + + /** + * @var string + */ + const INFO = 'info'; + + /** + * @var string + */ + const GROUP_END = 'groupEnd'; + + /** + * @var string + */ + const GROUP_COLLAPSED = 'groupCollapsed'; + + /** + * @var string + */ + const TABLE = 'table'; + + /** + * @var string + */ + protected $_php_version; + + /** + * @var int + */ + protected $_timestamp; + + /** + * @var array + */ + protected $_json = array( + 'version' => self::VERSION, + 'columns' => array('log', 'backtrace', 'type'), + 'rows' => array() + ); + + /** + * @var array + */ + protected $_backtraces = array(); + + /** + * @var bool + */ + protected $_error_triggered = false; + + /** + * @var array + */ + protected $_settings = array( + self::BACKTRACE_LEVEL => 1 + ); + + /** + * @var ChromePhp + */ + protected static $_instance; + + /** + * Prevent recursion when working with objects referring to each other + * + * @var array + */ + protected $_processed = array(); + + /** + * constructor + */ + private function __construct() + { + $this->_php_version = phpversion(); + $this->_timestamp = $this->_php_version >= 5.1 ? $_SERVER['REQUEST_TIME'] : time(); + $this->_json['request_uri'] = $_SERVER['REQUEST_URI']; + } + + /** + * gets instance of this class + * + * @return ChromePhp + */ + public static function getInstance() + { + if (self::$_instance === null) { + self::$_instance = new self(); + } + return self::$_instance; + } + + /** + * logs a variable to the console + * + * @param mixed $data,... unlimited OPTIONAL number of additional logs [...] + * @return void + */ + public static function log() + { + $args = func_get_args(); + return self::_log('', $args); + } + + /** + * logs a warning to the console + * + * @param mixed $data,... unlimited OPTIONAL number of additional logs [...] + * @return void + */ + public static function warn() + { + $args = func_get_args(); + return self::_log(self::WARN, $args); + } + + /** + * logs an error to the console + * + * @param mixed $data,... unlimited OPTIONAL number of additional logs [...] + * @return void + */ + public static function error() + { + $args = func_get_args(); + return self::_log(self::ERROR, $args); + } + + /** + * sends a group log + * + * @param string value + */ + public static function group() + { + $args = func_get_args(); + return self::_log(self::GROUP, $args); + } + + /** + * sends an info log + * + * @param mixed $data,... unlimited OPTIONAL number of additional logs [...] + * @return void + */ + public static function info() + { + $args = func_get_args(); + return self::_log(self::INFO, $args); + } + + /** + * sends a collapsed group log + * + * @param string value + */ + public static function groupCollapsed() + { + $args = func_get_args(); + return self::_log(self::GROUP_COLLAPSED, $args); + } + + /** + * ends a group log + * + * @param string value + */ + public static function groupEnd() + { + $args = func_get_args(); + return self::_log(self::GROUP_END, $args); + } + + /** + * sends a table log + * + * @param string value + */ + public static function table() + { + $args = func_get_args(); + return self::_log(self::TABLE, $args); + } + + /** + * internal logging call + * + * @param string $type + * @return void + */ + protected static function _log($type, array $args) + { + // nothing passed in, don't do anything + if (count($args) == 0 && $type != self::GROUP_END) { + return; + } + + $logger = self::getInstance(); + + $logger->_processed = array(); + + $logs = array(); + foreach ($args as $arg) { + $logs[] = $logger->_convert($arg); + } + + $backtrace = debug_backtrace(false); + $level = $logger->getSetting(self::BACKTRACE_LEVEL); + + $backtrace_message = 'unknown'; + if (isset($backtrace[$level]['file']) && isset($backtrace[$level]['line'])) { + $backtrace_message = $backtrace[$level]['file'] . ' : ' . $backtrace[$level]['line']; + } + + $logger->_addRow($logs, $backtrace_message, $type); + } + + /** + * converts an object to a better format for logging + * + * @param Object + * @return array + */ + protected function _convert($object) + { + // if this isn't an object then just return it + if (!is_object($object)) { + return $object; + } + + //Mark this object as processed so we don't convert it twice and it + //Also avoid recursion when objects refer to each other + $this->_processed[] = $object; + + $object_as_array = array(); + + // first add the class name + $object_as_array['___class_name'] = get_class($object); + + // loop through object vars + $object_vars = get_object_vars($object); + foreach ($object_vars as $key => $value) { + + // same instance as parent object + if ($value === $object || in_array($value, $this->_processed, true)) { + $value = 'recursion - parent object [' . get_class($value) . ']'; + } + $object_as_array[$key] = $this->_convert($value); + } + + $reflection = new ReflectionClass($object); + + // loop through the properties and add those + foreach ($reflection->getProperties() as $property) { + + // if one of these properties was already added above then ignore it + if (array_key_exists($property->getName(), $object_vars)) { + continue; + } + $type = $this->_getPropertyKey($property); + + if ($this->_php_version >= 5.3) { + $property->setAccessible(true); + } + + try { + $value = $property->getValue($object); + } catch (ReflectionException $e) { + $value = 'only PHP 5.3 can access private/protected properties'; + } + + // same instance as parent object + if ($value === $object || in_array($value, $this->_processed, true)) { + $value = 'recursion - parent object [' . get_class($value) . ']'; + } + + $object_as_array[$type] = $this->_convert($value); + } + return $object_as_array; + } + + /** + * takes a reflection property and returns a nicely formatted key of the property name + * + * @param ReflectionProperty + * @return string + */ + protected function _getPropertyKey(ReflectionProperty $property) + { + $static = $property->isStatic() ? ' static' : ''; + if ($property->isPublic()) { + return 'public' . $static . ' ' . $property->getName(); + } + + if ($property->isProtected()) { + return 'protected' . $static . ' ' . $property->getName(); + } + + if ($property->isPrivate()) { + return 'private' . $static . ' ' . $property->getName(); + } + } + + /** + * adds a value to the data array + * + * @var mixed + * @return void + */ + protected function _addRow(array $logs, $backtrace, $type) + { + // if this is logged on the same line for example in a loop, set it to null to save space + if (in_array($backtrace, $this->_backtraces)) { + $backtrace = null; + } + + // for group, groupEnd, and groupCollapsed + // take out the backtrace since it is not useful + if ($type == self::GROUP || $type == self::GROUP_END || $type == self::GROUP_COLLAPSED) { + $backtrace = null; + } + + if ($backtrace !== null) { + $this->_backtraces[] = $backtrace; + } + + $row = array($logs, $backtrace, $type); + + $this->_json['rows'][] = $row; + $this->_writeHeader($this->_json); + } + + protected function _writeHeader($data) + { + header(self::HEADER_NAME . ': ' . $this->_encode($data)); + } + + /** + * encodes the data to be sent along with the request + * + * @param array $data + * @return string + */ + protected function _encode($data) + { + return base64_encode(utf8_encode(json_encode($data))); + } + + /** + * adds a setting + * + * @param string key + * @param mixed value + * @return void + */ + public function addSetting($key, $value) + { + $this->_settings[$key] = $value; + } + + /** + * add ability to set multiple settings in one call + * + * @param array $settings + * @return void + */ + public function addSettings(array $settings) + { + foreach ($settings as $key => $value) { + $this->addSetting($key, $value); + } + } + + /** + * gets a setting + * + * @param string key + * @return mixed + */ + public function getSetting($key) + { + if (!isset($this->_settings[$key])) { + return null; + } + return $this->_settings[$key]; + } +} +} diff --git a/ThinkPHP/Lib/Behavior/ContentReplaceBehavior.class.php b/ThinkPHP/Library/Behavior/ContentReplaceBehavior.class.php similarity index 78% rename from ThinkPHP/Lib/Behavior/ContentReplaceBehavior.class.php rename to ThinkPHP/Library/Behavior/ContentReplaceBehavior.class.php index 0c899ead1..39c94557e 100644 --- a/ThinkPHP/Lib/Behavior/ContentReplaceBehavior.class.php +++ b/ThinkPHP/Library/Behavior/ContentReplaceBehavior.class.php @@ -2,20 +2,17 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK IT ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006-2013 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- - +namespace Behavior; +use Think\Behavior; defined('THINK_PATH') or exit(); /** * 系统行为扩展:模板内容输出替换 - * @category Think - * @package Think - * @subpackage Behavior - * @author liu21st */ class ContentReplaceBehavior extends Behavior { // 行为参数定义 @@ -37,14 +34,13 @@ public function run(&$content){ protected function templateContentReplace($content) { // 系统默认的特殊变量替换 $replace = array( - '__TMPL__' => APP_TMPL_PATH, // 项目模板目录 '__ROOT__' => __ROOT__, // 当前网站地址 - '__APP__' => __APP__, // 当前项目地址 - '__GROUP__' => defined('GROUP_NAME')?__GROUP__:__APP__, + '__APP__' => __APP__, // 当前应用地址 + '__MODULE__' => __MODULE__, '__ACTION__' => __ACTION__, // 当前操作地址 '__SELF__' => __SELF__, // 当前页面地址 - '__URL__' => __URL__, - '../Public' => APP_TMPL_PATH.'Public',// 项目公共模板目录 + '__CONTROLLER__'=> __CONTROLLER__, + '__URL__' => __CONTROLLER__, '__PUBLIC__' => __ROOT__.'/Public',// 站点公共目录 ); // 允许用户自定义模板的字符串替换 diff --git a/ThinkPHP/Library/Behavior/CronRunBehavior.class.php b/ThinkPHP/Library/Behavior/CronRunBehavior.class.php new file mode 100644 index 000000000..fa0335db4 --- /dev/null +++ b/ThinkPHP/Library/Behavior/CronRunBehavior.class.php @@ -0,0 +1,74 @@ + +// +---------------------------------------------------------------------- + +namespace Behavior; +use Think\Behavior; +defined('THINK_PATH') or exit(); +/** + * 自动执行任务 + * @category Extend + * @package Extend + * @subpackage Behavior + * @author liu21st + */ +class CronRunBehavior extends Behavior { + protected $options = array( + 'CRON_MAX_TIME' => 60, // 单个任务最大执行时间 + ); + public function run(&$params) { + // 锁定自动执行 + $lockfile = RUNTIME_PATH.'cron.lock'; + if(is_writable($lockfile) && filemtime($lockfile) > $_SERVER['REQUEST_TIME'] - C('CRON_MAX_TIME')) { + return ; + } else { + touch($lockfile); + } + set_time_limit(1000); + ignore_user_abort(true); + + // 载入cron配置文件 + // 格式 return array( + // 'cronname'=>array('filename',intervals,nextruntime),... + // ); + if(is_file(RUNTIME_PATH.'~crons.php')) { + $crons = include RUNTIME_PATH.'~crons.php'; + }elseif(is_file(CONF_PATH.'crons.php')){ + $crons = include CONF_PATH.'crons.php'; + } + if(isset($crons) && is_array($crons)) { + $update = false; + $log = array(); + foreach ($crons as $key=>$cron){ + if(empty($cron[2]) || $_SERVER['REQUEST_TIME']>=$cron[2]) { + // 到达时间 执行cron文件 + G('cronStart'); + include LIB_PATH.'Cron/'.$cron[0].'.php'; + $_useTime = G('cronStart','cronEnd', 6); + // 更新cron记录 + $cron[2] = $_SERVER['REQUEST_TIME']+$cron[1]; + $crons[$key] = $cron; + $log[] = "Cron:$key Runat ".date('Y-m-d H:i:s')." Use $_useTime s\n"; + $update = true; + } + } + if($update) { + // 记录Cron执行日志 + Log::write(implode('',$log)); + // 更新cron文件 + $content = ""; + file_put_contents(RUNTIME_PATH.'~crons.php',$content); + } + } + // 解除锁定 + unlink($lockfile); + return ; + } +} \ No newline at end of file diff --git a/ThinkPHP/Library/Behavior/FireShowPageTraceBehavior.class.php b/ThinkPHP/Library/Behavior/FireShowPageTraceBehavior.class.php new file mode 100644 index 000000000..08adf37d4 --- /dev/null +++ b/ThinkPHP/Library/Behavior/FireShowPageTraceBehavior.class.php @@ -0,0 +1,2094 @@ + +// +---------------------------------------------------------------------- +// $Id$ + +/** + +------------------------------------------------------------------------------ + * 将Trace信息输出到火狐的firebug,从而不影响ajax效果和页面的布局。 + +------------------------------------------------------------------------------ + * 使用前,你需要先在火狐浏览器上安装firebug和firePHP两个插件。 + * 定义应用的tags.php文件, + * + * array( + * 'FireShowPageTrace' + * ) + * ); + * + * 再将此文件放到应用的Behavior文件夹中即可 + * 如果trace信息没有正常输出,请查看您的日志。 + * firePHP,是通过http headers和firebug通讯的,所以要保证在输出trace信息之前不能有 + * headers输出,你可以在入口文件第一行加入代码 ob_start(); 或者配置output_buffering + * + */ +namespace Behavior; +use Think\Behavior; +defined('THINK_PATH') or exit(); +/** + +------------------------------------------------------------------------------ + * 系统行为扩展 页面Trace显示输出 + +------------------------------------------------------------------------------ + */ +class FireShowPageTraceBehavior extends Behavior { + // 行为参数定义 + protected $options = array( + 'FIRE_SHOW_PAGE_TRACE'=> true, // 显示页面Trace信息 + 'TRACE_PAGE_TABS'=> array('BASE'=>'基本','FILE'=>'文件','INFO'=>'流程','ERR|NOTIC'=>'错误','SQL'=>'SQL','DEBUG'=>'调试') + ); + + // 行为扩展的执行入口必须是run + public function run(&$params){ + if(C('FIRE_SHOW_PAGE_TRACE')) $this->showTrace(); + } + + /** + +---------------------------------------------------------- + * 显示页面Trace信息 + +---------------------------------------------------------- + * @access private + +---------------------------------------------------------- + */ + private function showTrace() { + // 系统默认显示信息 + $files = get_included_files(); + $info = array(); + foreach ($files as $key=>$file){ + $info[] = $file.' ( '.number_format(filesize($file)/1024,2).' KB )'; + } + $trace = array(); + $base = array( + '请求信息'=> date('Y-m-d H:i:s',$_SERVER['REQUEST_TIME']).' '.$_SERVER['SERVER_PROTOCOL'].' '.$_SERVER['REQUEST_METHOD'].' : '.__SELF__, + '运行时间'=> $this->showTime(), + '内存开销'=> MEMORY_LIMIT_ON?number_format((memory_get_usage() - $GLOBALS['_startUseMems'])/1024,2).' kb':'不支持', + '查询信息'=> N('db_query').' queries '.N('db_write').' writes ', + '文件加载'=> count(get_included_files()), + '缓存信息'=> N('cache_read').' gets '.N('cache_write').' writes ', + '配置加载'=> count(c()), + '会话信息'=> 'SESSION_ID='.session_id(), + ); + // 读取应用定义的Trace文件 + $traceFile = CONF_PATH.'trace.php'; + if(is_file($traceFile)) { + $base = array_merge($base,include $traceFile); + } + $debug = trace(); + $tabs = C('TRACE_PAGE_TABS'); + foreach ($tabs as $name=>$title){ + switch(strtoupper($name)) { + case 'BASE':// 基本信息 + $trace[$title] = $base; + break; + case 'FILE': // 文件信息 + $trace[$title] = $info; + break; + default:// 调试信息 + if(strpos($name,'|')) {// 多组信息 + $array = explode('|',$name); + $result = array(); + foreach($array as $name){ + $result += isset($debug[$name])?$debug[$name]:array(); + } + $trace[$title] = $result; + }else{ + $trace[$title] = isset($debug[$name])?$debug[$name]:''; + } + } + } + foreach ($trace as $key=>$val){ + if(!is_array($val) && empty($val)) + $val=array(); + if(is_array($val)){ + $fire=array( + array('','') + ); + foreach($val as $k=>$v){ + $fire[]=array($k,$v); + } + fb(array($key,$fire),FirePHP::TABLE); + }else{ + fb($val,$key); + } + } + unset($files,$info,$log,$base); + } + + /** + +---------------------------------------------------------- + * 获取运行时间 + +---------------------------------------------------------- + */ + private function showTime() { + // 显示运行时间 + G('beginTime',$GLOBALS['_beginTime']); + G('viewEndTime'); + // 显示详细运行时间 + 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 )'; + } + +} + + +function fb() +{ + $instance = FirePHP::getInstance(true); + + $args = func_get_args(); + return call_user_func_array(array($instance,'fb'),$args); +} + + +class FB +{ + /** + * Enable and disable logging to Firebug + * + * @see FirePHP->setEnabled() + * @param boolean $Enabled TRUE to enable, FALSE to disable + * @return void + */ + public static function setEnabled($Enabled) + { + $instance = FirePHP::getInstance(true); + $instance->setEnabled($Enabled); + } + + /** + * Check if logging is enabled + * + * @see FirePHP->getEnabled() + * @return boolean TRUE if enabled + */ + public static function getEnabled() + { + $instance = FirePHP::getInstance(true); + return $instance->getEnabled(); + } + + /** + * Specify a filter to be used when encoding an object + * + * Filters are used to exclude object members. + * + * @see FirePHP->setObjectFilter() + * @param string $Class The class name of the object + * @param array $Filter An array or members to exclude + * @return void + */ + public static function setObjectFilter($Class, $Filter) + { + $instance = FirePHP::getInstance(true); + $instance->setObjectFilter($Class, $Filter); + } + + /** + * Set some options for the library + * + * @see FirePHP->setOptions() + * @param array $Options The options to be set + * @return void + */ + public static function setOptions($Options) + { + $instance = FirePHP::getInstance(true); + $instance->setOptions($Options); + } + + /** + * Get options for the library + * + * @see FirePHP->getOptions() + * @return array The options + */ + public static function getOptions() + { + $instance = FirePHP::getInstance(true); + return $instance->getOptions(); + } + + /** + * Log object to firebug + * + * @see http://www.firephp.org/Wiki/Reference/Fb + * @param mixed $Object + * @return true + * @throws Exception + */ + public static function send() + { + $instance = FirePHP::getInstance(true); + $args = func_get_args(); + return call_user_func_array(array($instance,'fb'),$args); + } + + /** + * Start a group for following messages + * + * Options: + * Collapsed: [true|false] + * Color: [#RRGGBB|ColorName] + * + * @param string $Name + * @param array $Options OPTIONAL Instructions on how to log the group + * @return true + */ + public static function group($Name, $Options=null) + { + $instance = FirePHP::getInstance(true); + return $instance->group($Name, $Options); + } + + /** + * Ends a group you have started before + * + * @return true + * @throws Exception + */ + public static function groupEnd() + { + return self::send(null, null, FirePHP::GROUP_END); + } + + /** + * Log object with label to firebug console + * + * @see FirePHP::LOG + * @param mixes $Object + * @param string $Label + * @return true + * @throws Exception + */ + public static function log($Object, $Label=null) + { + return self::send($Object, $Label, FirePHP::LOG); + } + + /** + * Log object with label to firebug console + * + * @see FirePHP::INFO + * @param mixes $Object + * @param string $Label + * @return true + * @throws Exception + */ + public static function info($Object, $Label=null) + { + return self::send($Object, $Label, FirePHP::INFO); + } + + /** + * Log object with label to firebug console + * + * @see FirePHP::WARN + * @param mixes $Object + * @param string $Label + * @return true + * @throws Exception + */ + public static function warn($Object, $Label=null) + { + return self::send($Object, $Label, FirePHP::WARN); + } + + /** + * Log object with label to firebug console + * + * @see FirePHP::ERROR + * @param mixes $Object + * @param string $Label + * @return true + * @throws Exception + */ + public static function error($Object, $Label=null) + { + return self::send($Object, $Label, FirePHP::ERROR); + } + + /** + * Dumps key and variable to firebug server panel + * + * @see FirePHP::DUMP + * @param string $Key + * @param mixed $Variable + * @return true + * @throws Exception + */ + public static function dump($Key, $Variable) + { + return self::send($Variable, $Key, FirePHP::DUMP); + } + + /** + * Log a trace in the firebug console + * + * @see FirePHP::TRACE + * @param string $Label + * @return true + * @throws Exception + */ + public static function trace($Label) + { + return self::send($Label, FirePHP::TRACE); + } + + /** + * Log a table in the firebug console + * + * @see FirePHP::TABLE + * @param string $Label + * @param string $Table + * @return true + * @throws Exception + */ + public static function table($Label, $Table) + { + return self::send($Table, $Label, FirePHP::TABLE); + } + +} + +if (!defined('E_STRICT')) { + define('E_STRICT', 2048); +} +if (!defined('E_RECOVERABLE_ERROR')) { + define('E_RECOVERABLE_ERROR', 4096); +} +if (!defined('E_DEPRECATED')) { + define('E_DEPRECATED', 8192); +} +if (!defined('E_USER_DEPRECATED')) { + define('E_USER_DEPRECATED', 16384); +} + +/** + * Sends the given data to the FirePHP Firefox Extension. + * The data can be displayed in the Firebug Console or in the + * "Server" request tab. + * + * For more information see: http://www.firephp.org/ + * + * @copyright Copyright (C) 2007-2009 Christoph Dorn + * @author Christoph Dorn + * @license http://www.opensource.org/licenses/bsd-license.php + * @package FirePHPCore + */ +class FirePHP { + + /** + * FirePHP version + * + * @var string + */ + const VERSION = '0.3'; // @pinf replace '0.3' with '%%package.version%%' + + /** + * Firebug LOG level + * + * Logs a message to firebug console. + * + * @var string + */ + const LOG = 'LOG'; + + /** + * Firebug INFO level + * + * Logs a message to firebug console and displays an info icon before the message. + * + * @var string + */ + const INFO = 'INFO'; + + /** + * Firebug WARN level + * + * Logs a message to firebug console, displays an warning icon before the message and colors the line turquoise. + * + * @var string + */ + const WARN = 'WARN'; + + /** + * Firebug ERROR level + * + * Logs a message to firebug console, displays an error icon before the message and colors the line yellow. Also increments the firebug error count. + * + * @var string + */ + const ERROR = 'ERROR'; + + /** + * Dumps a variable to firebug's server panel + * + * @var string + */ + const DUMP = 'DUMP'; + + /** + * Displays a stack trace in firebug console + * + * @var string + */ + const TRACE = 'TRACE'; + + /** + * Displays an exception in firebug console + * + * Increments the firebug error count. + * + * @var string + */ + const EXCEPTION = 'EXCEPTION'; + + /** + * Displays an table in firebug console + * + * @var string + */ + const TABLE = 'TABLE'; + + /** + * Starts a group in firebug console + * + * @var string + */ + const GROUP_START = 'GROUP_START'; + + /** + * Ends a group in firebug console + * + * @var string + */ + const GROUP_END = 'GROUP_END'; + + /** + * Singleton instance of FirePHP + * + * @var FirePHP + */ + protected static $instance = null; + + /** + * Flag whether we are logging from within the exception handler + * + * @var boolean + */ + protected $inExceptionHandler = false; + + /** + * Flag whether to throw PHP errors that have been converted to ErrorExceptions + * + * @var boolean + */ + protected $throwErrorExceptions = true; + + /** + * Flag whether to convert PHP assertion errors to Exceptions + * + * @var boolean + */ + protected $convertAssertionErrorsToExceptions = true; + + /** + * Flag whether to throw PHP assertion errors that have been converted to Exceptions + * + * @var boolean + */ + protected $throwAssertionExceptions = false; + + /** + * Wildfire protocol message index + * + * @var int + */ + protected $messageIndex = 1; + + /** + * Options for the library + * + * @var array + */ + protected $options = array('maxDepth' => 10, + 'maxObjectDepth' => 5, + 'maxArrayDepth' => 5, + 'useNativeJsonEncode' => true, + 'includeLineNumbers' => true); + + /** + * Filters used to exclude object members when encoding + * + * @var array + */ + protected $objectFilters = array( + 'firephp' => array('objectStack', 'instance', 'json_objectStack'), + 'firephp_test_class' => array('objectStack', 'instance', 'json_objectStack') + ); + + /** + * A stack of objects used to detect recursion during object encoding + * + * @var object + */ + protected $objectStack = array(); + + /** + * Flag to enable/disable logging + * + * @var boolean + */ + protected $enabled = true; + + /** + * The insight console to log to if applicable + * + * @var object + */ + protected $logToInsightConsole = null; + + /** + * When the object gets serialized only include specific object members. + * + * @return array + */ + public function __sleep() + { + return array('options','objectFilters','enabled'); + } + + /** + * Gets singleton instance of FirePHP + * + * @param boolean $AutoCreate + * @return FirePHP + */ + public static function getInstance($AutoCreate = false) + { + if ($AutoCreate===true && !self::$instance) { + self::init(); + } + return self::$instance; + } + + /** + * Creates FirePHP object and stores it for singleton access + * + * @return FirePHP + */ + public static function init() + { + return self::setInstance(new self()); + } + + /** + * Set the instance of the FirePHP singleton + * + * @param FirePHP $instance The FirePHP object instance + * @return FirePHP + */ + public static function setInstance($instance) + { + return self::$instance = $instance; + } + + /** + * Set an Insight console to direct all logging calls to + * + * @param object $console The console object to log to + * @return void + */ + public function setLogToInsightConsole($console) + { + if(is_string($console)) { + if(get_class($this)!='FirePHP_Insight' && !is_subclass_of($this, 'FirePHP_Insight')) { + throw new Exception('FirePHP instance not an instance or subclass of FirePHP_Insight!'); + } + $this->logToInsightConsole = $this->to('request')->console($console); + } else { + $this->logToInsightConsole = $console; + } + } + + /** + * Enable and disable logging to Firebug + * + * @param boolean $Enabled TRUE to enable, FALSE to disable + * @return void + */ + public function setEnabled($Enabled) + { + $this->enabled = $Enabled; + } + + /** + * Check if logging is enabled + * + * @return boolean TRUE if enabled + */ + public function getEnabled() + { + return $this->enabled; + } + + /** + * Specify a filter to be used when encoding an object + * + * Filters are used to exclude object members. + * + * @param string $Class The class name of the object + * @param array $Filter An array of members to exclude + * @return void + */ + public function setObjectFilter($Class, $Filter) + { + $this->objectFilters[strtolower($Class)] = $Filter; + } + + /** + * Set some options for the library + * + * Options: + * - maxDepth: The maximum depth to traverse (default: 10) + * - maxObjectDepth: The maximum depth to traverse objects (default: 5) + * - maxArrayDepth: The maximum depth to traverse arrays (default: 5) + * - useNativeJsonEncode: If true will use json_encode() (default: true) + * - includeLineNumbers: If true will include line numbers and filenames (default: true) + * + * @param array $Options The options to be set + * @return void + */ + public function setOptions($Options) + { + $this->options = array_merge($this->options,$Options); + } + + /** + * Get options from the library + * + * @return array The currently set options + */ + public function getOptions() + { + return $this->options; + } + + /** + * Set an option for the library + * + * @param string $Name + * @param mixed $Value + * @throws Exception + * @return void + */ + public function setOption($Name, $Value) + { + if (!isset($this->options[$Name])) { + throw $this->newException('Unknown option: ' . $Name); + } + $this->options[$Name] = $Value; + } + + /** + * Get an option from the library + * + * @param string $Name + * @throws Exception + * @return mixed + */ + public function getOption($Name) + { + if (!isset($this->options[$Name])) { + throw $this->newException('Unknown option: ' . $Name); + } + return $this->options[$Name]; + } + + /** + * Register FirePHP as your error handler + * + * Will throw exceptions for each php error. + * + * @return mixed Returns a string containing the previously defined error handler (if any) + */ + public function registerErrorHandler($throwErrorExceptions = false) + { + //NOTE: The following errors will not be caught by this error handler: + // E_ERROR, E_PARSE, E_CORE_ERROR, + // E_CORE_WARNING, E_COMPILE_ERROR, + // E_COMPILE_WARNING, E_STRICT + + $this->throwErrorExceptions = $throwErrorExceptions; + + return set_error_handler(array($this,'errorHandler')); + } + + /** + * FirePHP's error handler + * + * Throws exception for each php error that will occur. + * + * @param int $errno + * @param string $errstr + * @param string $errfile + * @param int $errline + * @param array $errcontext + */ + public function errorHandler($errno, $errstr, $errfile, $errline, $errcontext) + { + // Don't throw exception if error reporting is switched off + if (error_reporting() == 0) { + return; + } + // Only throw exceptions for errors we are asking for + if (error_reporting() & $errno) { + + $exception = new ErrorException($errstr, 0, $errno, $errfile, $errline); + if ($this->throwErrorExceptions) { + throw $exception; + } else { + $this->fb($exception); + } + } + } + + /** + * Register FirePHP as your exception handler + * + * @return mixed Returns the name of the previously defined exception handler, + * or NULL on error. + * If no previous handler was defined, NULL is also returned. + */ + public function registerExceptionHandler() + { + return set_exception_handler(array($this,'exceptionHandler')); + } + + /** + * FirePHP's exception handler + * + * Logs all exceptions to your firebug console and then stops the script. + * + * @param Exception $Exception + * @throws Exception + */ + function exceptionHandler($Exception) + { + + $this->inExceptionHandler = true; + + header('HTTP/1.1 500 Internal Server Error'); + + try { + $this->fb($Exception); + } catch (Exception $e) { + echo 'We had an exception: ' . $e; + } + $this->inExceptionHandler = false; + } + + /** + * Register FirePHP driver as your assert callback + * + * @param boolean $convertAssertionErrorsToExceptions + * @param boolean $throwAssertionExceptions + * @return mixed Returns the original setting or FALSE on errors + */ + public function registerAssertionHandler($convertAssertionErrorsToExceptions = true, $throwAssertionExceptions = false) + { + $this->convertAssertionErrorsToExceptions = $convertAssertionErrorsToExceptions; + $this->throwAssertionExceptions = $throwAssertionExceptions; + + if ($throwAssertionExceptions && !$convertAssertionErrorsToExceptions) { + throw $this->newException('Cannot throw assertion exceptions as assertion errors are not being converted to exceptions!'); + } + + return assert_options(ASSERT_CALLBACK, array($this, 'assertionHandler')); + } + + /** + * FirePHP's assertion handler + * + * Logs all assertions to your firebug console and then stops the script. + * + * @param string $file File source of assertion + * @param int $line Line source of assertion + * @param mixed $code Assertion code + */ + public function assertionHandler($file, $line, $code) + { + if ($this->convertAssertionErrorsToExceptions) { + + $exception = new ErrorException('Assertion Failed - Code[ '.$code.' ]', 0, null, $file, $line); + + if ($this->throwAssertionExceptions) { + throw $exception; + } else { + $this->fb($exception); + } + + } else { + $this->fb($code, 'Assertion Failed', FirePHP::ERROR, array('File'=>$file,'Line'=>$line)); + } + } + + /** + * Start a group for following messages. + * + * Options: + * Collapsed: [true|false] + * Color: [#RRGGBB|ColorName] + * + * @param string $Name + * @param array $Options OPTIONAL Instructions on how to log the group + * @return true + * @throws Exception + */ + public function group($Name, $Options = null) + { + + if (!$Name) { + throw $this->newException('You must specify a label for the group!'); + } + + if ($Options) { + if (!is_array($Options)) { + throw $this->newException('Options must be defined as an array!'); + } + if (array_key_exists('Collapsed', $Options)) { + $Options['Collapsed'] = ($Options['Collapsed'])?'true':'false'; + } + } + + return $this->fb(null, $Name, FirePHP::GROUP_START, $Options); + } + + /** + * Ends a group you have started before + * + * @return true + * @throws Exception + */ + public function groupEnd() + { + return $this->fb(null, null, FirePHP::GROUP_END); + } + + /** + * Log object with label to firebug console + * + * @see FirePHP::LOG + * @param mixes $Object + * @param string $Label + * @return true + * @throws Exception + */ + public function log($Object, $Label = null, $Options = array()) + { + return $this->fb($Object, $Label, FirePHP::LOG, $Options); + } + + /** + * Log object with label to firebug console + * + * @see FirePHP::INFO + * @param mixes $Object + * @param string $Label + * @return true + * @throws Exception + */ + public function info($Object, $Label = null, $Options = array()) + { + return $this->fb($Object, $Label, FirePHP::INFO, $Options); + } + + /** + * Log object with label to firebug console + * + * @see FirePHP::WARN + * @param mixes $Object + * @param string $Label + * @return true + * @throws Exception + */ + public function warn($Object, $Label = null, $Options = array()) + { + return $this->fb($Object, $Label, FirePHP::WARN, $Options); + } + + /** + * Log object with label to firebug console + * + * @see FirePHP::ERROR + * @param mixes $Object + * @param string $Label + * @return true + * @throws Exception + */ + public function error($Object, $Label = null, $Options = array()) + { + return $this->fb($Object, $Label, FirePHP::ERROR, $Options); + } + + /** + * Dumps key and variable to firebug server panel + * + * @see FirePHP::DUMP + * @param string $Key + * @param mixed $Variable + * @return true + * @throws Exception + */ + public function dump($Key, $Variable, $Options = array()) + { + if (!is_string($Key)) { + throw $this->newException('Key passed to dump() is not a string'); + } + if (strlen($Key)>100) { + throw $this->newException('Key passed to dump() is longer than 100 characters'); + } + if (!preg_match_all('/^[a-zA-Z0-9-_\.:]*$/', $Key, $m)) { + throw $this->newException('Key passed to dump() contains invalid characters [a-zA-Z0-9-_\.:]'); + } + return $this->fb($Variable, $Key, FirePHP::DUMP, $Options); + } + + /** + * Log a trace in the firebug console + * + * @see FirePHP::TRACE + * @param string $Label + * @return true + * @throws Exception + */ + public function trace($Label) + { + return $this->fb($Label, FirePHP::TRACE); + } + + /** + * Log a table in the firebug console + * + * @see FirePHP::TABLE + * @param string $Label + * @param string $Table + * @return true + * @throws Exception + */ + public function table($Label, $Table, $Options = array()) + { + return $this->fb($Table, $Label, FirePHP::TABLE, $Options); + } + + /** + * Insight API wrapper + * + * @see Insight_Helper::to() + */ + public static function to() + { + $instance = self::getInstance(); + if (!method_exists($instance, "_to")) { + throw new Exception("FirePHP::to() implementation not loaded"); + } + $args = func_get_args(); + return call_user_func_array(array($instance, '_to'), $args); + } + + /** + * Insight API wrapper + * + * @see Insight_Helper::plugin() + */ + public static function plugin() + { + $instance = self::getInstance(); + if (!method_exists($instance, "_plugin")) { + throw new Exception("FirePHP::plugin() implementation not loaded"); + } + $args = func_get_args(); + return call_user_func_array(array($instance, '_plugin'), $args); + } + + /** + * Check if FirePHP is installed on client + * + * @return boolean + */ + public function detectClientExtension() + { + // Check if FirePHP is installed on client via User-Agent header + if (@preg_match_all('/\sFirePHP\/([\.\d]*)\s?/si',$this->getUserAgent(),$m) && + version_compare($m[1][0],'0.0.6','>=')) { + return true; + } else + // Check if FirePHP is installed on client via X-FirePHP-Version header + if (@preg_match_all('/^([\.\d]*)$/si',$this->getRequestHeader("X-FirePHP-Version"),$m) && + version_compare($m[1][0],'0.0.6','>=')) { + return true; + } + return false; + } + + /** + * Log varible to Firebug + * + * @see http://www.firephp.org/Wiki/Reference/Fb + * @param mixed $Object The variable to be logged + * @return true Return TRUE if message was added to headers, FALSE otherwise + * @throws Exception + */ + public function fb($Object) + { + if($this instanceof FirePHP_Insight && method_exists($this, '_logUpgradeClientMessage')) { + if(!FirePHP_Insight::$upgradeClientMessageLogged) { // avoid infinite recursion as _logUpgradeClientMessage() logs a message + $this->_logUpgradeClientMessage(); + } + } + + static $insightGroupStack = array(); + + if (!$this->getEnabled()) { + return false; + } + + if ($this->headersSent($filename, $linenum)) { + // If we are logging from within the exception handler we cannot throw another exception + if ($this->inExceptionHandler) { + // Simply echo the error out to the page + echo '
FirePHP ERROR: Headers already sent in '.$filename.' on line '.$linenum.'. Cannot send log data to FirePHP. You must have Output Buffering enabled via ob_start() or output_buffering ini directive.
'; + } else { + throw $this->newException('Headers already sent in '.$filename.' on line '.$linenum.'. Cannot send log data to FirePHP. You must have Output Buffering enabled via ob_start() or output_buffering ini directive.'); + } + } + + $Type = null; + $Label = null; + $Options = array(); + + if (func_num_args()==1) { + } else + if (func_num_args()==2) { + switch(func_get_arg(1)) { + case self::LOG: + case self::INFO: + case self::WARN: + case self::ERROR: + case self::DUMP: + case self::TRACE: + case self::EXCEPTION: + case self::TABLE: + case self::GROUP_START: + case self::GROUP_END: + $Type = func_get_arg(1); + break; + default: + $Label = func_get_arg(1); + break; + } + } else + if (func_num_args()==3) { + $Type = func_get_arg(2); + $Label = func_get_arg(1); + } else + if (func_num_args()==4) { + $Type = func_get_arg(2); + $Label = func_get_arg(1); + $Options = func_get_arg(3); + } else { + throw $this->newException('Wrong number of arguments to fb() function!'); + } + + if($this->logToInsightConsole!==null && (get_class($this)=='FirePHP_Insight' || is_subclass_of($this, 'FirePHP_Insight'))) { + $msg = $this->logToInsightConsole; + if ($Object instanceof Exception) { + $Type = self::EXCEPTION; + } + if($Label && $Type!=self::TABLE && $Type!=self::GROUP_START) { + $msg = $msg->label($Label); + } + switch($Type) { + case self::DUMP: + case self::LOG: + return $msg->log($Object); + case self::INFO: + return $msg->info($Object); + case self::WARN: + return $msg->warn($Object); + case self::ERROR: + return $msg->error($Object); + case self::TRACE: + return $msg->trace($Object); + case self::EXCEPTION: + return $this->plugin('engine')->handleException($Object, $msg); + case self::TABLE: + if (isset($Object[0]) && !is_string($Object[0]) && $Label) { + $Object = array($Label, $Object); + } + return $msg->table($Object[0], array_slice($Object[1],1), $Object[1][0]); + case self::GROUP_START: + $insightGroupStack[] = $msg->group(md5($Label))->open(); + return $msg->log($Label); + case self::GROUP_END: + if(count($insightGroupStack)==0) { + throw new Error('Too many groupEnd() as opposed to group() calls!'); + } + $group = array_pop($insightGroupStack); + return $group->close(); + default: + return $msg->log($Object); + } + } + + if (!$this->detectClientExtension()) { + return false; + } + + $meta = array(); + $skipFinalObjectEncode = false; + + if ($Object instanceof Exception) { + + $meta['file'] = $this->_escapeTraceFile($Object->getFile()); + $meta['line'] = $Object->getLine(); + + $trace = $Object->getTrace(); + if ($Object instanceof ErrorException + && isset($trace[0]['function']) + && $trace[0]['function']=='errorHandler' + && isset($trace[0]['class']) + && $trace[0]['class']=='FirePHP') { + + $severity = false; + switch($Object->getSeverity()) { + case E_WARNING: $severity = 'E_WARNING'; break; + case E_NOTICE: $severity = 'E_NOTICE'; break; + case E_USER_ERROR: $severity = 'E_USER_ERROR'; break; + case E_USER_WARNING: $severity = 'E_USER_WARNING'; break; + case E_USER_NOTICE: $severity = 'E_USER_NOTICE'; break; + case E_STRICT: $severity = 'E_STRICT'; break; + case E_RECOVERABLE_ERROR: $severity = 'E_RECOVERABLE_ERROR'; break; + case E_DEPRECATED: $severity = 'E_DEPRECATED'; break; + case E_USER_DEPRECATED: $severity = 'E_USER_DEPRECATED'; break; + } + + $Object = array('Class'=>get_class($Object), + 'Message'=>$severity.': '.$Object->getMessage(), + 'File'=>$this->_escapeTraceFile($Object->getFile()), + 'Line'=>$Object->getLine(), + 'Type'=>'trigger', + 'Trace'=>$this->_escapeTrace(array_splice($trace,2))); + $skipFinalObjectEncode = true; + } else { + $Object = array('Class'=>get_class($Object), + 'Message'=>$Object->getMessage(), + 'File'=>$this->_escapeTraceFile($Object->getFile()), + 'Line'=>$Object->getLine(), + 'Type'=>'throw', + 'Trace'=>$this->_escapeTrace($trace)); + $skipFinalObjectEncode = true; + } + $Type = self::EXCEPTION; + + } else + if ($Type==self::TRACE) { + + $trace = debug_backtrace(); + if (!$trace) return false; + for( $i=0 ; $i_standardizePath($trace[$i]['file']),-18,18)=='FirePHPCore/fb.php' + || substr($this->_standardizePath($trace[$i]['file']),-29,29)=='FirePHPCore/FirePHP.class.php')) { + /* Skip - FB::trace(), FB::send(), $firephp->trace(), $firephp->fb() */ + } else + if (isset($trace[$i]['class']) + && isset($trace[$i+1]['file']) + && $trace[$i]['class']=='FirePHP' + && substr($this->_standardizePath($trace[$i+1]['file']),-18,18)=='FirePHPCore/fb.php') { + /* Skip fb() */ + } else + if ($trace[$i]['function']=='fb' + || $trace[$i]['function']=='trace' + || $trace[$i]['function']=='send') { + + $Object = array('Class'=>isset($trace[$i]['class'])?$trace[$i]['class']:'', + 'Type'=>isset($trace[$i]['type'])?$trace[$i]['type']:'', + 'Function'=>isset($trace[$i]['function'])?$trace[$i]['function']:'', + 'Message'=>$trace[$i]['args'][0], + 'File'=>isset($trace[$i]['file'])?$this->_escapeTraceFile($trace[$i]['file']):'', + 'Line'=>isset($trace[$i]['line'])?$trace[$i]['line']:'', + 'Args'=>isset($trace[$i]['args'])?$this->encodeObject($trace[$i]['args']):'', + 'Trace'=>$this->_escapeTrace(array_splice($trace,$i+1))); + + $skipFinalObjectEncode = true; + $meta['file'] = isset($trace[$i]['file'])?$this->_escapeTraceFile($trace[$i]['file']):''; + $meta['line'] = isset($trace[$i]['line'])?$trace[$i]['line']:''; + break; + } + } + + } else + if ($Type==self::TABLE) { + + if (isset($Object[0]) && is_string($Object[0])) { + $Object[1] = $this->encodeTable($Object[1]); + } else { + $Object = $this->encodeTable($Object); + } + + $skipFinalObjectEncode = true; + + } else + if ($Type==self::GROUP_START) { + + if (!$Label) { + throw $this->newException('You must specify a label for the group!'); + } + + } else { + if ($Type===null) { + $Type = self::LOG; + } + } + + if ($this->options['includeLineNumbers']) { + if (!isset($meta['file']) || !isset($meta['line'])) { + + $trace = debug_backtrace(); + for( $i=0 ; $trace && $i_standardizePath($trace[$i]['file']),-18,18)=='FirePHPCore/fb.php' + || substr($this->_standardizePath($trace[$i]['file']),-29,29)=='FirePHPCore/FirePHP.class.php')) { + /* Skip - FB::trace(), FB::send(), $firephp->trace(), $firephp->fb() */ + } else + if (isset($trace[$i]['class']) + && isset($trace[$i+1]['file']) + && $trace[$i]['class']=='FirePHP' + && substr($this->_standardizePath($trace[$i+1]['file']),-18,18)=='FirePHPCore/fb.php') { + /* Skip fb() */ + } else + if (isset($trace[$i]['file']) + && substr($this->_standardizePath($trace[$i]['file']),-18,18)=='FirePHPCore/fb.php') { + /* Skip FB::fb() */ + } else { + $meta['file'] = isset($trace[$i]['file'])?$this->_escapeTraceFile($trace[$i]['file']):''; + $meta['line'] = isset($trace[$i]['line'])?$trace[$i]['line']:''; + break; + } + } + } + } else { + unset($meta['file']); + unset($meta['line']); + } + + $this->setHeader('X-Wf-Protocol-1','http://meta.wildfirehq.org/Protocol/JsonStream/0.2'); + $this->setHeader('X-Wf-1-Plugin-1','http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/'.self::VERSION); + + $structure_index = 1; + if ($Type==self::DUMP) { + $structure_index = 2; + $this->setHeader('X-Wf-1-Structure-2','http://meta.firephp.org/Wildfire/Structure/FirePHP/Dump/0.1'); + } else { + $this->setHeader('X-Wf-1-Structure-1','http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1'); + } + + if ($Type==self::DUMP) { + $msg = '{"'.$Label.'":'.$this->jsonEncode($Object, $skipFinalObjectEncode).'}'; + } else { + $msg_meta = $Options; + $msg_meta['Type'] = $Type; + if ($Label!==null) { + $msg_meta['Label'] = $Label; + } + if (isset($meta['file']) && !isset($msg_meta['File'])) { + $msg_meta['File'] = $meta['file']; + } + if (isset($meta['line']) && !isset($msg_meta['Line'])) { + $msg_meta['Line'] = $meta['line']; + } + $msg = '['.$this->jsonEncode($msg_meta).','.$this->jsonEncode($Object, $skipFinalObjectEncode).']'; + } + + $parts = explode("\n",chunk_split($msg, 5000, "\n")); + + for( $i=0 ; $i2) { + // Message needs to be split into multiple parts + $this->setHeader('X-Wf-1-'.$structure_index.'-'.'1-'.$this->messageIndex, + (($i==0)?strlen($msg):'') + . '|' . $part . '|' + . (($isetHeader('X-Wf-1-'.$structure_index.'-'.'1-'.$this->messageIndex, + strlen($part) . '|' . $part . '|'); + } + + $this->messageIndex++; + + if ($this->messageIndex > 99999) { + throw $this->newException('Maximum number (99,999) of messages reached!'); + } + } + } + + $this->setHeader('X-Wf-1-Index',$this->messageIndex-1); + + return true; + } + + /** + * Standardizes path for windows systems. + * + * @param string $Path + * @return string + */ + protected function _standardizePath($Path) + { + return preg_replace('/\\\\+/','/',$Path); + } + + /** + * Escape trace path for windows systems + * + * @param array $Trace + * @return array + */ + protected function _escapeTrace($Trace) + { + if (!$Trace) return $Trace; + for( $i=0 ; $i_escapeTraceFile($Trace[$i]['file']); + } + if (isset($Trace[$i]['args'])) { + $Trace[$i]['args'] = $this->encodeObject($Trace[$i]['args']); + } + } + return $Trace; + } + + /** + * Escape file information of trace for windows systems + * + * @param string $File + * @return string + */ + protected function _escapeTraceFile($File) + { + /* Check if we have a windows filepath */ + if (strpos($File,'\\')) { + /* First strip down to single \ */ + + $file = preg_replace('/\\\\+/','\\',$File); + + return $file; + } + return $File; + } + + /** + * Check if headers have already been sent + * + * @param string $Filename + * @param integer $Linenum + */ + protected function headersSent(&$Filename, &$Linenum) + { + return headers_sent($Filename, $Linenum); + } + + /** + * Send header + * + * @param string $Name + * @param string $Value + */ + protected function setHeader($Name, $Value) + { + return header($Name.': '.$Value); + } + + /** + * Get user agent + * + * @return string|false + */ + protected function getUserAgent() + { + if (!isset($_SERVER['HTTP_USER_AGENT'])) return false; + return $_SERVER['HTTP_USER_AGENT']; + } + + /** + * Get all request headers + * + * @return array + */ + public static function getAllRequestHeaders() { + static $_cached_headers = false; + if($_cached_headers!==false) { + return $_cached_headers; + } + $headers = array(); + if(function_exists('getallheaders')) { + foreach( getallheaders() as $name => $value ) { + $headers[strtolower($name)] = $value; + } + } else { + foreach($_SERVER as $name => $value) { + if(substr($name, 0, 5) == 'HTTP_') { + $headers[strtolower(str_replace(' ', '-', str_replace('_', ' ', substr($name, 5))))] = $value; + } + } + } + return $_cached_headers = $headers; + } + + /** + * Get a request header + * + * @return string|false + */ + protected function getRequestHeader($Name) + { + $headers = self::getAllRequestHeaders(); + if (isset($headers[strtolower($Name)])) { + return $headers[strtolower($Name)]; + } + return false; + } + + /** + * Returns a new exception + * + * @param string $Message + * @return Exception + */ + protected function newException($Message) + { + return new Exception($Message); + } + + /** + * Encode an object into a JSON string + * + * Uses PHP's jeson_encode() if available + * + * @param object $Object The object to be encoded + * @return string The JSON string + */ + public function jsonEncode($Object, $skipObjectEncode = false) + { + if (!$skipObjectEncode) { + $Object = $this->encodeObject($Object); + } + + if (function_exists('json_encode') + && $this->options['useNativeJsonEncode']!=false) { + + return json_encode($Object); + } else { + return $this->json_encode($Object); + } + } + + /** + * Encodes a table by encoding each row and column with encodeObject() + * + * @param array $Table The table to be encoded + * @return array + */ + protected function encodeTable($Table) + { + + if (!$Table) return $Table; + + $new_table = array(); + foreach($Table as $row) { + + if (is_array($row)) { + $new_row = array(); + + foreach($row as $item) { + $new_row[] = $this->encodeObject($item); + } + + $new_table[] = $new_row; + } + } + + return $new_table; + } + + /** + * Encodes an object including members with + * protected and private visibility + * + * @param Object $Object The object to be encoded + * @param int $Depth The current traversal depth + * @return array All members of the object + */ + protected function encodeObject($Object, $ObjectDepth = 1, $ArrayDepth = 1, $MaxDepth = 1) + { + if ($MaxDepth > $this->options['maxDepth']) { + return '** Max Depth ('.$this->options['maxDepth'].') **'; + } + + $return = array(); + + if (is_resource($Object)) { + + return '** '.(string)$Object.' **'; + + } else + if (is_object($Object)) { + + if ($ObjectDepth > $this->options['maxObjectDepth']) { + return '** Max Object Depth ('.$this->options['maxObjectDepth'].') **'; + } + + foreach ($this->objectStack as $refVal) { + if ($refVal === $Object) { + return '** Recursion ('.get_class($Object).') **'; + } + } + array_push($this->objectStack, $Object); + + $return['__className'] = $class = get_class($Object); + $class_lower = strtolower($class); + + $reflectionClass = new ReflectionClass($class); + $properties = array(); + foreach( $reflectionClass->getProperties() as $property) { + $properties[$property->getName()] = $property; + } + + $members = (array)$Object; + + foreach( $properties as $plain_name => $property ) { + + $name = $raw_name = $plain_name; + if ($property->isStatic()) { + $name = 'static:'.$name; + } + if ($property->isPublic()) { + $name = 'public:'.$name; + } else + if ($property->isPrivate()) { + $name = 'private:'.$name; + $raw_name = "\0".$class."\0".$raw_name; + } else + if ($property->isProtected()) { + $name = 'protected:'.$name; + $raw_name = "\0".'*'."\0".$raw_name; + } + + if (!(isset($this->objectFilters[$class_lower]) + && is_array($this->objectFilters[$class_lower]) + && in_array($plain_name,$this->objectFilters[$class_lower]))) { + + if (array_key_exists($raw_name,$members) + && !$property->isStatic()) { + + $return[$name] = $this->encodeObject($members[$raw_name], $ObjectDepth + 1, 1, $MaxDepth + 1); + + } else { + if (method_exists($property,'setAccessible')) { + $property->setAccessible(true); + $return[$name] = $this->encodeObject($property->getValue($Object), $ObjectDepth + 1, 1, $MaxDepth + 1); + } else + if ($property->isPublic()) { + $return[$name] = $this->encodeObject($property->getValue($Object), $ObjectDepth + 1, 1, $MaxDepth + 1); + } else { + $return[$name] = '** Need PHP 5.3 to get value **'; + } + } + } else { + $return[$name] = '** Excluded by Filter **'; + } + } + + // Include all members that are not defined in the class + // but exist in the object + foreach( $members as $raw_name => $value ) { + + $name = $raw_name; + + if ($name{0} == "\0") { + $parts = explode("\0", $name); + $name = $parts[2]; + } + + $plain_name = $name; + + if (!isset($properties[$name])) { + $name = 'undeclared:'.$name; + + if (!(isset($this->objectFilters[$class_lower]) + && is_array($this->objectFilters[$class_lower]) + && in_array($plain_name,$this->objectFilters[$class_lower]))) { + + $return[$name] = $this->encodeObject($value, $ObjectDepth + 1, 1, $MaxDepth + 1); + } else { + $return[$name] = '** Excluded by Filter **'; + } + } + } + + array_pop($this->objectStack); + + } elseif (is_array($Object)) { + + if ($ArrayDepth > $this->options['maxArrayDepth']) { + return '** Max Array Depth ('.$this->options['maxArrayDepth'].') **'; + } + + foreach ($Object as $key => $val) { + + // Encoding the $GLOBALS PHP array causes an infinite loop + // if the recursion is not reset here as it contains + // a reference to itself. This is the only way I have come up + // with to stop infinite recursion in this case. + if ($key=='GLOBALS' + && is_array($val) + && array_key_exists('GLOBALS',$val)) { + $val['GLOBALS'] = '** Recursion (GLOBALS) **'; + } + + $return[$key] = $this->encodeObject($val, 1, $ArrayDepth + 1, $MaxDepth + 1); + } + } else { + if (self::is_utf8($Object)) { + return $Object; + } else { + return utf8_encode($Object); + } + } + return $return; + } + + /** + * Returns true if $string is valid UTF-8 and false otherwise. + * + * @param mixed $str String to be tested + * @return boolean + */ + protected static function is_utf8($str) + { + if(function_exists('mb_detect_encoding')) { + return (mb_detect_encoding($str) == 'UTF-8'); + } + $c=0; $b=0; + $bits=0; + $len=strlen($str); + for($i=0; $i<$len; $i++){ + $c=ord($str[$i]); + if ($c > 128){ + if (($c >= 254)) return false; + elseif ($c >= 252) $bits=6; + elseif ($c >= 248) $bits=5; + elseif ($c >= 240) $bits=4; + elseif ($c >= 224) $bits=3; + elseif ($c >= 192) $bits=2; + else return false; + if (($i+$bits) > $len) return false; + while($bits > 1){ + $i++; + $b=ord($str[$i]); + if ($b < 128 || $b > 191) return false; + $bits--; + } + } + } + return true; + } + + /** + * Converts to and from JSON format. + * + * JSON (JavaScript Object Notation) is a lightweight data-interchange + * format. It is easy for humans to read and write. It is easy for machines + * to parse and generate. It is based on a subset of the JavaScript + * Programming Language, Standard ECMA-262 3rd Edition - December 1999. + * This feature can also be found in Python. JSON is a text format that is + * completely language independent but uses conventions that are familiar + * to programmers of the C-family of languages, including C, C++, C#, Java, + * JavaScript, Perl, TCL, and many others. These properties make JSON an + * ideal data-interchange language. + * + * This package provides a simple encoder and decoder for JSON notation. It + * is intended for use with client-side Javascript applications that make + * use of HTTPRequest to perform server communication functions - data can + * be encoded into JSON notation for use in a client-side javascript, or + * decoded from incoming Javascript requests. JSON format is native to + * Javascript, and can be directly eval()'ed with no further parsing + * overhead + * + * All strings should be in ASCII or UTF-8 format! + * + * LICENSE: Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: Redistributions of source code must retain the + * above copyright notice, this list of conditions and the following + * disclaimer. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN + * NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * @category + * @package Services_JSON + * @author Michal Migurski + * @author Matt Knapp + * @author Brett Stimmerman + * @author Christoph Dorn + * @copyright 2005 Michal Migurski + * @version CVS: $Id: JSON.php,v 1.31 2006/06/28 05:54:17 migurski Exp $ + * @license http://www.opensource.org/licenses/bsd-license.php + * @link http://pear.php.net/pepr/pepr-proposal-show.php?id=198 + */ + + + /** + * Keep a list of objects as we descend into the array so we can detect recursion. + */ + private $json_objectStack = array(); + + + /** + * convert a string from one UTF-8 char to one UTF-16 char + * + * Normally should be handled by mb_convert_encoding, but + * provides a slower PHP-only method for installations + * that lack the multibye string extension. + * + * @param string $utf8 UTF-8 character + * @return string UTF-16 character + * @access private + */ + private function json_utf82utf16($utf8) + { + // oh please oh please oh please oh please oh please + if (function_exists('mb_convert_encoding')) { + return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8'); + } + + switch(strlen($utf8)) { + case 1: + // this case should never be reached, because we are in ASCII range + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return $utf8; + + case 2: + // return a UTF-16 character from a 2-byte UTF-8 char + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr(0x07 & (ord($utf8{0}) >> 2)) + . chr((0xC0 & (ord($utf8{0}) << 6)) + | (0x3F & ord($utf8{1}))); + + case 3: + // return a UTF-16 character from a 3-byte UTF-8 char + // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + return chr((0xF0 & (ord($utf8{0}) << 4)) + | (0x0F & (ord($utf8{1}) >> 2))) + . chr((0xC0 & (ord($utf8{1}) << 6)) + | (0x7F & ord($utf8{2}))); + } + + // ignoring UTF-32 for now, sorry + return ''; + } + + /** + * encodes an arbitrary variable into JSON format + * + * @param mixed $var any number, boolean, string, array, or object to be encoded. + * see argument 1 to Services_JSON() above for array-parsing behavior. + * if var is a strng, note that encode() always expects it + * to be in ASCII or UTF-8 format! + * + * @return mixed JSON string representation of input var or an error if a problem occurs + * @access public + */ + private function json_encode($var) + { + + if (is_object($var)) { + if (in_array($var,$this->json_objectStack)) { + return '"** Recursion **"'; + } + } + + switch (gettype($var)) { + case 'boolean': + return $var ? 'true' : 'false'; + + case 'NULL': + return 'null'; + + case 'integer': + return (int) $var; + + case 'double': + case 'float': + return (float) $var; + + case 'string': + // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT + $ascii = ''; + $strlen_var = strlen($var); + + /* + * Iterate over every character in the string, + * escaping with a slash or encoding to UTF-8 where necessary + */ + for ($c = 0; $c < $strlen_var; ++$c) { + + $ord_var_c = ord($var{$c}); + + switch (true) { + case $ord_var_c == 0x08: + $ascii .= '\b'; + break; + case $ord_var_c == 0x09: + $ascii .= '\t'; + break; + case $ord_var_c == 0x0A: + $ascii .= '\n'; + break; + case $ord_var_c == 0x0C: + $ascii .= '\f'; + break; + case $ord_var_c == 0x0D: + $ascii .= '\r'; + break; + + case $ord_var_c == 0x22: + case $ord_var_c == 0x2F: + case $ord_var_c == 0x5C: + // double quote, slash, slosh + $ascii .= '\\'.$var{$c}; + break; + + case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)): + // characters U-00000000 - U-0000007F (same as ASCII) + $ascii .= $var{$c}; + break; + + case (($ord_var_c & 0xE0) == 0xC0): + // characters U-00000080 - U-000007FF, mask 110XXXXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, ord($var{$c + 1})); + $c += 1; + $utf16 = $this->json_utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xF0) == 0xE0): + // characters U-00000800 - U-0000FFFF, mask 1110XXXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2})); + $c += 2; + $utf16 = $this->json_utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xF8) == 0xF0): + // characters U-00010000 - U-001FFFFF, mask 11110XXX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2}), + ord($var{$c + 3})); + $c += 3; + $utf16 = $this->json_utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xFC) == 0xF8): + // characters U-00200000 - U-03FFFFFF, mask 111110XX + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2}), + ord($var{$c + 3}), + ord($var{$c + 4})); + $c += 4; + $utf16 = $this->json_utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + + case (($ord_var_c & 0xFE) == 0xFC): + // characters U-04000000 - U-7FFFFFFF, mask 1111110X + // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 + $char = pack('C*', $ord_var_c, + ord($var{$c + 1}), + ord($var{$c + 2}), + ord($var{$c + 3}), + ord($var{$c + 4}), + ord($var{$c + 5})); + $c += 5; + $utf16 = $this->json_utf82utf16($char); + $ascii .= sprintf('\u%04s', bin2hex($utf16)); + break; + } + } + + return '"'.$ascii.'"'; + + case 'array': + /* + * As per JSON spec if any array key is not an integer + * we must treat the the whole array as an object. We + * also try to catch a sparsely populated associative + * array with numeric keys here because some JS engines + * will create an array with empty indexes up to + * max_index which can cause memory issues and because + * the keys, which may be relevant, will be remapped + * otherwise. + * + * As per the ECMA and JSON specification an object may + * have any string as a property. Unfortunately due to + * a hole in the ECMA specification if the key is a + * ECMA reserved word or starts with a digit the + * parameter is only accessible using ECMAScript's + * bracket notation. + */ + + // treat as a JSON object + if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) { + + $this->json_objectStack[] = $var; + + $properties = array_map(array($this, 'json_name_value'), + array_keys($var), + array_values($var)); + + array_pop($this->json_objectStack); + + foreach($properties as $property) { + if ($property instanceof Exception) { + return $property; + } + } + + return '{' . join(',', $properties) . '}'; + } + + $this->json_objectStack[] = $var; + + // treat it like a regular array + $elements = array_map(array($this, 'json_encode'), $var); + + array_pop($this->json_objectStack); + + foreach($elements as $element) { + if ($element instanceof Exception) { + return $element; + } + } + + return '[' . join(',', $elements) . ']'; + + case 'object': + $vars = self::encodeObject($var); + + $this->json_objectStack[] = $var; + + $properties = array_map(array($this, 'json_name_value'), + array_keys($vars), + array_values($vars)); + + array_pop($this->json_objectStack); + + foreach($properties as $property) { + if ($property instanceof Exception) { + return $property; + } + } + + return '{' . join(',', $properties) . '}'; + + default: + return null; + } + } + + /** + * array-walking function for use in generating JSON-formatted name-value pairs + * + * @param string $name name of key to use + * @param mixed $value reference to an array element to be encoded + * + * @return string JSON-formatted name-value pair, like '"name":value' + * @access private + */ + private function json_name_value($name, $value) + { + // Encoding the $GLOBALS PHP array causes an infinite loop + // if the recursion is not reset here as it contains + // a reference to itself. This is the only way I have come up + // with to stop infinite recursion in this case. + if ($name=='GLOBALS' + && is_array($value) + && array_key_exists('GLOBALS',$value)) { + $value['GLOBALS'] = '** Recursion **'; + } + + $encoded_value = $this->json_encode($value); + + if ($encoded_value instanceof Exception) { + return $encoded_value; + } + + return $this->json_encode(strval($name)) . ':' . $encoded_value; + } + + /** + * @deprecated + */ + public function setProcessorUrl($URL) + { + trigger_error("The FirePHP::setProcessorUrl() method is no longer supported", E_USER_DEPRECATED); + } + + /** + * @deprecated + */ + public function setRendererUrl($URL) + { + trigger_error("The FirePHP::setRendererUrl() method is no longer supported", E_USER_DEPRECATED); + } +} diff --git a/ThinkPHP/Lib/Behavior/ParseTemplateBehavior.class.php b/ThinkPHP/Library/Behavior/ParseTemplateBehavior.class.php similarity index 81% rename from ThinkPHP/Lib/Behavior/ParseTemplateBehavior.class.php rename to ThinkPHP/Library/Behavior/ParseTemplateBehavior.class.php index bae368968..a1ed4e60a 100644 --- a/ThinkPHP/Lib/Behavior/ParseTemplateBehavior.class.php +++ b/ThinkPHP/Library/Behavior/ParseTemplateBehavior.class.php @@ -2,23 +2,22 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK IT ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006-2013 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- - +namespace Behavior; +use Think\Behavior; +use Think\Storage; +use Think\Think; defined('THINK_PATH') or exit(); /** * 系统行为扩展:模板解析 - * @category Think - * @package Think - * @subpackage Behavior - * @author liu21st */ class ParseTemplateBehavior extends Behavior { - // 行为参数定义(默认值) 可在项目配置中覆盖 + // 行为参数定义(默认值) 可在应用配置中覆盖 protected $options = array( // 布局设置 'TMPL_ENGINE_TYPE' => 'Think', // 默认模板引擎 以下设置仅对使用Think模板引擎有效 @@ -52,23 +51,25 @@ public function run(&$_data){ if('think'==$engine){ // 采用Think模板引擎 if((!empty($_data['content']) && $this->checkContentCache($_data['content'],$_data['prefix'])) || $this->checkCache($_data['file'],$_data['prefix'])) { // 缓存有效 - // 分解变量并载入模板缓存 - extract($_data['var'], EXTR_OVERWRITE); //载入模版缓存文件 - include C('CACHE_PATH').$_data['prefix'].md5($_content).C('TMPL_CACHFILE_SUFFIX'); + Storage::load(C('CACHE_PATH').$_data['prefix'].md5($_content).C('TMPL_CACHFILE_SUFFIX'),$_data['var'],'tpl'); }else{ - $tpl = Think::instance('ThinkTemplate'); + $tpl = Think::instance('Think\\Template'); // 编译并加载模板文件 $tpl->fetch($_content,$_data['var'],$_data['prefix']); } }else{ // 调用第三方模板引擎解析和输出 - $class = 'Template'.ucwords($engine); + if(strpos($engine,'\\')){ + $class = $engine; + }else{ + $class = 'Think\\Template\\Driver\\'.ucwords($engine); + } if(class_exists($class)) { $tpl = new $class; $tpl->fetch($_content,$_data['var']); }else { // 类没有定义 - throw_exception(L('_NOT_SUPPERT_').': ' . $class); + E(L('_NOT_SUPPERT_').': ' . $class); } } } @@ -84,19 +85,19 @@ protected function checkCache($tmplTemplateFile,$prefix='') { if (!C('TMPL_CACHE_ON')) // 优先对配置设定检测 return false; $tmplCacheFile = C('CACHE_PATH').$prefix.md5($tmplTemplateFile).C('TMPL_CACHFILE_SUFFIX'); - if(!is_file($tmplCacheFile)){ + if(!Storage::has($tmplCacheFile,'tpl')){ return false; - }elseif (filemtime($tmplTemplateFile) > filemtime($tmplCacheFile)) { + }elseif (filemtime($tmplTemplateFile) > Storage::get($tmplCacheFile,'mtime','tpl')) { // 模板文件如果有更新则缓存需要更新 return false; - }elseif (C('TMPL_CACHE_TIME') != 0 && time() > filemtime($tmplCacheFile)+C('TMPL_CACHE_TIME')) { + }elseif (C('TMPL_CACHE_TIME') != 0 && time() > Storage::get($tmplCacheFile,'mtime','tpl')+C('TMPL_CACHE_TIME')) { // 缓存是否在有效期 return false; } // 开启布局模板 if(C('LAYOUT_ON')) { $layoutFile = THEME_PATH.C('LAYOUT_NAME').C('TMPL_TEMPLATE_SUFFIX'); - if(filemtime($layoutFile) > filemtime($tmplCacheFile)) { + if(filemtime($layoutFile) > Storage::get($tmplCacheFile,'mtime','tpl')) { return false; } } @@ -112,10 +113,10 @@ protected function checkCache($tmplTemplateFile,$prefix='') { * @return boolean */ protected function checkContentCache($tmplContent,$prefix='') { - if(is_file(C('CACHE_PATH').$prefix.md5($tmplContent).C('TMPL_CACHFILE_SUFFIX'))){ + if(Storage::has(C('CACHE_PATH').$prefix.md5($tmplContent).C('TMPL_CACHFILE_SUFFIX'),'tpl')){ return true; }else{ return false; } } -} \ No newline at end of file +} diff --git a/ThinkPHP/Lib/Behavior/ReadHtmlCacheBehavior.class.php b/ThinkPHP/Library/Behavior/ReadHtmlCacheBehavior.class.php similarity index 68% rename from ThinkPHP/Lib/Behavior/ReadHtmlCacheBehavior.class.php rename to ThinkPHP/Library/Behavior/ReadHtmlCacheBehavior.class.php index 7131f2d4c..6f2d3cf8c 100644 --- a/ThinkPHP/Lib/Behavior/ReadHtmlCacheBehavior.class.php +++ b/ThinkPHP/Library/Behavior/ReadHtmlCacheBehavior.class.php @@ -2,20 +2,18 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK IT ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006-2013 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- - +namespace Behavior; +use Think\Behavior; +use Think\Storage; defined('THINK_PATH') or exit(); /** * 系统行为扩展:静态缓存读取 - * @category Think - * @package Think - * @subpackage Behavior - * @author liu21st */ class ReadHtmlCacheBehavior extends Behavior { protected $options = array( @@ -32,7 +30,7 @@ public function run(&$params){ $cacheTime = $this->requireHtmlCache(); if( false !== $cacheTime && $this->checkHTMLCache(HTML_FILE_NAME,$cacheTime)) { //静态页面有效 // 读取静态页面输出 - readfile(HTML_FILE_NAME); + echo Storage::read(HTML_FILE_NAME,'html'); exit(); } } @@ -47,7 +45,7 @@ static private function requireHtmlCache() { // 静态规则文件定义格式 actionName=>array('静态规则','缓存时间','附加规则') // 'read'=>array('{id},{name}',60,'md5') 必须保证静态规则的唯一性 和 可判断性 // 检测静态规则 - $moduleName = strtolower(MODULE_NAME); + $moduleName = strtolower(CONTROLLER_NAME); $actionName = strtolower(ACTION_NAME); if(isset($htmls[$moduleName.':'.$actionName])) { $html = $htmls[$moduleName.':'.$actionName]; // 某个模块的操作的静态规则 @@ -57,27 +55,33 @@ static private function requireHtmlCache() { $html = $htmls[$actionName]; // 所有操作的静态规则 }elseif(isset($htmls['*'])){ $html = $htmls['*']; // 全局静态规则 - }elseif(isset($htmls['empty:index']) && !class_exists(MODULE_NAME.'Action')){ - $html = $htmls['empty:index']; // 空模块静态规则 - }elseif(isset($htmls[$moduleName.':_empty']) && self::isEmptyAction(MODULE_NAME,ACTION_NAME)){ - $html = $htmls[$moduleName.':_empty']; // 空操作静态规则 } if(!empty($html)) { // 解读静态规则 $rule = $html[0]; // 以$_开头的系统变量 - $rule = preg_replace('/{\$(_\w+)\.(\w+)\|(\w+)}/e',"\\3(\$\\1['\\2'])",$rule); - $rule = preg_replace('/{\$(_\w+)\.(\w+)}/e',"\$\\1['\\2']",$rule); + $callback = function($match){ + switch($match[1]){ + case "_GET": $var = $_GET[$match[2]]; break; + case "_POST": $var = $_POST[$match[2]]; break; + case "_REQUEST": $var = $_REQUEST[$match[2]]; break; + case "_SERVER": $var = $_SERVER[$match[2]]; break; + case "_SESSION": $var = $_SESSION[$match[2]]; break; + case "_COOKIE": $var = $_COOKIE[$match[2]]; break; + } + return (count($match) == 4) ? $match[3]($var) : $var; + }; + $rule = preg_replace_callback('/{\$(_\w+)\.(\w+)(?:\|(\w+))?}/', $callback, $rule); // {ID|FUN} GET变量的简写 - $rule = preg_replace('/{(\w+)\|(\w+)}/e',"\\2(\$_GET['\\1'])",$rule); - $rule = preg_replace('/{(\w+)}/e',"\$_GET['\\1']",$rule); + $rule = preg_replace_callback('/{(\w+)\|(\w+)}/', function($match){return $match[2]($_GET[$match[1]]);}, $rule); + $rule = preg_replace_callback('/{(\w+)}/', function($match){return $_GET[$match[1]];}, $rule); // 特殊系统变量 $rule = str_ireplace( - array('{:app}','{:module}','{:action}','{:group}'), - array(APP_NAME,MODULE_NAME,ACTION_NAME,defined('GROUP_NAME')?GROUP_NAME:''), + array('{:controller}','{:action}','{:module}'), + array(CONTROLLER_NAME,ACTION_NAME,MODULE_NAME), $rule); // {|FUN} 单独使用函数 - $rule = preg_replace('/{|(\w+)}/e',"\\1()",$rule); + $rule = preg_replace_callback('/{|(\w+)}/', function($match){return $match[1]();},$rule); if(!empty($html[2])) $rule = $html[2]($rule); // 应用附加函数 $cacheTime = isset($html[1])?$html[1]:C('HTML_CACHE_TIME'); // 缓存有效期 // 当前缓存文件 @@ -100,12 +104,12 @@ static private function requireHtmlCache() { static public function checkHTMLCache($cacheFile='',$cacheTime='') { if(!is_file($cacheFile)){ return false; - }elseif (filemtime(C('TEMPLATE_NAME')) > filemtime($cacheFile)) { + }elseif (filemtime(C('TEMPLATE_NAME')) > Storage::get($cacheFile,'mtime','html')) { // 模板文件如果更新静态文件需要更新 return false; }elseif(!is_numeric($cacheTime) && function_exists($cacheTime)){ return $cacheTime($cacheFile); - }elseif ($cacheTime != 0 && NOW_TIME > filemtime($cacheFile)+$cacheTime) { + }elseif ($cacheTime != 0 && NOW_TIME > Storage::get($cacheFile,'mtime','html')+$cacheTime) { // 文件是否在有效期 return false; } @@ -113,11 +117,4 @@ static public function checkHTMLCache($cacheFile='',$cacheTime='') { return true; } - //检测是否是空操作 - static private function isEmptyAction($module,$action) { - $className = $module.'Action'; - $class = new $className; - return !method_exists($class,$action); - } - } \ No newline at end of file diff --git a/ThinkPHP/Library/Behavior/RobotCheckBehavior.class.php b/ThinkPHP/Library/Behavior/RobotCheckBehavior.class.php new file mode 100644 index 000000000..c4ae1f699 --- /dev/null +++ b/ThinkPHP/Library/Behavior/RobotCheckBehavior.class.php @@ -0,0 +1,46 @@ + +// +---------------------------------------------------------------------- +namespace Behavior; +use Think\Behavior; +defined('THINK_PATH') or exit(); +/** + * 机器人检测 + * @author liu21st + */ +class RobotCheckBehavior extends Behavior { + protected $options = array( + 'LIMIT_ROBOT_VISIT' => true, // 禁止机器人访问 + ); + + public function run(&$params) { + // 机器人访问检测 + if(C('LIMIT_ROBOT_VISIT') && self::isRobot()) { + // 禁止机器人访问 + exit('Access Denied'); + } + } + + static private function isRobot() { + static $_robot = null; + if(is_null($_robot)) { + $spiders = 'Bot|Crawl|Spider|slurp|sohu-search|lycos|robozilla'; + $browsers = 'MSIE|Netscape|Opera|Konqueror|Mozilla'; + if(preg_match("/($browsers)/", $_SERVER['HTTP_USER_AGENT'])) { + $_robot = false ; + } elseif(preg_match("/($spiders)/", $_SERVER['HTTP_USER_AGENT'])) { + $_robot = true; + } else { + $_robot = false; + } + } + return $_robot; + } +} \ No newline at end of file diff --git a/ThinkPHP/Lib/Behavior/ShowPageTraceBehavior.class.php b/ThinkPHP/Library/Behavior/ShowPageTraceBehavior.class.php similarity index 95% rename from ThinkPHP/Lib/Behavior/ShowPageTraceBehavior.class.php rename to ThinkPHP/Library/Behavior/ShowPageTraceBehavior.class.php index 760d5b9a9..df4117da2 100644 --- a/ThinkPHP/Lib/Behavior/ShowPageTraceBehavior.class.php +++ b/ThinkPHP/Library/Behavior/ShowPageTraceBehavior.class.php @@ -2,20 +2,18 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK IT ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006-2013 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- - +namespace Behavior; +use Think\Behavior; +use Think\Log; defined('THINK_PATH') or exit(); /** * 系统行为扩展:页面Trace显示输出 - * @category Think - * @package Think - * @subpackage Behavior - * @author liu21st */ class ShowPageTraceBehavior extends Behavior { // 行为参数定义 @@ -55,8 +53,8 @@ private function showTrace() { '配置加载' => count(c()), '会话信息' => 'SESSION_ID='.session_id(), ); - // 读取项目定义的Trace文件 - $traceFile = CONF_PATH.'trace.php'; + // 读取应用定义的Trace文件 + $traceFile = COMMON_PATH.'Conf/trace.php'; if(is_file($traceFile)) { $base = array_merge($base,include $traceFile); } diff --git a/ThinkPHP/Lib/Behavior/ShowRuntimeBehavior.class.php b/ThinkPHP/Library/Behavior/ShowRuntimeBehavior.class.php similarity index 95% rename from ThinkPHP/Lib/Behavior/ShowRuntimeBehavior.class.php rename to ThinkPHP/Library/Behavior/ShowRuntimeBehavior.class.php index f8c86cedf..a0e390241 100644 --- a/ThinkPHP/Lib/Behavior/ShowRuntimeBehavior.class.php +++ b/ThinkPHP/Library/Behavior/ShowRuntimeBehavior.class.php @@ -2,20 +2,17 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK IT ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006-2013 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- - +namespace Behavior; +use Think\Behavior; defined('THINK_PATH') or exit(); /** * 系统行为扩展:运行时间信息显示 - * @category Think - * @package Think - * @subpackage Behavior - * @author liu21st */ class ShowRuntimeBehavior extends Behavior { // 行为参数定义 diff --git a/ThinkPHP/Lib/Behavior/TokenBuildBehavior.class.php b/ThinkPHP/Library/Behavior/TokenBuildBehavior.class.php similarity index 68% rename from ThinkPHP/Lib/Behavior/TokenBuildBehavior.class.php rename to ThinkPHP/Library/Behavior/TokenBuildBehavior.class.php index ea91c59da..d728bcd10 100644 --- a/ThinkPHP/Lib/Behavior/TokenBuildBehavior.class.php +++ b/ThinkPHP/Library/Behavior/TokenBuildBehavior.class.php @@ -8,14 +8,11 @@ // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- - +namespace Behavior; +use Think\Behavior; defined('THINK_PATH') or exit(); /** * 系统行为扩展:表单令牌生成 - * @category Think - * @package Think - * @subpackage Behavior - * @author liu21st */ class TokenBuildBehavior extends Behavior { // 行为参数定义 @@ -28,24 +25,20 @@ class TokenBuildBehavior extends Behavior { public function run(&$content){ if(C('TOKEN_ON')) { - list($tokenName,$tokenKey,$tokenValue)=$this->getToken(); - $input_token = ''; - $meta_token = ''; if(strpos($content,'{__TOKEN__}')) { // 指定表单令牌隐藏域位置 - $content = str_replace('{__TOKEN__}',$input_token,$content); + $content = str_replace('{__TOKEN__}',$this->buildToken(),$content); }elseif(preg_match('/<\/form(\s*)>/is',$content,$match)) { // 智能生成表单令牌隐藏域 - $content = str_replace($match[0],$input_token.$match[0],$content); + $content = str_replace($match[0],$this->buildToken().$match[0],$content); } - $content = str_ireplace('',$meta_token.'',$content); }else{ $content = str_replace('{__TOKEN__}','',$content); } } - //获得token - private function getToken(){ + // 创建表单令牌 + private function buildToken() { $tokenName = C('TOKEN_NAME'); $tokenType = C('TOKEN_TYPE'); if(!isset($_SESSION[$tokenName])) { @@ -58,9 +51,8 @@ private function getToken(){ }else{ $tokenValue = $tokenType(microtime(TRUE)); $_SESSION[$tokenName][$tokenKey] = $tokenValue; - if(IS_AJAX && C('TOKEN_RESET')) - header($tokenName.': '.$tokenKey.'_'.$tokenValue); //ajax需要获得这个header并替换页面中meta中的token值 } - return array($tokenName,$tokenKey,$tokenValue); + $token = ''; + return $token; } -} +} \ No newline at end of file diff --git a/ThinkPHP/Library/Behavior/UpgradeNoticeBehavior.class.php b/ThinkPHP/Library/Behavior/UpgradeNoticeBehavior.class.php new file mode 100644 index 000000000..4999eb127 --- /dev/null +++ b/ThinkPHP/Library/Behavior/UpgradeNoticeBehavior.class.php @@ -0,0 +1,129 @@ + +// +---------------------------------------------------------------------- +namespace Behavior; +use Think\Behavior; +defined('THINK_PATH') or exit(); +/** + * 升级短信通知, 如果有ThinkPHP新版升级,或者重要的更新,会发送短信通知你。 + * 需要使用SAE的短信服务。请先找一个SAE的应用开通短信服务。 + * 使用步骤如下: + * 1,在项目的Conf目录下建立tags.php配置文件,内容如下: + * + * array('UpgradeNotice') + * ); + * + * + * 2,将此文件放在应用的Lib/Behavior文件夹下。 + *注:在SAE上面使用时,以上两步可以省略 + * 3,在config.php中配置: + * 'UPGRADE_NOTICE_ON'=>true,//开启短信升级提醒功能 + * 'UPGRADE_NOTICE_AKEY'=>'your akey',//SAE应用的AKEY,如果在SAE上使用可以不填 + * 'UPGRADE_NOTICE_SKEY'=>'your skey',//SAE应用的SKEY,如果在SAE上使用可以不填 + *'UPGRADE_NOTICE_MOBILE'=>'136456789',//接受短信的手机号 + *'UPGRADE_NOTICE_CHECK_INTERVAL' => 604800,//检测频率,单位秒,默认是一周 + *'UPGRADE_CURRENT_VERSION'=>'0',//升级后的版本号,会在短信中告诉你填写什么 + *UPGRADE_NOTICE_DEBUG=>true, //调试默认,如果为true,UPGRADE_NOTICE_CHECK_INTERVAL配置不起作用,每次都会进行版本检查,此时用于调试,调试完毕后请设置次配置为false + * + */ + +class UpgradeNoticeBehavior extends Behavior { + // 行为参数定义(默认值) 可在应用配置中覆盖 + protected $options = array( + 'UPGRADE_NOTICE_ON' => false, // 是否开启升级提醒 + 'UPGRADE_NOTICE_DEBUG'=>false, + 'UPGRADE_NOTICE_QUEUE'=>'',//队列名称, 在SAE平台上设置 + 'UPGRADE_NOTICE_AKEY' => '', //SAE应用的AKEY + 'UPGRADE_NOTICE_SKEY' => '', //SAE应用的SKEY + 'UPGRADE_NOTICE_MOBILE' => '', //接受短信的手机号 + 'UPGRADE_CURRENT_VERSION'=>'0', + 'UPGRADE_NOTICE_CHECK_INTERVAL' => 604800, //检测频率,单位秒,默认是一周 + ); + protected $header_ = ''; + protected $httpCode_; + protected $httpDesc_; + protected $accesskey_; + protected $secretkey_; + public function run(&$params) { + if (C('UPGRADE_NOTICE_ON') && (!S('think_upgrade_interval') || C('UPGRADE_NOTICE_DEBUG'))) { + if(IS_SAE && C('UPGRADE_NOTICE_QUEUE') && !isset($_POST['think_upgrade_queque'])){ + $queue=new SaeTaskQueue(C('UPGRADE_NOTICE_QUEUE')); + $queue->addTask('http://'.$_SERVER['HTTP_HOST'].__APP__,'think_upgrade_queque=1'); + if(!$queue->push()){ + trace('升级提醒队列执行失败,错误原因:'.$queue->errmsg(), '升级通知出错', 'NOTIC', true); + } + return ; + } + $akey = C('UPGRADE_NOTICE_AKEY'); + $skey = C('UPGRADE_NOTICE_SKEY'); + $this->accesskey_ = $akey ? $akey : (defined('SAE_ACCESSKEY') ? SAE_ACCESSKEY : ''); + $this->secretkey_ = $skey ? $skey : (defined('SAE_SECRETKEY') ? SAE_SECRETKEY : ''); + $current_version = C('UPGRADE_CURRENT_VERSION'); + //读取接口 + $info = $this->send('http://sinaclouds.sinaapp.com/thinkapi/upgrade.php?v=' . $current_version); + if ($info['version'] != $current_version) { + if($this->send_sms($info['msg'])) trace($info['msg'], '升级通知成功', 'NOTIC', true); //发送升级短信 + } + S('think_upgrade_interval', true, C('UPGRADE_NOTICE_CHECK_INTERVAL')); + } + } + private function send_sms($msg) { + $timestamp=time(); + $url = 'http://inno.smsinter.sina.com.cn/sae_sms_service/sendsms.php'; //发送短信的接口地址 + $content = "FetchUrl" . $url . "TimeStamp" . $timestamp . "AccessKey" . $this->accesskey_; + $signature = (base64_encode(hash_hmac('sha256', $content, $this->secretkey_, true))); + $headers = array( + "FetchUrl: $url", + "AccessKey: ".$this->accesskey_, + "TimeStamp: " . $timestamp, + "Signature: $signature" + ); + $data = array( + 'mobile' => C('UPGRADE_NOTICE_MOBILE') , + 'msg' => $msg, + 'encoding' => 'UTF-8' + ); + if(!$ret = $this->send('http://g.apibus.io', $data, $headers)){ + return false; + } + if (isset($ret['ApiBusError'])) { + trace('errno:' . $ret['ApiBusError']['errcode'] . ',errmsg:' . $ret['ApiBusError']['errdesc'], '升级通知出错', 'NOTIC', true); + + return false; + } + + return true; + } + private function send($url, $params = array() , $headers = array()) { + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $url); + if (!empty($params)) { + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, $params); + } + if (!empty($headers)) curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + $txt = curl_exec($ch); + if (curl_errno($ch)) { + trace(curl_error($ch) , '升级通知出错', 'NOTIC', true); + + return false; + } + curl_close($ch); + $ret = json_decode($txt, true); + if (!$ret) { + trace('接口[' . $url . ']返回格式不正确', '升级通知出错', 'NOTIC', true); + + return false; + } + + return $ret; + } +} diff --git a/ThinkPHP/Lib/Behavior/WriteHtmlCacheBehavior.class.php b/ThinkPHP/Library/Behavior/WriteHtmlCacheBehavior.class.php similarity index 60% rename from ThinkPHP/Lib/Behavior/WriteHtmlCacheBehavior.class.php rename to ThinkPHP/Library/Behavior/WriteHtmlCacheBehavior.class.php index 42aff99d4..bbf6982e1 100644 --- a/ThinkPHP/Lib/Behavior/WriteHtmlCacheBehavior.class.php +++ b/ThinkPHP/Library/Behavior/WriteHtmlCacheBehavior.class.php @@ -2,20 +2,18 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK IT ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006-2013 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- - +namespace Behavior; +use Think\Behavior; +use Think\Storage; defined('THINK_PATH') or exit(); /** * 系统行为扩展:静态缓存写入 - * @category Think - * @package Think - * @subpackage Behavior - * @author liu21st */ class WriteHtmlCacheBehavior extends Behavior { @@ -23,12 +21,7 @@ class WriteHtmlCacheBehavior extends Behavior { public function run(&$content){ if(C('HTML_CACHE_ON') && defined('HTML_FILE_NAME')) { //静态文件写入 - // 如果开启HTML功能 检查并重写HTML文件 - // 没有模版的操作不生成静态文件 - if(!is_dir(dirname(HTML_FILE_NAME))) - mkdir(dirname(HTML_FILE_NAME),0755,true); - if( false === file_put_contents( HTML_FILE_NAME , $content )) - throw_exception(L('_CACHE_WRITE_ERROR_').':'.HTML_FILE_NAME); + Storage::put(HTML_FILE_NAME , $content,'html'); } } } \ No newline at end of file diff --git a/ThinkPHP/Lib/Core/App.class.php b/ThinkPHP/Library/Think/App.class.php similarity index 78% rename from ThinkPHP/Lib/Core/App.class.php rename to ThinkPHP/Library/Think/App.class.php index 7442e3961..d5a1ff54e 100644 --- a/ThinkPHP/Lib/Core/App.class.php +++ b/ThinkPHP/Library/Think/App.class.php @@ -2,20 +2,15 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK IT ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006-2013 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- - +namespace Think; /** * ThinkPHP 应用程序类 执行应用过程管理 - * 可以在模式扩展中重新定义 但是必须具有Run方法接口 - * @category Think - * @package Think - * @subpackage Core - * @author liu21st */ class App { @@ -25,15 +20,8 @@ class App { * @return void */ static public function init() { - // 页面压缩输出支持 - if(C('OUTPUT_ENCODE')){ - $zlib = ini_get('zlib.output_compression'); - if(empty($zlib)) ob_start('ob_gzhandler'); - } - // 设置系统时区 - date_default_timezone_set(C('DEFAULT_TIMEZONE')); - // 加载动态项目公共文件和配置 - load_ext_file(); + // 加载动态应用公共文件和配置 + load_ext_file(COMMON_PATH); // URL调度 Dispatcher::dispatch(); @@ -47,19 +35,11 @@ static public function init() { define('IS_AJAX', ((isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') || !empty($_POST[C('VAR_AJAX_SUBMIT')]) || !empty($_GET[C('VAR_AJAX_SUBMIT')])) ? true : false); // URL调度结束标签 - tag('url_dispatch'); - // 系统变量安全过滤 - if(C('VAR_FILTERS')) { - $filters = explode(',',C('VAR_FILTERS')); - foreach($filters as $filter){ - // 全局参数过滤 - array_walk_recursive($_POST,$filter); - array_walk_recursive($_GET,$filter); - } - } + Hook::listen('url_dispatch'); + // 日志目录转换为绝对路径 C('LOG_PATH',realpath(LOG_PATH).'/'); - //动态配置 TMPL_EXCEPTION_FILE,改为绝对地址 + // TMPL_EXCEPTION_FILE 改为绝对地址 C('TMPL_EXCEPTION_FILE',realpath(C('TMPL_EXCEPTION_FILE'))); return ; } @@ -70,32 +50,23 @@ static public function init() { * @return void */ static public function exec() { - if(!preg_match('/^[A-Za-z](\w)*$/',MODULE_NAME)){ // 安全检测 + if(!preg_match('/^[A-Za-z](\/|\w)*$/',CONTROLLER_NAME)){ // 安全检测 $module = false; }else{ //创建Action控制器实例 - $group = defined('GROUP_NAME') && C('APP_GROUP_MODE')==0 ? GROUP_NAME.'/' : ''; - $module = A($group.MODULE_NAME); + $module = A(CONTROLLER_NAME); } if(!$module) { - if('4e5e5d7364f443e28fbf0d3ae744a59a' == MODULE_NAME) { + if('4e5e5d7364f443e28fbf0d3ae744a59a' == CONTROLLER_NAME) { header("Content-type:image/png"); exit(base64_decode(App::logo())); } - if(function_exists('__hack_module')) { - // hack 方式定义扩展模块 返回Action对象 - $module = __hack_module(); - if(!is_object($module)) { - // 不再继续执行 直接返回 - return ; - } - }else{ - // 是否定义Empty模块 - $module = A($group.'Empty'); - if(!$module){ - _404(L('_MODULE_NOT_EXIST_').':'.MODULE_NAME); - } + + // 是否定义Empty模块 + $module = A('Empty'); + if(!$module){ + E(L('_CONTROLLER_NOT_EXIST_').':'.CONTROLLER_NAME); } } // 获取当前操作名 支持动态路由 @@ -104,12 +75,12 @@ static public function exec() { try{ if(!preg_match('/^[A-Za-z](\w)*$/',$action)){ // 非法操作 - throw new ReflectionException(); + throw new \ReflectionException(); } //执行当前操作 - $method = new ReflectionMethod($module, $action); - if($method->isPublic()) { - $class = new ReflectionClass($module); + $method = new \ReflectionMethod($module, $action); + if($method->isPublic() && !$method->isStatic()) { + $class = new \ReflectionClass($module); // 前置操作 if($class->hasMethod('_before_'.$action)) { $before = $class->getMethod('_before_'.$action); @@ -130,15 +101,18 @@ static public function exec() { $vars = $_GET; } $params = $method->getParameters(); + $paramsBindType = C('URL_PARAMS_BIND_TYPE'); foreach ($params as $param){ $name = $param->getName(); - if(isset($vars[$name])) { - $args[] = $vars[$name]; + if( 1 == $paramsBindType && !empty($vars) ){ + $args[] = array_shift($vars); + }elseif( 0 == $paramsBindType && isset($vars[$name])){ + $args[] = $vars[$name]; }elseif($param->isDefaultValueAvailable()){ - $args[] = $param->getDefaultValue(); + $args[] = $param->getDefaultValue(); }else{ - throw_exception(L('_PARAM_ERROR_').':'.$name); - } + E(L('_PARAM_ERROR_').':'.$name); + } } $method->invokeArgs($module,$args); }else{ @@ -153,11 +127,11 @@ static public function exec() { } }else{ // 操作方法不是Public 抛出异常 - throw new ReflectionException(); + throw new \ReflectionException(); } - } catch (ReflectionException $e) { + } catch (\ReflectionException $e) { // 方法调用发生异常后 引导到__call方法处理 - $method = new ReflectionMethod($module,'__call'); + $method = new \ReflectionMethod($module,'__call'); $method->invokeArgs($module,array($action,'')); } return ; @@ -169,22 +143,24 @@ static public function exec() { * @return void */ static public function run() { - // 项目初始化标签 - tag('app_init'); + // 应用初始化标签 + Hook::listen('app_init'); App::init(); - // 项目开始标签 - tag('app_begin'); + // 应用开始标签 + Hook::listen('app_begin'); // Session初始化 - session(C('SESSION_OPTIONS')); + if(!IS_CLI){ + session(C('SESSION_OPTIONS')); + } // 记录应用初始化时间 G('initTime'); App::exec(); - // 项目结束标签 - tag('app_end'); + // 应用结束标签 + Hook::listen('app_end'); return ; } static public function logo(){ return 'iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyBpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBXaW5kb3dzIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjVERDVENkZGQjkyNDExRTE5REY3RDQ5RTQ2RTRDQUJCIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjVERDVENzAwQjkyNDExRTE5REY3RDQ5RTQ2RTRDQUJCIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6NURENUQ2RkRCOTI0MTFFMTlERjdENDlFNDZFNENBQkIiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NURENUQ2RkVCOTI0MTFFMTlERjdENDlFNDZFNENBQkIiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz5fx6IRAAAMCElEQVR42sxae3BU1Rk/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'; } -} +} \ No newline at end of file diff --git a/ThinkPHP/Lib/Core/Behavior.class.php b/ThinkPHP/Library/Think/Behavior.class.php similarity index 90% rename from ThinkPHP/Lib/Core/Behavior.class.php rename to ThinkPHP/Library/Think/Behavior.class.php index 86354e75c..1e065942c 100644 --- a/ThinkPHP/Lib/Core/Behavior.class.php +++ b/ThinkPHP/Library/Think/Behavior.class.php @@ -2,19 +2,15 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK IT ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006-2013 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- - +namespace Think; /** * ThinkPHP Behavior基础类 - * @category Think - * @package Think - * @subpackage Core - * @author liu21st */ abstract class Behavior { diff --git a/ThinkPHP/Lib/Core/Cache.class.php b/ThinkPHP/Library/Think/Cache.class.php similarity index 82% rename from ThinkPHP/Lib/Core/Cache.class.php rename to ThinkPHP/Library/Think/Cache.class.php index 2fbda1278..3bb4c1211 100644 --- a/ThinkPHP/Lib/Core/Cache.class.php +++ b/ThinkPHP/Library/Think/Cache.class.php @@ -2,19 +2,15 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK IT ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006-2013 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- - +namespace Think; /** * 缓存管理类 - * @category Think - * @package Think - * @subpackage Core - * @author liu21st */ class Cache { @@ -41,15 +37,34 @@ class Cache { */ public function connect($type='',$options=array()) { if(empty($type)) $type = C('DATA_CACHE_TYPE'); - $type = strtolower(trim($type)); - $class = 'Cache'.ucwords($type); + if(strpos($type,'\\')){ // 驱动类支持使用独立的命名空间 + $class = $type; + }else{ + $class = 'Think\\Cache\\Driver\\'.ucwords(strtolower($type)); + } if(class_exists($class)) $cache = new $class($options); else - throw_exception(L('_CACHE_TYPE_INVALID_').':'.$type); + E(L('_CACHE_TYPE_INVALID_').':'.$type); return $cache; } + /** + * 取得缓存类实例 + * @static + * @access public + * @return mixed + */ + static function getInstance($type='',$options=array()) { + static $_instance = array(); + $guid = $type.to_guid_string($options); + if(!isset($_instance[$guid])){ + $obj = new Cache(); + $_instance[$guid] = $obj->connect($type,$options); + } + return $_instance[$guid]; + } + public function __get($name) { return $this->get($name); } @@ -69,17 +84,6 @@ public function getOptions($name) { return $this->options[$name]; } - /** - * 取得缓存类实例 - * @static - * @access public - * @return mixed - */ - static function getInstance() { - $param = func_get_args(); - return get_instance_of(__CLASS__,'connect',$param); - } - /** * 队列缓存 * @access protected @@ -120,7 +124,7 @@ public function __call($method,$args){ if(method_exists($this->handler, $method)){ return call_user_func_array(array($this->handler,$method), $args); }else{ - throw_exception(__CLASS__.':'.$method.L('_METHOD_NOT_EXIST_')); + E(__CLASS__.':'.$method.L('_METHOD_NOT_EXIST_')); return; } } diff --git a/ThinkPHP/Library/Think/Cache/Driver/Apachenote.class.php b/ThinkPHP/Library/Think/Cache/Driver/Apachenote.class.php new file mode 100644 index 000000000..a14881a5e --- /dev/null +++ b/ThinkPHP/Library/Think/Cache/Driver/Apachenote.class.php @@ -0,0 +1,124 @@ + +// +---------------------------------------------------------------------- +namespace Think\Cache\Driver; +use Think\Cache; +defined('THINK_PATH') or exit(); +/** + * Apachenote缓存驱动 + */ +class Apachenote extends Cache { + + /** + * 架构函数 + * @param array $options 缓存参数 + * @access public + */ + public function __construct($options=array()) { + if(!empty($options)) { + $this->options = $options; + } + if(empty($options)) { + $options = array ( + 'host' => '127.0.0.1', + 'port' => 1042, + 'timeout' => 10, + ); + } + $this->options = $options; + $this->options['prefix'] = isset($options['prefix'])? $options['prefix'] : C('DATA_CACHE_PREFIX'); + $this->options['length'] = isset($options['length'])? $options['length'] : 0; + $this->handler = null; + $this->open(); + } + + /** + * 读取缓存 + * @access public + * @param string $name 缓存变量名 + * @return mixed + */ + public function get($name) { + $this->open(); + $name = $this->options['prefix'].$name; + $s = 'F' . pack('N', strlen($name)) . $name; + fwrite($this->handler, $s); + + for ($data = ''; !feof($this->handler);) { + $data .= fread($this->handler, 4096); + } + N('cache_read',1); + $this->close(); + return $data === '' ? '' : unserialize($data); + } + + /** + * 写入缓存 + * @access public + * @param string $name 缓存变量名 + * @param mixed $value 存储数据 + * @return boolen + */ + public function set($name, $value) { + N('cache_write',1); + $this->open(); + $value = serialize($value); + $name = $this->options['prefix'].$name; + $s = 'S' . pack('NN', strlen($name), strlen($value)) . $name . $value; + + fwrite($this->handler, $s); + $ret = fgets($this->handler); + $this->close(); + if($ret === "OK\n") { + if($this->options['length']>0) { + // 记录缓存队列 + $this->queue($name); + } + return true; + } + return false; + } + + /** + * 删除缓存 + * @access public + * @param string $name 缓存变量名 + * @return boolen + */ + public function rm($name) { + $this->open(); + $name = $this->options['prefix'].$name; + $s = 'D' . pack('N', strlen($name)) . $name; + fwrite($this->handler, $s); + $ret = fgets($this->handler); + $this->close(); + return $ret === "OK\n"; + } + + /** + * 关闭缓存 + * @access private + */ + private function close() { + fclose($this->handler); + $this->handler = false; + } + + /** + * 打开缓存 + * @access private + */ + private function open() { + if (!is_resource($this->handler)) { + $this->handler = fsockopen($this->options['host'], $this->options['port'], $_, $_, $this->options['timeout']); + } + } + +} \ No newline at end of file diff --git a/ThinkPHP/Library/Think/Cache/Driver/Apc.class.php b/ThinkPHP/Library/Think/Cache/Driver/Apc.class.php new file mode 100644 index 000000000..d38cc748e --- /dev/null +++ b/ThinkPHP/Library/Think/Cache/Driver/Apc.class.php @@ -0,0 +1,86 @@ + +// +---------------------------------------------------------------------- +namespace Think\Cache\Driver; +use Think\Cache; +defined('THINK_PATH') or exit(); +/** + * Apc缓存驱动 + */ +class Apc extends Cache { + + /** + * 架构函数 + * @param array $options 缓存参数 + * @access public + */ + public function __construct($options=array()) { + if(!function_exists('apc_cache_info')) { + throw_exception(L('_NOT_SUPPERT_').':Apc'); + } + $this->options['prefix'] = isset($options['prefix'])? $options['prefix'] : C('DATA_CACHE_PREFIX'); + $this->options['length'] = isset($options['length'])? $options['length'] : 0; + $this->options['expire'] = isset($options['expire'])? $options['expire'] : C('DATA_CACHE_TIME'); + } + + /** + * 读取缓存 + * @access public + * @param string $name 缓存变量名 + * @return mixed + */ + public function get($name) { + N('cache_read',1); + return apc_fetch($this->options['prefix'].$name); + } + + /** + * 写入缓存 + * @access public + * @param string $name 缓存变量名 + * @param mixed $value 存储数据 + * @param integer $expire 有效时间(秒) + * @return boolen + */ + public function set($name, $value, $expire = null) { + N('cache_write',1); + if(is_null($expire)) { + $expire = $this->options['expire']; + } + $name = $this->options['prefix'].$name; + if($result = apc_store($name, $value, $expire)) { + if($this->options['length']>0) { + // 记录缓存队列 + $this->queue($name); + } + } + return $result; + } + + /** + * 删除缓存 + * @access public + * @param string $name 缓存变量名 + * @return boolen + */ + public function rm($name) { + return apc_delete($this->options['prefix'].$name); + } + + /** + * 清除缓存 + * @access public + * @return boolen + */ + public function clear() { + return apc_clear_cache(); + } + +} \ No newline at end of file diff --git a/ThinkPHP/Library/Think/Cache/Driver/Db.class.php b/ThinkPHP/Library/Think/Cache/Driver/Db.class.php new file mode 100644 index 000000000..2577d0229 --- /dev/null +++ b/ThinkPHP/Library/Think/Cache/Driver/Db.class.php @@ -0,0 +1,138 @@ + +// +---------------------------------------------------------------------- +namespace Think\Cache\Driver; +use Think\Cache; +defined('THINK_PATH') or exit(); +/** + * 数据库方式缓存驱动 + * CREATE TABLE think_cache ( + * cachekey varchar(255) NOT NULL, + * expire int(11) NOT NULL, + * data blob, + * datacrc int(32), + * UNIQUE KEY `cachekey` (`cachekey`) + * ); + */ +class Db extends Cache { + + /** + * 架构函数 + * @param array $options 缓存参数 + * @access public + */ + public function __construct($options=array()) { + if(empty($options)) { + $options = array ( + 'table' => C('DATA_CACHE_TABLE'), + ); + } + $this->options = $options; + $this->options['prefix'] = isset($options['prefix'])? $options['prefix'] : C('DATA_CACHE_PREFIX'); + $this->options['length'] = isset($options['length'])? $options['length'] : 0; + $this->options['expire'] = isset($options['expire'])? $options['expire'] : C('DATA_CACHE_TIME'); + $this->handler = Think\Db::getInstance(); + } + + /** + * 读取缓存 + * @access public + * @param string $name 缓存变量名 + * @return mixed + */ + public function get($name) { + $name = $this->options['prefix'].addslashes($name); + N('cache_read',1); + $result = $this->handler->query('SELECT `data`,`datacrc` FROM `'.$this->options['table'].'` WHERE `cachekey`=\''.$name.'\' AND (`expire` =0 OR `expire`>'.time().') LIMIT 0,1'); + if(false !== $result ) { + $result = $result[0]; + if(C('DATA_CACHE_CHECK')) {//开启数据校验 + if($result['datacrc'] != md5($result['data'])) {//校验错误 + return false; + } + } + $content = $result['data']; + if(C('DATA_CACHE_COMPRESS') && function_exists('gzcompress')) { + //启用数据压缩 + $content = gzuncompress($content); + } + $content = unserialize($content); + return $content; + } + else { + return false; + } + } + + /** + * 写入缓存 + * @access public + * @param string $name 缓存变量名 + * @param mixed $value 存储数据 + * @param integer $expire 有效时间(秒) + * @return boolen + */ + public function set($name, $value,$expire=null) { + $data = serialize($value); + $name = $this->options['prefix'].addslashes($name); + N('cache_write',1); + if( C('DATA_CACHE_COMPRESS') && function_exists('gzcompress')) { + //数据压缩 + $data = gzcompress($data,3); + } + if(C('DATA_CACHE_CHECK')) {//开启数据校验 + $crc = md5($data); + }else { + $crc = ''; + } + if(is_null($expire)) { + $expire = $this->options['expire']; + } + $expire = ($expire==0)?0: (time()+$expire) ;//缓存有效期为0表示永久缓存 + $result = $this->handler->query('select `cachekey` from `'.$this->options['table'].'` where `cachekey`=\''.$name.'\' limit 0,1'); + if(!empty($result) ) { + //更新记录 + $result = $this->handler->execute('UPDATE '.$this->options['table'].' SET data=\''.$data.'\' ,datacrc=\''.$crc.'\',expire='.$expire.' WHERE `cachekey`=\''.$name.'\''); + }else { + //新增记录 + $result = $this->handler->execute('INSERT INTO '.$this->options['table'].' (`cachekey`,`data`,`datacrc`,`expire`) VALUES (\''.$name.'\',\''.$data.'\',\''.$crc.'\','.$expire.')'); + } + if($result) { + if($this->options['length']>0) { + // 记录缓存队列 + $this->queue($name); + } + return true; + }else { + return false; + } + } + + /** + * 删除缓存 + * @access public + * @param string $name 缓存变量名 + * @return boolen + */ + public function rm($name) { + $name = $this->options['prefix'].addslashes($name); + return $this->handler->execute('DELETE FROM `'.$this->options['table'].'` WHERE `cachekey`=\''.$name.'\''); + } + + /** + * 清除缓存 + * @access public + * @return boolen + */ + public function clear() { + return $this->handler->execute('TRUNCATE TABLE `'.$this->options['table'].'`'); + } + +} \ No newline at end of file diff --git a/ThinkPHP/Library/Think/Cache/Driver/Eaccelerator.class.php b/ThinkPHP/Library/Think/Cache/Driver/Eaccelerator.class.php new file mode 100644 index 000000000..49e20189e --- /dev/null +++ b/ThinkPHP/Library/Think/Cache/Driver/Eaccelerator.class.php @@ -0,0 +1,77 @@ + +// +---------------------------------------------------------------------- +namespace Think\Cache\Driver; +use Think\Cache; +defined('THINK_PATH') or exit(); +/** + * Eaccelerator缓存驱动 + */ +class Eaccelerator extends Cache { + + /** + * 架构函数 + * @param array $options 缓存参数 + * @access public + */ + public function __construct($options=array()) { + $this->options['expire'] = isset($options['expire'])? $options['expire'] : C('DATA_CACHE_TIME'); + $this->options['prefix'] = isset($options['prefix'])? $options['prefix'] : C('DATA_CACHE_PREFIX'); + $this->options['length'] = isset($options['length'])? $options['length'] : 0; + } + + /** + * 读取缓存 + * @access public + * @param string $name 缓存变量名 + * @return mixed + */ + public function get($name) { + N('cache_read',1); + return eaccelerator_get($this->options['prefix'].$name); + } + + /** + * 写入缓存 + * @access public + * @param string $name 缓存变量名 + * @param mixed $value 存储数据 + * @param integer $expire 有效时间(秒) + * @return boolen + */ + public function set($name, $value, $expire = null) { + N('cache_write',1); + if(is_null($expire)) { + $expire = $this->options['expire']; + } + $name = $this->options['prefix'].$name; + eaccelerator_lock($name); + if(eaccelerator_put($name, $value, $expire)) { + if($this->options['length']>0) { + // 记录缓存队列 + $this->queue($name); + } + return true; + } + return false; + } + + + /** + * 删除缓存 + * @access public + * @param string $name 缓存变量名 + * @return boolen + */ + public function rm($name) { + return eaccelerator_rm($this->options['prefix'].$name); + } + +} \ No newline at end of file diff --git a/ThinkPHP/Lib/Driver/Cache/CacheFile.class.php b/ThinkPHP/Library/Think/Cache/Driver/File.class.php similarity index 95% rename from ThinkPHP/Lib/Driver/Cache/CacheFile.class.php rename to ThinkPHP/Library/Think/Cache/Driver/File.class.php index 8f5c30132..4c91b956c 100644 --- a/ThinkPHP/Lib/Driver/Cache/CacheFile.class.php +++ b/ThinkPHP/Library/Think/Cache/Driver/File.class.php @@ -2,22 +2,19 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK IT ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006-2013 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- - +namespace Think\Cache\Driver; +use Think\Cache; defined('THINK_PATH') or exit(); /** * 文件类型缓存类 - * @category Think - * @package Think - * @subpackage Driver.Cache - * @author liu21st */ -class CacheFile extends Cache { +class File extends Cache { /** * 架构函数 @@ -41,7 +38,7 @@ public function __construct($options=array()) { * @return boolen */ private function init() { - // 创建项目缓存目录 + // 创建应用缓存目录 if (!is_dir($this->options['temp'])) { mkdir($this->options['temp']); } diff --git a/ThinkPHP/Library/Think/Cache/Driver/Memcache.class.php b/ThinkPHP/Library/Think/Cache/Driver/Memcache.class.php new file mode 100644 index 000000000..11998474a --- /dev/null +++ b/ThinkPHP/Library/Think/Cache/Driver/Memcache.class.php @@ -0,0 +1,103 @@ + +// +---------------------------------------------------------------------- +namespace Think\Cache\Driver; +use Think\Cache; +defined('THINK_PATH') or exit(); +/** + * Memcache缓存驱动 + */ +class Memcache extends Cache { + + /** + * 架构函数 + * @param array $options 缓存参数 + * @access public + */ + function __construct($options=array()) { + if ( !extension_loaded('memcache') ) { + throw_exception(L('_NOT_SUPPERT_').':memcache'); + } + + $options = array_merge(array ( + 'host' => C('MEMCACHE_HOST') ? C('MEMCACHE_HOST') : '127.0.0.1', + 'port' => C('MEMCACHE_PORT') ? C('MEMCACHE_PORT') : 11211, + 'timeout' => C('DATA_CACHE_TIMEOUT') ? C('DATA_CACHE_TIMEOUT') : false, + 'persistent' => false, + ),$options); + + $this->options = $options; + $this->options['expire'] = isset($options['expire'])? $options['expire'] : C('DATA_CACHE_TIME'); + $this->options['prefix'] = isset($options['prefix'])? $options['prefix'] : C('DATA_CACHE_PREFIX'); + $this->options['length'] = isset($options['length'])? $options['length'] : 0; + $func = $options['persistent'] ? 'pconnect' : 'connect'; + $this->handler = new \Memcache; + $options['timeout'] === false ? + $this->handler->$func($options['host'], $options['port']) : + $this->handler->$func($options['host'], $options['port'], $options['timeout']); + } + + /** + * 读取缓存 + * @access public + * @param string $name 缓存变量名 + * @return mixed + */ + public function get($name) { + N('cache_read',1); + return $this->handler->get($this->options['prefix'].$name); + } + + /** + * 写入缓存 + * @access public + * @param string $name 缓存变量名 + * @param mixed $value 存储数据 + * @param integer $expire 有效时间(秒) + * @return boolen + */ + public function set($name, $value, $expire = null) { + N('cache_write',1); + if(is_null($expire)) { + $expire = $this->options['expire']; + } + $name = $this->options['prefix'].$name; + if($this->handler->set($name, $value, 0, $expire)) { + if($this->options['length']>0) { + // 记录缓存队列 + $this->queue($name); + } + return true; + } + return false; + } + + /** + * 删除缓存 + * @access public + * @param string $name 缓存变量名 + * @return boolen + */ + public function rm($name, $ttl = false) { + $name = $this->options['prefix'].$name; + return $ttl === false ? + $this->handler->delete($name) : + $this->handler->delete($name, $ttl); + } + + /** + * 清除缓存 + * @access public + * @return boolen + */ + public function clear() { + return $this->handler->flush(); + } +} \ No newline at end of file diff --git a/ThinkPHP/Library/Think/Cache/Driver/Memcachesae.class.php b/ThinkPHP/Library/Think/Cache/Driver/Memcachesae.class.php new file mode 100644 index 000000000..4a911b38e --- /dev/null +++ b/ThinkPHP/Library/Think/Cache/Driver/Memcachesae.class.php @@ -0,0 +1,153 @@ + +// +---------------------------------------------------------------------- +namespace Think\Cache\Driver; +use Think\Cache; + +defined('THINK_PATH') or exit(); +/** + * Memcache缓存驱动 + * @category Extend + * @package Extend + * @subpackage Driver.Cache + * @author liu21st + */ +class Memcachesae extends Cache { + + /** + * 架构函数 + * @param array $options 缓存参数 + * @access public + */ + function __construct($options=array()) { + //[sae] 下不用判断memcache是否存在 + // if ( !extension_loaded('memcache') ) { + // throw_exception(L('_NOT_SUPPERT_').':memcache'); + // } + if(empty($options)) { + $options = array ( + 'host' => C('MEMCACHE_HOST') ? C('MEMCACHE_HOST') : '127.0.0.1', + 'port' => C('MEMCACHE_PORT') ? C('MEMCACHE_PORT') : 11211, + 'timeout' => C('DATA_CACHE_TIMEOUT') ? C('DATA_CACHE_TIMEOUT') : false, + 'persistent' => false, + ); + } + $this->options = $options; + $this->options['expire'] = isset($options['expire'])? $options['expire'] : C('DATA_CACHE_TIME'); + $this->options['prefix'] = isset($options['prefix'])? $options['prefix'] : C('DATA_CACHE_PREFIX'); + $this->options['length'] = isset($options['length'])? $options['length'] : 0; + // $func = isset($options['persistent']) ? 'pconnect' : 'connect'; + $this->handler = memcache_init();//[sae] 下实例化 + //[sae] 下不用链接 + $this->connected=true; + // $this->connected = $options['timeout'] === false ? + // $this->handler->$func($options['host'], $options['port']) : + // $this->handler->$func($options['host'], $options['port'], $options['timeout']); + } + + /** + * 是否连接 + * @access private + * @return boolen + */ + private function isConnected() { + return $this->connected; + } + + /** + * 读取缓存 + * @access public + * @param string $name 缓存变量名 + * @return mixed + */ + public function get($name) { + N('cache_read',1); + return $this->handler->get($_SERVER['HTTP_APPVERSION'].'/'.$this->options['prefix'].$name); + } + + /** + * 写入缓存 + * @access public + * @param string $name 缓存变量名 + * @param mixed $value 存储数据 + * @param integer $expire 有效时间(秒) + * @return boolen + */ + public function set($name, $value, $expire = null) { + N('cache_write',1); + if(is_null($expire)) { + $expire = $this->options['expire']; + } + $name = $this->options['prefix'].$name; + if($this->handler->set($_SERVER['HTTP_APPVERSION'].'/'.$name, $value, 0, $expire)) { + if($this->options['length']>0) { + // 记录缓存队列 + $this->queue($name); + } + return true; + } + return false; + } + + /** + * 删除缓存 + * @access public + * @param string $name 缓存变量名 + * @return boolen + */ + public function rm($name, $ttl = false) { + $name = $_SERVER['HTTP_APPVERSION'].'/'.$this->options['prefix'].$name; + return $ttl === false ? + $this->handler->delete($name) : + $this->handler->delete($name, $ttl); + } + + /** + * 清除缓存 + * @access public + * @return boolen + */ + public function clear() { + return $this->handler->flush(); + } + + /** + * 队列缓存 + * @access protected + * @param string $key 队列名 + * @return mixed + */ + //[sae] 下重写queque队列缓存方法 + protected function queue($key) { + $queue_name=isset($this->options['queue_name'])?$this->options['queue_name']:'think_queue'; + $value = F($queue_name); + if(!$value) { + $value = array(); + } + // 进列 + if(false===array_search($key, $value)) array_push($value,$key); + if(count($value) > $this->options['length']) { + // 出列 + $key = array_shift($value); + // 删除缓存 + $this->rm($key); + if (APP_DEBUG) { + //调试模式下记录出队次数 + $counter = Think::instance('SaeCounter'); + if ($counter->exists($queue_name.'_out_times')) + $counter->incr($queue_name.'_out_times'); + else + $counter->create($queue_name.'_out_times', 1); + } + } + return F($queue_name,$value); + } + +} diff --git a/ThinkPHP/Library/Think/Cache/Driver/Redis.class.php b/ThinkPHP/Library/Think/Cache/Driver/Redis.class.php new file mode 100644 index 000000000..ceb6f5246 --- /dev/null +++ b/ThinkPHP/Library/Think/Cache/Driver/Redis.class.php @@ -0,0 +1,108 @@ + +// +---------------------------------------------------------------------- +namespace Think\Cache\Driver; +use Think\Cache; +defined('THINK_PATH') or exit(); + +/** + * Redis缓存驱动 + * 要求安装phpredis扩展:https://github.com/nicolasff/phpredis + */ +class Redis extends Cache { + /** + * 架构函数 + * @param array $options 缓存参数 + * @access public + */ + public function __construct($options=array()) { + if ( !extension_loaded('redis') ) { + throw_exception(L('_NOT_SUPPERT_').':redis'); + } + if(empty($options)) { + $options = array ( + 'host' => C('REDIS_HOST') ? C('REDIS_HOST') : '127.0.0.1', + 'port' => C('REDIS_PORT') ? C('REDIS_PORT') : 6379, + 'timeout' => C('DATA_CACHE_TIMEOUT') ? C('DATA_CACHE_TIMEOUT') : false, + 'persistent' => false, + ); + } + $this->options = $options; + $this->options['expire'] = isset($options['expire'])? $options['expire'] : C('DATA_CACHE_TIME'); + $this->options['prefix'] = isset($options['prefix'])? $options['prefix'] : C('DATA_CACHE_PREFIX'); + $this->options['length'] = isset($options['length'])? $options['length'] : 0; + $func = $options['persistent'] ? 'pconnect' : 'connect'; + $this->handler = new \Redis; + $options['timeout'] === false ? + $this->handler->$func($options['host'], $options['port']) : + $this->handler->$func($options['host'], $options['port'], $options['timeout']); + } + + /** + * 读取缓存 + * @access public + * @param string $name 缓存变量名 + * @return mixed + */ + public function get($name) { + N('cache_read',1); + $value = $this->handler->get($this->options['prefix'].$name); + $jsonData = json_decode( $value, true ); + return ($jsonData === NULL) ? $value : $jsonData; //检测是否为JSON数据 true 返回JSON解析数组, false返回源数据 + } + + /** + * 写入缓存 + * @access public + * @param string $name 缓存变量名 + * @param mixed $value 存储数据 + * @param integer $expire 有效时间(秒) + * @return boolen + */ + public function set($name, $value, $expire = null) { + N('cache_write',1); + if(is_null($expire)) { + $expire = $this->options['expire']; + } + $name = $this->options['prefix'].$name; + //对数组/对象数据进行缓存处理,保证数据完整性 + $value = (is_object($value) || is_array($value)) ? json_encode($value) : $value; + if(is_int($expire)) { + $result = $this->handler->setex($name, $expire, $value); + }else{ + $result = $this->handler->set($name, $value); + } + if($result && $this->options['length']>0) { + // 记录缓存队列 + $this->queue($name); + } + return $result; + } + + /** + * 删除缓存 + * @access public + * @param string $name 缓存变量名 + * @return boolen + */ + public function rm($name) { + return $this->handler->delete($this->options['prefix'].$name); + } + + /** + * 清除缓存 + * @access public + * @return boolen + */ + public function clear() { + return $this->handler->flushDB(); + } + +} diff --git a/ThinkPHP/Library/Think/Cache/Driver/Shmop.class.php b/ThinkPHP/Library/Think/Cache/Driver/Shmop.class.php new file mode 100644 index 000000000..54a661044 --- /dev/null +++ b/ThinkPHP/Library/Think/Cache/Driver/Shmop.class.php @@ -0,0 +1,186 @@ + +// +---------------------------------------------------------------------- +namespace Think\Cache\Driver; +use Think\Cache; +defined('THINK_PATH') or exit(); +/** + * Shmop缓存驱动 + */ +class Shmop extends Cache { + + /** + * 架构函数 + * @param array $options 缓存参数 + * @access public + */ + public function __construct($options=array()) { + if ( !extension_loaded('shmop') ) { + throw_exception(L('_NOT_SUPPERT_').':shmop'); + } + if(!empty($options)){ + $options = array( + 'size' => C('SHARE_MEM_SIZE'), + 'temp' => TEMP_PATH, + 'project' => 's', + 'length' => 0, + ); + } + $this->options = $options; + $this->options['prefix'] = isset($options['prefix'])? $options['prefix'] : C('DATA_CACHE_PREFIX'); + $this->options['length'] = isset($options['length'])? $options['length'] : 0; + $this->handler = $this->_ftok($this->options['project']); + } + + /** + * 读取缓存 + * @access public + * @param string $name 缓存变量名 + * @return mixed + */ + public function get($name = false) { + N('cache_read',1); + $id = shmop_open($this->handler, 'c', 0600, 0); + if ($id !== false) { + $ret = unserialize(shmop_read($id, 0, shmop_size($id))); + shmop_close($id); + + if ($name === false) { + return $ret; + } + $name = $this->options['prefix'].$name; + if(isset($ret[$name])) { + $content = $ret[$name]; + if(C('DATA_CACHE_COMPRESS') && function_exists('gzcompress')) { + //启用数据压缩 + $content = gzuncompress($content); + } + return $content; + }else { + return null; + } + }else { + return false; + } + } + + /** + * 写入缓存 + * @access public + * @param string $name 缓存变量名 + * @param mixed $value 存储数据 + * @return boolen + */ + public function set($name, $value) { + N('cache_write',1); + $lh = $this->_lock(); + $val = $this->get(); + if (!is_array($val)) $val = array(); + if( C('DATA_CACHE_COMPRESS') && function_exists('gzcompress')) { + //数据压缩 + $value = gzcompress($value,3); + } + $name = $this->options['prefix'].$name; + $val[$name] = $value; + $val = serialize($val); + if($this->_write($val, $lh)) { + if($this->options['length']>0) { + // 记录缓存队列 + $this->queue($name); + } + return true; + } + return false; + } + + /** + * 删除缓存 + * @access public + * @param string $name 缓存变量名 + * @return boolen + */ + public function rm($name) { + $lh = $this->_lock(); + $val = $this->get(); + if (!is_array($val)) $val = array(); + $name = $this->options['prefix'].$name; + unset($val[$name]); + $val = serialize($val); + return $this->_write($val, $lh); + } + + /** + * 生成IPC key + * @access private + * @param string $project 项目标识名 + * @return integer + */ + private function _ftok($project) { + if (function_exists('ftok')) return ftok(__FILE__, $project); + if(strtoupper(PHP_OS) == 'WINNT'){ + $s = stat(__FILE__); + return sprintf("%u", (($s['ino'] & 0xffff) | (($s['dev'] & 0xff) << 16) | + (($project & 0xff) << 24))); + }else { + $filename = __FILE__ . (string) $project; + for($key = array(); sizeof($key) < strlen($filename); $key[] = ord(substr($filename, sizeof($key), 1))); + return dechex(array_sum($key)); + } + } + + /** + * 写入操作 + * @access private + * @param string $name 缓存变量名 + * @return integer|boolen + */ + private function _write(&$val, &$lh) { + $id = shmop_open($this->handler, 'c', 0600, $this->options['size']); + if ($id) { + $ret = shmop_write($id, $val, 0) == strlen($val); + shmop_close($id); + $this->_unlock($lh); + return $ret; + } + $this->_unlock($lh); + return false; + } + + /** + * 共享锁定 + * @access private + * @param string $name 缓存变量名 + * @return boolen + */ + private function _lock() { + if (function_exists('sem_get')) { + $fp = sem_get($this->handler, 1, 0600, 1); + sem_acquire ($fp); + } else { + $fp = fopen($this->options['temp'].$this->options['prefix'].md5($this->handler), 'w'); + flock($fp, LOCK_EX); + } + return $fp; + } + + /** + * 解除共享锁定 + * @access private + * @param string $name 缓存变量名 + * @return boolen + */ + private function _unlock(&$fp) { + if (function_exists('sem_release')) { + sem_release($fp); + } else { + fclose($fp); + } + } +} \ No newline at end of file diff --git a/ThinkPHP/Library/Think/Cache/Driver/Sqlite.class.php b/ThinkPHP/Library/Think/Cache/Driver/Sqlite.class.php new file mode 100644 index 000000000..be379a832 --- /dev/null +++ b/ThinkPHP/Library/Think/Cache/Driver/Sqlite.class.php @@ -0,0 +1,119 @@ + +// +---------------------------------------------------------------------- +namespace Think\Cache\Driver; +use Think\Cache; +defined('THINK_PATH') or exit(); +/** + * Sqlite缓存驱动 + */ +class Sqlite extends Cache { + + /** + * 架构函数 + * @param array $options 缓存参数 + * @access public + */ + public function __construct($options=array()) { + if ( !extension_loaded('sqlite') ) { + throw_exception(L('_NOT_SUPPERT_').':sqlite'); + } + if(empty($options)) { + $options = array ( + 'db' => ':memory:', + 'table' => 'sharedmemory', + ); + } + $this->options = $options; + $this->options['prefix'] = isset($options['prefix'])? $options['prefix'] : C('DATA_CACHE_PREFIX'); + $this->options['length'] = isset($options['length'])? $options['length'] : 0; + $this->options['expire'] = isset($options['expire'])? $options['expire'] : C('DATA_CACHE_TIME'); + + $func = $this->options['persistent'] ? 'sqlite_popen' : 'sqlite_open'; + $this->handler = $func($this->options['db']); + } + + /** + * 读取缓存 + * @access public + * @param string $name 缓存变量名 + * @return mixed + */ + public function get($name) { + N('cache_read',1); + $name = $this->options['prefix'].sqlite_escape_string($name); + $sql = 'SELECT value FROM '.$this->options['table'].' WHERE var=\''.$name.'\' AND (expire=0 OR expire >'.time().') LIMIT 1'; + $result = sqlite_query($this->handler, $sql); + if (sqlite_num_rows($result)) { + $content = sqlite_fetch_single($result); + if(C('DATA_CACHE_COMPRESS') && function_exists('gzcompress')) { + //启用数据压缩 + $content = gzuncompress($content); + } + return unserialize($content); + } + return false; + } + + /** + * 写入缓存 + * @access public + * @param string $name 缓存变量名 + * @param mixed $value 存储数据 + * @param integer $expire 有效时间(秒) + * @return boolen + */ + public function set($name, $value,$expire=null) { + N('cache_write',1); + $name = $this->options['prefix'].sqlite_escape_string($name); + $value = sqlite_escape_string(serialize($value)); + if(is_null($expire)) { + $expire = $this->options['expire']; + } + $expire = ($expire==0)?0: (time()+$expire) ;//缓存有效期为0表示永久缓存 + if( C('DATA_CACHE_COMPRESS') && function_exists('gzcompress')) { + //数据压缩 + $value = gzcompress($value,3); + } + $sql = 'REPLACE INTO '.$this->options['table'].' (var, value,expire) VALUES (\''.$name.'\', \''.$value.'\', \''.$expire.'\')'; + if(sqlite_query($this->handler, $sql)){ + if($this->options['length']>0) { + // 记录缓存队列 + $this->queue($name); + } + return true; + } + return false; + } + + /** + * 删除缓存 + * @access public + * @param string $name 缓存变量名 + * @return boolen + */ + public function rm($name) { + $name = $this->options['prefix'].sqlite_escape_string($name); + $sql = 'DELETE FROM '.$this->options['table'].' WHERE var=\''.$name.'\''; + sqlite_query($this->handler, $sql); + return true; + } + + /** + * 清除缓存 + * @access public + * @return boolen + */ + public function clear() { + $sql = 'DELETE FROM '.$this->options['table']; + sqlite_query($this->handler, $sql); + return ; + } +} \ No newline at end of file diff --git a/ThinkPHP/Library/Think/Cache/Driver/Wincache.class.php b/ThinkPHP/Library/Think/Cache/Driver/Wincache.class.php new file mode 100644 index 000000000..39142f502 --- /dev/null +++ b/ThinkPHP/Library/Think/Cache/Driver/Wincache.class.php @@ -0,0 +1,79 @@ + +// +---------------------------------------------------------------------- +namespace Think\Cache\Driver; +use Think\Cache; +defined('THINK_PATH') or exit(); +/** + * Wincache缓存驱动 + */ +class Wincache extends Cache { + + /** + * 架构函数 + * @param array $options 缓存参数 + * @access public + */ + public function __construct($options=array()) { + if ( !function_exists('wincache_ucache_info') ) { + throw_exception(L('_NOT_SUPPERT_').':WinCache'); + } + $this->options['expire'] = isset($options['expire'])? $options['expire'] : C('DATA_CACHE_TIME'); + $this->options['prefix'] = isset($options['prefix'])? $options['prefix'] : C('DATA_CACHE_PREFIX'); + $this->options['length'] = isset($options['length'])? $options['length'] : 0; + } + + /** + * 读取缓存 + * @access public + * @param string $name 缓存变量名 + * @return mixed + */ + public function get($name) { + N('cache_read',1); + $name = $this->options['prefix'].$name; + return wincache_ucache_exists($name)? wincache_ucache_get($name) : false; + } + + /** + * 写入缓存 + * @access public + * @param string $name 缓存变量名 + * @param mixed $value 存储数据 + * @param integer $expire 有效时间(秒) + * @return boolen + */ + public function set($name, $value,$expire=null) { + N('cache_write',1); + if(is_null($expire)) { + $expire = $this->options['expire']; + } + $name = $this->options['prefix'].$name; + if(wincache_ucache_set($name, $value, $expire)) { + if($this->options['length']>0) { + // 记录缓存队列 + $this->queue($name); + } + return true; + } + return false; + } + + /** + * 删除缓存 + * @access public + * @param string $name 缓存变量名 + * @return boolen + */ + public function rm($name) { + return wincache_ucache_delete($this->options['prefix'].$name); + } + +} \ No newline at end of file diff --git a/ThinkPHP/Library/Think/Cache/Driver/Xcache.class.php b/ThinkPHP/Library/Think/Cache/Driver/Xcache.class.php new file mode 100644 index 000000000..d9ba2d911 --- /dev/null +++ b/ThinkPHP/Library/Think/Cache/Driver/Xcache.class.php @@ -0,0 +1,81 @@ + +// +---------------------------------------------------------------------- +namespace Think\Cache\Driver; +use Think\Cache; +defined('THINK_PATH') or exit(); +/** + * Xcache缓存驱动 + */ +class Xcache extends Cache { + + /** + * 架构函数 + * @param array $options 缓存参数 + * @access public + */ + public function __construct($options=array()) { + if ( !function_exists('xcache_info') ) { + throw_exception(L('_NOT_SUPPERT_').':Xcache'); + } + $this->options['expire'] = isset($options['expire'])?$options['expire']:C('DATA_CACHE_TIME'); + $this->options['prefix'] = isset($options['prefix'])?$options['prefix']:C('DATA_CACHE_PREFIX'); + $this->options['length'] = isset($options['length'])?$options['length']:0; + } + + /** + * 读取缓存 + * @access public + * @param string $name 缓存变量名 + * @return mixed + */ + public function get($name) { + N('cache_read',1); + $name = $this->options['prefix'].$name; + if (xcache_isset($name)) { + return xcache_get($name); + } + return false; + } + + /** + * 写入缓存 + * @access public + * @param string $name 缓存变量名 + * @param mixed $value 存储数据 + * @param integer $expire 有效时间(秒) + * @return boolen + */ + public function set($name, $value,$expire=null) { + N('cache_write',1); + if(is_null($expire)) { + $expire = $this->options['expire'] ; + } + $name = $this->options['prefix'].$name; + if(xcache_set($name, $value, $expire)) { + if($this->options['length']>0) { + // 记录缓存队列 + $this->queue($name); + } + return true; + } + return false; + } + + /** + * 删除缓存 + * @access public + * @param string $name 缓存变量名 + * @return boolen + */ + public function rm($name) { + return xcache_unset($this->options['prefix'].$name); + } +} \ No newline at end of file diff --git a/ThinkPHP/Lib/Core/Action.class.php b/ThinkPHP/Library/Think/Controller.class.php similarity index 64% rename from ThinkPHP/Lib/Core/Action.class.php rename to ThinkPHP/Library/Think/Controller.class.php index 7e43deed8..97541dade 100644 --- a/ThinkPHP/Lib/Core/Action.class.php +++ b/ThinkPHP/Library/Think/Controller.class.php @@ -1,411 +1,303 @@ - -// +---------------------------------------------------------------------- - -/** - * ThinkPHP Action控制器基类 抽象类 - * @category Think - * @package Think - * @subpackage Core - * @author liu21st - */ -abstract class Action { - - /** - * 视图实例对象 - * @var view - * @access protected - */ - protected $view = null; - - /** - * 当前控制器名称 - * @var name - * @access protected - */ - private $name = ''; - - /** - * 控制器参数 - * @var config - * @access protected - */ - protected $config = array(); - - /** - * 架构函数 取得模板对象实例 - * @access public - */ - public function __construct() { - tag('action_begin',$this->config); - //实例化视图类 - $this->view = Think::instance('View'); - //控制器初始化 - if(method_exists($this,'_initialize')) - $this->_initialize(); - } - - /** - * 获取当前Action名称 - * @access protected - */ - protected function getActionName() { - if(empty($this->name)) { - // 获取Action名称 - $this->name = substr(get_class($this),0,-6); - } - return $this->name; - } - - /** - * 是否AJAX请求 - * @access protected - * @return bool - */ - protected function isAjax() { - if(isset($_SERVER['HTTP_X_REQUESTED_WITH']) ) { - if('xmlhttprequest' == strtolower($_SERVER['HTTP_X_REQUESTED_WITH'])) - return true; - } - if(!empty($_POST[C('VAR_AJAX_SUBMIT')]) || !empty($_GET[C('VAR_AJAX_SUBMIT')])) - // 判断Ajax方式提交 - return true; - return false; - } - - /** - * 模板显示 调用内置的模板引擎显示方法, - * @access protected - * @param string $templateFile 指定要调用的模板文件 - * 默认为空 由系统自动定位模板文件 - * @param string $charset 输出编码 - * @param string $contentType 输出类型 - * @param string $content 输出内容 - * @param string $prefix 模板缓存前缀 - * @return void - */ - protected function display($templateFile='',$charset='',$contentType='',$content='',$prefix='') { - $this->view->display($templateFile,$charset,$contentType,$content,$prefix); - } - - /** - * 输出内容文本可以包括Html 并支持内容解析 - * @access protected - * @param string $content 输出内容 - * @param string $charset 模板输出字符集 - * @param string $contentType 输出类型 - * @param string $prefix 模板缓存前缀 - * @return mixed - */ - protected function show($content,$charset='',$contentType='',$prefix='') { - $this->view->display('',$charset,$contentType,$content,$prefix); - } - - /** - * 获取输出页面内容 - * 调用内置的模板引擎fetch方法, - * @access protected - * @param string $templateFile 指定要调用的模板文件 - * 默认为空 由系统自动定位模板文件 - * @param string $content 模板输出内容 - * @param string $prefix 模板缓存前缀* - * @return string - */ - protected function fetch($templateFile='',$content='',$prefix='') { - return $this->view->fetch($templateFile,$content,$prefix); - } - - /** - * 创建静态页面 - * @access protected - * @htmlfile 生成的静态文件名称 - * @htmlpath 生成的静态文件路径 - * @param string $templateFile 指定要调用的模板文件 - * 默认为空 由系统自动定位模板文件 - * @return string - */ - protected function buildHtml($htmlfile='',$htmlpath='',$templateFile='') { - $content = $this->fetch($templateFile); - $htmlpath = !empty($htmlpath)?$htmlpath:HTML_PATH; - $htmlfile = $htmlpath.$htmlfile.C('HTML_FILE_SUFFIX'); - if(!is_dir(dirname($htmlfile))) - // 如果静态目录不存在 则创建 - mkdir(dirname($htmlfile),0755,true); - if(false === file_put_contents($htmlfile,$content)) - throw_exception(L('_CACHE_WRITE_ERROR_').':'.$htmlfile); - return $content; - } - - /** - * 模板主题设置 - * @access protected - * @param string $theme 模版主题 - * @return Action - */ - protected function theme($theme){ - $this->view->theme($theme); - return $this; - } - - /** - * 模板变量赋值 - * @access protected - * @param mixed $name 要显示的模板变量 - * @param mixed $value 变量的值 - * @return Action - */ - protected function assign($name,$value='') { - $this->view->assign($name,$value); - return $this; - } - - public function __set($name,$value) { - $this->assign($name,$value); - } - - /** - * 取得模板显示变量的值 - * @access protected - * @param string $name 模板显示变量 - * @return mixed - */ - public function get($name='') { - return $this->view->get($name); - } - - public function __get($name) { - return $this->get($name); - } - - /** - * 检测模板变量的值 - * @access public - * @param string $name 名称 - * @return boolean - */ - public function __isset($name) { - return $this->get($name); - } - - /** - * 魔术方法 有不存在的操作的时候执行 - * @access public - * @param string $method 方法名 - * @param array $args 参数 - * @return mixed - */ - public function __call($method,$args) { - if( 0 === strcasecmp($method,ACTION_NAME.C('ACTION_SUFFIX'))) { - if(method_exists($this,'_empty')) { - // 如果定义了_empty操作 则调用 - $this->_empty($method,$args); - }elseif(file_exists_case($this->view->parseTemplate())){ - // 检查是否存在默认模版 如果有直接输出模版 - $this->display(); - }elseif(function_exists('__hack_action')) { - // hack 方式定义扩展操作 - __hack_action(); - }else{ - _404(L('_ERROR_ACTION_').':'.ACTION_NAME); - } - }else{ - switch(strtolower($method)) { - // 判断提交方式 - case 'ispost' : - case 'isget' : - case 'ishead' : - case 'isdelete' : - case 'isput' : - return strtolower($_SERVER['REQUEST_METHOD']) == strtolower(substr($method,2)); - // 获取变量 支持过滤和默认值 调用方式 $this->_post($key,$filter,$default); - case '_get' : $input =& $_GET;break; - case '_post' : $input =& $_POST;break; - case '_put' : parse_str(file_get_contents('php://input'), $input);break; - case '_param' : - switch($_SERVER['REQUEST_METHOD']) { - case 'POST': - $input = $_POST; - break; - case 'PUT': - parse_str(file_get_contents('php://input'), $input); - break; - default: - $input = $_GET; - } - if(C('VAR_URL_PARAMS') && isset($_GET[C('VAR_URL_PARAMS')])){ - $input = array_merge($input,$_GET[C('VAR_URL_PARAMS')]); - } - break; - case '_request' : $input =& $_REQUEST; break; - case '_session' : $input =& $_SESSION; break; - case '_cookie' : $input =& $_COOKIE; break; - case '_server' : $input =& $_SERVER; break; - case '_globals' : $input =& $GLOBALS; break; - default: - throw_exception(__CLASS__.':'.$method.L('_METHOD_NOT_EXIST_')); - } - if(!isset($args[0])) { // 获取全局变量 - $data = $input; // 由VAR_FILTERS配置进行过滤 - }elseif(isset($input[$args[0]])) { // 取值操作 - $data = $input[$args[0]]; - $filters = isset($args[1])?$args[1]:C('DEFAULT_FILTER'); - if($filters) {// 2012/3/23 增加多方法过滤支持 - $filters = explode(',',$filters); - foreach($filters as $filter){ - if(function_exists($filter)) { - $data = is_array($data)?array_map($filter,$data):$filter($data); // 参数过滤 - } - } - } - }else{ // 变量默认值 - $data = isset($args[2])?$args[2]:NULL; - } - Log::record('建议使用I方法替代'.$method,Log::NOTICE); - return $data; - } - } - - /** - * 操作错误跳转的快捷方法 - * @access protected - * @param string $message 错误信息 - * @param string $jumpUrl 页面跳转地址 - * @param mixed $ajax 是否为Ajax方式 当数字时指定跳转时间 - * @return void - */ - protected function error($message='',$jumpUrl='',$ajax=false) { - $this->dispatchJump($message,0,$jumpUrl,$ajax); - } - - /** - * 操作成功跳转的快捷方法 - * @access protected - * @param string $message 提示信息 - * @param string $jumpUrl 页面跳转地址 - * @param mixed $ajax 是否为Ajax方式 当数字时指定跳转时间 - * @return void - */ - protected function success($message='',$jumpUrl='',$ajax=false) { - $this->dispatchJump($message,1,$jumpUrl,$ajax); - } - - /** - * Ajax方式返回数据到客户端 - * @access protected - * @param mixed $data 要返回的数据 - * @param String $type AJAX返回数据格式 - * @return void - */ - protected function ajaxReturn($data,$type='') { - if(func_num_args()>2) {// 兼容3.0之前用法 - $args = func_get_args(); - array_shift($args); - $info = array(); - $info['data'] = $data; - $info['info'] = array_shift($args); - $info['status'] = array_shift($args); - $data = $info; - $type = $args?array_shift($args):''; - } - if(empty($type)) $type = C('DEFAULT_AJAX_RETURN'); - switch (strtoupper($type)){ - case 'JSON' : - // 返回JSON数据格式到客户端 包含状态信息 - header('Content-Type:application/json; charset=utf-8'); - exit(json_encode($data)); - case 'XML' : - // 返回xml格式数据 - header('Content-Type:text/xml; charset=utf-8'); - exit(xml_encode($data)); - case 'JSONP': - // 返回JSON数据格式到客户端 包含状态信息 - header('Content-Type:application/json; charset=utf-8'); - $handler = isset($_GET[C('VAR_JSONP_HANDLER')]) ? $_GET[C('VAR_JSONP_HANDLER')] : C('DEFAULT_JSONP_HANDLER'); - exit($handler.'('.json_encode($data).');'); - case 'EVAL' : - // 返回可执行的js脚本 - header('Content-Type:text/html; charset=utf-8'); - exit($data); - default : - // 用于扩展其他返回格式数据 - tag('ajax_return',$data); - } - } - - /** - * Action跳转(URL重定向) 支持指定模块和延时跳转 - * @access protected - * @param string $url 跳转的URL表达式 - * @param array $params 其它URL参数 - * @param integer $delay 延时跳转的时间 单位为秒 - * @param string $msg 跳转提示信息 - * @return void - */ - protected function redirect($url,$params=array(),$delay=0,$msg='') { - $url = U($url,$params); - redirect($url,$delay,$msg); - } - - /** - * 默认跳转操作 支持错误导向和正确跳转 - * 调用模板显示 默认为public目录下面的success页面 - * 提示页面为可配置 支持模板标签 - * @param string $message 提示信息 - * @param Boolean $status 状态 - * @param string $jumpUrl 页面跳转地址 - * @param mixed $ajax 是否为Ajax方式 当数字时指定跳转时间 - * @access private - * @return void - */ - private function dispatchJump($message,$status=1,$jumpUrl='',$ajax=false) { - if(true === $ajax || IS_AJAX) {// AJAX提交 - $data = is_array($ajax)?$ajax:array(); - $data['info'] = $message; - $data['status'] = $status; - $data['url'] = $jumpUrl; - $this->ajaxReturn($data); - } - if(is_int($ajax)) $this->assign('waitSecond',$ajax); - if(!empty($jumpUrl)) $this->assign('jumpUrl',$jumpUrl); - // 提示标题 - $this->assign('msgTitle',$status? L('_OPERATION_SUCCESS_') : L('_OPERATION_FAIL_')); - //如果设置了关闭窗口,则提示完毕后自动关闭窗口 - if($this->get('closeWin')) $this->assign('jumpUrl','javascript:window.close();'); - $this->assign('status',$status); // 状态 - //保证输出不受静态缓存影响 - C('HTML_CACHE_ON',false); - if($status) { //发送成功信息 - $this->assign('message',$message);// 提示信息 - // 成功操作后默认停留1秒 - if(!isset($this->waitSecond)) $this->assign('waitSecond','1'); - // 默认操作成功自动返回操作前页面 - if(!isset($this->jumpUrl)) $this->assign("jumpUrl",$_SERVER["HTTP_REFERER"]); - $this->display(C('TMPL_ACTION_SUCCESS')); - }else{ - $this->assign('error',$message);// 提示信息 - //发生错误时候默认停留3秒 - if(!isset($this->waitSecond)) $this->assign('waitSecond','3'); - // 默认发生错误的话自动返回上页 - if(!isset($this->jumpUrl)) $this->assign('jumpUrl',"javascript:history.back(-1);"); - $this->display(C('TMPL_ACTION_ERROR')); - // 中止执行 避免出错后继续执行 - exit ; - } - } - - /** - * 析构方法 - * @access public - */ - public function __destruct() { - // 执行后续操作 - tag('action_end'); - } -} \ No newline at end of file + +// +---------------------------------------------------------------------- +namespace Think; +/** + * ThinkPHP 控制器基类 抽象类 + */ +abstract class Controller { + + /** + * 视图实例对象 + * @var view + * @access protected + */ + protected $view = null; + + /** + * 控制器参数 + * @var config + * @access protected + */ + protected $config = array(); + + /** + * 架构函数 取得模板对象实例 + * @access public + */ + public function __construct() { + Hook::listen('action_begin',$this->config); + //实例化视图类 + $this->view = Think::instance('Think\View'); + //控制器初始化 + if(method_exists($this,'_initialize')) + $this->_initialize(); + } + + /** + * 模板显示 调用内置的模板引擎显示方法, + * @access protected + * @param string $templateFile 指定要调用的模板文件 + * 默认为空 由系统自动定位模板文件 + * @param string $charset 输出编码 + * @param string $contentType 输出类型 + * @param string $content 输出内容 + * @param string $prefix 模板缓存前缀 + * @return void + */ + protected function display($templateFile='',$charset='',$contentType='',$content='',$prefix='') { + $this->view->display($templateFile,$charset,$contentType,$content,$prefix); + } + + /** + * 输出内容文本可以包括Html 并支持内容解析 + * @access protected + * @param string $content 输出内容 + * @param string $charset 模板输出字符集 + * @param string $contentType 输出类型 + * @param string $prefix 模板缓存前缀 + * @return mixed + */ + protected function show($content,$charset='',$contentType='',$prefix='') { + $this->view->display('',$charset,$contentType,$content,$prefix); + } + + /** + * 获取输出页面内容 + * 调用内置的模板引擎fetch方法, + * @access protected + * @param string $templateFile 指定要调用的模板文件 + * 默认为空 由系统自动定位模板文件 + * @param string $content 模板输出内容 + * @param string $prefix 模板缓存前缀* + * @return string + */ + protected function fetch($templateFile='',$content='',$prefix='') { + return $this->view->fetch($templateFile,$content,$prefix); + } + + /** + * 创建静态页面 + * @access protected + * @htmlfile 生成的静态文件名称 + * @htmlpath 生成的静态文件路径 + * @param string $templateFile 指定要调用的模板文件 + * 默认为空 由系统自动定位模板文件 + * @return string + */ + protected function buildHtml($htmlfile='',$htmlpath='',$templateFile='') { + $content = $this->fetch($templateFile); + $htmlpath = !empty($htmlpath)?$htmlpath:HTML_PATH; + $htmlfile = $htmlpath.$htmlfile.C('HTML_FILE_SUFFIX'); + Storage::put($htmlfile,$content,'html'); + return $content; + } + + /** + * 模板主题设置 + * @access protected + * @param string $theme 模版主题 + * @return Action + */ + protected function theme($theme){ + $this->view->theme($theme); + return $this; + } + + /** + * 模板变量赋值 + * @access protected + * @param mixed $name 要显示的模板变量 + * @param mixed $value 变量的值 + * @return Action + */ + protected function assign($name,$value='') { + $this->view->assign($name,$value); + return $this; + } + + public function __set($name,$value) { + $this->assign($name,$value); + } + + /** + * 取得模板显示变量的值 + * @access protected + * @param string $name 模板显示变量 + * @return mixed + */ + public function get($name='') { + return $this->view->get($name); + } + + public function __get($name) { + return $this->get($name); + } + + /** + * 检测模板变量的值 + * @access public + * @param string $name 名称 + * @return boolean + */ + public function __isset($name) { + return $this->get($name); + } + + /** + * 魔术方法 有不存在的操作的时候执行 + * @access public + * @param string $method 方法名 + * @param array $args 参数 + * @return mixed + */ + public function __call($method,$args) { + if( 0 === strcasecmp($method,ACTION_NAME.C('ACTION_SUFFIX'))) { + if(method_exists($this,'_empty')) { + // 如果定义了_empty操作 则调用 + $this->_empty($method,$args); + }elseif(file_exists_case($this->view->parseTemplate())){ + // 检查是否存在默认模版 如果有直接输出模版 + $this->display(); + }else{ + E(L('_ERROR_ACTION_').':'.ACTION_NAME); + } + } + } + + /** + * 操作错误跳转的快捷方法 + * @access protected + * @param string $message 错误信息 + * @param string $jumpUrl 页面跳转地址 + * @param mixed $ajax 是否为Ajax方式 当数字时指定跳转时间 + * @return void + */ + protected function error($message='',$jumpUrl='',$ajax=false) { + $this->dispatchJump($message,0,$jumpUrl,$ajax); + } + + /** + * 操作成功跳转的快捷方法 + * @access protected + * @param string $message 提示信息 + * @param string $jumpUrl 页面跳转地址 + * @param mixed $ajax 是否为Ajax方式 当数字时指定跳转时间 + * @return void + */ + protected function success($message='',$jumpUrl='',$ajax=false) { + $this->dispatchJump($message,1,$jumpUrl,$ajax); + } + + /** + * Ajax方式返回数据到客户端 + * @access protected + * @param mixed $data 要返回的数据 + * @param String $type AJAX返回数据格式 + * @return void + */ + protected function ajaxReturn($data,$type='') { + if(empty($type)) $type = C('DEFAULT_AJAX_RETURN'); + switch (strtoupper($type)){ + case 'JSON' : + // 返回JSON数据格式到客户端 包含状态信息 + header('Content-Type:application/json; charset=utf-8'); + exit(json_encode($data)); + case 'XML' : + // 返回xml格式数据 + header('Content-Type:text/xml; charset=utf-8'); + exit(xml_encode($data)); + case 'JSONP': + // 返回JSON数据格式到客户端 包含状态信息 + header('Content-Type:application/json; charset=utf-8'); + $handler = isset($_GET[C('VAR_JSONP_HANDLER')]) ? $_GET[C('VAR_JSONP_HANDLER')] : C('DEFAULT_JSONP_HANDLER'); + exit($handler.'('.json_encode($data).');'); + case 'EVAL' : + // 返回可执行的js脚本 + header('Content-Type:text/html; charset=utf-8'); + exit($data); + default : + // 用于扩展其他返回格式数据 + Hook::listen('ajax_return',$data); + } + } + + /** + * Action跳转(URL重定向) 支持指定模块和延时跳转 + * @access protected + * @param string $url 跳转的URL表达式 + * @param array $params 其它URL参数 + * @param integer $delay 延时跳转的时间 单位为秒 + * @param string $msg 跳转提示信息 + * @return void + */ + protected function redirect($url,$params=array(),$delay=0,$msg='') { + $url = U($url,$params); + redirect($url,$delay,$msg); + } + + /** + * 默认跳转操作 支持错误导向和正确跳转 + * 调用模板显示 默认为public目录下面的success页面 + * 提示页面为可配置 支持模板标签 + * @param string $message 提示信息 + * @param Boolean $status 状态 + * @param string $jumpUrl 页面跳转地址 + * @param mixed $ajax 是否为Ajax方式 当数字时指定跳转时间 + * @access private + * @return void + */ + private function dispatchJump($message,$status=1,$jumpUrl='',$ajax=false) { + if(true === $ajax || IS_AJAX) {// AJAX提交 + $data = is_array($ajax)?$ajax:array(); + $data['info'] = $message; + $data['status'] = $status; + $data['url'] = $jumpUrl; + $this->ajaxReturn($data); + } + if(is_int($ajax)) $this->assign('waitSecond',$ajax); + if(!empty($jumpUrl)) $this->assign('jumpUrl',$jumpUrl); + // 提示标题 + $this->assign('msgTitle',$status? L('_OPERATION_SUCCESS_') : L('_OPERATION_FAIL_')); + //如果设置了关闭窗口,则提示完毕后自动关闭窗口 + if($this->get('closeWin')) $this->assign('jumpUrl','javascript:window.close();'); + $this->assign('status',$status); // 状态 + //保证输出不受静态缓存影响 + C('HTML_CACHE_ON',false); + if($status) { //发送成功信息 + $this->assign('message',$message);// 提示信息 + // 成功操作后默认停留1秒 + if(!isset($this->waitSecond)) $this->assign('waitSecond','1'); + // 默认操作成功自动返回操作前页面 + if(!isset($this->jumpUrl)) $this->assign("jumpUrl",$_SERVER["HTTP_REFERER"]); + $this->display(C('TMPL_ACTION_SUCCESS')); + }else{ + $this->assign('error',$message);// 提示信息 + //发生错误时候默认停留3秒 + if(!isset($this->waitSecond)) $this->assign('waitSecond','3'); + // 默认发生错误的话自动返回上页 + if(!isset($this->jumpUrl)) $this->assign('jumpUrl',"javascript:history.back(-1);"); + $this->display(C('TMPL_ACTION_ERROR')); + // 中止执行 避免出错后继续执行 + exit ; + } + } + + /** + * 析构方法 + * @access public + */ + public function __destruct() { + // 执行后续操作 + Hook::listen('action_end'); + } +} +// 设置控制器别名 便于升级 +class_alias('Think\Controller','Think\Action'); \ No newline at end of file diff --git a/ThinkPHP/Library/Think/Crypt.class.php b/ThinkPHP/Library/Think/Crypt.class.php new file mode 100644 index 000000000..b7fcf9c55 --- /dev/null +++ b/ThinkPHP/Library/Think/Crypt.class.php @@ -0,0 +1,57 @@ + +// +---------------------------------------------------------------------- +namespace Think; +/** + * 加密解密类 + */ +class Crypt { + + private static $handler = ''; + + public static function init($type=''){ + $type = $type?$type:C('DATA_CRYPT_TYPE'); + if(strpos($type,'\\')){ + $class = $type; + }else{ + $class = 'Think\\Crypt\\Driver\\'. ucwords(strtolower($type)); + } + self::$handler = $class; + } + + /** + * 加密字符串 + * @param string $str 字符串 + * @param string $key 加密key + * @param integer $expire 有效期(秒) 0 为永久有效 + * @return string + */ + public static function encrypt($data,$key,$expire=0){ + if(empty(self::$handler)){ + self::init(); + } + $class = self::$handler; + return $class::encrypt($data,$key,$expire); + } + + /** + * 解密字符串 + * @param string $str 字符串 + * @param string $key 加密key + * @return string + */ + public static function decrypt($data,$key){ + if(empty(self::$handler)){ + self::init(); + } + $class = self::$handler; + return $class::decrypt($data,$key); + } +} \ No newline at end of file diff --git a/ThinkPHP/Library/Think/Crypt/Driver/Base64.class.php b/ThinkPHP/Library/Think/Crypt/Driver/Base64.class.php new file mode 100644 index 000000000..44f6014db --- /dev/null +++ b/ThinkPHP/Library/Think/Crypt/Driver/Base64.class.php @@ -0,0 +1,74 @@ + +// +---------------------------------------------------------------------- +namespace Think\Crypt\Driver; +/** + * Base64 加密实现类 + */ +class Base64 { + + /** + * 加密字符串 + * @param string $str 字符串 + * @param string $key 加密key + * @param integer $expire 有效期(秒) + * @return string + */ + public static function encrypt($data,$key,$expire=0) { + $expire = sprintf('%010d', $expire ? $expire + time():0); + $key = md5($key); + $data = base64_encode($expire.$data); + $x=0; + $len = strlen($data); + $l = strlen($key); + for ($i=0;$i< $len;$i++) { + if ($x== $l) $x=0; + $char .=substr($key,$x,1); + $x++; + } + + for ($i=0;$i< $len;$i++) { + $str .=chr(ord(substr($data,$i,1))+(ord(substr($char,$i,1)))%256); + } + return $str; + } + + /** + * 解密字符串 + * @param string $str 字符串 + * @param string $key 加密key + * @return string + */ + public static function decrypt($data,$key) { + $key = md5($key); + $x=0; + $len = strlen($data); + $l = strlen($key); + for ($i=0;$i< $len;$i++) { + if ($x== $l) $x=0; + $char .=substr($key,$x,1); + $x++; + } + for ($i=0;$i< $len;$i++) { + if (ord(substr($data,$i,1)) 0 && $expire < time()) { + return ''; + } + $data = substr($data,10); + return $data; + } +} \ No newline at end of file diff --git a/ThinkPHP/Library/Think/Crypt/Driver/Crypt.class.php b/ThinkPHP/Library/Think/Crypt/Driver/Crypt.class.php new file mode 100644 index 000000000..e25468619 --- /dev/null +++ b/ThinkPHP/Library/Think/Crypt/Driver/Crypt.class.php @@ -0,0 +1,83 @@ + +// +---------------------------------------------------------------------- +namespace Think\Crypt\Driver; +/** + * Crypt 加密实现类 + * @category ORG + * @package ORG + * @subpackage Crypt + * @author liu21st + */ +class Crypt { + + /** + * 加密字符串 + * @param string $str 字符串 + * @param string $key 加密key + * @param integer $expire 有效期(秒) + * @return string + */ + public static function encrypt($str,$key,$expire=0){ + $expire = sprintf('%010d', $expire ? $expire + time():0); + $r = md5($key); + $c=0; + $v = ""; + $str = $expire.$str; + $len = strlen($str); + $l = strlen($r); + for ($i=0;$i<$len;$i++){ + if ($c== $l) $c=0; + $v.= substr($r,$c,1) . + (substr($str,$i,1) ^ substr($r,$c,1)); + $c++; + } + return self::ed($v,$key); + } + + /** + * 解密字符串 + * @param string $str 字符串 + * @param string $key 加密key + * @return string + */ + public static function decrypt($str,$key) { + $str = self::ed($str,$key); + $v = ""; + $len = strlen($str); + for ($i=0;$i<$len;$i++){ + $md5 = substr($str,$i,1); + $i++; + $v.= (substr($str,$i,1) ^ $md5); + } + $data = $v; + $expire = substr($data,0,10); + if($expire > 0 && $expire < time()) { + return ''; + } + $data = substr($data,10); + return $data; + } + + + function ed($str,$key) { + $r = md5($key); + $c=0; + $v = ""; + $len = strlen($str); + $l = strlen($r); + for ($i=0;$i<$len;$i++) { + if ($c==$l) $c=0; + $v.= substr($str,$i,1) ^ substr($r,$c,1); + $c++; + } + return $v; + } +} \ No newline at end of file diff --git a/ThinkPHP/Library/Think/Crypt/Driver/Des.class.php b/ThinkPHP/Library/Think/Crypt/Driver/Des.class.php new file mode 100644 index 000000000..db1bad61e --- /dev/null +++ b/ThinkPHP/Library/Think/Crypt/Driver/Des.class.php @@ -0,0 +1,241 @@ + +// +---------------------------------------------------------------------- +namespace Think\Crypt\Driver; +/** + * Des 加密实现类 + * Converted from JavaScript to PHP by Jim Gibbs, June 2004 Paul Tero, July 2001 + * Optimised for performance with large blocks by Michael Hayworth, November 2001 + * http://www.netdealing.com + */ + +class Des { + + /** + * 加密字符串 + * @param string $str 字符串 + * @param string $key 加密key + * @param integer $expire 有效期(秒) + * @return string + */ + public static function encrypt($str, $key,$expire=0) { + if ($str == "") { + return ""; + } + $expire = sprintf('%010d', $expire ? $expire + time():0); + $str = $expire.$str; + return self::_des($key,$str,1); + } + + /** + * 解密字符串 + * @param string $str 字符串 + * @param string $key 加密key + * @return string + */ + public static function decrypt($str, $key) { + if ($str == "") { + return ""; + } + $data = self::_des($key,$str,0); + $expire = substr($data,0,10); + if($expire > 0 && $expire < time()) { + return ''; + } + $data = substr($data,10); + return $data; + } + + /** + * Des算法 + * @param string $str 字符串 + * @param string $key 加密key + * @return string + */ + private static function _des($key, $message, $encrypt, $mode=0, $iv=null) { + //declaring this locally speeds things up a bit + $spfunction1 = array (0x1010400,0,0x10000,0x1010404,0x1010004,0x10404,0x4,0x10000,0x400,0x1010400,0x1010404,0x400,0x1000404,0x1010004,0x1000000,0x4,0x404,0x1000400,0x1000400,0x10400,0x10400,0x1010000,0x1010000,0x1000404,0x10004,0x1000004,0x1000004,0x10004,0,0x404,0x10404,0x1000000,0x10000,0x1010404,0x4,0x1010000,0x1010400,0x1000000,0x1000000,0x400,0x1010004,0x10000,0x10400,0x1000004,0x400,0x4,0x1000404,0x10404,0x1010404,0x10004,0x1010000,0x1000404,0x1000004,0x404,0x10404,0x1010400,0x404,0x1000400,0x1000400,0,0x10004,0x10400,0,0x1010004); + $spfunction2 = array (-0x7fef7fe0,-0x7fff8000,0x8000,0x108020,0x100000,0x20,-0x7fefffe0,-0x7fff7fe0,-0x7fffffe0,-0x7fef7fe0,-0x7fef8000,-0x80000000,-0x7fff8000,0x100000,0x20,-0x7fefffe0,0x108000,0x100020,-0x7fff7fe0,0,-0x80000000,0x8000,0x108020,-0x7ff00000,0x100020,-0x7fffffe0,0,0x108000,0x8020,-0x7fef8000,-0x7ff00000,0x8020,0,0x108020,-0x7fefffe0,0x100000,-0x7fff7fe0,-0x7ff00000,-0x7fef8000,0x8000,-0x7ff00000,-0x7fff8000,0x20,-0x7fef7fe0,0x108020,0x20,0x8000,-0x80000000,0x8020,-0x7fef8000,0x100000,-0x7fffffe0,0x100020,-0x7fff7fe0,-0x7fffffe0,0x100020,0x108000,0,-0x7fff8000,0x8020,-0x80000000,-0x7fefffe0,-0x7fef7fe0,0x108000); + $spfunction3 = array (0x208,0x8020200,0,0x8020008,0x8000200,0,0x20208,0x8000200,0x20008,0x8000008,0x8000008,0x20000,0x8020208,0x20008,0x8020000,0x208,0x8000000,0x8,0x8020200,0x200,0x20200,0x8020000,0x8020008,0x20208,0x8000208,0x20200,0x20000,0x8000208,0x8,0x8020208,0x200,0x8000000,0x8020200,0x8000000,0x20008,0x208,0x20000,0x8020200,0x8000200,0,0x200,0x20008,0x8020208,0x8000200,0x8000008,0x200,0,0x8020008,0x8000208,0x20000,0x8000000,0x8020208,0x8,0x20208,0x20200,0x8000008,0x8020000,0x8000208,0x208,0x8020000,0x20208,0x8,0x8020008,0x20200); + $spfunction4 = array (0x802001,0x2081,0x2081,0x80,0x802080,0x800081,0x800001,0x2001,0,0x802000,0x802000,0x802081,0x81,0,0x800080,0x800001,0x1,0x2000,0x800000,0x802001,0x80,0x800000,0x2001,0x2080,0x800081,0x1,0x2080,0x800080,0x2000,0x802080,0x802081,0x81,0x800080,0x800001,0x802000,0x802081,0x81,0,0,0x802000,0x2080,0x800080,0x800081,0x1,0x802001,0x2081,0x2081,0x80,0x802081,0x81,0x1,0x2000,0x800001,0x2001,0x802080,0x800081,0x2001,0x2080,0x800000,0x802001,0x80,0x800000,0x2000,0x802080); + $spfunction5 = array (0x100,0x2080100,0x2080000,0x42000100,0x80000,0x100,0x40000000,0x2080000,0x40080100,0x80000,0x2000100,0x40080100,0x42000100,0x42080000,0x80100,0x40000000,0x2000000,0x40080000,0x40080000,0,0x40000100,0x42080100,0x42080100,0x2000100,0x42080000,0x40000100,0,0x42000000,0x2080100,0x2000000,0x42000000,0x80100,0x80000,0x42000100,0x100,0x2000000,0x40000000,0x2080000,0x42000100,0x40080100,0x2000100,0x40000000,0x42080000,0x2080100,0x40080100,0x100,0x2000000,0x42080000,0x42080100,0x80100,0x42000000,0x42080100,0x2080000,0,0x40080000,0x42000000,0x80100,0x2000100,0x40000100,0x80000,0,0x40080000,0x2080100,0x40000100); + $spfunction6 = array (0x20000010,0x20400000,0x4000,0x20404010,0x20400000,0x10,0x20404010,0x400000,0x20004000,0x404010,0x400000,0x20000010,0x400010,0x20004000,0x20000000,0x4010,0,0x400010,0x20004010,0x4000,0x404000,0x20004010,0x10,0x20400010,0x20400010,0,0x404010,0x20404000,0x4010,0x404000,0x20404000,0x20000000,0x20004000,0x10,0x20400010,0x404000,0x20404010,0x400000,0x4010,0x20000010,0x400000,0x20004000,0x20000000,0x4010,0x20000010,0x20404010,0x404000,0x20400000,0x404010,0x20404000,0,0x20400010,0x10,0x4000,0x20400000,0x404010,0x4000,0x400010,0x20004010,0,0x20404000,0x20000000,0x400010,0x20004010); + $spfunction7 = array (0x200000,0x4200002,0x4000802,0,0x800,0x4000802,0x200802,0x4200800,0x4200802,0x200000,0,0x4000002,0x2,0x4000000,0x4200002,0x802,0x4000800,0x200802,0x200002,0x4000800,0x4000002,0x4200000,0x4200800,0x200002,0x4200000,0x800,0x802,0x4200802,0x200800,0x2,0x4000000,0x200800,0x4000000,0x200800,0x200000,0x4000802,0x4000802,0x4200002,0x4200002,0x2,0x200002,0x4000000,0x4000800,0x200000,0x4200800,0x802,0x200802,0x4200800,0x802,0x4000002,0x4200802,0x4200000,0x200800,0,0x2,0x4200802,0,0x200802,0x4200000,0x800,0x4000002,0x4000800,0x800,0x200002); + $spfunction8 = array (0x10001040,0x1000,0x40000,0x10041040,0x10000000,0x10001040,0x40,0x10000000,0x40040,0x10040000,0x10041040,0x41000,0x10041000,0x41040,0x1000,0x40,0x10040000,0x10000040,0x10001000,0x1040,0x41000,0x40040,0x10040040,0x10041000,0x1040,0,0,0x10040040,0x10000040,0x10001000,0x41040,0x40000,0x41040,0x40000,0x10041000,0x1000,0x40,0x10040040,0x1000,0x41040,0x10001000,0x40,0x10000040,0x10040000,0x10040040,0x10000000,0x40000,0x10001040,0,0x10041040,0x40040,0x10000040,0x10040000,0x10001000,0x10001040,0,0x10041040,0x41000,0x41000,0x1040,0x1040,0x40040,0x10000000,0x10041000); + $masks = array (4294967295,2147483647,1073741823,536870911,268435455,134217727,67108863,33554431,16777215,8388607,4194303,2097151,1048575,524287,262143,131071,65535,32767,16383,8191,4095,2047,1023,511,255,127,63,31,15,7,3,1,0); + + //create the 16 or 48 subkeys we will need + $keys = self::_createKeys ($key); + $m=0; + $len = strlen($message); + $chunk = 0; + //set up the loops for single and triple des + $iterations = ((count($keys) == 32) ? 3 : 9); //single or triple des + if ($iterations == 3) {$looping = (($encrypt) ? array (0, 32, 2) : array (30, -2, -2));} + else {$looping = (($encrypt) ? array (0, 32, 2, 62, 30, -2, 64, 96, 2) : array (94, 62, -2, 32, 64, 2, 30, -2, -2));} + + $message .= (chr(0) . chr(0) . chr(0) . chr(0) . chr(0) . chr(0) . chr(0) . chr(0)); //pad the message out with null bytes + //store the result here + $result = ""; + $tempresult = ""; + + if ($mode == 1) { //CBC mode + $cbcleft = (ord($iv{$m++}) << 24) | (ord($iv{$m++}) << 16) | (ord($iv{$m++}) << 8) | ord($iv{$m++}); + $cbcright = (ord($iv{$m++}) << 24) | (ord($iv{$m++}) << 16) | (ord($iv{$m++}) << 8) | ord($iv{$m++}); + $m=0; + } + + //loop through each 64 bit chunk of the message + while ($m < $len) { + $left = (ord($message{$m++}) << 24) | (ord($message{$m++}) << 16) | (ord($message{$m++}) << 8) | ord($message{$m++}); + $right = (ord($message{$m++}) << 24) | (ord($message{$m++}) << 16) | (ord($message{$m++}) << 8) | ord($message{$m++}); + + //for Cipher Block Chaining mode, xor the message with the previous result + if ($mode == 1) {if ($encrypt) {$left ^= $cbcleft; $right ^= $cbcright;} else {$cbcleft2 = $cbcleft; $cbcright2 = $cbcright; $cbcleft = $left; $cbcright = $right;}} + + //first each 64 but chunk of the message must be permuted according to IP + $temp = (($left >> 4 & $masks[4]) ^ $right) & 0x0f0f0f0f; $right ^= $temp; $left ^= ($temp << 4); + $temp = (($left >> 16 & $masks[16]) ^ $right) & 0x0000ffff; $right ^= $temp; $left ^= ($temp << 16); + $temp = (($right >> 2 & $masks[2]) ^ $left) & 0x33333333; $left ^= $temp; $right ^= ($temp << 2); + $temp = (($right >> 8 & $masks[8]) ^ $left) & 0x00ff00ff; $left ^= $temp; $right ^= ($temp << 8); + $temp = (($left >> 1 & $masks[1]) ^ $right) & 0x55555555; $right ^= $temp; $left ^= ($temp << 1); + + $left = (($left << 1) | ($left >> 31 & $masks[31])); + $right = (($right << 1) | ($right >> 31 & $masks[31])); + + //do this either 1 or 3 times for each chunk of the message + for ($j=0; $j<$iterations; $j+=3) { + $endloop = $looping[$j+1]; + $loopinc = $looping[$j+2]; + //now go through and perform the encryption or decryption + for ($i=$looping[$j]; $i!=$endloop; $i+=$loopinc) { //for efficiency + $right1 = $right ^ $keys[$i]; + $right2 = (($right >> 4 & $masks[4]) | ($right << 28)) ^ $keys[$i+1]; + //the result is attained by passing these bytes through the S selection functions + $temp = $left; + $left = $right; + $right = $temp ^ ($spfunction2[($right1 >> 24 & $masks[24]) & 0x3f] | $spfunction4[($right1 >> 16 & $masks[16]) & 0x3f] + | $spfunction6[($right1 >> 8 & $masks[8]) & 0x3f] | $spfunction8[$right1 & 0x3f] + | $spfunction1[($right2 >> 24 & $masks[24]) & 0x3f] | $spfunction3[($right2 >> 16 & $masks[16]) & 0x3f] + | $spfunction5[($right2 >> 8 & $masks[8]) & 0x3f] | $spfunction7[$right2 & 0x3f]); + } + $temp = $left; $left = $right; $right = $temp; //unreverse left and right + } //for either 1 or 3 iterations + + //move then each one bit to the right + $left = (($left >> 1 & $masks[1]) | ($left << 31)); + $right = (($right >> 1 & $masks[1]) | ($right << 31)); + + //now perform IP-1, which is IP in the opposite direction + $temp = (($left >> 1 & $masks[1]) ^ $right) & 0x55555555; $right ^= $temp; $left ^= ($temp << 1); + $temp = (($right >> 8 & $masks[8]) ^ $left) & 0x00ff00ff; $left ^= $temp; $right ^= ($temp << 8); + $temp = (($right >> 2 & $masks[2]) ^ $left) & 0x33333333; $left ^= $temp; $right ^= ($temp << 2); + $temp = (($left >> 16 & $masks[16]) ^ $right) & 0x0000ffff; $right ^= $temp; $left ^= ($temp << 16); + $temp = (($left >> 4 & $masks[4]) ^ $right) & 0x0f0f0f0f; $right ^= $temp; $left ^= ($temp << 4); + + //for Cipher Block Chaining mode, xor the message with the previous result + if ($mode == 1) {if ($encrypt) {$cbcleft = $left; $cbcright = $right;} else {$left ^= $cbcleft2; $right ^= $cbcright2;}} + $tempresult .= (chr($left>>24 & $masks[24]) . chr(($left>>16 & $masks[16]) & 0xff) . chr(($left>>8 & $masks[8]) & 0xff) . chr($left & 0xff) . chr($right>>24 & $masks[24]) . chr(($right>>16 & $masks[16]) & 0xff) . chr(($right>>8 & $masks[8]) & 0xff) . chr($right & 0xff)); + + $chunk += 8; + if ($chunk == 512) {$result .= $tempresult; $tempresult = ""; $chunk = 0;} + } //for every 8 characters, or 64 bits in the message + + //return the result as an array + return ($result . $tempresult); + } //end of des + + /** + * createKeys + * this takes as input a 64 bit key (even though only 56 bits are used) + * as an array of 2 integers, and returns 16 48 bit keys + * @param string $key 加密key + * @return string + */ + private static function _createKeys ($key) { + //declaring this locally speeds things up a bit + $pc2bytes0 = array (0,0x4,0x20000000,0x20000004,0x10000,0x10004,0x20010000,0x20010004,0x200,0x204,0x20000200,0x20000204,0x10200,0x10204,0x20010200,0x20010204); + $pc2bytes1 = array (0,0x1,0x100000,0x100001,0x4000000,0x4000001,0x4100000,0x4100001,0x100,0x101,0x100100,0x100101,0x4000100,0x4000101,0x4100100,0x4100101); + $pc2bytes2 = array (0,0x8,0x800,0x808,0x1000000,0x1000008,0x1000800,0x1000808,0,0x8,0x800,0x808,0x1000000,0x1000008,0x1000800,0x1000808); + $pc2bytes3 = array (0,0x200000,0x8000000,0x8200000,0x2000,0x202000,0x8002000,0x8202000,0x20000,0x220000,0x8020000,0x8220000,0x22000,0x222000,0x8022000,0x8222000); + $pc2bytes4 = array (0,0x40000,0x10,0x40010,0,0x40000,0x10,0x40010,0x1000,0x41000,0x1010,0x41010,0x1000,0x41000,0x1010,0x41010); + $pc2bytes5 = array (0,0x400,0x20,0x420,0,0x400,0x20,0x420,0x2000000,0x2000400,0x2000020,0x2000420,0x2000000,0x2000400,0x2000020,0x2000420); + $pc2bytes6 = array (0,0x10000000,0x80000,0x10080000,0x2,0x10000002,0x80002,0x10080002,0,0x10000000,0x80000,0x10080000,0x2,0x10000002,0x80002,0x10080002); + $pc2bytes7 = array (0,0x10000,0x800,0x10800,0x20000000,0x20010000,0x20000800,0x20010800,0x20000,0x30000,0x20800,0x30800,0x20020000,0x20030000,0x20020800,0x20030800); + $pc2bytes8 = array (0,0x40000,0,0x40000,0x2,0x40002,0x2,0x40002,0x2000000,0x2040000,0x2000000,0x2040000,0x2000002,0x2040002,0x2000002,0x2040002); + $pc2bytes9 = array (0,0x10000000,0x8,0x10000008,0,0x10000000,0x8,0x10000008,0x400,0x10000400,0x408,0x10000408,0x400,0x10000400,0x408,0x10000408); + $pc2bytes10 = array (0,0x20,0,0x20,0x100000,0x100020,0x100000,0x100020,0x2000,0x2020,0x2000,0x2020,0x102000,0x102020,0x102000,0x102020); + $pc2bytes11 = array (0,0x1000000,0x200,0x1000200,0x200000,0x1200000,0x200200,0x1200200,0x4000000,0x5000000,0x4000200,0x5000200,0x4200000,0x5200000,0x4200200,0x5200200); + $pc2bytes12 = array (0,0x1000,0x8000000,0x8001000,0x80000,0x81000,0x8080000,0x8081000,0x10,0x1010,0x8000010,0x8001010,0x80010,0x81010,0x8080010,0x8081010); + $pc2bytes13 = array (0,0x4,0x100,0x104,0,0x4,0x100,0x104,0x1,0x5,0x101,0x105,0x1,0x5,0x101,0x105); + $masks = array (4294967295,2147483647,1073741823,536870911,268435455,134217727,67108863,33554431,16777215,8388607,4194303,2097151,1048575,524287,262143,131071,65535,32767,16383,8191,4095,2047,1023,511,255,127,63,31,15,7,3,1,0); + + //how many iterations (1 for des, 3 for triple des) + $iterations = ((strlen($key) >= 24) ? 3 : 1); + //stores the return keys + $keys = array (); // size = 32 * iterations but you don't specify this in php + //now define the left shifts which need to be done + $shifts = array (0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0); + //other variables + $m=0; + $n=0; + + for ($j=0; $j<$iterations; $j++) { //either 1 or 3 iterations + $left = (ord($key{$m++}) << 24) | (ord($key{$m++}) << 16) | (ord($key{$m++}) << 8) | ord($key{$m++}); + $right = (ord($key{$m++}) << 24) | (ord($key{$m++}) << 16) | (ord($key{$m++}) << 8) | ord($key{$m++}); + + $temp = (($left >> 4 & $masks[4]) ^ $right) & 0x0f0f0f0f; $right ^= $temp; $left ^= ($temp << 4); + $temp = (($right >> 16 & $masks[16]) ^ $left) & 0x0000ffff; $left ^= $temp; $right ^= ($temp << -16); + $temp = (($left >> 2 & $masks[2]) ^ $right) & 0x33333333; $right ^= $temp; $left ^= ($temp << 2); + $temp = (($right >> 16 & $masks[16]) ^ $left) & 0x0000ffff; $left ^= $temp; $right ^= ($temp << -16); + $temp = (($left >> 1 & $masks[1]) ^ $right) & 0x55555555; $right ^= $temp; $left ^= ($temp << 1); + $temp = (($right >> 8 & $masks[8]) ^ $left) & 0x00ff00ff; $left ^= $temp; $right ^= ($temp << 8); + $temp = (($left >> 1 & $masks[1]) ^ $right) & 0x55555555; $right ^= $temp; $left ^= ($temp << 1); + + //the right side needs to be shifted and to get the last four bits of the left side + $temp = ($left << 8) | (($right >> 20 & $masks[20]) & 0x000000f0); + //left needs to be put upside down + $left = ($right << 24) | (($right << 8) & 0xff0000) | (($right >> 8 & $masks[8]) & 0xff00) | (($right >> 24 & $masks[24]) & 0xf0); + $right = $temp; + + //now go through and perform these shifts on the left and right keys + for ($i=0; $i < count($shifts); $i++) { + //shift the keys either one or two bits to the left + if ($shifts[$i] > 0) { + $left = (($left << 2) | ($left >> 26 & $masks[26])); + $right = (($right << 2) | ($right >> 26 & $masks[26])); + } else { + $left = (($left << 1) | ($left >> 27 & $masks[27])); + $right = (($right << 1) | ($right >> 27 & $masks[27])); + } + $left = $left & -0xf; + $right = $right & -0xf; + + //now apply PC-2, in such a way that E is easier when encrypting or decrypting + //this conversion will look like PC-2 except only the last 6 bits of each byte are used + //rather than 48 consecutive bits and the order of lines will be according to + //how the S selection functions will be applied: S2, S4, S6, S8, S1, S3, S5, S7 + $lefttemp = $pc2bytes0[$left >> 28 & $masks[28]] | $pc2bytes1[($left >> 24 & $masks[24]) & 0xf] + | $pc2bytes2[($left >> 20 & $masks[20]) & 0xf] | $pc2bytes3[($left >> 16 & $masks[16]) & 0xf] + | $pc2bytes4[($left >> 12 & $masks[12]) & 0xf] | $pc2bytes5[($left >> 8 & $masks[8]) & 0xf] + | $pc2bytes6[($left >> 4 & $masks[4]) & 0xf]; + $righttemp = $pc2bytes7[$right >> 28 & $masks[28]] | $pc2bytes8[($right >> 24 & $masks[24]) & 0xf] + | $pc2bytes9[($right >> 20 & $masks[20]) & 0xf] | $pc2bytes10[($right >> 16 & $masks[16]) & 0xf] + | $pc2bytes11[($right >> 12 & $masks[12]) & 0xf] | $pc2bytes12[($right >> 8 & $masks[8]) & 0xf] + | $pc2bytes13[($right >> 4 & $masks[4]) & 0xf]; + $temp = (($righttemp >> 16 & $masks[16]) ^ $lefttemp) & 0x0000ffff; + $keys[$n++] = $lefttemp ^ $temp; $keys[$n++] = $righttemp ^ ($temp << 16); + } + } //for each iterations + //return the keys we've created + return $keys; + } //end of des_createKeys + +} \ No newline at end of file diff --git a/ThinkPHP/Library/Think/Crypt/Driver/Think.class.php b/ThinkPHP/Library/Think/Crypt/Driver/Think.class.php new file mode 100644 index 000000000..f8ae9e15c --- /dev/null +++ b/ThinkPHP/Library/Think/Crypt/Driver/Think.class.php @@ -0,0 +1,86 @@ + +// +---------------------------------------------------------------------- +namespace Think\Crypt\Driver; +/** + * Base64 加密实现类 + */ +class Think { + + /** + * 加密字符串 + * @param string $str 字符串 + * @param string $key 加密key + * @param integer $expire 有效期(秒) + * @return string + */ + public static function encrypt($data,$key,$expire=0) { + $expire = sprintf('%010d', $expire ? $expire + time():0); + $key = md5($key); + $data = base64_encode($expire.$data); + $x = 0; + $len = strlen($data); + $l = strlen($key); + $char = $str = ''; + + for ($i = 0; $i < $len; $i++) { + if ($x == $l) $x = 0; + $char .= substr($key, $x, 1); + $x++; + } + + for ($i = 0; $i < $len; $i++) { + $str .= chr(ord(substr($data, $i, 1)) + (ord(substr($char, $i, 1)))%256); + } + return str_replace(array('+','/','='),array('-','_',''),base64_encode($str)); + } + + /** + * 解密字符串 + * @param string $str 字符串 + * @param string $key 加密key + * @return string + */ + public static function decrypt($data,$key) { + $key = md5($key); + $data = str_replace(array('-','_'),array('+','/'),$data); + $mod4 = strlen($data) % 4; + if ($mod4) { + $data .= substr('====', $mod4); + } + $data = base64_decode($data); + + $x = 0; + $len = strlen($data); + $l = strlen($key); + $char = $str = ''; + + for ($i = 0; $i < $len; $i++) { + if ($x == $l) $x = 0; + $char .= substr($key, $x, 1); + $x++; + } + + for ($i = 0; $i < $len; $i++) { + if (ord(substr($data, $i, 1)) 0 && $expire < time()) { + return ''; + } + $data = substr($data,10); + return $data; + } +} \ No newline at end of file diff --git a/ThinkPHP/Library/Think/Crypt/Driver/Xxtea.class.php b/ThinkPHP/Library/Think/Crypt/Driver/Xxtea.class.php new file mode 100644 index 000000000..3f506a196 --- /dev/null +++ b/ThinkPHP/Library/Think/Crypt/Driver/Xxtea.class.php @@ -0,0 +1,116 @@ + +// +---------------------------------------------------------------------- +namespace Think\Crypt\Driver; +/** + * Xxtea 加密实现类 + */ +class Xxtea { + + /** + * 加密字符串 + * @param string $str 字符串 + * @param string $key 加密key + * @param integer $expire 有效期(秒) + * @return string + */ + public static function encrypt($str, $key,$expire=0) { + $expire = sprintf('%010d', $expire ? $expire + time():0); + $str = $expire.$str; + $v = self::str2long($str, true); + $k = self::str2long($key, false); + $n = count($v) - 1; + + $z = $v[$n]; + $y = $v[0]; + $delta = 0x9E3779B9; + $q = floor(6 + 52 / ($n + 1)); + $sum = 0; + while (0 < $q--) { + $sum = self::int32($sum + $delta); + $e = $sum >> 2 & 3; + for ($p = 0; $p < $n; $p++) { + $y = $v[$p + 1]; + $mx = self::int32((($z >> 5 & 0x07ffffff) ^ $y << 2) + (($y >> 3 & 0x1fffffff) ^ $z << 4)) ^ self::int32(($sum ^ $y) + ($k[$p & 3 ^ $e] ^ $z)); + $z = $v[$p] = self::int32($v[$p] + $mx); + } + $y = $v[0]; + $mx = self::int32((($z >> 5 & 0x07ffffff) ^ $y << 2) + (($y >> 3 & 0x1fffffff) ^ $z << 4)) ^ self::int32(($sum ^ $y) + ($k[$p & 3 ^ $e] ^ $z)); + $z = $v[$n] = self::int32($v[$n] + $mx); + } + return self::long2str($v, false); + } + + /** + * 解密字符串 + * @param string $str 字符串 + * @param string $key 加密key + * @return string + */ + public static function decrypt($str, $key) { + $v = self::str2long($str, false); + $k = self::str2long($key, false); + $n = count($v) - 1; + + $z = $v[$n]; + $y = $v[0]; + $delta = 0x9E3779B9; + $q = floor(6 + 52 / ($n + 1)); + $sum = self::int32($q * $delta); + while ($sum != 0) { + $e = $sum >> 2 & 3; + for ($p = $n; $p > 0; $p--) { + $z = $v[$p - 1]; + $mx = self::int32((($z >> 5 & 0x07ffffff) ^ $y << 2) + (($y >> 3 & 0x1fffffff) ^ $z << 4)) ^ self::int32(($sum ^ $y) + ($k[$p & 3 ^ $e] ^ $z)); + $y = $v[$p] = self::int32($v[$p] - $mx); + } + $z = $v[$n]; + $mx = self::int32((($z >> 5 & 0x07ffffff) ^ $y << 2) + (($y >> 3 & 0x1fffffff) ^ $z << 4)) ^ self::int32(($sum ^ $y) + ($k[$p & 3 ^ $e] ^ $z)); + $y = $v[0] = self::int32($v[0] - $mx); + $sum = self::int32($sum - $delta); + } + $data = self::long2str($v, true); + $expire = substr($data,0,10); + if($expire > 0 && $expire < time()) { + return ''; + } + $data = substr($data,10); + return $data; + } + + private static function long2str($v, $w) { + $len = count($v); + $s = array(); + for ($i = 0; $i < $len; $i++) { + $s[$i] = pack("V", $v[$i]); + } + if ($w) { + return substr(join('', $s), 0, $v[$len - 1]); + }else{ + return join('', $s); + } + } + + private static function str2long($s, $w) { + $v = unpack("V*", $s. str_repeat("\0", (4 - strlen($s) % 4) & 3)); + $v = array_values($v); + if ($w) { + $v[count($v)] = strlen($s); + } + return $v; + } + + private static function int32($n) { + while ($n >= 2147483648) $n -= 4294967296; + while ($n <= -2147483649) $n += 4294967296; + return (int)$n; + } + +} \ No newline at end of file diff --git a/ThinkPHP/Lib/Core/Db.class.php b/ThinkPHP/Library/Think/Db.class.php similarity index 92% rename from ThinkPHP/Lib/Core/Db.class.php rename to ThinkPHP/Library/Think/Db.class.php index 573bd9df5..3a6fda535 100644 --- a/ThinkPHP/Lib/Core/Db.class.php +++ b/ThinkPHP/Library/Think/Db.class.php @@ -1,921 +1,917 @@ - -// +---------------------------------------------------------------------- - -/** - * ThinkPHP 数据库中间层实现类 - * @category Think - * @package Think - * @subpackage Core - * @author liu21st - */ -class Db { - // 数据库类型 - protected $dbType = null; - // 是否自动释放查询结果 - protected $autoFree = false; - // 当前操作所属的模型名 - protected $model = '_think_'; - // 是否使用永久连接 - protected $pconnect = false; - // 当前SQL指令 - protected $queryStr = ''; - protected $modelSql = array(); - // 最后插入ID - protected $lastInsID = null; - // 返回或者影响记录数 - protected $numRows = 0; - // 返回字段数 - protected $numCols = 0; - // 事务指令数 - protected $transTimes = 0; - // 错误信息 - protected $error = ''; - // 数据库连接ID 支持多个连接 - protected $linkID = array(); - // 当前连接ID - protected $_linkID = null; - // 当前查询ID - protected $queryID = null; - // 是否已经连接数据库 - protected $connected = false; - // 数据库连接参数配置 - protected $config = ''; - // 数据库表达式 - protected $comparison = array('eq'=>'=','neq'=>'<>','gt'=>'>','egt'=>'>=','lt'=>'<','elt'=>'<=','notlike'=>'NOT LIKE','like'=>'LIKE','in'=>'IN','notin'=>'NOT IN'); - // 查询表达式 - protected $selectSql = 'SELECT%DISTINCT% %FIELD% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%%ORDER%%LIMIT% %UNION%%COMMENT%'; - // 参数绑定 - protected $bind = array(); - - /** - * 取得数据库类实例 - * @static - * @access public - * @return mixed 返回数据库驱动类 - */ - public static function getInstance() { - $args = func_get_args(); - return get_instance_of(__CLASS__,'factory',$args); - } - - /** - * 加载数据库 支持配置文件或者 DSN - * @access public - * @param mixed $db_config 数据库配置信息 - * @return string - */ - public function factory($db_config='') { - // 读取数据库配置 - $db_config = $this->parseConfig($db_config); - if(empty($db_config['dbms'])) - throw_exception(L('_NO_DB_CONFIG_')); - // 数据库类型 - $this->dbType = ucwords(strtolower($db_config['dbms'])); - $class = 'Db'. $this->dbType; - // 检查驱动类 - if(class_exists($class)) { - $db = new $class($db_config); - // 获取当前的数据库类型 - if( 'pdo' != strtolower($db_config['dbms']) ) - $db->dbType = strtoupper($this->dbType); - else - $db->dbType = $this->_getDsnType($db_config['dsn']); - }else { - // 类没有定义 - throw_exception(L('_NO_DB_DRIVER_').': ' . $class); - } - return $db; - } - - /** - * 根据DSN获取数据库类型 返回大写 - * @access protected - * @param string $dsn dsn字符串 - * @return string - */ - protected function _getDsnType($dsn) { - $match = explode(':',$dsn); - $dbType = strtoupper(trim($match[0])); - return $dbType; - } - - /** - * 分析数据库配置信息,支持数组和DSN - * @access private - * @param mixed $db_config 数据库配置信息 - * @return string - */ - private function parseConfig($db_config='') { - if ( !empty($db_config) && is_string($db_config)) { - // 如果DSN字符串则进行解析 - $db_config = $this->parseDSN($db_config); - }elseif(is_array($db_config)) { // 数组配置 - $db_config = array_change_key_case($db_config); - $db_config = array( - 'dbms' => $db_config['db_type'], - 'username' => $db_config['db_user'], - 'password' => $db_config['db_pwd'], - 'hostname' => $db_config['db_host'], - 'hostport' => $db_config['db_port'], - 'database' => $db_config['db_name'], - 'dsn' => $db_config['db_dsn'], - 'params' => $db_config['db_params'], - ); - }elseif(empty($db_config)) { - // 如果配置为空,读取配置文件设置 - if( C('DB_DSN') && 'pdo' != strtolower(C('DB_TYPE')) ) { // 如果设置了DB_DSN 则优先 - $db_config = $this->parseDSN(C('DB_DSN')); - }else{ - $db_config = array ( - 'dbms' => C('DB_TYPE'), - 'username' => C('DB_USER'), - 'password' => C('DB_PWD'), - 'hostname' => C('DB_HOST'), - 'hostport' => C('DB_PORT'), - 'database' => C('DB_NAME'), - 'dsn' => C('DB_DSN'), - 'params' => C('DB_PARAMS'), - ); - } - } - return $db_config; - } - - /** - * 初始化数据库连接 - * @access protected - * @param boolean $master 主服务器 - * @return void - */ - protected function initConnect($master=true) { - if(1 == C('DB_DEPLOY_TYPE')) - // 采用分布式数据库 - $this->_linkID = $this->multiConnect($master); - else - // 默认单数据库 - if ( !$this->connected ) $this->_linkID = $this->connect(); - } - - /** - * 连接分布式服务器 - * @access protected - * @param boolean $master 主服务器 - * @return void - */ - protected function multiConnect($master=false) { - static $_config = array(); - if(empty($_config)) { - // 缓存分布式数据库配置解析 - foreach ($this->config as $key=>$val){ - $_config[$key] = explode(',',$val); - } - } - // 数据库读写是否分离 - if(C('DB_RW_SEPARATE')){ - // 主从式采用读写分离 - if($master) - // 主服务器写入 - $r = floor(mt_rand(0,C('DB_MASTER_NUM')-1)); - else{ - if(is_numeric(C('DB_SLAVE_NO'))) {// 指定服务器读 - $r = C('DB_SLAVE_NO'); - }else{ - // 读操作连接从服务器 - $r = floor(mt_rand(C('DB_MASTER_NUM'),count($_config['hostname'])-1)); // 每次随机连接的数据库 - } - } - }else{ - // 读写操作不区分服务器 - $r = floor(mt_rand(0,count($_config['hostname'])-1)); // 每次随机连接的数据库 - } - $db_config = array( - 'username' => isset($_config['username'][$r])?$_config['username'][$r]:$_config['username'][0], - 'password' => isset($_config['password'][$r])?$_config['password'][$r]:$_config['password'][0], - 'hostname' => isset($_config['hostname'][$r])?$_config['hostname'][$r]:$_config['hostname'][0], - 'hostport' => isset($_config['hostport'][$r])?$_config['hostport'][$r]:$_config['hostport'][0], - 'database' => isset($_config['database'][$r])?$_config['database'][$r]:$_config['database'][0], - 'dsn' => isset($_config['dsn'][$r])?$_config['dsn'][$r]:$_config['dsn'][0], - 'params' => isset($_config['params'][$r])?$_config['params'][$r]:$_config['params'][0], - ); - return $this->connect($db_config,$r); - } - - /** - * DSN解析 - * 格式: mysql://username:passwd@localhost:3306/DbName - * @static - * @access public - * @param string $dsnStr - * @return array - */ - public function parseDSN($dsnStr) { - if( empty($dsnStr) ){return false;} - $info = parse_url($dsnStr); - if($info['scheme']){ - $dsn = array( - 'dbms' => $info['scheme'], - 'username' => isset($info['user']) ? $info['user'] : '', - 'password' => isset($info['pass']) ? $info['pass'] : '', - 'hostname' => isset($info['host']) ? $info['host'] : '', - 'hostport' => isset($info['port']) ? $info['port'] : '', - 'database' => isset($info['path']) ? substr($info['path'],1) : '' - ); - }else { - preg_match('/^(.*?)\:\/\/(.*?)\:(.*?)\@(.*?)\:([0-9]{1, 6})\/(.*?)$/',trim($dsnStr),$matches); - $dsn = array ( - 'dbms' => $matches[1], - 'username' => $matches[2], - 'password' => $matches[3], - 'hostname' => $matches[4], - 'hostport' => $matches[5], - 'database' => $matches[6] - ); - } - $dsn['dsn'] = ''; // 兼容配置信息数组 - return $dsn; - } - - /** - * 数据库调试 记录当前SQL - * @access protected - */ - protected function debug() { - $this->modelSql[$this->model] = $this->queryStr; - $this->model = '_think_'; - // 记录操作结束时间 - if (C('DB_SQL_LOG')) { - G('queryEndTime'); - trace($this->queryStr.' [ RunTime:'.G('queryStartTime','queryEndTime',6).'s ]','','SQL'); - } - } - - /** - * 设置锁机制 - * @access protected - * @return string - */ - protected function parseLock($lock=false) { - if(!$lock) return ''; - if('ORACLE' == $this->dbType) { - return ' FOR UPDATE NOWAIT '; - } - return ' FOR UPDATE '; - } - - /** - * set分析 - * @access protected - * @param array $data - * @return string - */ - protected function parseSet($data) { - foreach ($data as $key=>$val){ - if(is_array($val) && 'exp' == $val[0]){ - $set[] = $this->parseKey($key).'='.$val[1]; - }elseif(is_scalar($val) || is_null(($val))) { // 过滤非标量数据 - if(C('DB_BIND_PARAM') && 0 !== strpos($val,':')){ - $name = md5($key); - $set[] = $this->parseKey($key).'=:'.$name; - $this->bindParam($name,$val); - }else{ - $set[] = $this->parseKey($key).'='.$this->parseValue($val); - } - } - } - return ' SET '.implode(',',$set); - } - - /** - * 参数绑定 - * @access protected - * @param string $name 绑定参数名 - * @param mixed $value 绑定值 - * @return void - */ - protected function bindParam($name,$value){ - $this->bind[':'.$name] = $value; - } - - /** - * 参数绑定分析 - * @access protected - * @param array $bind - * @return array - */ - protected function parseBind($bind){ - $bind = array_merge($this->bind,$bind); - $this->bind = array(); - return $bind; - } - - /** - * 字段名分析 - * @access protected - * @param string $key - * @return string - */ - protected function parseKey(&$key) { - return $key; - } - - /** - * value分析 - * @access protected - * @param mixed $value - * @return string - */ - protected function parseValue($value) { - if(is_string($value)) { - $value = '\''.$this->escapeString($value).'\''; - }elseif(isset($value[0]) && is_string($value[0]) && strtolower($value[0]) == 'exp'){ - $value = $this->escapeString($value[1]); - }elseif(is_array($value)) { - $value = array_map(array($this, 'parseValue'),$value); - }elseif(is_bool($value)){ - $value = $value ? '1' : '0'; - }elseif(is_null($value)){ - $value = 'null'; - } - return $value; - } - - /** - * field分析 - * @access protected - * @param mixed $fields - * @return string - */ - protected function parseField($fields) { - if(is_string($fields) && strpos($fields,',')) { - $fields = explode(',',$fields); - } - if(is_array($fields)) { - // 完善数组方式传字段名的支持 - // 支持 'field1'=>'field2' 这样的字段别名定义 - $array = array(); - foreach ($fields as $key=>$field){ - if(!is_numeric($key)) - $array[] = $this->parseKey($key).' AS '.$this->parseKey($field); - else - $array[] = $this->parseKey($field); - } - $fieldsStr = implode(',', $array); - }elseif(is_string($fields) && !empty($fields)) { - $fieldsStr = $this->parseKey($fields); - }else{ - $fieldsStr = '*'; - } - //TODO 如果是查询全部字段,并且是join的方式,那么就把要查的表加个别名,以免字段被覆盖 - return $fieldsStr; - } - - /** - * table分析 - * @access protected - * @param mixed $table - * @return string - */ - protected function parseTable($tables) { - if(is_array($tables)) {// 支持别名定义 - $array = array(); - foreach ($tables as $table=>$alias){ - if(!is_numeric($table)) - $array[] = $this->parseKey($table).' '.$this->parseKey($alias); - else - $array[] = $this->parseKey($table); - } - $tables = $array; - }elseif(is_string($tables)){ - $tables = explode(',',$tables); - array_walk($tables, array(&$this, 'parseKey')); - } - return implode(',',$tables); - } - - /** - * where分析 - * @access protected - * @param mixed $where - * @return string - */ - protected function parseWhere($where) { - $whereStr = ''; - if(is_string($where)) { - // 直接使用字符串条件 - $whereStr = $where; - }else{ // 使用数组表达式 - $operate = isset($where['_logic'])?strtoupper($where['_logic']):''; - if(in_array($operate,array('AND','OR','XOR'))){ - // 定义逻辑运算规则 例如 OR XOR AND NOT - $operate = ' '.$operate.' '; - unset($where['_logic']); - }else{ - // 默认进行 AND 运算 - $operate = ' AND '; - } - foreach ($where as $key=>$val){ - $whereStr .= '( '; - if(is_numeric($key)){ - $key = '_complex'; - } - if(0===strpos($key,'_')) { - // 解析特殊条件表达式 - $whereStr .= $this->parseThinkWhere($key,$val); - }else{ - // 查询字段的安全过滤 - if(!preg_match('/^[A-Z_\|\&\-.a-z0-9\(\)\,]+$/',trim($key))){ - throw_exception(L('_EXPRESS_ERROR_').':'.$key); - } - // 多条件支持 - $multi = is_array($val) && isset($val['_multi']); - $key = trim($key); - if(strpos($key,'|')) { // 支持 name|title|nickname 方式定义查询字段 - $array = explode('|',$key); - $str = array(); - foreach ($array as $m=>$k){ - $v = $multi?$val[$m]:$val; - $str[] = '('.$this->parseWhereItem($this->parseKey($k),$v).')'; - } - $whereStr .= implode(' OR ',$str); - }elseif(strpos($key,'&')){ - $array = explode('&',$key); - $str = array(); - foreach ($array as $m=>$k){ - $v = $multi?$val[$m]:$val; - $str[] = '('.$this->parseWhereItem($this->parseKey($k),$v).')'; - } - $whereStr .= implode(' AND ',$str); - }else{ - $whereStr .= $this->parseWhereItem($this->parseKey($key),$val); - } - } - $whereStr .= ' )'.$operate; - } - $whereStr = substr($whereStr,0,-strlen($operate)); - } - return empty($whereStr)?'':' WHERE '.$whereStr; - } - - // where子单元分析 - protected function parseWhereItem($key,$val) { - $whereStr = ''; - if(is_array($val)) { - if(is_string($val[0])) { - if(preg_match('/^(EQ|NEQ|GT|EGT|LT|ELT)$/i',$val[0])) { // 比较运算 - $whereStr .= $key.' '.$this->comparison[strtolower($val[0])].' '.$this->parseValue($val[1]); - }elseif(preg_match('/^(NOTLIKE|LIKE)$/i',$val[0])){// 模糊查找 - if(is_array($val[1])) { - $likeLogic = isset($val[2])?strtoupper($val[2]):'OR'; - if(in_array($likeLogic,array('AND','OR','XOR'))){ - $likeStr = $this->comparison[strtolower($val[0])]; - $like = array(); - foreach ($val[1] as $item){ - $like[] = $key.' '.$likeStr.' '.$this->parseValue($item); - } - $whereStr .= '('.implode(' '.$likeLogic.' ',$like).')'; - } - }else{ - $whereStr .= $key.' '.$this->comparison[strtolower($val[0])].' '.$this->parseValue($val[1]); - } - }elseif('exp'==strtolower($val[0])){ // 使用表达式 - $whereStr .= ' ('.$key.' '.$val[1].') '; - }elseif(preg_match('/IN/i',$val[0])){ // IN 运算 - if(isset($val[2]) && 'exp'==$val[2]) { - $whereStr .= $key.' '.strtoupper($val[0]).' '.$val[1]; - }else{ - if(is_string($val[1])) { - $val[1] = explode(',',$val[1]); - } - $zone = implode(',',$this->parseValue($val[1])); - $whereStr .= $key.' '.strtoupper($val[0]).' ('.$zone.')'; - } - }elseif(preg_match('/BETWEEN/i',$val[0])){ // BETWEEN运算 - $data = is_string($val[1])? explode(',',$val[1]):$val[1]; - $whereStr .= ' ('.$key.' '.strtoupper($val[0]).' '.$this->parseValue($data[0]).' AND '.$this->parseValue($data[1]).' )'; - }else{ - throw_exception(L('_EXPRESS_ERROR_').':'.$val[0]); - } - }else { - $count = count($val); - $rule = isset($val[$count-1])?strtoupper($val[$count-1]):''; - if(in_array($rule,array('AND','OR','XOR'))) { - $count = $count -1; - }else{ - $rule = 'AND'; - } - for($i=0;$i<$count;$i++) { - $data = is_array($val[$i])?$val[$i][1]:$val[$i]; - if('exp'==strtolower($val[$i][0])) { - $whereStr .= '('.$key.' '.$data.') '.$rule.' '; - }else{ - $whereStr .= '('.$this->parseWhereItem($key,$val[$i]).') '.$rule.' '; - } - } - $whereStr = substr($whereStr,0,-4); - } - }else { - //对字符串类型字段采用模糊匹配 - if(C('DB_LIKE_FIELDS') && preg_match('/('.C('DB_LIKE_FIELDS').')/i',$key)) { - $val = '%'.$val.'%'; - $whereStr .= $key.' LIKE '.$this->parseValue($val); - }else { - $whereStr .= $key.' = '.$this->parseValue($val); - } - } - return $whereStr; - } - - /** - * 特殊条件分析 - * @access protected - * @param string $key - * @param mixed $val - * @return string - */ - protected function parseThinkWhere($key,$val) { - $whereStr = ''; - switch($key) { - case '_string': - // 字符串模式查询条件 - $whereStr = $val; - break; - case '_complex': - // 复合查询条件 - $whereStr = is_string($val)? $val : substr($this->parseWhere($val),6); - break; - case '_query': - // 字符串模式查询条件 - parse_str($val,$where); - if(isset($where['_logic'])) { - $op = ' '.strtoupper($where['_logic']).' '; - unset($where['_logic']); - }else{ - $op = ' AND '; - } - $array = array(); - foreach ($where as $field=>$data) - $array[] = $this->parseKey($field).' = '.$this->parseValue($data); - $whereStr = implode($op,$array); - break; - } - return $whereStr; - } - - /** - * limit分析 - * @access protected - * @param mixed $lmit - * @return string - */ - protected function parseLimit($limit) { - return !empty($limit)? ' LIMIT '.$limit.' ':''; - } - - /** - * join分析 - * @access protected - * @param mixed $join - * @return string - */ - protected function parseJoin($join) { - $joinStr = ''; - if(!empty($join)) { - if(is_array($join)) { - foreach ($join as $key=>$_join){ - if(false !== stripos($_join,'JOIN')) - $joinStr .= ' '.$_join; - else - $joinStr .= ' LEFT JOIN ' .$_join; - } - }else{ - $joinStr .= ' LEFT JOIN ' .$join; - } - } - //将__TABLE_NAME__这样的字符串替换成正规的表名,并且带上前缀和后缀 - $joinStr = preg_replace("/__([A-Z_-]+)__/esU",C("DB_PREFIX").".strtolower('$1')",$joinStr); - return $joinStr; - } - - /** - * order分析 - * @access protected - * @param mixed $order - * @return string - */ - protected function parseOrder($order) { - if(is_array($order)) { - $array = array(); - foreach ($order as $key=>$val){ - if(is_numeric($key)) { - $array[] = $this->parseKey($val); - }else{ - $array[] = $this->parseKey($key).' '.$val; - } - } - $order = implode(',',$array); - } - return !empty($order)? ' ORDER BY '.$order:''; - } - - /** - * group分析 - * @access protected - * @param mixed $group - * @return string - */ - protected function parseGroup($group) { - return !empty($group)? ' GROUP BY '.$group:''; - } - - /** - * having分析 - * @access protected - * @param string $having - * @return string - */ - protected function parseHaving($having) { - return !empty($having)? ' HAVING '.$having:''; - } - - /** - * comment分析 - * @access protected - * @param string $comment - * @return string - */ - protected function parseComment($comment) { - return !empty($comment)? ' /* '.$comment.' */':''; - } - - /** - * distinct分析 - * @access protected - * @param mixed $distinct - * @return string - */ - protected function parseDistinct($distinct) { - return !empty($distinct)? ' DISTINCT ' :''; - } - - /** - * union分析 - * @access protected - * @param mixed $union - * @return string - */ - protected function parseUnion($union) { - if(empty($union)) return ''; - if(isset($union['_all'])) { - $str = 'UNION ALL '; - unset($union['_all']); - }else{ - $str = 'UNION '; - } - foreach ($union as $u){ - $sql[] = $str.(is_array($u)?$this->buildSelectSql($u):$u); - } - return implode(' ',$sql); - } - - /** - * 插入记录 - * @access public - * @param mixed $data 数据 - * @param array $options 参数表达式 - * @param boolean $replace 是否replace - * @return false | integer - */ - public function insert($data,$options=array(),$replace=false) { - $values = $fields = array(); - $this->model = $options['model']; - foreach ($data as $key=>$val){ - if(is_array($val) && 'exp' == $val[0]){ - $fields[] = $this->parseKey($key); - $values[] = $val[1]; - }elseif(is_scalar($val) || is_null(($val))) { // 过滤非标量数据 - $fields[] = $this->parseKey($key); - if(C('DB_BIND_PARAM') && 0 !== strpos($val,':')){ - $name = md5($key); - $values[] = ':'.$name; - $this->bindParam($name,$val); - }else{ - $values[] = $this->parseValue($val); - } - } - } - $sql = ($replace?'REPLACE':'INSERT').' INTO '.$this->parseTable($options['table']).' ('.implode(',', $fields).') VALUES ('.implode(',', $values).')'; - $sql .= $this->parseLock(isset($options['lock'])?$options['lock']:false); - $sql .= $this->parseComment(!empty($options['comment'])?$options['comment']:''); - return $this->execute($sql,$this->parseBind(!empty($options['bind'])?$options['bind']:array())); - } - - /** - * 通过Select方式插入记录 - * @access public - * @param string $fields 要插入的数据表字段名 - * @param string $table 要插入的数据表名 - * @param array $option 查询数据参数 - * @return false | integer - */ - public function selectInsert($fields,$table,$options=array()) { - $this->model = $options['model']; - if(is_string($fields)) $fields = explode(',',$fields); - array_walk($fields, array($this, 'parseKey')); - $sql = 'INSERT INTO '.$this->parseTable($table).' ('.implode(',', $fields).') '; - $sql .= $this->buildSelectSql($options); - return $this->execute($sql,$this->parseBind(!empty($options['bind'])?$options['bind']:array())); - } - - /** - * 更新记录 - * @access public - * @param mixed $data 数据 - * @param array $options 表达式 - * @return false | integer - */ - public function update($data,$options) { - $this->model = $options['model']; - $sql = 'UPDATE ' - .$this->parseTable($options['table']) - .$this->parseSet($data) - .$this->parseWhere(!empty($options['where'])?$options['where']:'') - .$this->parseOrder(!empty($options['order'])?$options['order']:'') - .$this->parseLimit(!empty($options['limit'])?$options['limit']:'') - .$this->parseLock(isset($options['lock'])?$options['lock']:false) - .$this->parseComment(!empty($options['comment'])?$options['comment']:''); - return $this->execute($sql,$this->parseBind(!empty($options['bind'])?$options['bind']:array())); - } - - /** - * 删除记录 - * @access public - * @param array $options 表达式 - * @return false | integer - */ - public function delete($options=array()) { - $this->model = $options['model']; - $sql = 'DELETE FROM ' - .$this->parseTable($options['table']) - .$this->parseWhere(!empty($options['where'])?$options['where']:'') - .$this->parseOrder(!empty($options['order'])?$options['order']:'') - .$this->parseLimit(!empty($options['limit'])?$options['limit']:'') - .$this->parseLock(isset($options['lock'])?$options['lock']:false) - .$this->parseComment(!empty($options['comment'])?$options['comment']:''); - return $this->execute($sql,$this->parseBind(!empty($options['bind'])?$options['bind']:array())); - } - - /** - * 查找记录 - * @access public - * @param array $options 表达式 - * @return mixed - */ - public function select($options=array()) { - $this->model = $options['model']; - $sql = $this->buildSelectSql($options); - $cache = isset($options['cache'])?$options['cache']:false; - if($cache) { // 查询缓存检测 - $key = is_string($cache['key'])?$cache['key']:md5($sql); - $value = S($key,'',$cache); - if(false !== $value) { - return $value; - } - } - $result = $this->query($sql,$this->parseBind(!empty($options['bind'])?$options['bind']:array())); - if($cache && false !== $result ) { // 查询缓存写入 - S($key,$result,$cache); - } - return $result; - } - - /** - * 生成查询SQL - * @access public - * @param array $options 表达式 - * @return string - */ - public function buildSelectSql($options=array()) { - if(isset($options['page'])) { - // 根据页数计算limit - if(strpos($options['page'],',')) { - list($page,$listRows) = explode(',',$options['page']); - }else{ - $page = $options['page']; - } - $page = $page?$page:1; - $listRows= isset($listRows)?$listRows:(is_numeric($options['limit'])?$options['limit']:20); - $offset = $listRows*((int)$page-1); - $options['limit'] = $offset.','.$listRows; - } - if(C('DB_SQL_BUILD_CACHE')) { // SQL创建缓存 - $key = md5(serialize($options)); - $value = S($key); - if(false !== $value) { - return $value; - } - } - $sql = $this->parseSql($this->selectSql,$options); - $sql .= $this->parseLock(isset($options['lock'])?$options['lock']:false); - if(isset($key)) { // 写入SQL创建缓存 - S($key,$sql,array('expire'=>0,'length'=>C('DB_SQL_BUILD_LENGTH'),'queue'=>C('DB_SQL_BUILD_QUEUE'))); - } - return $sql; - } - - /** - * 替换SQL语句中表达式 - * @access public - * @param array $options 表达式 - * @return string - */ - public function parseSql($sql,$options=array()){ - $sql = str_replace( - array('%TABLE%','%DISTINCT%','%FIELD%','%JOIN%','%WHERE%','%GROUP%','%HAVING%','%ORDER%','%LIMIT%','%UNION%','%COMMENT%'), - array( - $this->parseTable($options['table']), - $this->parseDistinct(isset($options['distinct'])?$options['distinct']:false), - $this->parseField(!empty($options['field'])?$options['field']:'*'), - $this->parseJoin(!empty($options['join'])?$options['join']:''), - $this->parseWhere(!empty($options['where'])?$options['where']:''), - $this->parseGroup(!empty($options['group'])?$options['group']:''), - $this->parseHaving(!empty($options['having'])?$options['having']:''), - $this->parseOrder(!empty($options['order'])?$options['order']:''), - $this->parseLimit(!empty($options['limit'])?$options['limit']:''), - $this->parseUnion(!empty($options['union'])?$options['union']:''), - $this->parseComment(!empty($options['comment'])?$options['comment']:'') - ),$sql); - return $sql; - } - - /** - * 获取最近一次查询的sql语句 - * @param string $model 模型名 - * @access public - * @return string - */ - public function getLastSql($model='') { - return $model?$this->modelSql[$model]:$this->queryStr; - } - - /** - * 获取最近插入的ID - * @access public - * @return string - */ - public function getLastInsID() { - return $this->lastInsID; - } - - /** - * 获取最近的错误信息 - * @access public - * @return string - */ - public function getError() { - return $this->error; - } - - /** - * SQL指令安全过滤 - * @access public - * @param string $str SQL字符串 - * @return string - */ - public function escapeString($str) { - return addslashes($str); - } - - /** - * 设置当前操作模型 - * @access public - * @param string $model 模型名 - * @return void - */ - public function setModel($model){ - $this->model = $model; - } - - /** - * 析构方法 - * @access public - */ - public function __destruct() { - // 释放查询 - if ($this->queryID){ - $this->free(); - } - // 关闭连接 - $this->close(); - } - - // 关闭数据库 由驱动类定义 - public function close(){} + +// +---------------------------------------------------------------------- +namespace Think; +/** + * ThinkPHP 数据库中间层实现类 + */ +class Db { + // 数据库类型 + protected $dbType = null; + // 是否自动释放查询结果 + protected $autoFree = false; + // 当前操作所属的模型名 + protected $model = '_think_'; + // 是否使用永久连接 + protected $pconnect = false; + // 当前SQL指令 + protected $queryStr = ''; + protected $modelSql = array(); + // 最后插入ID + protected $lastInsID = null; + // 返回或者影响记录数 + protected $numRows = 0; + // 返回字段数 + protected $numCols = 0; + // 事务指令数 + protected $transTimes = 0; + // 错误信息 + protected $error = ''; + // 数据库连接ID 支持多个连接 + protected $linkID = array(); + // 当前连接ID + protected $_linkID = null; + // 当前查询ID + protected $queryID = null; + // 是否已经连接数据库 + protected $connected = false; + // 数据库连接参数配置 + protected $config = ''; + // 数据库表达式 + protected $comparison = array('eq'=>'=','neq'=>'<>','gt'=>'>','egt'=>'>=','lt'=>'<','elt'=>'<=','notlike'=>'NOT LIKE','like'=>'LIKE','in'=>'IN','notin'=>'NOT IN'); + // 查询表达式 + protected $selectSql = 'SELECT%DISTINCT% %FIELD% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%%ORDER%%LIMIT% %UNION%%COMMENT%'; + // 参数绑定 + protected $bind = array(); + + /** + * 取得数据库类实例 + * @static + * @access public + * @return mixed 返回数据库驱动类 + */ + public static function getInstance($db_config='') { + static $_instance = array(); + $guid = to_guid_string($db_config); + if(!isset($_instance[$guid])){ + $obj = new Db(); + $_instance[$guid] = $obj->factory($db_config); + } + return $_instance[$guid]; + } + + /** + * 加载数据库 支持配置文件或者 DSN + * @access public + * @param mixed $db_config 数据库配置信息 + * @return string + */ + public function factory($db_config='') { + // 读取数据库配置 + $db_config = $this->parseConfig($db_config); + if(empty($db_config['dbms'])) + E(L('_NO_DB_CONFIG_')); + // 数据库类型 + if(strpos($db_config['dbms'],'\\')){ + $class = $db_config['dbms']; + }else{ + $dbType = ucwords(strtolower($db_config['dbms'])); + $class = 'Think\\Db\\Driver\\'. $dbType; + } + // 检查驱动类 + if(class_exists($class)) { + $db = new $class($db_config); + }else { + // 类没有定义 + E(L('_NO_DB_DRIVER_').': ' . $class); + } + return $db; + } + + /** + * 根据DSN获取数据库类型 返回大写 + * @access protected + * @param string $dsn dsn字符串 + * @return string + */ + protected function _getDsnType($dsn) { + $match = explode(':',$dsn); + $dbType = strtoupper(trim($match[0])); + return $dbType; + } + + /** + * 分析数据库配置信息,支持数组和DSN + * @access private + * @param mixed $db_config 数据库配置信息 + * @return string + */ + private function parseConfig($db_config='') { + if ( !empty($db_config) && is_string($db_config)) { + // 如果DSN字符串则进行解析 + $db_config = $this->parseDSN($db_config); + }elseif(is_array($db_config)) { // 数组配置 + $db_config = array_change_key_case($db_config); + $db_config = array( + 'dbms' => $db_config['db_type'], + 'username' => $db_config['db_user'], + 'password' => $db_config['db_pwd'], + 'hostname' => $db_config['db_host'], + 'hostport' => $db_config['db_port'], + 'database' => $db_config['db_name'], + 'dsn' => $db_config['db_dsn'], + 'params' => $db_config['db_params'], + ); + }elseif(empty($db_config)) { + // 如果配置为空,读取配置文件设置 + if( C('DB_DSN') && 'pdo' != strtolower(C('DB_TYPE')) ) { // 如果设置了DB_DSN 则优先 + $db_config = $this->parseDSN(C('DB_DSN')); + }else{ + $db_config = array ( + 'dbms' => C('DB_TYPE'), + 'username' => C('DB_USER'), + 'password' => C('DB_PWD'), + 'hostname' => C('DB_HOST'), + 'hostport' => C('DB_PORT'), + 'database' => C('DB_NAME'), + 'dsn' => C('DB_DSN'), + 'params' => C('DB_PARAMS'), + ); + } + } + return $db_config; + } + + /** + * 初始化数据库连接 + * @access protected + * @param boolean $master 主服务器 + * @return void + */ + protected function initConnect($master=true) { + if(1 == C('DB_DEPLOY_TYPE')) + // 采用分布式数据库 + $this->_linkID = $this->multiConnect($master); + else + // 默认单数据库 + if ( !$this->connected ) $this->_linkID = $this->connect(); + } + + /** + * 连接分布式服务器 + * @access protected + * @param boolean $master 主服务器 + * @return void + */ + protected function multiConnect($master=false) { + static $_config = array(); + if(empty($_config)) { + // 缓存分布式数据库配置解析 + foreach ($this->config as $key=>$val){ + $_config[$key] = explode(',',$val); + } + } + // 数据库读写是否分离 + if(C('DB_RW_SEPARATE')){ + // 主从式采用读写分离 + if($master) + // 主服务器写入 + $r = floor(mt_rand(0,C('DB_MASTER_NUM')-1)); + else{ + if(is_numeric(C('DB_SLAVE_NO'))) {// 指定服务器读 + $r = C('DB_SLAVE_NO'); + }else{ + // 读操作连接从服务器 + $r = floor(mt_rand(C('DB_MASTER_NUM'),count($_config['hostname'])-1)); // 每次随机连接的数据库 + } + } + }else{ + // 读写操作不区分服务器 + $r = floor(mt_rand(0,count($_config['hostname'])-1)); // 每次随机连接的数据库 + } + $db_config = array( + 'username' => isset($_config['username'][$r])?$_config['username'][$r]:$_config['username'][0], + 'password' => isset($_config['password'][$r])?$_config['password'][$r]:$_config['password'][0], + 'hostname' => isset($_config['hostname'][$r])?$_config['hostname'][$r]:$_config['hostname'][0], + 'hostport' => isset($_config['hostport'][$r])?$_config['hostport'][$r]:$_config['hostport'][0], + 'database' => isset($_config['database'][$r])?$_config['database'][$r]:$_config['database'][0], + 'dsn' => isset($_config['dsn'][$r])?$_config['dsn'][$r]:$_config['dsn'][0], + 'params' => isset($_config['params'][$r])?$_config['params'][$r]:$_config['params'][0], + ); + return $this->connect($db_config,$r); + } + + /** + * DSN解析 + * 格式: mysql://username:passwd@localhost:3306/DbName + * @static + * @access public + * @param string $dsnStr + * @return array + */ + public function parseDSN($dsnStr) { + if( empty($dsnStr) ){return false;} + $info = parse_url($dsnStr); + if($info['scheme']){ + $dsn = array( + 'dbms' => $info['scheme'], + 'username' => isset($info['user']) ? $info['user'] : '', + 'password' => isset($info['pass']) ? $info['pass'] : '', + 'hostname' => isset($info['host']) ? $info['host'] : '', + 'hostport' => isset($info['port']) ? $info['port'] : '', + 'database' => isset($info['path']) ? substr($info['path'],1) : '' + ); + }else { + preg_match('/^(.*?)\:\/\/(.*?)\:(.*?)\@(.*?)\:([0-9]{1, 6})\/(.*?)$/',trim($dsnStr),$matches); + $dsn = array ( + 'dbms' => $matches[1], + 'username' => $matches[2], + 'password' => $matches[3], + 'hostname' => $matches[4], + 'hostport' => $matches[5], + 'database' => $matches[6] + ); + } + $dsn['dsn'] = ''; // 兼容配置信息数组 + return $dsn; + } + + /** + * 数据库调试 记录当前SQL + * @access protected + */ + protected function debug() { + $this->modelSql[$this->model] = $this->queryStr; + $this->model = '_think_'; + // 记录操作结束时间 + if (C('DB_SQL_LOG')) { + G('queryEndTime'); + trace($this->queryStr.' [ RunTime:'.G('queryStartTime','queryEndTime',6).'s ]','','SQL'); + } + } + + /** + * 设置锁机制 + * @access protected + * @return string + */ + protected function parseLock($lock=false) { + if(!$lock) return ''; + if('ORACLE' == $this->dbType) { + return ' FOR UPDATE NOWAIT '; + } + return ' FOR UPDATE '; + } + + /** + * set分析 + * @access protected + * @param array $data + * @return string + */ + protected function parseSet($data) { + foreach ($data as $key=>$val){ + if(is_array($val) && 'exp' == $val[0]){ + $set[] = $this->parseKey($key).'='.$val[1]; + }elseif(is_scalar($val) || is_null($val)) { // 过滤非标量数据 + if(C('DB_BIND_PARAM') && 0 !== strpos($val,':')){ + $name = md5($key); + $set[] = $this->parseKey($key).'=:'.$name; + $this->bindParam($name,$val); + }else{ + $set[] = $this->parseKey($key).'='.$this->parseValue($val); + } + } + } + return ' SET '.implode(',',$set); + } + + /** + * 参数绑定 + * @access protected + * @param string $name 绑定参数名 + * @param mixed $value 绑定值 + * @return void + */ + protected function bindParam($name,$value){ + $this->bind[':'.$name] = $value; + } + + /** + * 参数绑定分析 + * @access protected + * @param array $bind + * @return array + */ + protected function parseBind($bind){ + $bind = array_merge($this->bind,$bind); + $this->bind = array(); + return $bind; + } + + /** + * 字段名分析 + * @access protected + * @param string $key + * @return string + */ + protected function parseKey(&$key) { + return $key; + } + + /** + * value分析 + * @access protected + * @param mixed $value + * @return string + */ + protected function parseValue($value) { + if(is_string($value)) { + $value = '\''.$this->escapeString($value).'\''; + }elseif(isset($value[0]) && is_string($value[0]) && strtolower($value[0]) == 'exp'){ + $value = $this->escapeString($value[1]); + }elseif(is_array($value)) { + $value = array_map(array($this, 'parseValue'),$value); + }elseif(is_bool($value)){ + $value = $value ? '1' : '0'; + }elseif(is_null($value)){ + $value = 'null'; + } + return $value; + } + + /** + * field分析 + * @access protected + * @param mixed $fields + * @return string + */ + protected function parseField($fields) { + if(is_string($fields) && strpos($fields,',')) { + $fields = explode(',',$fields); + } + if(is_array($fields)) { + // 完善数组方式传字段名的支持 + // 支持 'field1'=>'field2' 这样的字段别名定义 + $array = array(); + foreach ($fields as $key=>$field){ + if(!is_numeric($key)) + $array[] = $this->parseKey($key).' AS '.$this->parseKey($field); + else + $array[] = $this->parseKey($field); + } + $fieldsStr = implode(',', $array); + }elseif(is_string($fields) && !empty($fields)) { + $fieldsStr = $this->parseKey($fields); + }else{ + $fieldsStr = '*'; + } + //TODO 如果是查询全部字段,并且是join的方式,那么就把要查的表加个别名,以免字段被覆盖 + return $fieldsStr; + } + + /** + * table分析 + * @access protected + * @param mixed $table + * @return string + */ + protected function parseTable($tables) { + if(is_array($tables)) {// 支持别名定义 + $array = array(); + foreach ($tables as $table=>$alias){ + if(!is_numeric($table)) + $array[] = $this->parseKey($table).' '.$this->parseKey($alias); + else + $array[] = $this->parseKey($table); + } + $tables = $array; + }elseif(is_string($tables)){ + $tables = explode(',',$tables); + array_walk($tables, array(&$this, 'parseKey')); + } + //将__TABLE_NAME__这样的字符串替换成正规的表名,并且带上前缀 + $tables = preg_replace_callback("/__([A-Z_-]+)__/sU", function($match){ return C('DB_PREFIX').strtolower($match[1]);}, implode(',',$tables)); + return $tables; + } + + /** + * where分析 + * @access protected + * @param mixed $where + * @return string + */ + protected function parseWhere($where) { + $whereStr = ''; + if(is_string($where)) { + // 直接使用字符串条件 + $whereStr = $where; + }else{ // 使用数组表达式 + $operate = isset($where['_logic'])?strtoupper($where['_logic']):''; + if(in_array($operate,array('AND','OR','XOR'))){ + // 定义逻辑运算规则 例如 OR XOR AND NOT + $operate = ' '.$operate.' '; + unset($where['_logic']); + }else{ + // 默认进行 AND 运算 + $operate = ' AND '; + } + foreach ($where as $key=>$val){ + $whereStr .= '( '; + if(is_numeric($key)){ + $key = '_complex'; + } + if(0===strpos($key,'_')) { + // 解析特殊条件表达式 + $whereStr .= $this->parseThinkWhere($key,$val); + }else{ + // 查询字段的安全过滤 + if(!preg_match('/^[A-Z_\|\&\-.a-z0-9\(\)\,]+$/',trim($key))){ + E(L('_EXPRESS_ERROR_').':'.$key); + } + // 多条件支持 + $multi = is_array($val) && isset($val['_multi']); + $key = trim($key); + if(strpos($key,'|')) { // 支持 name|title|nickname 方式定义查询字段 + $array = explode('|',$key); + $str = array(); + foreach ($array as $m=>$k){ + $v = $multi?$val[$m]:$val; + $str[] = '('.$this->parseWhereItem($this->parseKey($k),$v).')'; + } + $whereStr .= implode(' OR ',$str); + }elseif(strpos($key,'&')){ + $array = explode('&',$key); + $str = array(); + foreach ($array as $m=>$k){ + $v = $multi?$val[$m]:$val; + $str[] = '('.$this->parseWhereItem($this->parseKey($k),$v).')'; + } + $whereStr .= implode(' AND ',$str); + }else{ + $whereStr .= $this->parseWhereItem($this->parseKey($key),$val); + } + } + $whereStr .= ' )'.$operate; + } + $whereStr = substr($whereStr,0,-strlen($operate)); + } + return empty($whereStr)?'':' WHERE '.$whereStr; + } + + // where子单元分析 + protected function parseWhereItem($key,$val) { + $whereStr = ''; + if(is_array($val)) { + if(is_string($val[0])) { + if(preg_match('/^(EQ|NEQ|GT|EGT|LT|ELT)$/i',$val[0])) { // 比较运算 + $whereStr .= $key.' '.$this->comparison[strtolower($val[0])].' '.$this->parseValue($val[1]); + }elseif(preg_match('/^(NOTLIKE|LIKE)$/i',$val[0])){// 模糊查找 + if(is_array($val[1])) { + $likeLogic = isset($val[2])?strtoupper($val[2]):'OR'; + if(in_array($likeLogic,array('AND','OR','XOR'))){ + $likeStr = $this->comparison[strtolower($val[0])]; + $like = array(); + foreach ($val[1] as $item){ + $like[] = $key.' '.$likeStr.' '.$this->parseValue($item); + } + $whereStr .= '('.implode(' '.$likeLogic.' ',$like).')'; + } + }else{ + $whereStr .= $key.' '.$this->comparison[strtolower($val[0])].' '.$this->parseValue($val[1]); + } + }elseif('exp'==strtolower($val[0])){ // 使用表达式 + $whereStr .= ' ('.$key.' '.$val[1].') '; + }elseif(preg_match('/IN/i',$val[0])){ // IN 运算 + if(isset($val[2]) && 'exp'==$val[2]) { + $whereStr .= $key.' '.strtoupper($val[0]).' '.$val[1]; + }else{ + if(is_string($val[1])) { + $val[1] = explode(',',$val[1]); + } + $zone = implode(',',$this->parseValue($val[1])); + $whereStr .= $key.' '.strtoupper($val[0]).' ('.$zone.')'; + } + }elseif(preg_match('/BETWEEN/i',$val[0])){ // BETWEEN运算 + $data = is_string($val[1])? explode(',',$val[1]):$val[1]; + $whereStr .= ' ('.$key.' '.strtoupper($val[0]).' '.$this->parseValue($data[0]).' AND '.$this->parseValue($data[1]).' )'; + }else{ + E(L('_EXPRESS_ERROR_').':'.$val[0]); + } + }else { + $count = count($val); + $rule = isset($val[$count-1]) ? (is_array($val[$count-1]) ? strtoupper($val[$count-1][0]) : strtoupper($val[$count-1]) ) : '' ; + if(in_array($rule,array('AND','OR','XOR'))) { + $count = $count -1; + }else{ + $rule = 'AND'; + } + for($i=0;$i<$count;$i++) { + $data = is_array($val[$i])?$val[$i][1]:$val[$i]; + if('exp'==strtolower($val[$i][0])) { + $whereStr .= '('.$key.' '.$data.') '.$rule.' '; + }else{ + $op = is_array($val[$i])?$this->comparison[strtolower($val[$i][0])]:'='; + $whereStr .= '('.$this->parseWhereItem($key,$val[$i]).') '.$rule.' '; + } + } + $whereStr = substr($whereStr,0,-4); + } + }else { + //对字符串类型字段采用模糊匹配 + if(C('DB_LIKE_FIELDS') && preg_match('/('.C('DB_LIKE_FIELDS').')/i',$key)) { + $val = '%'.$val.'%'; + $whereStr .= $key.' LIKE '.$this->parseValue($val); + }else { + $whereStr .= $key.' = '.$this->parseValue($val); + } + } + return $whereStr; + } + + /** + * 特殊条件分析 + * @access protected + * @param string $key + * @param mixed $val + * @return string + */ + protected function parseThinkWhere($key,$val) { + $whereStr = ''; + switch($key) { + case '_string': + // 字符串模式查询条件 + $whereStr = $val; + break; + case '_complex': + // 复合查询条件 + $whereStr = is_string($val)? $val : substr($this->parseWhere($val),6); + break; + case '_query': + // 字符串模式查询条件 + parse_str($val,$where); + if(isset($where['_logic'])) { + $op = ' '.strtoupper($where['_logic']).' '; + unset($where['_logic']); + }else{ + $op = ' AND '; + } + $array = array(); + foreach ($where as $field=>$data) + $array[] = $this->parseKey($field).' = '.$this->parseValue($data); + $whereStr = implode($op,$array); + break; + } + return $whereStr; + } + + /** + * limit分析 + * @access protected + * @param mixed $lmit + * @return string + */ + protected function parseLimit($limit) { + return !empty($limit)? ' LIMIT '.$limit.' ':''; + } + + /** + * join分析 + * @access protected + * @param mixed $join + * @return string + */ + protected function parseJoin($join) { + $joinStr = ''; + if(!empty($join)) { + foreach ($join as $key=>$_join){ + $joinStr .= false !== stripos($_join,'JOIN')? ' '.$_join : ' JOIN ' .$_join; + } + //将__TABLE_NAME__这样的字符串替换成正规的表名,并且带上前缀和后缀 + $joinStr = preg_replace_callback("/__([A-Z_-]+)__/sU", function($match){ return C('DB_PREFIX').strtolower($match[1]);}, $joinStr); + } + return $joinStr; + } + + /** + * order分析 + * @access protected + * @param mixed $order + * @return string + */ + protected function parseOrder($order) { + if(is_array($order)) { + $array = array(); + foreach ($order as $key=>$val){ + if(is_numeric($key)) { + $array[] = $this->parseKey($val); + }else{ + $array[] = $this->parseKey($key).' '.$val; + } + } + $order = implode(',',$array); + } + return !empty($order)? ' ORDER BY '.$order:''; + } + + /** + * group分析 + * @access protected + * @param mixed $group + * @return string + */ + protected function parseGroup($group) { + return !empty($group)? ' GROUP BY '.$group:''; + } + + /** + * having分析 + * @access protected + * @param string $having + * @return string + */ + protected function parseHaving($having) { + return !empty($having)? ' HAVING '.$having:''; + } + + /** + * comment分析 + * @access protected + * @param string $comment + * @return string + */ + protected function parseComment($comment) { + return !empty($comment)? ' /* '.$comment.' */':''; + } + + /** + * distinct分析 + * @access protected + * @param mixed $distinct + * @return string + */ + protected function parseDistinct($distinct) { + return !empty($distinct)? ' DISTINCT ' :''; + } + + /** + * union分析 + * @access protected + * @param mixed $union + * @return string + */ + protected function parseUnion($union) { + if(empty($union)) return ''; + if(isset($union['_all'])) { + $str = 'UNION ALL '; + unset($union['_all']); + }else{ + $str = 'UNION '; + } + foreach ($union as $u){ + $sql[] = $str.(is_array($u)?$this->buildSelectSql($u):$u); + } + return implode(' ',$sql); + } + + /** + * 插入记录 + * @access public + * @param mixed $data 数据 + * @param array $options 参数表达式 + * @param boolean $replace 是否replace + * @return false | integer + */ + public function insert($data,$options=array(),$replace=false) { + $values = $fields = array(); + $this->model = $options['model']; + foreach ($data as $key=>$val){ + if(is_array($val) && 'exp' == $val[0]){ + $fields[] = $this->parseKey($key); + $values[] = $val[1]; + }elseif(is_scalar($val) || is_null($val)) { // 过滤非标量数据 + $fields[] = $this->parseKey($key); + if(C('DB_BIND_PARAM') && 0 !== strpos($val,':')){ + $name = md5($key); + $values[] = ':'.$name; + $this->bindParam($name,$val); + }else{ + $values[] = $this->parseValue($val); + } + } + } + $sql = ($replace?'REPLACE':'INSERT').' INTO '.$this->parseTable($options['table']).' ('.implode(',', $fields).') VALUES ('.implode(',', $values).')'; + $sql .= $this->parseLock(isset($options['lock'])?$options['lock']:false); + $sql .= $this->parseComment(!empty($options['comment'])?$options['comment']:''); + return $this->execute($sql,$this->parseBind(!empty($options['bind'])?$options['bind']:array())); + } + + /** + * 通过Select方式插入记录 + * @access public + * @param string $fields 要插入的数据表字段名 + * @param string $table 要插入的数据表名 + * @param array $option 查询数据参数 + * @return false | integer + */ + public function selectInsert($fields,$table,$options=array()) { + $this->model = $options['model']; + if(is_string($fields)) $fields = explode(',',$fields); + array_walk($fields, array($this, 'parseKey')); + $sql = 'INSERT INTO '.$this->parseTable($table).' ('.implode(',', $fields).') '; + $sql .= $this->buildSelectSql($options); + return $this->execute($sql,$this->parseBind(!empty($options['bind'])?$options['bind']:array())); + } + + /** + * 更新记录 + * @access public + * @param mixed $data 数据 + * @param array $options 表达式 + * @return false | integer + */ + public function update($data,$options) { + $this->model = $options['model']; + $sql = 'UPDATE ' + .$this->parseTable($options['table']) + .$this->parseSet($data) + .$this->parseWhere(!empty($options['where'])?$options['where']:'') + .$this->parseOrder(!empty($options['order'])?$options['order']:'') + .$this->parseLimit(!empty($options['limit'])?$options['limit']:'') + .$this->parseLock(isset($options['lock'])?$options['lock']:false) + .$this->parseComment(!empty($options['comment'])?$options['comment']:''); + return $this->execute($sql,$this->parseBind(!empty($options['bind'])?$options['bind']:array())); + } + + /** + * 删除记录 + * @access public + * @param array $options 表达式 + * @return false | integer + */ + public function delete($options=array()) { + $this->model = $options['model']; + $sql = 'DELETE FROM ' + .$this->parseTable($options['table']) + .$this->parseWhere(!empty($options['where'])?$options['where']:'') + .$this->parseOrder(!empty($options['order'])?$options['order']:'') + .$this->parseLimit(!empty($options['limit'])?$options['limit']:'') + .$this->parseLock(isset($options['lock'])?$options['lock']:false) + .$this->parseComment(!empty($options['comment'])?$options['comment']:''); + return $this->execute($sql,$this->parseBind(!empty($options['bind'])?$options['bind']:array())); + } + + /** + * 查找记录 + * @access public + * @param array $options 表达式 + * @return mixed + */ + public function select($options=array()) { + $this->model = $options['model']; + $sql = $this->buildSelectSql($options); + $cache = isset($options['cache'])?$options['cache']:false; + if($cache) { // 查询缓存检测 + $key = is_string($cache['key'])?$cache['key']:md5($sql); + $value = S($key,'',$cache); + if(false !== $value) { + return $value; + } + } + $result = $this->query($sql,$this->parseBind(!empty($options['bind'])?$options['bind']:array())); + if($cache && false !== $result ) { // 查询缓存写入 + S($key,$result,$cache); + } + return $result; + } + + /** + * 生成查询SQL + * @access public + * @param array $options 表达式 + * @return string + */ + public function buildSelectSql($options=array()) { + if(isset($options['page'])) { + // 根据页数计算limit + if(strpos($options['page'],',')) { + list($page,$listRows) = explode(',',$options['page']); + }else{ + $page = $options['page']; + } + $page = $page?$page:1; + $listRows= isset($listRows)?$listRows:(is_numeric($options['limit'])?$options['limit']:20); + $offset = $listRows*((int)$page-1); + $options['limit'] = $offset.','.$listRows; + } + if(C('DB_SQL_BUILD_CACHE')) { // SQL创建缓存 + $key = md5(serialize($options)); + $value = S($key); + if(false !== $value) { + return $value; + } + } + $sql = $this->parseSql($this->selectSql,$options); + $sql .= $this->parseLock(isset($options['lock'])?$options['lock']:false); + if(isset($key)) { // 写入SQL创建缓存 + S($key,$sql,array('expire'=>0,'length'=>C('DB_SQL_BUILD_LENGTH'),'queue'=>C('DB_SQL_BUILD_QUEUE'))); + } + return $sql; + } + + /** + * 替换SQL语句中表达式 + * @access public + * @param array $options 表达式 + * @return string + */ + public function parseSql($sql,$options=array()){ + $sql = str_replace( + array('%TABLE%','%DISTINCT%','%FIELD%','%JOIN%','%WHERE%','%GROUP%','%HAVING%','%ORDER%','%LIMIT%','%UNION%','%COMMENT%'), + array( + $this->parseTable($options['table']), + $this->parseDistinct(isset($options['distinct'])?$options['distinct']:false), + $this->parseField(!empty($options['field'])?$options['field']:'*'), + $this->parseJoin(!empty($options['join'])?$options['join']:''), + $this->parseWhere(!empty($options['where'])?$options['where']:''), + $this->parseGroup(!empty($options['group'])?$options['group']:''), + $this->parseHaving(!empty($options['having'])?$options['having']:''), + $this->parseOrder(!empty($options['order'])?$options['order']:''), + $this->parseLimit(!empty($options['limit'])?$options['limit']:''), + $this->parseUnion(!empty($options['union'])?$options['union']:''), + $this->parseComment(!empty($options['comment'])?$options['comment']:'') + ),$sql); + return $sql; + } + + /** + * 获取最近一次查询的sql语句 + * @param string $model 模型名 + * @access public + * @return string + */ + public function getLastSql($model='') { + return $model?$this->modelSql[$model]:$this->queryStr; + } + + /** + * 获取最近插入的ID + * @access public + * @return string + */ + public function getLastInsID() { + return $this->lastInsID; + } + + /** + * 获取最近的错误信息 + * @access public + * @return string + */ + public function getError() { + return $this->error; + } + + /** + * SQL指令安全过滤 + * @access public + * @param string $str SQL字符串 + * @return string + */ + public function escapeString($str) { + return addslashes($str); + } + + /** + * 设置当前操作模型 + * @access public + * @param string $model 模型名 + * @return void + */ + public function setModel($model){ + $this->model = $model; + } + + /** + * 析构方法 + * @access public + */ + public function __destruct() { + // 释放查询 + if ($this->queryID){ + $this->free(); + } + // 关闭连接 + $this->close(); + } + + // 关闭数据库 由驱动类定义 + public function close(){} } \ No newline at end of file diff --git a/ThinkPHP/Library/Think/Db/Driver/Ibase.class.php b/ThinkPHP/Library/Think/Db/Driver/Ibase.class.php new file mode 100644 index 000000000..1821e8307 --- /dev/null +++ b/ThinkPHP/Library/Think/Db/Driver/Ibase.class.php @@ -0,0 +1,335 @@ + +// +---------------------------------------------------------------------- +namespace Think\Db\Driver; +use Think\Db; +defined('THINK_PATH') or exit(); +/** + * Firebird数据库驱动 + */ +class Ibase extends Db{ + + protected $selectSql = 'SELECT %LIMIT% %DISTINCT% %FIELD% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%%ORDER%'; + /** + * 架构函数 读取数据库配置信息 + * @access public + * @param array $config 数据库配置数组 + */ + public function __construct($config='') { + if ( !extension_loaded('interbase') ) { + throw_exception(L('_NOT_SUPPERT_').':Interbase or Firebird'); + } + if(!empty($config)) { + $this->config = $config; + if(empty($this->config['params'])) { + $this->config['params'] = array(); + } + } + } + + /** + * 连接数据库方法 + * @access public + * @throws Think\Execption + */ + public function connect($config='',$linkNum=0) { + if ( !isset($this->linkID[$linkNum]) ) { + if(empty($config)) $config = $this->config; + $pconnect = !empty($config['params']['persist'])? $config['params']['persist']:$this->pconnect; + $conn = $pconnect ? 'ibase_pconnect':'ibase_connect'; + // 处理不带端口号的socket连接情况 + $host = $config['hostname'].($config['hostport']?"/{$config['hostport']}":''); + $this->linkID[$linkNum] = $conn($host.':'.$config['database'], $config['username'], $config['password'],C('DB_CHARSET'),0,3); + if ( !$this->linkID[$linkNum]) { + throw_exception(ibase_errmsg()); + } + // 标记连接成功 + $this->connected = true; + // 注销数据库连接配置信息 + if(1 != C('DB_DEPLOY_TYPE')) unset($this->config); + } + return $this->linkID[$linkNum]; + } + + /** + * 释放查询结果 + * @access public + */ + public function free() { + ibase_free_result($this->queryID); + $this->queryID = null; + } + + /** + * 执行查询 返回数据集 + * @access public + * @param string $str sql指令 + * @return mixed + */ + public function query($str) { + $this->initConnect(false); + if ( !$this->_linkID ) return false; + $this->queryStr = $str; + //释放前次的查询结果 + if ( $this->queryID ) $this->free(); + N('db_query',1); + // 记录开始执行时间 + G('queryStartTime'); + $this->queryID = ibase_query($this->_linkID, $str); + $this->debug(); + if ( false === $this->queryID ) { + $this->error(); + return false; + } else { + return $this->getAll(); + } + } + + /** + * 执行语句 + * @access public + * @param string $str sql指令 + * @return integer + */ + public function execute($str) { + $this->initConnect(true); + if ( !$this->_linkID ) return false; + $this->queryStr = $str; + //释放前次的查询结果 + if ( $this->queryID ) $this->free(); + N('db_write',1); + // 记录开始执行时间 + G('queryStartTime'); + $result = ibase_query($this->_linkID, $str) ; + $this->debug(); + if ( false === $result) { + $this->error(); + return false; + } else { + $this->numRows = ibase_affected_rows($this->_linkID); + $this->lastInsID =0; + return $this->numRows; + } + } + + public function startTrans() { + $this->initConnect(true); + if ( !$this->_linkID ) return false; + //数据rollback 支持 + if ($this->transTimes == 0) { + ibase_trans( IBASE_DEFAULT, $this->_linkID); + } + $this->transTimes++; + return ; + } + + /** + * 用于非自动提交状态下面的查询提交 + * @access public + * @return boolen + */ + public function commit() { + if ($this->transTimes > 0) { + $result = ibase_commit($this->_linkID); + $this->transTimes = 0; + if(!$result){ + $this->error(); + return false; + } + } + return true; + } + + /** + * 事务回滚 + * @access public + * @return boolen + */ + public function rollback() { + if ($this->transTimes > 0) { + $result =ibase_rollback($this->_linkID); + $this->transTimes = 0; + if(!$result){ + $this->error(); + return false; + } + } + return true; + } + + /** + * BLOB字段解密函数 Firebird特有 + * @access public + * @param $blob 待解密的BLOB + * @return 二进制数据 + */ + public function BlobDecode($blob) { + $maxblobsize = 262144; + $blob_data = ibase_blob_info($this->_linkID, $blob ); + $blobid = ibase_blob_open($this->_linkID, $blob ); + if( $blob_data[0] > $maxblobsize ) { + $realblob = ibase_blob_get($blobid, $maxblobsize); + while($string = ibase_blob_get($blobid, 8192)){ + $realblob .= $string; + } + } else { + $realblob = ibase_blob_get($blobid, $blob_data[0]); + } + ibase_blob_close( $blobid ); + return( $realblob ); + } + + /** + * 获得所有的查询数据 + * @access private + * @return array + */ + private function getAll() { + //返回数据集 + $result = array(); + while ( $row = ibase_fetch_assoc($this->queryID)) { + $result[] = $row; + } + //剑雷 2007.12.30 自动解密BLOB字段 + //取BLOB字段清单 + $bloblist = array(); + $fieldCount = ibase_num_fields($this->queryID); + for ($i = 0; $i < $fieldCount; $i++) { + $col_info = ibase_field_info($this->queryID, $i); + if ($col_info['type']=='BLOB') { + $bloblist[]=trim($col_info['name']); + } + } + //如果有BLOB字段,就进行解密处理 + if (!empty($bloblist)) { + $i=0; + foreach ($result as $row) { + foreach($bloblist as $field) { + if (!empty($row[$field])) $result[$i][$field]=$this->BlobDecode($row[$field]); + } + $i++; + } + } + return $result; + } + + /** + * 取得数据表的字段信息 + * @access public + */ + public function getFields($tableName) { + $result = $this->query('SELECT RDB$FIELD_NAME AS FIELD, RDB$DEFAULT_VALUE AS DEFAULT1, RDB$NULL_FLAG AS NULL1 FROM RDB$RELATION_FIELDS WHERE RDB$RELATION_NAME=UPPER(\''.$tableName.'\') ORDER By RDB$FIELD_POSITION'); + $info = array(); + if($result) { + foreach ($result as $key => $val) { + $info[trim($val['FIELD'])] = array( + 'name' => trim($val['FIELD']), + 'type' => '', + 'notnull' => (bool) ($val['NULL1'] ==1), // 1表示不为Null + 'default' => $val['DEFAULT1'], + 'primary' => false, + 'autoinc' => false, + ); + } + } + //剑雷 取表字段类型 + $sql='select first 1 * from '. $tableName; + $rs_temp = ibase_query ($this->_linkID, $sql); + $fieldCount = ibase_num_fields($rs_temp); + + for ($i = 0; $i < $fieldCount; $i++) + { + $col_info = ibase_field_info($rs_temp, $i); + $info[trim($col_info['name'])]['type']=$col_info['type']; + } + ibase_free_result ($rs_temp); + + //剑雷 取表的主键 + $sql='select b.rdb$field_name as FIELD_NAME from rdb$relation_constraints a join rdb$index_segments b +on a.rdb$index_name=b.rdb$index_name +where a.rdb$constraint_type=\'PRIMARY KEY\' and a.rdb$relation_name=UPPER(\''.$tableName.'\')'; + $rs_temp = ibase_query ($this->_linkID, $sql); + while ($row=ibase_fetch_object($rs_temp)) { + $info[trim($row->FIELD_NAME)]['primary']=True; + } + ibase_free_result ($rs_temp); + + return $info; + } + + /** + * 取得数据库的表信息 + * @access public + */ + public function getTables($dbName='') { + $sql='SELECT DISTINCT RDB$RELATION_NAME FROM RDB$RELATION_FIELDS WHERE RDB$SYSTEM_FLAG=0'; + $result = $this->query($sql); + $info = array(); + foreach ($result as $key => $val) { + $info[$key] = trim(current($val)); + } + return $info; + } + + /** + * 关闭数据库 + * @access public + */ + public function close() { + if ($this->_linkID){ + ibase_close($this->_linkID); + } + $this->_linkID = null; + } + + /** + * 数据库错误信息 + * 并显示当前的SQL语句 + * @access public + * @return string + */ + public function error() { + $this->error = ibase_errcode().':'.ibase_errmsg(); + if('' != $this->queryStr){ + $this->error .= "\n [ SQL语句 ] : ".$this->queryStr; + } + trace($this->error,'','ERR'); + return $this->error; + } + + /** + * SQL指令安全过滤 + * @access public + * @param string $str SQL指令 + * @return string + */ + public function escapeString($str) { + return str_replace("'", "''", $str); + } + + /** + * limit + * @access public + * @param $limit limit表达式 + * @return string + */ + public function parseLimit($limit) { + $limitStr = ''; + if(!empty($limit)) { + $limit = explode(',',$limit); + if(count($limit)>1) { + $limitStr = ' FIRST '.($limit[1]-$limit[0]).' SKIP '.$limit[0].' '; + }else{ + $limitStr = ' FIRST '.$limit[0].' '; + } + } + return $limitStr; + } +} \ No newline at end of file diff --git a/ThinkPHP/Library/Think/Db/Driver/Mongo.class.php b/ThinkPHP/Library/Think/Db/Driver/Mongo.class.php new file mode 100644 index 000000000..779272e93 --- /dev/null +++ b/ThinkPHP/Library/Think/Db/Driver/Mongo.class.php @@ -0,0 +1,753 @@ + +// +---------------------------------------------------------------------- +namespace Think\Db\Driver; +use Think\Db; +defined('THINK_PATH') or exit(); +/** + * Mongo数据库驱动 必须配合MongoModel使用 + */ +class Mongo extends Db{ + + protected $_mongo = null; // MongoDb Object + protected $_collection = null; // MongoCollection Object + protected $_dbName = ''; // dbName + protected $_collectionName = ''; // collectionName + protected $_cursor = null; // MongoCursor Object + protected $comparison = array('neq'=>'ne','ne'=>'ne','gt'=>'gt','egt'=>'gte','gte'=>'gte','lt'=>'lt','elt'=>'lte','lte'=>'lte','in'=>'in','not in'=>'nin','nin'=>'nin'); + + /** + * 架构函数 读取数据库配置信息 + * @access public + * @param array $config 数据库配置数组 + */ + public function __construct($config=''){ + if ( !class_exists('mongoClient') ) { + throw_exception(L('_NOT_SUPPERT_').':mongoClient'); + } + if(!empty($config)) { + $this->config = $config; + if(empty($this->config['params'])) { + $this->config['params'] = array(); + } + } + } + + /** + * 连接数据库方法 + * @access public + */ + public function connect($config='',$linkNum=0) { + if ( !isset($this->linkID[$linkNum]) ) { + if(empty($config)) $config = $this->config; + $host = 'mongodb://'.($config['username']?"{$config['username']}":'').($config['password']?":{$config['password']}@":'').$config['hostname'].($config['hostport']?":{$config['hostport']}":'').'/'.($config['database']?"{$config['database']}":''); + try{ + $this->linkID[$linkNum] = new \mongoClient( $host,$config['params']); + }catch (\MongoConnectionException $e){ + throw_exception($e->getmessage()); + } + // 标记连接成功 + $this->connected = true; + // 注销数据库连接配置信息 + if(1 != C('DB_DEPLOY_TYPE')) unset($this->config); + } + return $this->linkID[$linkNum]; + } + + /** + * 切换当前操作的Db和Collection + * @access public + * @param string $collection collection + * @param string $db db + * @param boolean $master 是否主服务器 + * @return void + */ + public function switchCollection($collection,$db='',$master=true){ + // 当前没有连接 则首先进行数据库连接 + if ( !$this->_linkID ) $this->initConnect($master); + try{ + if(!empty($db)) { // 传人Db则切换数据库 + // 当前MongoDb对象 + $this->_dbName = $db; + $this->_mongo = $this->_linkID->selectDb($db); + } + // 当前MongoCollection对象 + if(C('DB_SQL_LOG')) { + $this->queryStr = $this->_dbName.'.getCollection('.$collection.')'; + } + if($this->_collectionName != $collection) { + N('db_read',1); + // 记录开始执行时间 + G('queryStartTime'); + $this->_collection = $this->_mongo->selectCollection($collection); + $this->debug(); + $this->_collectionName = $collection; // 记录当前Collection名称 + } + }catch (MongoException $e){ + throw_exception($e->getMessage()); + } + } + + /** + * 释放查询结果 + * @access public + */ + public function free() { + $this->_cursor = null; + } + + /** + * 执行命令 + * @access public + * @param array $command 指令 + * @return array + */ + public function command($command=array()) { + N('db_write',1); + $this->queryStr = 'command:'.json_encode($command); + // 记录开始执行时间 + G('queryStartTime'); + $result = $this->_mongo->command($command); + $this->debug(); + if(!$result['ok']) { + throw_exception($result['errmsg']); + } + return $result; + } + + /** + * 执行语句 + * @access public + * @param string $code sql指令 + * @param array $args 参数 + * @return mixed + */ + public function execute($code,$args=array()) { + N('db_write',1); + $this->queryStr = 'execute:'.$code; + // 记录开始执行时间 + G('queryStartTime'); + $result = $this->_mongo->execute($code,$args); + $this->debug(); + if($result['ok']) { + return $result['retval']; + }else{ + throw_exception($result['errmsg']); + } + } + + /** + * 关闭数据库 + * @access public + */ + public function close() { + if($this->_linkID) { + $this->_linkID->close(); + $this->_linkID = null; + $this->_mongo = null; + $this->_collection = null; + $this->_cursor = null; + } + } + + /** + * 数据库错误信息 + * @access public + * @return string + */ + public function error() { + $this->error = $this->_mongo->lastError(); + trace($this->error,'','ERR'); + return $this->error; + } + + /** + * 插入记录 + * @access public + * @param mixed $data 数据 + * @param array $options 参数表达式 + * @param boolean $replace 是否replace + * @return false | integer + */ + public function insert($data,$options=array(),$replace=false) { + if(isset($options['table'])) { + $this->switchCollection($options['table']); + } + $this->model = $options['model']; + N('db_write',1); + if(C('DB_SQL_LOG')) { + $this->queryStr = $this->_dbName.'.'.$this->_collectionName.'.insert('; + $this->queryStr .= $data?json_encode($data):'{}'; + $this->queryStr .= ')'; + } + try{ + // 记录开始执行时间 + G('queryStartTime'); + $result = $replace? $this->_collection->save($data): $this->_collection->insert($data); + $this->debug(); + if($result) { + $_id = $data['_id']; + if(is_object($_id)) { + $_id = $_id->__toString(); + } + $this->lastInsID = $_id; + } + return $result; + } catch (MongoCursorException $e) { + throw_exception($e->getMessage()); + } + } + + /** + * 插入多条记录 + * @access public + * @param array $dataList 数据 + * @param array $options 参数表达式 + * @return bool + */ + public function insertAll($dataList,$options=array()) { + if(isset($options['table'])) { + $this->switchCollection($options['table']); + } + $this->model = $options['model']; + N('db_write',1); + try{ + // 记录开始执行时间 + G('queryStartTime'); + $result = $this->_collection->batchInsert($dataList); + $this->debug(); + return $result; + } catch (MongoCursorException $e) { + throw_exception($e->getMessage()); + } + } + + /** + * 生成下一条记录ID 用于自增非MongoId主键 + * @access public + * @param string $pk 主键名 + * @return integer + */ + public function mongo_next_id($pk) { + N('db_read',1); + if(C('DB_SQL_LOG')) { + $this->queryStr = $this->_dbName.'.'.$this->_collectionName.'.find({},{'.$pk.':1}).sort({'.$pk.':-1}).limit(1)'; + } + try{ + // 记录开始执行时间 + G('queryStartTime'); + $result = $this->_collection->find(array(),array($pk=>1))->sort(array($pk=>-1))->limit(1); + $this->debug(); + } catch (MongoCursorException $e) { + throw_exception($e->getMessage()); + } + $data = $result->getNext(); + return isset($data[$pk])?$data[$pk]+1:1; + } + + /** + * 更新记录 + * @access public + * @param mixed $data 数据 + * @param array $options 表达式 + * @return bool + */ + public function update($data,$options) { + if(isset($options['table'])) { + $this->switchCollection($options['table']); + } + $this->model = $options['model']; + N('db_write',1); + $query = $this->parseWhere($options['where']); + $set = $this->parseSet($data); + if(C('DB_SQL_LOG')) { + $this->queryStr = $this->_dbName.'.'.$this->_collectionName.'.update('; + $this->queryStr .= $query?json_encode($query):'{}'; + $this->queryStr .= ','.json_encode($set).')'; + } + try{ + // 记录开始执行时间 + G('queryStartTime'); + if(isset($options['limit']) && $options['limit'] == 1) { + $multiple = array("multiple" => false); + }else{ + $multiple = array("multiple" => true); + } + $result = $this->_collection->update($query,$set,$multiple); + $this->debug(); + return $result; + } catch (MongoCursorException $e) { + throw_exception($e->getMessage()); + } + } + + /** + * 删除记录 + * @access public + * @param array $options 表达式 + * @return false | integer + */ + public function delete($options=array()) { + if(isset($options['table'])) { + $this->switchCollection($options['table']); + } + $query = $this->parseWhere($options['where']); + $this->model = $options['model']; + N('db_write',1); + if(C('DB_SQL_LOG')) { + $this->queryStr = $this->_dbName.'.'.$this->_collectionName.'.remove('.json_encode($query).')'; + } + try{ + // 记录开始执行时间 + G('queryStartTime'); + $result = $this->_collection->remove($query); + $this->debug(); + return $result; + } catch (MongoCursorException $e) { + throw_exception($e->getMessage()); + } + } + + /** + * 清空记录 + * @access public + * @param array $options 表达式 + * @return false | integer + */ + public function clear($options=array()){ + if(isset($options['table'])) { + $this->switchCollection($options['table']); + } + $this->model = $options['model']; + N('db_write',1); + if(C('DB_SQL_LOG')) { + $this->queryStr = $this->_dbName.'.'.$this->_collectionName.'.remove({})'; + } + try{ + // 记录开始执行时间 + G('queryStartTime'); + $result = $this->_collection->drop(); + $this->debug(); + return $result; + } catch (MongoCursorException $e) { + throw_exception($e->getMessage()); + } + } + + /** + * 查找记录 + * @access public + * @param array $options 表达式 + * @return iterator + */ + public function select($options=array()) { + if(isset($options['table'])) { + $this->switchCollection($options['table'],'',false); + } + $cache = isset($options['cache'])?$options['cache']:false; + if($cache) { // 查询缓存检测 + $key = is_string($cache['key'])?$cache['key']:md5(serialize($options)); + $value = S($key,'','',$cache['type']); + if(false !== $value) { + return $value; + } + } + $this->model = $options['model']; + N('db_query',1); + $query = $this->parseWhere($options['where']); + $field = $this->parseField($options['field']); + try{ + if(C('DB_SQL_LOG')) { + $this->queryStr = $this->_dbName.'.'.$this->_collectionName.'.find('; + $this->queryStr .= $query? json_encode($query):'{}'; + $this->queryStr .= $field? ','.json_encode($field):''; + $this->queryStr .= ')'; + } + // 记录开始执行时间 + G('queryStartTime'); + $_cursor = $this->_collection->find($query,$field); + if($options['order']) { + $order = $this->parseOrder($options['order']); + if(C('DB_SQL_LOG')) { + $this->queryStr .= '.sort('.json_encode($order).')'; + } + $_cursor = $_cursor->sort($order); + } + if(isset($options['page'])) { // 根据页数计算limit + if(strpos($options['page'],',')) { + list($page,$length) = explode(',',$options['page']); + }else{ + $page = $options['page']; + } + $page = $page?$page:1; + $length = isset($length)?$length:(is_numeric($options['limit'])?$options['limit']:20); + $offset = $length*((int)$page-1); + $options['limit'] = $offset.','.$length; + } + if(isset($options['limit'])) { + list($offset,$length) = $this->parseLimit($options['limit']); + if(!empty($offset)) { + if(C('DB_SQL_LOG')) { + $this->queryStr .= '.skip('.intval($offset).')'; + } + $_cursor = $_cursor->skip(intval($offset)); + } + if(C('DB_SQL_LOG')) { + $this->queryStr .= '.limit('.intval($length).')'; + } + $_cursor = $_cursor->limit(intval($length)); + } + $this->debug(); + $this->_cursor = $_cursor; + $resultSet = iterator_to_array($_cursor); + if($cache && $resultSet ) { // 查询缓存写入 + S($key,$resultSet,$cache['expire'],$cache['type']); + } + return $resultSet; + } catch (MongoCursorException $e) { + throw_exception($e->getMessage()); + } + } + + /** + * 查找某个记录 + * @access public + * @param array $options 表达式 + * @return array + */ + public function find($options=array()){ + if(isset($options['table'])) { + $this->switchCollection($options['table'],'',false); + } + $cache = isset($options['cache'])?$options['cache']:false; + if($cache) { // 查询缓存检测 + $key = is_string($cache['key'])?$cache['key']:md5(serialize($options)); + $value = S($key,'','',$cache['type']); + if(false !== $value) { + return $value; + } + } + $this->model = $options['model']; + N('db_query',1); + $query = $this->parseWhere($options['where']); + $fields = $this->parseField($options['field']); + if(C('DB_SQL_LOG')) { + $this->queryStr = $this->_dbName.'.'.$this->_collectionName.'.findOne('; + $this->queryStr .= $query?json_encode($query):'{}'; + $this->queryStr .= $fields?','.json_encode($fields):''; + $this->queryStr .= ')'; + } + try{ + // 记录开始执行时间 + G('queryStartTime'); + $result = $this->_collection->findOne($query,$fields); + $this->debug(); + if($cache && $result ) { // 查询缓存写入 + S($key,$result,$cache['expire'],$cache['type']); + } + return $result; + } catch (MongoCursorException $e) { + throw_exception($e->getMessage()); + } + } + + /** + * 统计记录数 + * @access public + * @param array $options 表达式 + * @return iterator + */ + public function count($options=array()){ + if(isset($options['table'])) { + $this->switchCollection($options['table'],'',false); + } + $this->model = $options['model']; + N('db_query',1); + $query = $this->parseWhere($options['where']); + if(C('DB_SQL_LOG')) { + $this->queryStr = $this->_dbName.'.'.$this->_collectionName; + $this->queryStr .= $query?'.find('.json_encode($query).')':''; + $this->queryStr .= '.count()'; + } + try{ + // 记录开始执行时间 + G('queryStartTime'); + $count = $this->_collection->count($query); + $this->debug(); + return $count; + } catch (MongoCursorException $e) { + throw_exception($e->getMessage()); + } + } + + public function group($keys,$initial,$reduce,$options=array()){ + $this->_collection->group($keys,$initial,$reduce,$options); + } + + /** + * 取得数据表的字段信息 + * @access public + * @return array + */ + public function getFields($collection=''){ + if(!empty($collection) && $collection != $this->_collectionName) { + $this->switchCollection($collection,'',false); + } + N('db_query',1); + if(C('DB_SQL_LOG')) { + $this->queryStr = $this->_dbName.'.'.$this->_collectionName.'.findOne()'; + } + try{ + // 记录开始执行时间 + G('queryStartTime'); + $result = $this->_collection->findOne(); + $this->debug(); + } catch (MongoCursorException $e) { + throw_exception($e->getMessage()); + } + if($result) { // 存在数据则分析字段 + $info = array(); + foreach ($result as $key=>$val){ + $info[$key] = array( + 'name'=>$key, + 'type'=>getType($val), + ); + } + return $info; + } + // 暂时没有数据 返回false + return false; + } + + /** + * 取得当前数据库的collection信息 + * @access public + */ + public function getTables(){ + if(C('DB_SQL_LOG')) { + $this->queryStr = $this->_dbName.'.getCollenctionNames()'; + } + N('db_query',1); + // 记录开始执行时间 + G('queryStartTime'); + $list = $this->_mongo->listCollections(); + $this->debug(); + $info = array(); + foreach ($list as $collection){ + $info[] = $collection->getName(); + } + return $info; + } + + /** + * set分析 + * @access protected + * @param array $data + * @return string + */ + protected function parseSet($data) { + $result = array(); + foreach ($data as $key=>$val){ + if(is_array($val)) { + switch($val[0]) { + case 'inc': + $result['$inc'][$key] = (int)$val[1]; + break; + case 'set': + case 'unset': + case 'push': + case 'pushall': + case 'addtoset': + case 'pop': + case 'pull': + case 'pullall': + $result['$'.$val[0]][$key] = $val[1]; + break; + default: + $result['$set'][$key] = $val; + } + }else{ + $result['$set'][$key] = $val; + } + } + return $result; + } + + /** + * order分析 + * @access protected + * @param mixed $order + * @return array + */ + protected function parseOrder($order) { + if(is_string($order)) { + $array = explode(',',$order); + $order = array(); + foreach ($array as $key=>$val){ + $arr = explode(' ',trim($val)); + if(isset($arr[1])) { + $arr[1] = $arr[1]=='asc'?1:-1; + }else{ + $arr[1] = 1; + } + $order[$arr[0]] = $arr[1]; + } + } + return $order; + } + + /** + * limit分析 + * @access protected + * @param mixed $limit + * @return array + */ + protected function parseLimit($limit) { + if(strpos($limit,',')) { + $array = explode(',',$limit); + }else{ + $array = array(0,$limit); + } + return $array; + } + + /** + * field分析 + * @access protected + * @param mixed $fields + * @return array + */ + public function parseField($fields){ + if(empty($fields)) { + $fields = array(); + } + if(is_string($fields)) { + $fields = explode(',',$fields); + } + return $fields; + } + + /** + * where分析 + * @access protected + * @param mixed $where + * @return array + */ + public function parseWhere($where){ + $query = array(); + foreach ($where as $key=>$val){ + if('_id' != $key && 0===strpos($key,'_')) { + // 解析特殊条件表达式 + $query = $this->parseThinkWhere($key,$val); + }else{ + // 查询字段的安全过滤 + if(!preg_match('/^[A-Z_\|\&\-.a-z0-9]+$/',trim($key))){ + throw_exception(L('_ERROR_QUERY_').':'.$key); + } + $key = trim($key); + if(strpos($key,'|')) { + $array = explode('|',$key); + $str = array(); + foreach ($array as $k){ + $str[] = $this->parseWhereItem($k,$val); + } + $query['$or'] = $str; + }elseif(strpos($key,'&')){ + $array = explode('&',$key); + $str = array(); + foreach ($array as $k){ + $str[] = $this->parseWhereItem($k,$val); + } + $query = array_merge($query,$str); + }else{ + $str = $this->parseWhereItem($key,$val); + $query = array_merge($query,$str); + } + } + } + return $query; + } + + /** + * 特殊条件分析 + * @access protected + * @param string $key + * @param mixed $val + * @return string + */ + protected function parseThinkWhere($key,$val) { + $query = array(); + switch($key) { + case '_query': // 字符串模式查询条件 + parse_str($val,$query); + if(isset($query['_logic']) && strtolower($query['_logic']) == 'or' ) { + unset($query['_logic']); + $query['$or'] = $query; + } + break; + case '_string':// MongoCode查询 + $query['$where'] = new MongoCode($val); + break; + } + return $query; + } + + /** + * where子单元分析 + * @access protected + * @param string $key + * @param mixed $val + * @return array + */ + protected function parseWhereItem($key,$val) { + $query = array(); + if(is_array($val)) { + if(is_string($val[0])) { + $con = strtolower($val[0]); + if(in_array($con,array('neq','ne','gt','egt','gte','lt','lte','elt'))) { // 比较运算 + $k = '$'.$this->comparison[$con]; + $query[$key] = array($k=>$val[1]); + }elseif('like'== $con){ // 模糊查询 采用正则方式 + $query[$key] = new MongoRegex("/".$val[1]."/"); + }elseif('mod'==$con){ // mod 查询 + $query[$key] = array('$mod'=>$val[1]); + }elseif('regex'==$con){ // 正则查询 + $query[$key] = new MongoRegex($val[1]); + }elseif(in_array($con,array('in','nin','not in'))){ // IN NIN 运算 + $data = is_string($val[1])? explode(',',$val[1]):$val[1]; + $k = '$'.$this->comparison[$con]; + $query[$key] = array($k=>$data); + }elseif('all'==$con){ // 满足所有指定条件 + $data = is_string($val[1])? explode(',',$val[1]):$val[1]; + $query[$key] = array('$all'=>$data); + }elseif('between'==$con){ // BETWEEN运算 + $data = is_string($val[1])? explode(',',$val[1]):$val[1]; + $query[$key] = array('$gte'=>$data[0],'$lte'=>$data[1]); + }elseif('not between'==$con){ + $data = is_string($val[1])? explode(',',$val[1]):$val[1]; + $query[$key] = array('$lt'=>$data[0],'$gt'=>$data[1]); + }elseif('exp'==$con){ // 表达式查询 + $query['$where'] = new MongoCode($val[1]); + }elseif('exists'==$con){ // 字段是否存在 + $query[$key] =array('$exists'=>(bool)$val[1]); + }elseif('size'==$con){ // 限制属性大小 + $query[$key] =array('$size'=>intval($val[1])); + }elseif('type'==$con){ // 限制字段类型 1 浮点型 2 字符型 3 对象或者MongoDBRef 5 MongoBinData 7 MongoId 8 布尔型 9 MongoDate 10 NULL 15 MongoCode 16 32位整型 17 MongoTimestamp 18 MongoInt64 如果是数组的话判断元素的类型 + $query[$key] =array('$type'=>intval($val[1])); + }else{ + $query[$key] = $val; + } + return $query; + } + } + $query[$key] = $val; + return $query; + } +} \ No newline at end of file diff --git a/ThinkPHP/Library/Think/Db/Driver/Mssql.class.php b/ThinkPHP/Library/Think/Db/Driver/Mssql.class.php new file mode 100644 index 000000000..661cb190a --- /dev/null +++ b/ThinkPHP/Library/Think/Db/Driver/Mssql.class.php @@ -0,0 +1,331 @@ + +// +---------------------------------------------------------------------- +namespace Think\Db\Driver; +use Think\Db; +defined('THINK_PATH') or exit(); +/** + * MSsql数据库驱动 要求sqlserver2005 + */ +class Mssql extends Db{ + protected $selectSql = 'SELECT T1.* FROM (SELECT thinkphp.*, ROW_NUMBER() OVER (%ORDER%) AS ROW_NUMBER FROM (SELECT %DISTINCT% %FIELD% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%) AS thinkphp) AS T1 %LIMIT%%COMMENT%'; + /** + * 架构函数 读取数据库配置信息 + * @access public + * @param array $config 数据库配置数组 + */ + public function __construct($config=''){ + if ( !function_exists('mssql_connect') ) { + throw_exception(L('_NOT_SUPPERT_').':mssql'); + } + if(!empty($config)) { + $this->config = $config; + if(empty($this->config['params'])) { + $this->config['params'] = array(); + } + } + } + + /** + * 连接数据库方法 + * @access public + */ + public function connect($config='',$linkNum=0) { + if ( !isset($this->linkID[$linkNum]) ) { + if(empty($config)) $config = $this->config; + $pconnect = !empty($config['params']['persist'])? $config['params']['persist']:$this->pconnect; + $conn = $pconnect ? 'mssql_pconnect':'mssql_connect'; + // 处理不带端口号的socket连接情况 + $sepr = IS_WIN ? ',' : ':'; + $host = $config['hostname'].($config['hostport']?$sepr."{$config['hostport']}":''); + $this->linkID[$linkNum] = $conn( $host, $config['username'], $config['password']); + if ( !$this->linkID[$linkNum] ) throw_exception("Couldn't connect to SQL Server on $host"); + if ( !empty($config['database']) && !mssql_select_db($config['database'], $this->linkID[$linkNum]) ) { + throw_exception("Couldn't open database '".$config['database']); + } + // 标记连接成功 + $this->connected = true; + //注销数据库安全信息 + if(1 != C('DB_DEPLOY_TYPE')) unset($this->config); + } + return $this->linkID[$linkNum]; + } + + /** + * 释放查询结果 + * @access public + */ + public function free() { + mssql_free_result($this->queryID); + $this->queryID = null; + } + + /** + * 执行查询 返回数据集 + * @access public + * @param string $str sql指令 + * @return mixed + */ + public function query($str) { + $this->initConnect(false); + if ( !$this->_linkID ) return false; + $this->queryStr = $str; + //释放前次的查询结果 + if ( $this->queryID ) $this->free(); + N('db_query',1); + // 记录开始执行时间 + G('queryStartTime'); + $this->queryID = mssql_query($str, $this->_linkID); + $this->debug(); + if ( false === $this->queryID ) { + $this->error(); + return false; + } else { + $this->numRows = mssql_num_rows($this->queryID); + return $this->getAll(); + } + } + + /** + * 执行语句 + * @access public + * @param string $str sql指令 + * @return integer + */ + public function execute($str) { + $this->initConnect(true); + if ( !$this->_linkID ) return false; + $this->queryStr = $str; + //释放前次的查询结果 + if ( $this->queryID ) $this->free(); + N('db_write',1); + // 记录开始执行时间 + G('queryStartTime'); + $result = mssql_query($str, $this->_linkID); + $this->debug(); + if ( false === $result ) { + $this->error(); + return false; + } else { + $this->numRows = mssql_rows_affected($this->_linkID); + $this->lastInsID = $this->mssql_insert_id(); + return $this->numRows; + } + } + + /** + * 用于获取最后插入的ID + * @access public + * @return integer + */ + public function mssql_insert_id() { + $query = "SELECT @@IDENTITY as last_insert_id"; + $result = mssql_query($query, $this->_linkID); + list($last_insert_id) = mssql_fetch_row($result); + mssql_free_result($result); + return $last_insert_id; + } + + /** + * 启动事务 + * @access public + * @return void + */ + public function startTrans() { + $this->initConnect(true); + if ( !$this->_linkID ) return false; + //数据rollback 支持 + if ($this->transTimes == 0) { + mssql_query('BEGIN TRAN', $this->_linkID); + } + $this->transTimes++; + return ; + } + + /** + * 用于非自动提交状态下面的查询提交 + * @access public + * @return boolen + */ + public function commit() { + if ($this->transTimes > 0) { + $result = mssql_query('COMMIT TRAN', $this->_linkID); + $this->transTimes = 0; + if(!$result){ + $this->error(); + return false; + } + } + return true; + } + + /** + * 事务回滚 + * @access public + * @return boolen + */ + public function rollback() { + if ($this->transTimes > 0) { + $result = mssql_query('ROLLBACK TRAN', $this->_linkID); + $this->transTimes = 0; + if(!$result){ + $this->error(); + return false; + } + } + return true; + } + + /** + * 获得所有的查询数据 + * @access private + * @return array + */ + private function getAll() { + //返回数据集 + $result = array(); + if($this->numRows >0) { + while($row = mssql_fetch_assoc($this->queryID)) + $result[] = $row; + } + return $result; + } + + /** + * 取得数据表的字段信息 + * @access public + * @return array + */ + public function getFields($tableName) { + $result = $this->query("SELECT column_name, data_type, column_default, is_nullable + FROM information_schema.tables AS t + JOIN information_schema.columns AS c + ON t.table_catalog = c.table_catalog + AND t.table_schema = c.table_schema + AND t.table_name = c.table_name + WHERE t.table_name = '$tableName'"); + $info = array(); + if($result) { + foreach ($result as $key => $val) { + $info[$val['column_name']] = array( + 'name' => $val['column_name'], + 'type' => $val['data_type'], + 'notnull' => (bool) ($val['is_nullable'] === ''), // not null is empty, null is yes + 'default' => $val['column_default'], + 'primary' => false, + 'autoinc' => false, + ); + } + } + return $info; + } + + /** + * 取得数据表的字段信息 + * @access public + * @return array + */ + public function getTables($dbName='') { + $result = $this->query("SELECT TABLE_NAME + FROM INFORMATION_SCHEMA.TABLES + WHERE TABLE_TYPE = 'BASE TABLE' + "); + $info = array(); + foreach ($result as $key => $val) { + $info[$key] = current($val); + } + return $info; + } + + /** + * order分析 + * @access protected + * @param mixed $order + * @return string + */ + protected function parseOrder($order) { + return !empty($order)? ' ORDER BY '.$order:' ORDER BY rand()'; + } + + /** + * limit + * @access public + * @return string + */ + public function parseLimit($limit) { + if(empty($limit)) return ''; + $limit = explode(',',$limit); + if(count($limit)>1) + $limitStr = '(T1.ROW_NUMBER BETWEEN '.$limit[0].' + 1 AND '.$limit[0].' + '.$limit[1].')'; + else + $limitStr = '(T1.ROW_NUMBER BETWEEN 1 AND '.$limit[0].")"; + return 'WHERE '.$limitStr; + } + + /** + * 更新记录 + * @access public + * @param mixed $data 数据 + * @param array $options 表达式 + * @return false | integer + */ + public function update($data,$options) { + $this->model = $options['model']; + $sql = 'UPDATE ' + .$this->parseTable($options['table']) + .$this->parseSet($data) + .$this->parseWhere(!empty($options['where'])?$options['where']:'') + .$this->parseLock(isset($options['lock'])?$options['lock']:false) + .$this->parseComment(!empty($options['comment'])?$options['comment']:''); + return $this->execute($sql); + } + + /** + * 删除记录 + * @access public + * @param array $options 表达式 + * @return false | integer + */ + public function delete($options=array()) { + $this->model = $options['model']; + $sql = 'DELETE FROM ' + .$this->parseTable($options['table']) + .$this->parseWhere(!empty($options['where'])?$options['where']:'') + .$this->parseLock(isset($options['lock'])?$options['lock']:false) + .$this->parseComment(!empty($options['comment'])?$options['comment']:''); + return $this->execute($sql); + } + + /** + * 关闭数据库 + * @access public + */ + public function close() { + if ($this->_linkID){ + mssql_close($this->_linkID); + } + $this->_linkID = null; + } + + /** + * 数据库错误信息 + * 并显示当前的SQL语句 + * @access public + * @return string + */ + public function error() { + $this->error = mssql_get_last_message(); + if('' != $this->queryStr){ + $this->error .= "\n [ SQL语句 ] : ".$this->queryStr; + } + trace($this->error,'','ERR'); + return $this->error; + } +} \ No newline at end of file diff --git a/ThinkPHP/Lib/Driver/Db/DbMysql.class.php b/ThinkPHP/Library/Think/Db/Driver/Mysql.class.php similarity index 97% rename from ThinkPHP/Lib/Driver/Db/DbMysql.class.php rename to ThinkPHP/Library/Think/Db/Driver/Mysql.class.php index 4d3a7835f..f96d0c1f3 100644 --- a/ThinkPHP/Lib/Driver/Db/DbMysql.class.php +++ b/ThinkPHP/Library/Think/Db/Driver/Mysql.class.php @@ -2,23 +2,20 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK IT ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006-2013 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- - +namespace Think\Db\Driver; +use Think\Db; defined('THINK_PATH') or exit(); /** * Mysql数据库驱动类 - * @category Think - * @package Think - * @subpackage Driver.Db - * @author liu21st */ -class DbMysql extends Db{ +class Mysql extends Db{ /** * 架构函数 读取数据库配置信息 @@ -27,7 +24,7 @@ class DbMysql extends Db{ */ public function __construct($config=''){ if ( !extension_loaded('mysql') ) { - throw_exception(L('_NOT_SUPPERT_').':mysql'); + E(L('_NOT_SUPPERT_').':mysql'); } if(!empty($config)) { $this->config = $config; @@ -55,7 +52,7 @@ public function connect($config='',$linkNum=0,$force=false) { $this->linkID[$linkNum] = mysql_connect( $host, $config['username'], $config['password'],true,131072); } if ( !$this->linkID[$linkNum] || (!empty($config['database']) && !mysql_select_db($config['database'], $this->linkID[$linkNum])) ) { - throw_exception(mysql_error()); + E(mysql_error()); } $dbVersion = mysql_get_server_info($this->linkID[$linkNum]); //使用UTF8存取数据库 diff --git a/ThinkPHP/Lib/Driver/Db/DbMysqli.class.php b/ThinkPHP/Library/Think/Db/Driver/Mysqli.class.php similarity index 95% rename from ThinkPHP/Lib/Driver/Db/DbMysqli.class.php rename to ThinkPHP/Library/Think/Db/Driver/Mysqli.class.php index a79606313..be2e61026 100644 --- a/ThinkPHP/Lib/Driver/Db/DbMysqli.class.php +++ b/ThinkPHP/Library/Think/Db/Driver/Mysqli.class.php @@ -8,16 +8,13 @@ // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- - +namespace Think\Db\Driver; +use Think\Db; defined('THINK_PATH') or exit(); /** * Mysqli数据库驱动类 - * @category Think - * @package Think - * @subpackage Driver.Db - * @author liu21st */ -class DbMysqli extends Db{ +class Mysqli extends Db{ /** * 架构函数 读取数据库配置信息 @@ -26,7 +23,7 @@ class DbMysqli extends Db{ */ public function __construct($config=''){ if ( !extension_loaded('mysqli') ) { - throw_exception(L('_NOT_SUPPERT_').':mysqli'); + E(L('_NOT_SUPPERT_').':mysqli'); } if(!empty($config)) { $this->config = $config; @@ -44,8 +41,8 @@ public function __construct($config=''){ public function connect($config='',$linkNum=0) { if ( !isset($this->linkID[$linkNum]) ) { if(empty($config)) $config = $this->config; - $this->linkID[$linkNum] = new mysqli($config['hostname'],$config['username'],$config['password'],$config['database'],$config['hostport']?intval($config['hostport']):3306); - if (mysqli_connect_errno()) throw_exception(mysqli_connect_error()); + $this->linkID[$linkNum] = new \mysqli($config['hostname'],$config['username'],$config['password'],$config['database'],$config['hostport']?intval($config['hostport']):3306); + if (mysqli_connect_errno()) E(mysqli_connect_error()); $dbVersion = $this->linkID[$linkNum]->server_version; // 设置数据库编码 diff --git a/ThinkPHP/Library/Think/Db/Driver/Oracle.class.php b/ThinkPHP/Library/Think/Db/Driver/Oracle.class.php new file mode 100644 index 000000000..d994c0580 --- /dev/null +++ b/ThinkPHP/Library/Think/Db/Driver/Oracle.class.php @@ -0,0 +1,334 @@ + +// +---------------------------------------------------------------------- +namespace Think\Db\Driver; +use Think\Db; +defined('THINK_PATH') or exit(); +/** + * Oracle数据库驱动 + */ +class Oracle extends Db{ + + private $mode = OCI_COMMIT_ON_SUCCESS; + private $table = ''; + protected $selectSql = 'SELECT * FROM (SELECT thinkphp.*, rownum AS numrow FROM (SELECT %DISTINCT% %FIELD% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%%ORDER%) thinkphp ) %LIMIT%%COMMENT%'; + + /** + * 架构函数 读取数据库配置信息 + * @access public + * @param array $config 数据库配置数组 + */ + public function __construct($config=''){ + putenv("NLS_LANG=AMERICAN_AMERICA.UTF8"); + if ( !extension_loaded('oci8') ) { + throw_exception(L('_NOT_SUPPERT_').'oracle'); + } + if(!empty($config)) { + $this->config = $config; + if(empty($this->config['params'])) { + $this->config['params'] = array(); + } + } + } + + /** + * 连接数据库方法 + * @access public + */ + public function connect($config='',$linkNum=0) { + if ( !isset($this->linkID[$linkNum]) ) { + if(empty($config)) $config = $this->config; + $pconnect = !empty($config['params']['persist'])? $config['params']['persist']:$this->pconnect; + $conn = $pconnect ? 'oci_pconnect':'oci_new_connect'; + $this->linkID[$linkNum] = $conn($config['username'], $config['password'],$config['database']);//modify by wyfeng at 2008.12.19 + + if (!$this->linkID[$linkNum]){ + $this->error(false); + } + // 标记连接成功 + $this->connected = true; + //注销数据库安全信息 + if(1 != C('DB_DEPLOY_TYPE')) unset($this->config); + } + return $this->linkID[$linkNum]; + } + + /** + * 释放查询结果 + * @access public + */ + public function free() { + oci_free_statement($this->queryID); + $this->queryID = null; + } + + /** + * 执行查询 返回数据集 + * @access public + * @param string $str sql指令 + * @return mixed + */ + public function query($str) { + $this->initConnect(false); + if ( !$this->_linkID ) return false; + $this->queryStr = $str; + //更改事务模式 + $this->mode = OCI_COMMIT_ON_SUCCESS; + //释放前次的查询结果 + if ( $this->queryID ) $this->free(); + N('db_query',1); + // 记录开始执行时间 + G('queryStartTime'); + $this->queryID = oci_parse($this->_linkID,$str); + $this->debug(); + if (false === oci_execute($this->queryID, $this->mode)) { + $this->error(); + return false; + } else { + return $this->getAll(); + } + } + + /** + * 执行语句 + * @access public + * @param string $str sql指令 + * @return integer + */ + public function execute($str) { + $this->initConnect(true); + if ( !$this->_linkID ) return false; + $this->queryStr = $str; + // 判断新增操作 + $flag = false; + if(preg_match("/^\s*(INSERT\s+INTO)\s+(\w+)\s+/i", $this->queryStr, $match)) { + $this->table = C("DB_SEQUENCE_PREFIX") .str_ireplace(C("DB_PREFIX"), "", $match[2]); + $flag = (boolean)$this->query("SELECT * FROM user_sequences WHERE sequence_name='" . strtoupper($this->table) . "'"); + }//modify by wyfeng at 2009.08.28 + + //更改事务模式 + $this->mode = OCI_COMMIT_ON_SUCCESS; + //释放前次的查询结果 + if ( $this->queryID ) $this->free(); + N('db_write',1); + // 记录开始执行时间 + G('queryStartTime'); + $stmt = oci_parse($this->_linkID,$str); + $this->debug(); + if (false === oci_execute($stmt)) { + $this->error(); + return false; + } else { + $this->numRows = oci_num_rows($stmt); + $this->lastInsID = $flag?$this->insertLastId():0;//modify by wyfeng at 2009.08.28 + return $this->numRows; + } + } + + /** + * 启动事务 + * @access public + * @return void + */ + public function startTrans() { + $this->initConnect(true); + if ( !$this->_linkID ) return false; + //数据rollback 支持 + if ($this->transTimes == 0) { + $this->mode = OCI_DEFAULT; + } + $this->transTimes++; + return ; + } + + /** + * 用于非自动提交状态下面的查询提交 + * @access public + * @return boolen + */ + public function commit(){ + if ($this->transTimes > 0) { + $result = oci_commit($this->_linkID); + if(!$result){ + $this->error(); + return false; + } + $this->transTimes = 0; + } + return true; + } + + /** + * 事务回滚 + * @access public + * @return boolen + */ + public function rollback(){ + if ($this->transTimes > 0) { + $result = oci_rollback($this->_linkID); + if(!$result){ + $this->error(); + return false; + } + $this->transTimes = 0; + } + return true; + } + + /** + * 获得所有的查询数据 + * @access private + * @return array + */ + private function getAll() { + //返回数据集 + $result = array(); + $this->numRows = oci_fetch_all($this->queryID, $result, 0, -1, OCI_FETCHSTATEMENT_BY_ROW); + //add by wyfeng at 2008-12-23 强制将字段名转换为小写,以配合Model类函数如count等 + if(C("DB_CASE_LOWER")) { + foreach($result as $k=>$v) { + $result[$k] = array_change_key_case($result[$k], CASE_LOWER); + } + } + return $result; + } + + + /** + * 取得数据表的字段信息 + * @access public + */ + public function getFields($tableName) { + $result = $this->query("select a.column_name,data_type,decode(nullable,'Y',0,1) notnull,data_default,decode(a.column_name,b.column_name,1,0) pk " + ."from user_tab_columns a,(select column_name from user_constraints c,user_cons_columns col " + ."where c.constraint_name=col.constraint_name and c.constraint_type='P'and c.table_name='".strtoupper($tableName) + ."') b where table_name='".strtoupper($tableName)."' and a.column_name=b.column_name(+)"); + $info = array(); + if($result) { + foreach ($result as $key => $val) { + $info[strtolower($val['column_name'])] = array( + 'name' => strtolower($val['column_name']), + 'type' => strtolower($val['data_type']), + 'notnull' => $val['notnull'], + 'default' => $val['data_default'], + 'primary' => $val['pk'], + 'autoinc' => $val['pk'], + ); + } + } + return $info; + } + + /** + * 取得数据库的表信息(暂时实现取得用户表信息) + * @access public + */ + public function getTables($dbName='') { + $result = $this->query("select table_name from user_tables"); + $info = array(); + foreach ($result as $key => $val) { + $info[$key] = current($val); + } + return $info; + } + + /** + * 关闭数据库 + * @access public + */ + public function close() { + if($this->_linkID){ + oci_close($this->_linkID); + } + $this->_linkID = null; + } + + /** + * 数据库错误信息 + * 并显示当前的SQL语句 + * @access public + * @return string + */ + public function error($result = true) { + if($result){ + $error = oci_error($this->queryID); + }elseif(!$this->_linkID){ + $error = oci_error(); + }else{ + $error = oci_error($this->_linkID); + } + if('' != $this->queryStr){ + $error['message'] .= "\n [ SQL语句 ] : ".$this->queryStr; + } + $result? trace($error['message'],'','ERR'):throw_exception($error['message'],'',$error['code']); + $this->error = $error['message']; + return $this->error; + } + + /** + * SQL指令安全过滤 + * @access public + * @param string $str SQL指令 + * @return string + */ + public function escapeString($str) { + return str_ireplace("'", "''", $str); + } + + /** + * 获取最后插入id ,仅适用于采用序列+触发器结合生成ID的方式 + * 在config.php中指定 + 'DB_TRIGGER_PREFIX' => 'tr_', + 'DB_SEQUENCE_PREFIX' => 'ts_', + * eg:表 tb_user + 相对tb_user的序列为: + -- Create sequence + create sequence TS_USER + minvalue 1 + maxvalue 999999999999999999999999999 + start with 1 + increment by 1 + nocache; + 相对tb_user,ts_user的触发器为: + create or replace trigger TR_USER + before insert on "TB_USER" + for each row + begin + select "TS_USER".nextval into :NEW.ID from dual; + end; + * @access public + * @return integer + */ + public function insertLastId() { + if(empty($this->table)) { + return 0; + } + $sequenceName = $this->table; + $vo = $this->query("SELECT {$sequenceName}.currval currval FROM dual"); + return $vo?$vo[0]["currval"]:0; + } + + /** + * limit + * @access public + * @return string + */ + public function parseLimit($limit) { + $limitStr = ''; + if(!empty($limit)) { + $limit = explode(',',$limit); + if(count($limit)>1) + $limitStr = "(numrow>" . $limit[0] . ") AND (numrow<=" . ($limit[0]+$limit[1]) . ")"; + else + $limitStr = "(numrow>0 AND numrow<=".$limit[0].")"; + } + return $limitStr?' WHERE '.$limitStr:''; + } +} \ No newline at end of file diff --git a/ThinkPHP/Library/Think/Db/Driver/Pdo.class.php b/ThinkPHP/Library/Think/Db/Driver/Pdo.class.php new file mode 100644 index 000000000..6eee2324b --- /dev/null +++ b/ThinkPHP/Library/Think/Db/Driver/Pdo.class.php @@ -0,0 +1,490 @@ + +// +---------------------------------------------------------------------- +namespace Think\Db\Driver; +use Think\Db; +defined('THINK_PATH') or exit(); +/** + * PDO数据库驱动 + */ +class Pdo extends Db{ + + protected $PDOStatement = null; + private $table = ''; + + /** + * 架构函数 读取数据库配置信息 + * @access public + * @param array $config 数据库配置数组 + */ + public function __construct($config=''){ + if(!empty($config)) { + $this->config = $config; + if(empty($this->config['params'])) { + $this->config['params'] = array(); + } + } + + } + + /** + * 连接数据库方法 + * @access public + */ + public function connect($config='',$linkNum=0) { + if ( !isset($this->linkID[$linkNum]) ) { + if(empty($config)) $config = $this->config; + if($this->pconnect) { + $config['params'][\PDO::ATTR_PERSISTENT] = true; + } + //$config['params'][PDO::ATTR_CASE] = C("DB_CASE_LOWER")?PDO::CASE_LOWER:PDO::CASE_UPPER; + try{ + $this->linkID[$linkNum] = new \PDO( $config['dsn'], $config['username'], $config['password'],$config['params']); + }catch (\PDOException $e) { + throw_exception($e->getMessage()); + } + // 因为PDO的连接切换可能导致数据库类型不同,因此重新获取下当前的数据库类型 + $this->dbType = $this->_getDsnType($config['dsn']); + if(in_array($this->dbType,array('MSSQL','ORACLE','IBASE','OCI'))) { + // 由于PDO对于以上的数据库支持不够完美,所以屏蔽了 如果仍然希望使用PDO 可以注释下面一行代码 + throw_exception('由于目前PDO暂时不能完美支持'.$this->dbType.' 请使用官方的'.$this->dbType.'驱动'); + } + $this->linkID[$linkNum]->exec('SET NAMES '.C('DB_CHARSET')); + // 标记连接成功 + $this->connected = true; + // 注销数据库连接配置信息 + if(1 != C('DB_DEPLOY_TYPE')) unset($this->config); + } + return $this->linkID[$linkNum]; + } + + /** + * 释放查询结果 + * @access public + */ + public function free() { + $this->PDOStatement = null; + } + + /** + * 执行查询 返回数据集 + * @access public + * @param string $str sql指令 + * @param array $bind 参数绑定 + * @return mixed + */ + public function query($str,$bind=array()) { + $this->initConnect(false); + if ( !$this->_linkID ) return false; + $this->queryStr = $str; + if(!empty($bind)){ + $this->queryStr .= '[ '.print_r($bind,true).' ]'; + } + //释放前次的查询结果 + if ( !empty($this->PDOStatement) ) $this->free(); + N('db_query',1); + // 记录开始执行时间 + G('queryStartTime'); + $this->PDOStatement = $this->_linkID->prepare($str); + if(false === $this->PDOStatement) + throw_exception($this->error()); + // 参数绑定 + $this->bindParam($bind); + $result = $this->PDOStatement->execute(); + $this->debug(); + if ( false === $result ) { + $this->error(); + return false; + } else { + return $this->getAll(); + } + } + + /** + * 执行语句 + * @access public + * @param string $str sql指令 + * @param array $bind 参数绑定 + * @return integer + */ + public function execute($str,$bind=array()) { + $this->initConnect(true); + if ( !$this->_linkID ) return false; + $this->queryStr = $str; + if(!empty($bind)){ + $this->queryStr .= '[ '.print_r($bind,true).' ]'; + } + $flag = false; + if($this->dbType == 'OCI') { + if(preg_match("/^\s*(INSERT\s+INTO)\s+(\w+)\s+/i", $this->queryStr, $match)) { + $this->table = C("DB_SEQUENCE_PREFIX").str_ireplace(C("DB_PREFIX"), "", $match[2]); + $flag = (boolean)$this->query("SELECT * FROM user_sequences WHERE sequence_name='" . strtoupper($this->table) . "'"); + } + } + //释放前次的查询结果 + if ( !empty($this->PDOStatement) ) $this->free(); + N('db_write',1); + // 记录开始执行时间 + G('queryStartTime'); + $this->PDOStatement = $this->_linkID->prepare($str); + if(false === $this->PDOStatement) { + throw_exception($this->error()); + } + // 参数绑定 + $this->bindParam($bind); + $result = $this->PDOStatement->execute(); + $this->debug(); + if ( false === $result) { + $this->error(); + return false; + } else { + $this->numRows = $this->PDOStatement->rowCount(); + if($flag || preg_match("/^\s*(INSERT\s+INTO|REPLACE\s+INTO)\s+/i", $str)) { + $this->lastInsID = $this->getLastInsertId(); + } + return $this->numRows; + } + } + + /** + * 参数绑定 + * @access protected + * @return void + */ + protected function bindParam($bind){ + // 参数绑定 + foreach($bind as $key=>$val){ + if(is_array($val)){ + array_unshift($val,$key); + }else{ + $val = array($key,$val); + } + call_user_func_array(array($this->PDOStatement,'bindParam'),$val); + } + } + + /** + * 启动事务 + * @access public + * @return void + */ + public function startTrans() { + $this->initConnect(true); + if ( !$this->_linkID ) return false; + //数据rollback 支持 + if ($this->transTimes == 0) { + $this->_linkID->beginTransaction(); + } + $this->transTimes++; + return ; + } + + /** + * 用于非自动提交状态下面的查询提交 + * @access public + * @return boolen + */ + public function commit() { + if ($this->transTimes > 0) { + $result = $this->_linkID->commit(); + $this->transTimes = 0; + if(!$result){ + $this->error(); + return false; + } + } + return true; + } + + /** + * 事务回滚 + * @access public + * @return boolen + */ + public function rollback() { + if ($this->transTimes > 0) { + $result = $this->_linkID->rollback(); + $this->transTimes = 0; + if(!$result){ + $this->error(); + return false; + } + } + return true; + } + + /** + * 获得所有的查询数据 + * @access private + * @return array + */ + private function getAll() { + //返回数据集 + $result = $this->PDOStatement->fetchAll(\PDO::FETCH_ASSOC); + $this->numRows = count( $result ); + return $result; + } + + /** + * 取得数据表的字段信息 + * @access public + */ + public function getFields($tableName) { + $this->initConnect(true); + if(C('DB_DESCRIBE_TABLE_SQL')) { + // 定义特殊的字段查询SQL + $sql = str_replace('%table%',$tableName,C('DB_DESCRIBE_TABLE_SQL')); + }else{ + switch($this->dbType) { + case 'MSSQL': + case 'SQLSRV': + $sql = "SELECT column_name as 'Name', data_type as 'Type', column_default as 'Default', is_nullable as 'Null' + FROM information_schema.tables AS t + JOIN information_schema.columns AS c + ON t.table_catalog = c.table_catalog + AND t.table_schema = c.table_schema + AND t.table_name = c.table_name + WHERE t.table_name = '$tableName'"; + break; + case 'SQLITE': + $sql = 'PRAGMA table_info ('.$tableName.') '; + break; + case 'ORACLE': + case 'OCI': + $sql = "SELECT a.column_name \"Name\",data_type \"Type\",decode(nullable,'Y',0,1) notnull,data_default \"Default\",decode(a.column_name,b.column_name,1,0) \"pk\" " + ."FROM user_tab_columns a,(SELECT column_name FROM user_constraints c,user_cons_columns col " + ."WHERE c.constraint_name=col.constraint_name AND c.constraint_type='P' and c.table_name='".strtoupper($tableName) + ."') b where table_name='".strtoupper($tableName)."' and a.column_name=b.column_name(+)"; + break; + case 'PGSQL': + $sql = 'select fields_name as "Name",fields_type as "Type",fields_not_null as "Null",fields_key_name as "Key",fields_default as "Default",fields_default as "Extra" from table_msg('.$tableName.');'; + break; + case 'IBASE': + break; + case 'MYSQL': + default: + $sql = 'DESCRIBE '.$tableName;//备注: 驱动类不只针对mysql,不能加`` + } + } + $result = $this->query($sql); + $info = array(); + if($result) { + foreach ($result as $key => $val) { + $val = array_change_key_case($val); + $val['name'] = isset($val['name'])?$val['name']:""; + $val['type'] = isset($val['type'])?$val['type']:""; + $name = isset($val['field'])?$val['field']:$val['name']; + $info[$name] = array( + 'name' => $name , + 'type' => $val['type'], + 'notnull' => (bool)(((isset($val['null'])) && ($val['null'] === '')) || ((isset($val['notnull'])) && ($val['notnull'] === ''))), // not null is empty, null is yes + 'default' => isset($val['default'])? $val['default'] :(isset($val['dflt_value'])?$val['dflt_value']:""), + 'primary' => isset($val['key'])?strtolower($val['key']) == 'pri':(isset($val['pk'])?$val['pk']:false), + 'autoinc' => isset($val['extra'])?strtolower($val['extra']) == 'auto_increment':(isset($val['key'])?$val['key']:false), + ); + } + } + return $info; + } + + /** + * 取得数据库的表信息 + * @access public + */ + public function getTables($dbName='') { + if(C('DB_FETCH_TABLES_SQL')) { + // 定义特殊的表查询SQL + $sql = str_replace('%db%',$dbName,C('DB_FETCH_TABLES_SQL')); + }else{ + switch($this->dbType) { + case 'ORACLE': + case 'OCI': + $sql = 'SELECT table_name FROM user_tables'; + break; + case 'MSSQL': + case 'SQLSRV': + $sql = "SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE'"; + break; + case 'PGSQL': + $sql = "select tablename as Tables_in_test from pg_tables where schemaname ='public'"; + break; + case 'IBASE': + // 暂时不支持 + throw_exception(L('_NOT_SUPPORT_DB_').':IBASE'); + break; + case 'SQLITE': + $sql = "SELECT name FROM sqlite_master WHERE type='table' " + . "UNION ALL SELECT name FROM sqlite_temp_master " + . "WHERE type='table' ORDER BY name"; + break; + case 'MYSQL': + default: + if(!empty($dbName)) { + $sql = 'SHOW TABLES FROM '.$dbName; + }else{ + $sql = 'SHOW TABLES '; + } + } + } + $result = $this->query($sql); + $info = array(); + foreach ($result as $key => $val) { + $info[$key] = current($val); + } + return $info; + } + + /** + * limit分析 + * @access protected + * @param mixed $lmit + * @return string + */ + protected function parseLimit($limit) { + $limitStr = ''; + if(!empty($limit)) { + switch($this->dbType){ + case 'PGSQL': + case 'SQLITE': + $limit = explode(',',$limit); + if(count($limit)>1) { + $limitStr .= ' LIMIT '.$limit[1].' OFFSET '.$limit[0].' '; + }else{ + $limitStr .= ' LIMIT '.$limit[0].' '; + } + break; + case 'MSSQL': + case 'SQLSRV': + break; + case 'IBASE': + // 暂时不支持 + break; + case 'ORACLE': + case 'OCI': + break; + case 'MYSQL': + default: + $limitStr .= ' LIMIT '.$limit.' '; + } + } + return $limitStr; + } + + /** + * 字段和表名处理 + * @access protected + * @param string $key + * @return string + */ + protected function parseKey(&$key) { + if($this->dbType=='MYSQL'){ + $key = trim($key); + if(!preg_match('/[,\'\"\*\(\)`.\s]/',$key)) { + $key = '`'.$key.'`'; + } + return $key; + }else{ + return parent::parseKey($key); + } + + } + + /** + * 关闭数据库 + * @access public + */ + public function close() { + $this->_linkID = null; + } + + /** + * 数据库错误信息 + * 并显示当前的SQL语句 + * @access public + * @return string + */ + public function error() { + if($this->PDOStatement) { + $error = $this->PDOStatement->errorInfo(); + $this->error = $error[1].':'.$error[2]; + }else{ + $this->error = ''; + } + if('' != $this->queryStr){ + $this->error .= "\n [ SQL语句 ] : ".$this->queryStr; + } + trace($this->error,'','ERR'); + return $this->error; + } + + /** + * SQL指令安全过滤 + * @access public + * @param string $str SQL指令 + * @return string + */ + public function escapeString($str) { + switch($this->dbType) { + case 'PGSQL': + case 'MSSQL': + case 'SQLSRV': + case 'MYSQL': + return addslashes($str); + case 'IBASE': + case 'SQLITE': + case 'ORACLE': + case 'OCI': + return str_ireplace("'", "''", $str); + } + } + + /** + * value分析 + * @access protected + * @param mixed $value + * @return string + */ + protected function parseValue($value) { + if(is_string($value)) { + $value = strpos($value,':') === 0 ? $this->escapeString($value) : '\''.$this->escapeString($value).'\''; + }elseif(isset($value[0]) && is_string($value[0]) && strtolower($value[0]) == 'exp'){ + $value = $this->escapeString($value[1]); + }elseif(is_array($value)) { + $value = array_map(array($this, 'parseValue'),$value); + }elseif(is_bool($value)){ + $value = $value ? '1' : '0'; + }elseif(is_null($value)){ + $value = 'null'; + } + return $value; + } + + /** + * 获取最后插入id + * @access public + * @return integer + */ + public function getLastInsertId() { + switch($this->dbType) { + case 'PGSQL': + case 'SQLITE': + case 'MSSQL': + case 'SQLSRV': + case 'IBASE': + case 'MYSQL': + return $this->_linkID->lastInsertId(); + case 'ORACLE': + case 'OCI': + $sequenceName = $this->table; + $vo = $this->query("SELECT {$sequenceName}.currval currval FROM dual"); + return $vo?$vo[0]["currval"]:0; + } + } +} \ No newline at end of file diff --git a/ThinkPHP/Library/Think/Db/Driver/Pgsql.class.php b/ThinkPHP/Library/Think/Db/Driver/Pgsql.class.php new file mode 100644 index 000000000..662d35012 --- /dev/null +++ b/ThinkPHP/Library/Think/Db/Driver/Pgsql.class.php @@ -0,0 +1,297 @@ + +// +---------------------------------------------------------------------- +namespace Think\Db\Driver; +use Think\Db; +defined('THINK_PATH') or exit(); +/** + * Pgsql数据库驱动 + */ +class Pgsql extends Db{ + + /** + * 架构函数 读取数据库配置信息 + * @access public + * @param array $config 数据库配置数组 + */ + public function __construct($config='') { + if ( !extension_loaded('pgsql') ) { + throw_exception(L('_NOT_SUPPERT_').':pgsql'); + } + if(!empty($config)) { + $this->config = $config; + if(empty($this->config['params'])) { + $this->config['params'] = array(); + } + } + } + + /** + * 连接数据库方法 + * @access public + */ + public function connect($config='',$linkNum=0) { + if ( !isset($this->linkID[$linkNum]) ) { + if(empty($config)) $config = $this->config; + $pconnect = !empty($config['params']['persist'])? $config['params']['persist']:$this->pconnect; + $conn = $pconnect ? 'pg_pconnect':'pg_connect'; + $this->linkID[$linkNum] = $conn('host='.$config['hostname'].' port='.$config['hostport'].' dbname='.$config['database'].' user='.$config['username'].' password='.$config['password']); + if (0 !== pg_connection_status($this->linkID[$linkNum])){ + throw_exception($this->error(false)); + } + //设置编码 + pg_set_client_encoding($this->linkID[$linkNum], C('DB_CHARSET')); + //$pgInfo = pg_version($this->linkID[$linkNum]); + //$dbVersion = $pgInfo['server']; + // 标记连接成功 + $this->connected = true; + //注销数据库安全信息 + if(1 != C('DB_DEPLOY_TYPE')) unset($this->config); + } + return $this->linkID[$linkNum]; + } + + /** + * 释放查询结果 + * @access public + */ + public function free() { + pg_free_result($this->queryID); + $this->queryID = null; + } + + /** + * 执行查询 返回数据集 + * @access public + * @param string $str sql指令 + * @return mixed + */ + public function query($str) { + $this->initConnect(false); + if ( !$this->_linkID ) return false; + $this->queryStr = $str; + //释放前次的查询结果 + if ( $this->queryID ) $this->free(); + N('db_query',1); + // 记录开始执行时间 + G('queryStartTime'); + $this->queryID = pg_query($this->_linkID,$str); + $this->debug(); + if ( false === $this->queryID ) { + $this->error(); + return false; + } else { + $this->numRows = pg_num_rows($this->queryID); + return $this->getAll(); + } + } + + /** + * 执行语句 + * @access public + * @param string $str sql指令 + * @return integer + */ + public function execute($str) { + $this->initConnect(true); + if ( !$this->_linkID ) return false; + $this->queryStr = $str; + //释放前次的查询结果 + if ( $this->queryID ) $this->free(); + N('db_write',1); + // 记录开始执行时间 + G('queryStartTime'); + $result = pg_query($this->_linkID,$str); + $this->debug(); + if ( false === $result ) { + $this->error(); + return false; + } else { + $this->numRows = pg_affected_rows($result); + $this->lastInsID = $this->last_insert_id(); + return $this->numRows; + } + } + + /** + * 用于获取最后插入的ID + * @access public + * @return integer + */ + public function last_insert_id() { + $query = "SELECT LASTVAL() AS insert_id"; + $result = pg_query($this->_linkID,$query); + list($last_insert_id) = pg_fetch_array($result,null,PGSQL_ASSOC); + pg_free_result($result); + return $last_insert_id; + } + + /** + * 启动事务 + * @access public + * @return void + */ + public function startTrans() { + $this->initConnect(true); + if ( !$this->_linkID ) return false; + //数据rollback 支持 + if ($this->transTimes == 0) { + pg_exec($this->_linkID,'begin;'); + } + $this->transTimes++; + return ; + } + + /** + * 用于非自动提交状态下面的查询提交 + * @access public + * @return boolen + */ + public function commit() { + if ($this->transTimes > 0) { + $result = pg_exec($this->_linkID,'end;'); + if(!$result){ + $this->error(); + return false; + } + $this->transTimes = 0; + } + return true; + } + + /** + * 事务回滚 + * @access public + * @return boolen + */ + public function rollback() { + if ($this->transTimes > 0) { + $result = pg_exec($this->_linkID,'abort;'); + if(!$result){ + $this->error(); + return false; + } + $this->transTimes = 0; + } + return true; + } + + /** + * 获得所有的查询数据 + * @access private + * @return array + */ + private function getAll() { + //返回数据集 + $result = pg_fetch_all($this->queryID); + pg_result_seek($this->queryID,0); + return $result; + } + + /** + * 取得数据表的字段信息 + * @access public + */ + public function getFields($tableName) { + $result = $this->query("select a.attname as \"Field\", + t.typname as \"Type\", + a.attnotnull as \"Null\", + i.indisprimary as \"Key\", + d.adsrc as \"Default\" + from pg_class c + inner join pg_attribute a on a.attrelid = c.oid + inner join pg_type t on a.atttypid = t.oid + left join pg_attrdef d on a.attrelid=d.adrelid and d.adnum=a.attnum + left join pg_index i on a.attnum=ANY(i.indkey) and c.oid = i.indrelid + where (c.relname='{$tableName}' or c.relname = lower('{$tableName}')) AND a.attnum > 0 + order by a.attnum asc;"); + $info = array(); + if($result) { + foreach ($result as $key => $val) { + $info[$val['Field']] = array( + 'name' => $val['Field'], + 'type' => $val['Type'], + 'notnull' => (bool) ($val['Null'] == 't'?1:0), // 't' is 'not null' + 'default' => $val['Default'], + 'primary' => (strtolower($val['Key']) == 't'), + 'autoinc' => (strtolower($val['Default']) == "nextval('{$tableName}_id_seq'::regclass)"), + ); + } + } + return $info; + } + + /** + * 取得数据库的表信息 + * @access public + */ + public function getTables($dbName='') { + $result = $this->query("select tablename as Tables_in_test from pg_tables where schemaname ='public'"); + $info = array(); + foreach ($result as $key => $val) { + $info[$key] = current($val); + } + return $info; + } + + /** + * 关闭数据库 + * @access public + */ + public function close() { + if($this->_linkID){ + pg_close($this->_linkID); + } + $this->_linkID = null; + } + + /** + * 数据库错误信息 + * 并显示当前的SQL语句 + * @access public + * @return string + */ + public function error($result = true) { + $this->error = $result?pg_result_error($this->queryID): pg_last_error($this->_linkID); + if('' != $this->queryStr){ + $this->error .= "\n [ SQL语句 ] : ".$this->queryStr; + } + trace($this->error,'','ERR'); + return $this->error; + } + + /** + * SQL指令安全过滤 + * @access public + * @param string $str SQL指令 + * @return string + */ + public function escapeString($str) { + return pg_escape_string($str); + } + + /** + * limit + * @access public + * @return string + */ + public function parseLimit($limit) { + $limitStr = ''; + if(!empty($limit)) { + $limit = explode(',',$limit); + if(count($limit)>1) { + $limitStr .= ' LIMIT '.$limit[1].' OFFSET '.$limit[0].' '; + }else{ + $limitStr .= ' LIMIT '.$limit[0].' '; + } + } + return $limitStr; + } +} \ No newline at end of file diff --git a/ThinkPHP/Library/Think/Db/Driver/Sqlite.class.php b/ThinkPHP/Library/Think/Db/Driver/Sqlite.class.php new file mode 100644 index 000000000..6fe38ec11 --- /dev/null +++ b/ThinkPHP/Library/Think/Db/Driver/Sqlite.class.php @@ -0,0 +1,282 @@ + +// +---------------------------------------------------------------------- +namespace Think\Db\Driver; +use Think\Db; +defined('THINK_PATH') or exit(); +/** + * Sqlite数据库驱动 + */ +class Sqlite extends Db { + + /** + * 架构函数 读取数据库配置信息 + * @access public + * @param array $config 数据库配置数组 + */ + public function __construct($config='') { + if ( !extension_loaded('sqlite') ) { + throw_exception(L('_NOT_SUPPERT_').':sqlite'); + } + if(!empty($config)) { + if(!isset($config['mode'])) { + $config['mode'] = 0666; + } + $this->config = $config; + if(empty($this->config['params'])) { + $this->config['params'] = array(); + } + } + } + + /** + * 连接数据库方法 + * @access public + */ + public function connect($config='',$linkNum=0) { + if ( !isset($this->linkID[$linkNum]) ) { + if(empty($config)) $config = $this->config; + $pconnect = !empty($config['params']['persist'])? $config['params']['persist']:$this->pconnect; + $conn = $pconnect ? 'sqlite_popen':'sqlite_open'; + $this->linkID[$linkNum] = $conn($config['database'],$config['mode']); + if ( !$this->linkID[$linkNum]) { + throw_exception(sqlite_error_string()); + } + // 标记连接成功 + $this->connected = true; + //注销数据库安全信息 + if(1 != C('DB_DEPLOY_TYPE')) unset($this->config); + } + return $this->linkID[$linkNum]; + } + + /** + * 释放查询结果 + * @access public + */ + public function free() { + $this->queryID = null; + } + + /** + * 执行查询 返回数据集 + * @access public + * @param string $str sql指令 + * @return mixed + */ + public function query($str) { + $this->initConnect(false); + if ( !$this->_linkID ) return false; + $this->queryStr = $str; + //释放前次的查询结果 + if ( $this->queryID ) $this->free(); + N('db_query',1); + // 记录开始执行时间 + G('queryStartTime'); + $this->queryID = sqlite_query($this->_linkID,$str); + $this->debug(); + if ( false === $this->queryID ) { + $this->error(); + return false; + } else { + $this->numRows = sqlite_num_rows($this->queryID); + return $this->getAll(); + } + } + + /** + * 执行语句 + * @access public + * @param string $str sql指令 + * @return integer + */ + public function execute($str) { + $this->initConnect(true); + if ( !$this->_linkID ) return false; + $this->queryStr = $str; + //释放前次的查询结果 + if ( $this->queryID ) $this->free(); + N('db_write',1); + // 记录开始执行时间 + G('queryStartTime'); + $result = sqlite_exec($this->_linkID,$str); + $this->debug(); + if ( false === $result ) { + $this->error(); + return false; + } else { + $this->numRows = sqlite_changes($this->_linkID); + $this->lastInsID = sqlite_last_insert_rowid($this->_linkID); + return $this->numRows; + } + } + + /** + * 启动事务 + * @access public + * @return void + */ + public function startTrans() { + $this->initConnect(true); + if ( !$this->_linkID ) return false; + //数据rollback 支持 + if ($this->transTimes == 0) { + sqlite_query($this->_linkID,'BEGIN TRANSACTION'); + } + $this->transTimes++; + return ; + } + + /** + * 用于非自动提交状态下面的查询提交 + * @access public + * @return boolen + */ + public function commit() { + if ($this->transTimes > 0) { + $result = sqlite_query($this->_linkID,'COMMIT TRANSACTION'); + if(!$result){ + $this->error(); + return false; + } + $this->transTimes = 0; + } + return true; + } + + /** + * 事务回滚 + * @access public + * @return boolen + */ + public function rollback() { + if ($this->transTimes > 0) { + $result = sqlite_query($this->_linkID,'ROLLBACK TRANSACTION'); + if(!$result){ + $this->error(); + return false; + } + $this->transTimes = 0; + } + return true; + } + + /** + * 获得所有的查询数据 + * @access private + * @return array + */ + private function getAll() { + //返回数据集 + $result = array(); + if($this->numRows >0) { + for($i=0;$i<$this->numRows ;$i++ ){ + // 返回数组集 + $result[$i] = sqlite_fetch_array($this->queryID,SQLITE_ASSOC); + } + sqlite_seek($this->queryID,0); + } + return $result; + } + + /** + * 取得数据表的字段信息 + * @access public + * @return array + */ + public function getFields($tableName) { + $result = $this->query('PRAGMA table_info( '.$tableName.' )'); + $info = array(); + if($result){ + foreach ($result as $key => $val) { + $info[$val['Field']] = array( + 'name' => $val['Field'], + 'type' => $val['Type'], + 'notnull' => (bool) ($val['Null'] === ''), // not null is empty, null is yes + 'default' => $val['Default'], + 'primary' => (strtolower($val['Key']) == 'pri'), + 'autoinc' => (strtolower($val['Extra']) == 'auto_increment'), + ); + } + } + return $info; + } + + /** + * 取得数据库的表信息 + * @access public + * @return array + */ + public function getTables($dbName='') { + $result = $this->query("SELECT name FROM sqlite_master WHERE type='table' " + . "UNION ALL SELECT name FROM sqlite_temp_master " + . "WHERE type='table' ORDER BY name"); + $info = array(); + foreach ($result as $key => $val) { + $info[$key] = current($val); + } + return $info; + } + + /** + * 关闭数据库 + * @access public + */ + public function close() { + if ($this->_linkID){ + sqlite_close($this->_linkID); + } + $this->_linkID = null; + } + + /** + * 数据库错误信息 + * 并显示当前的SQL语句 + * @access public + * @return string + */ + public function error() { + $code = sqlite_last_error($this->_linkID); + $this->error = $code.':'.sqlite_error_string($code); + if('' != $this->queryStr){ + $this->error .= "\n [ SQL语句 ] : ".$this->queryStr; + } + trace($this->error,'','ERR'); + return $this->error; + } + + /** + * SQL指令安全过滤 + * @access public + * @param string $str SQL指令 + * @return string + */ + public function escapeString($str) { + return sqlite_escape_string($str); + } + + /** + * limit + * @access public + * @return string + */ + public function parseLimit($limit) { + $limitStr = ''; + if(!empty($limit)) { + $limit = explode(',',$limit); + if(count($limit)>1) { + $limitStr .= ' LIMIT '.$limit[1].' OFFSET '.$limit[0].' '; + }else{ + $limitStr .= ' LIMIT '.$limit[0].' '; + } + } + return $limitStr; + } +} \ No newline at end of file diff --git a/ThinkPHP/Library/Think/Db/Driver/Sqlsrv.class.php b/ThinkPHP/Library/Think/Db/Driver/Sqlsrv.class.php new file mode 100644 index 000000000..4ca478796 --- /dev/null +++ b/ThinkPHP/Library/Think/Db/Driver/Sqlsrv.class.php @@ -0,0 +1,349 @@ + +// +---------------------------------------------------------------------- +namespace Think\Db\Driver; +use Think\Db; +defined('THINK_PATH') or exit(); +/** + * Sqlsrv数据库驱动 + */ +class Sqlsrv extends Db{ + protected $selectSql = 'SELECT T1.* FROM (SELECT thinkphp.*, ROW_NUMBER() OVER (%ORDER%) AS ROW_NUMBER FROM (SELECT %DISTINCT% %FIELD% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%) AS thinkphp) AS T1 %LIMIT%%COMMENT%'; + /** + * 架构函数 读取数据库配置信息 + * @access public + * @param array $config 数据库配置数组 + */ + public function __construct($config='') { + if ( !function_exists('sqlsrv_connect') ) { + throw_exception(L('_NOT_SUPPERT_').':sqlsrv'); + } + if(!empty($config)) { + $this->config = $config; + } + } + + /** + * 连接数据库方法 + * @access public + */ + public function connect($config='',$linkNum=0) { + if ( !isset($this->linkID[$linkNum]) ) { + if(empty($config)) $config = $this->config; + $host = $config['hostname'].($config['hostport']?",{$config['hostport']}":''); + $connectInfo = array('Database'=>$config['database'],'UID'=>$config['username'],'PWD'=>$config['password'],'CharacterSet' => C('DEFAULT_CHARSET')); + $this->linkID[$linkNum] = sqlsrv_connect( $host, $connectInfo); + if ( !$this->linkID[$linkNum] ) $this->error(false); + // 标记连接成功 + $this->connected = true; + //注销数据库安全信息 + if(1 != C('DB_DEPLOY_TYPE')) unset($this->config); + } + return $this->linkID[$linkNum]; + } + + /** + * 释放查询结果 + * @access public + */ + public function free() { + sqlsrv_free_stmt($this->queryID); + $this->queryID = null; + } + + /** + * 执行查询 返回数据集 + * @access public + * @param string $str sql指令 + * @param array $bind 参数绑定 + * @return mixed + */ + public function query($str,$bind=array()) { + $this->initConnect(false); + if ( !$this->_linkID ) return false; + //释放前次的查询结果 + if ( $this->queryID ) $this->free(); + N('db_query',1); + // 记录开始执行时间 + G('queryStartTime'); + $str = str_replace(array_keys($bind),'?',$str); + $bind = array_values($bind); + $this->queryStr = $str; + $this->queryID = sqlsrv_query($this->_linkID,$str,$bind, array( "Scrollable" => SQLSRV_CURSOR_KEYSET)); + $this->debug(); + if ( false === $this->queryID ) { + $this->error(); + return false; + } else { + $this->numRows = sqlsrv_num_rows($this->queryID); + return $this->getAll(); + } + } + + /** + * 执行语句 + * @access public + * @param string $str sql指令 + * @param array $bind 参数绑定 + * @return integer + */ + public function execute($str,$bind=array()) { + $this->initConnect(true); + if ( !$this->_linkID ) return false; + //释放前次的查询结果 + if ( $this->queryID ) $this->free(); + N('db_write',1); + // 记录开始执行时间 + G('queryStartTime'); + $str = str_replace(array_keys($bind),'?',$str); + $bind = array_values($bind); + $this->queryStr = $str; + $this->queryID= sqlsrv_query($this->_linkID,$str,$bind); + $this->debug(); + if ( false === $this->queryID ) { + $this->error(); + return false; + } else { + $this->numRows = sqlsrv_rows_affected($this->queryID); + $this->lastInsID = $this->mssql_insert_id(); + return $this->numRows; + } + } + + /** + * 用于获取最后插入的ID + * @access public + * @return integer + */ + public function mssql_insert_id() { + $query = "SELECT @@IDENTITY as last_insert_id"; + $result = sqlsrv_query($this->_linkID,$query); + list($last_insert_id) = sqlsrv_fetch_array($result); + sqlsrv_free_stmt($result); + return $last_insert_id; + } + + /** + * 启动事务 + * @access public + * @return void + */ + public function startTrans() { + $this->initConnect(true); + if ( !$this->_linkID ) return false; + //数据rollback 支持 + if ($this->transTimes == 0) { + sqlsrv_begin_transaction($this->_linkID); + } + $this->transTimes++; + return ; + } + + /** + * 用于非自动提交状态下面的查询提交 + * @access public + * @return boolen + */ + public function commit() { + if ($this->transTimes > 0) { + $result = sqlsrv_commit($this->_linkID); + $this->transTimes = 0; + if(!$result){ + $this->error(); + return false; + } + } + return true; + } + + /** + * 事务回滚 + * @access public + * @return boolen + */ + public function rollback() { + if ($this->transTimes > 0) { + $result = sqlsrv_rollback($this->_linkID); + $this->transTimes = 0; + if(!$result){ + $this->error(); + return false; + } + } + return true; + } + + /** + * 获得所有的查询数据 + * @access private + * @return array + */ + private function getAll() { + //返回数据集 + $result = array(); + if($this->numRows >0) { + while($row = sqlsrv_fetch_array($this->queryID,SQLSRV_FETCH_ASSOC)) + $result[] = $row; + } + return $result; + } + + /** + * 取得数据表的字段信息 + * @access public + * @return array + */ + public function getFields($tableName) { + $result = $this->query(" + SELECT column_name,data_type,column_default,is_nullable + FROM information_schema.tables AS t + JOIN information_schema.columns AS c + ON t.table_catalog = c.table_catalog + AND t.table_schema = c.table_schema + AND t.table_name = c.table_name + WHERE t.table_name = '{$tableName}'"); + $pk = $this->query("SELECT * FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE TABLE_NAME='{$tableName}'"); + $info = array(); + if($result) { + foreach ($result as $key => $val) { + $info[$val['column_name']] = array( + 'name' => $val['column_name'], + 'type' => $val['data_type'], + 'notnull' => (bool) ($val['is_nullable'] === ''), // not null is empty, null is yes + 'default' => $val['column_default'], + 'primary' => $val['column_name'] == $pk[0]['COLUMN_NAME'], + 'autoinc' => false, + ); + } + } + return $info; + } + + /** + * 取得数据表的字段信息 + * @access public + * @return array + */ + public function getTables($dbName='') { + $result = $this->query("SELECT TABLE_NAME + FROM INFORMATION_SCHEMA.TABLES + WHERE TABLE_TYPE = 'BASE TABLE' + "); + $info = array(); + foreach ($result as $key => $val) { + $info[$key] = current($val); + } + return $info; + } + + /** + * order分析 + * @access protected + * @param mixed $order + * @return string + */ + protected function parseOrder($order) { + return !empty($order)? ' ORDER BY '.$order:' ORDER BY rand()'; + } + + /** + * 字段名分析 + * @access protected + * @param string $key + * @return string + */ + protected function parseKey(&$key) { + $key = trim($key); + if(!preg_match('/[,\'\"\*\(\)\[.\s]/',$key)) { + $key = '['.$key.']'; + } + return $key; + } + + /** + * limit + * @access public + * @param mixed $limit + * @return string + */ + public function parseLimit($limit) { + if(empty($limit)) return ''; + $limit = explode(',',$limit); + if(count($limit)>1) + $limitStr = '(T1.ROW_NUMBER BETWEEN '.$limit[0].' + 1 AND '.$limit[0].' + '.$limit[1].')'; + else + $limitStr = '(T1.ROW_NUMBER BETWEEN 1 AND '.$limit[0].")"; + return 'WHERE '.$limitStr; + } + + /** + * 更新记录 + * @access public + * @param mixed $data 数据 + * @param array $options 表达式 + * @return false | integer + */ + public function update($data,$options) { + $this->model = $options['model']; + $sql = 'UPDATE ' + .$this->parseTable($options['table']) + .$this->parseSet($data) + .$this->parseWhere(!empty($options['where'])?$options['where']:'') + .$this->parseLock(isset($options['lock'])?$options['lock']:false) + .$this->parseComment(!empty($options['comment'])?$options['comment']:''); + return $this->execute($sql,$this->parseBind(!empty($options['bind'])?$options['bind']:array())); + } + + /** + * 删除记录 + * @access public + * @param array $options 表达式 + * @return false | integer + */ + public function delete($options=array()) { + $this->model = $options['model']; + $sql = 'DELETE FROM ' + .$this->parseTable($options['table']) + .$this->parseWhere(!empty($options['where'])?$options['where']:'') + .$this->parseLock(isset($options['lock'])?$options['lock']:false) + .$this->parseComment(!empty($options['comment'])?$options['comment']:''); + return $this->execute($sql,$this->parseBind(!empty($options['bind'])?$options['bind']:array())); + } + + /** + * 关闭数据库 + * @access public + */ + public function close() { + if ($this->_linkID){ + sqlsrv_close($this->_linkID); + } + $this->_linkID = null; + } + + /** + * 数据库错误信息 + * 并显示当前的SQL语句 + * @access public + * @return string + */ + public function error($result = true) { + $errors = sqlsrv_errors(); + $this->error = ''; + foreach( $errors as $error ) { + $this->error .= $error['code'].':'.$error['message']; + } + if('' != $this->queryStr){ + $this->error .= "\n [ SQL语句 ] : ".$this->queryStr; + } + $result? trace($this->error,'','ERR'):throw_exception($this->error); + return $this->error; + } +} \ No newline at end of file diff --git a/ThinkPHP/Library/Think/Dispatcher.class.php b/ThinkPHP/Library/Think/Dispatcher.class.php new file mode 100644 index 000000000..abd163bbc --- /dev/null +++ b/ThinkPHP/Library/Think/Dispatcher.class.php @@ -0,0 +1,323 @@ + +// +---------------------------------------------------------------------- +namespace Think; +/** + * ThinkPHP内置的Dispatcher类 + * 完成URL解析、路由和调度 + */ +class Dispatcher { + + /** + * URL映射到控制器 + * @access public + * @return void + */ + static public function dispatch() { + + $varPath = C('VAR_PATHINFO'); + $varModule = C('VAR_MODULE'); + $varController = C('VAR_CONTROLLER'); + $varAction = C('VAR_ACTION'); + if(isset($_GET[$varPath])) { // 判断URL里面是否有兼容模式参数 + $_SERVER['PATH_INFO'] = $_GET[$varPath]; + unset($_GET[$varPath]); + }elseif(IS_CLI){ // CLI模式下 index.php module/controller/action/params/... + $_SERVER['PATH_INFO'] = isset($_SERVER['argv'][1]) ? $_SERVER['argv'][1] : ''; + } + + // 开启子域名部署 + if(C('APP_SUB_DOMAIN_DEPLOY')) { + $rules = C('APP_SUB_DOMAIN_RULES'); + if(isset($rules[$_SERVER['HTTP_HOST']])) { // 完整域名或者IP配置 + define('APP_DOMAIN',$_SERVER['HTTP_HOST']); // 当前完整域名 + $rule = $rules[APP_DOMAIN]; + }else{ + if(strpos(C('APP_DOMAIN_SUFFIX'),'.')){ // com.cn net.cn + $domain = array_slice(explode('.', $_SERVER['HTTP_HOST']), 0, -3); + }else{ + $domain = array_slice(explode('.', $_SERVER['HTTP_HOST']), 0, -2); + } + if(!empty($domain)) { + $subDomain = implode('.', $domain); + define('SUB_DOMAIN',$subDomain); // 当前完整子域名 + $domain2 = array_pop($domain); // 二级域名 + if($domain) { // 存在三级域名 + $domain3 = array_pop($domain); + } + if(isset($rules[$subDomain])) { // 子域名 + $rule = $rules[$subDomain]; + }elseif(isset($rules['*.' . $domain2]) && !empty($domain3)){ // 泛三级域名 + $rule = $rules['*.' . $domain2]; + $panDomain = $domain3; + }elseif(isset($rules['*']) && !empty($domain2) && 'www' != $domain2 ){ // 泛二级域名 + $rule = $rules['*']; + $panDomain = $domain2; + } + } + } + + if(!empty($rule)) { + // 子域名部署规则 '子域名'=>array('模块名[/控制器名]','var1=a&var2=b'); + if(is_array($rule)){ + list($rule,$vars) = $rule; + } + $array = explode('/',$rule); + // 模块绑定 + $_GET[$varModule] = array_shift($array); + define('BIND_MODULE',$_GET[$varModule]); + $domainModule = true; + // 控制器绑定 + if(!empty($array)) { + $controller = array_shift($array); + if($controller){ + $_GET[$varController] = $controller; + $domainController = true; + } + + } + if(isset($vars)) { // 传入参数 + parse_str($vars,$parms); + if(isset($panDomain)){ + $pos = array_search('*', $parms); + if(false !== $pos) { + // 泛域名作为参数 + $parms[$pos] = $panDomain; + } + } + $_GET = array_merge($_GET,$parms); + } + } + }elseif(isset($_GET[$varModule])){ + // 绑定模块 + define('BIND_MODULE',$_GET[$varModule]); + } + // 分析PATHINFO信息 + if(!isset($_SERVER['PATH_INFO'])) { + $types = explode(',',C('URL_PATHINFO_FETCH')); + foreach ($types as $type){ + if(0===strpos($type,':')) {// 支持函数判断 + $_SERVER['PATH_INFO'] = call_user_func(substr($type,1)); + break; + }elseif(!empty($_SERVER[$type])) { + $_SERVER['PATH_INFO'] = (0 === strpos($_SERVER[$type],$_SERVER['SCRIPT_NAME']))? + substr($_SERVER[$type], strlen($_SERVER['SCRIPT_NAME'])) : $_SERVER[$type]; + break; + } + } + } + if(empty($_SERVER['PATH_INFO'])) { + $_SERVER['PATH_INFO'] = ''; + } + $depr = C('URL_PATHINFO_DEPR'); + define('MODULE_PATHINFO_DEPR', $depr); + define('__INFO__', trim($_SERVER['PATH_INFO'],$depr)); + // URL后缀 + define('__EXT__', strtolower(pathinfo($_SERVER['PATH_INFO'],PATHINFO_EXTENSION))); + + if (__INFO__ && C('MULTI_MODULE') && !isset($_GET[$varModule])){ // 获取模块 + $paths = explode($depr,__INFO__,2); + $allowList = C('MODULE_ALLOW_LIST'); + $module = preg_replace('/\.' . __EXT__ . '$/i', '',$paths[0]); + if( empty($allowList) || (is_array($allowList) && in_array_case($module, $allowList))){ + $_GET[$varModule] = $module; + $_SERVER['PATH_INFO'] = isset($paths[1])?$paths[1]:''; + }else{ + $_SERVER['PATH_INFO'] = __INFO__; + } + }else{ + $_SERVER['PATH_INFO'] = __INFO__; + } + + // URL常量 + define('__SELF__',strip_tags($_SERVER[C('URL_REQUEST_URI')])); + + // 获取模块名称 + define('MODULE_NAME', self::getModule($varModule)); + // 检测模块是否存在 + if( MODULE_NAME && (!in_array_case(MODULE_NAME,C('MODULE_DENY_LIST')) || $domainModule ) && is_dir(APP_PATH.MODULE_NAME)){ + + // 定义当前模块路径 + define('MODULE_PATH', APP_PATH.MODULE_NAME.'/'); + // 定义当前模块的模版缓存路径 + C('CACHE_PATH',CACHE_PATH.MODULE_NAME.'/'); + + // 加载模块配置文件 + if(is_file(MODULE_PATH.'Conf/config.php')) + C(include MODULE_PATH.'Conf/config.php'); + // 加载模块别名定义 + if(is_file(MODULE_PATH.'Conf/alias.php')) + Think::addMap(include MODULE_PATH.'Conf/alias.php'); + // 加载模块tags文件定义 + if(is_file(MODULE_PATH.'Conf/tags.php')) + Hook::import(include MODULE_PATH.'Conf/tags.php'); + // 加载模块函数文件 + if(is_file(MODULE_PATH.'Common/function.php')) + include MODULE_PATH.'Common/function.php'; + // 加载模块的扩展配置文件 + load_ext_file(MODULE_PATH); + }else{ + E(L('_MODULE_NOT_EXIST_').':'.MODULE_NAME); + } + if(!IS_CLI){ + $urlMode = C('URL_MODEL'); + if($urlMode == URL_COMPAT ){// 兼容模式判断 + define('PHP_FILE',_PHP_FILE_.'?'.$varPath.'='); + }elseif($urlMode == URL_REWRITE ) { + $url = dirname(_PHP_FILE_); + if($url == '/' || $url == '\\') + $url = ''; + define('PHP_FILE',$url); + }else { + define('PHP_FILE',_PHP_FILE_); + } + // 当前应用地址 + define('__APP__',strip_tags(PHP_FILE)); + // 模块URL地址 + $moduleName = defined('MODULE_ALIAS')?MODULE_ALIAS:MODULE_NAME; + define('__MODULE__',(!empty($domainModule) || !C('MULTI_MODULE'))?__APP__ : __APP__.'/'.(C('URL_CASE_INSENSITIVE') ? strtolower($moduleName) : $moduleName)); + } + + if('' != $_SERVER['PATH_INFO'] && (!C('URL_ROUTER_ON') || !Route::check()) ){ // 检测路由规则 如果没有则按默认规则调度URL + Hook::listen('path_info'); + // 检查禁止访问的URL后缀 + if(C('URL_DENY_SUFFIX') && preg_match('/\.('.trim(C('URL_DENY_SUFFIX'),'.').')$/i', $_SERVER['PATH_INFO'])){ + send_http_status(404); + exit; + } + + if(C('URL_HTML_SUFFIX')) { + $_SERVER['PATH_INFO'] = preg_replace('/\.('.trim(C('URL_HTML_SUFFIX'),'.').')$/i', '', $_SERVER['PATH_INFO']); + }else{ + $_SERVER['PATH_INFO'] = preg_replace('/\.'.__EXT__.'$/i','',$_SERVER['PATH_INFO']); + } + + $depr = C('URL_PATHINFO_DEPR'); + $paths = explode($depr,trim($_SERVER['PATH_INFO'],$depr)); + + if(!isset($_GET[$varController])) {// 获取控制器 + if(C('CONTROLLER_LEVEL')>1){// 控制器层次 + $_GET[$varController] = implode('/',array_slice($paths,0,C('CONTROLLER_LEVEL'))); + $paths = array_slice($paths, C('CONTROLLER_LEVEL')); + }else{ + $_GET[$varController] = array_shift($paths); + } + } + // 获取操作 + $_GET[$varAction] = array_shift($paths); + // 解析剩余的URL参数 + $var = array(); + if(C('URL_PARAMS_BIND') && 1 == C('URL_PARAMS_BIND_TYPE')){ + // URL参数按顺序绑定变量 + $var = $paths; + }else{ + preg_replace_callback('/(\w+)\/([^\/]+)/', function($match) use(&$var){$var[$match[1]]=strip_tags($match[2]);}, implode('/',$paths)); + } + $_GET = array_merge($var,$_GET); + } + define('CONTROLLER_NAME', self::getController($varController)); + define('ACTION_NAME', self::getAction($varAction)); + if(!IS_CLI){ + // 当前控制器地址 + $controllerName = defined('CONTROLLER_ALIAS')?CONTROLLER_ALIAS:CONTROLLER_NAME; + define('__CONTROLLER__',!empty($domainController)?__MODULE__.$depr : __MODULE__.$depr.( C('URL_CASE_INSENSITIVE') ? strtolower($controllerName) : $controllerName ) ); + + // 当前操作地址 + define('__ACTION__',__CONTROLLER__.$depr.(defined('ACTION_ALIAS')?ACTION_ALIAS:ACTION_NAME)); + } + + //保证$_REQUEST正常取值 + $_REQUEST = array_merge($_POST,$_GET); + } + + /** + * 获得实际的控制器名称 + * @access private + * @return string + */ + static private function getController($var) { + $controller = (!empty($_GET[$var])? $_GET[$var]:C('DEFAULT_CONTROLLER')); + unset($_GET[$var]); + if($maps = C('URL_CONTROLLER_MAP')) { + if(isset($maps[strtolower($controller)])) { + // 记录当前别名 + define('CONTROLLER_ALIAS',strtolower($controller)); + // 获取实际的控制器名 + return $maps[CONTROLLER_ALIAS]; + }elseif(array_search(strtolower($controller),$maps)){ + // 禁止访问原始控制器 + return ''; + } + } + if(C('URL_CASE_INSENSITIVE')) { + // URL地址不区分大小写 + // 智能识别方式 user_type 识别到 UserTypeController 控制器 + $controller = ucfirst(parse_name($controller,1)); + } + return strip_tags($controller); + } + + /** + * 获得实际的操作名称 + * @access private + * @return string + */ + static private function getAction($var) { + $action = !empty($_POST[$var]) ? + $_POST[$var] : + (!empty($_GET[$var])?$_GET[$var]:C('DEFAULT_ACTION')); + unset($_POST[$var],$_GET[$var]); + if($maps = C('URL_ACTION_MAP')) { + if(isset($maps[strtolower(CONTROLLER_NAME)])) { + $maps = $maps[strtolower(CONTROLLER_NAME)]; + if(isset($maps[strtolower($action)])) { + // 记录当前别名 + define('ACTION_ALIAS',strtolower($action)); + // 获取实际的操作名 + if(is_array($maps[ACTION_ALIAS])){ + parse_str($maps[ACTION_ALIAS][1],$vars); + $_GET = array_merge($_GET,$vars); + return $maps[ACTION_ALIAS][0]; + }else{ + return $maps[ACTION_ALIAS]; + } + + }elseif(array_search(strtolower($action),$maps)){ + // 禁止访问原始操作 + return ''; + } + } + } + return strip_tags(C('URL_CASE_INSENSITIVE')?strtolower($action):$action); + } + + /** + * 获得实际的模块名称 + * @access private + * @return string + */ + static private function getModule($var) { + $module = (!empty($_GET[$var])?$_GET[$var]:C('DEFAULT_MODULE')); + unset($_GET[$var]); + if($maps = C('URL_MODULE_MAP')) { + if(isset($maps[strtolower($module)])) { + // 记录当前别名 + define('MODULE_ALIAS',strtolower($module)); + // 获取实际的模块名 + return ucfirst($maps[MODULE_ALIAS]); + }elseif(array_search(strtolower($module),$maps)){ + // 禁止访问原始模块 + return ''; + } + } + return strip_tags(C('URL_CASE_INSENSITIVE') ?ucfirst(strtolower($module)):$module); + } + +} diff --git a/ThinkPHP/Lib/Core/ThinkException.class.php b/ThinkPHP/Library/Think/Exception.class.php similarity index 73% rename from ThinkPHP/Lib/Core/ThinkException.class.php rename to ThinkPHP/Library/Think/Exception.class.php index 64dd38070..925c2e302 100644 --- a/ThinkPHP/Lib/Core/ThinkException.class.php +++ b/ThinkPHP/Library/Think/Exception.class.php @@ -2,19 +2,15 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK IT ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006-2013 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- - +namespace Think; /** * ThinkPHP系统异常基类 - * @category Think - * @package Think - * @subpackage Core - * @author liu21st */ -class ThinkException extends Exception { +class Exception extends \Exception { } \ No newline at end of file diff --git a/ThinkPHP/Library/Think/Hook.class.php b/ThinkPHP/Library/Think/Hook.class.php new file mode 100644 index 000000000..5bd414408 --- /dev/null +++ b/ThinkPHP/Library/Think/Hook.class.php @@ -0,0 +1,125 @@ + +// +---------------------------------------------------------------------- +namespace Think; +/** + * ThinkPHP系统钩子实现 + */ +class Hook { + + static private $tags = array(); + + /** + * 动态添加插件到某个标签 + * @param string $tag 标签名称 + * @param mixed $name 插件名称 + * @return void + */ + static public function add($tag,$name) { + if(!isset(self::$tags[$tag])){ + self::$tags[$tag] = array(); + } + if(is_array($name)){ + self::$tags[$tag] = array_merge(self::$tags[$tag],$name); + }else{ + self::$tags[$tag][] = $name; + } + } + + /** + * 批量导入插件 + * @param array $data 插件信息 + * @param boolean $recursive 是否递归合并 + * @return void + */ + static public function import($data,$recursive=true) { + if(!$recursive){ // 覆盖导入 + self::$tags = array_merge(self::$tags,$data); + }else{ // 合并导入 + foreach ($data as $tag=>$val){ + if(!isset(self::$tags[$tag])) + self::$tags[$tag] = array(); + if(!empty($val['_overlay'])){ + // 可以针对某个标签指定覆盖模式 + unset($val['_overlay']); + self::$tags[$tag] = $val; + }else{ + // 合并模式 + self::$tags[$tag] = array_merge(self::$tags[$tag],$val); + } + } + } + } + + /** + * 获取插件信息 + * @param string $tag 插件位置 留空获取全部 + * @return array + */ + static public function get($tag='') { + if(empty($tag)){ + // 获取全部的插件信息 + return self::$tags; + }else{ + return self::$tags[$tag]; + } + } + + /** + * 监听标签的插件 + * @param string $tag 标签名称 + * @param mixed $params 传入参数 + * @return void + */ + static public function listen($tag, &$params=NULL) { + if(isset(self::$tags[$tag])) { + if(APP_DEBUG) { + G($tag.'Start'); + trace('[ '.$tag.' ] --START--','','INFO'); + } + foreach (self::$tags[$tag] as $name) { + APP_DEBUG && G($name.'_start'); + $result = self::exec($name, $tag,$params); + if(APP_DEBUG){ + G($name.'_end'); + trace('Run '.$name.' [ RunTime:'.G($name.'_start',$name.'_end',6).'s ]','','INFO'); + } + if(false === $result) { + // 如果返回false 则中断插件执行 + return ; + } + } + if(APP_DEBUG) { // 记录行为的执行日志 + trace('[ '.$tag.' ] --END-- [ RunTime:'.G($tag.'Start',$tag.'End',6).'s ]','','INFO'); + } + } + return; + } + + /** + * 执行某个插件 + * @param string $name 插件名称 + * @param string $tag 方法名(标签名) + * @param Mixed $params 传入的参数 + * @return void + */ + static public function exec($name, $tag,&$params=NULL) { + if(false === strpos($name,'\\')) { + // 插件(多个入口) + $class = "Addons\\{$name}\\{$name}Addon"; + }else{ + // 行为扩展(只有一个run入口方法) + $class = $name.'Behavior'; + $tag = 'run'; + } + $addon = new $class(); + return $addon->$tag($params); + } +} diff --git a/ThinkPHP/Library/Think/Image.class.php b/ThinkPHP/Library/Think/Image.class.php new file mode 100644 index 000000000..e0aadfb11 --- /dev/null +++ b/ThinkPHP/Library/Think/Image.class.php @@ -0,0 +1,190 @@ + +// +---------------------------------------------------------------------- +// | ThinkImage.class.php 2013-03-05 +// +---------------------------------------------------------------------- + +namespace Think; + +/** + * 图片处理驱动类,可配置图片处理库 + * 目前支持GD库和imagick + * @author 麦当苗儿 + */ +class Image{ + /* 驱动相关常量定义 */ + const IMAGE_GD = 1; //常量,标识GD库类型 + const IMAGE_IMAGICK = 2; //常量,标识imagick库类型 + + /* 缩略图相关常量定义 */ + const IMAGE_THUMB_SCALING = 1 ; //常量,标识缩略图等比例缩放类型 + const IMAGE_THUMB_FILLED = 2 ; //常量,标识缩略图缩放后填充类型 + const IMAGE_THUMB_CENTER = 3 ; //常量,标识缩略图居中裁剪类型 + const IMAGE_THUMB_NORTHWEST = 4 ; //常量,标识缩略图左上角裁剪类型 + const IMAGE_THUMB_SOUTHEAST = 5 ; //常量,标识缩略图右下角裁剪类型 + const IMAGE_THUMB_FIXED = 6 ; //常量,标识缩略图固定尺寸缩放类型 + + /* 水印相关常量定义 */ + const IMAGE_WATER_NORTHWEST = 1 ; //常量,标识左上角水印 + const IMAGE_WATER_NORTH = 2 ; //常量,标识上居中水印 + const IMAGE_WATER_NORTHEAST = 3 ; //常量,标识右上角水印 + const IMAGE_WATER_WEST = 4 ; //常量,标识左居中水印 + const IMAGE_WATER_CENTER = 5 ; //常量,标识居中水印 + const IMAGE_WATER_EAST = 6 ; //常量,标识右居中水印 + const IMAGE_WATER_SOUTHWEST = 7 ; //常量,标识左下角水印 + const IMAGE_WATER_SOUTH = 8 ; //常量,标识下居中水印 + const IMAGE_WATER_SOUTHEAST = 9 ; //常量,标识右下角水印 + + /** + * 图片资源 + * @var resource + */ + private $img; + + /** + * 构造方法,用于实例化一个图片处理对象 + * @param string $type 要使用的类库,默认使用GD库 + */ + public function __construct($type = self::IMAGE_GD, $imgname = null){ + /* 判断调用库的类型 */ + switch ($type) { + case self::IMAGE_GD: + $class = 'ImageGd'; + break; + case self::IMAGE_IMAGICK: + $class = 'ImageImagick'; + break; + default: + throw new Exception('不支持的图片处理库类型'); + } + + /* 引入处理库,实例化图片处理对象 */ + $class = "Think\\Image\\Driver\\{$class}"; + $this->img = new $class($imgname); + } + + /** + * 打开一幅图像 + * @param string $imgname 图片路径 + * @return Object 当前图片处理库对象 + */ + public function open($imgname){ + $this->img->open($imgname); + return $this; + } + + /** + * 保存图片 + * @param string $imgname 图片保存名称 + * @param string $type 图片类型 + * @param boolean $interlace 是否对JPEG类型图片设置隔行扫描 + * @return Object 当前图片处理库对象 + */ + public function save($imgname, $type = null, $interlace = true){ + $this->img->save($imgname, $type, $interlace); + return $this; + } + + /** + * 返回图片宽度 + * @return integer 图片宽度 + */ + public function width(){ + return $this->img->width(); + } + + /** + * 返回图片高度 + * @return integer 图片高度 + */ + public function height(){ + return $this->img->height(); + } + + /** + * 返回图像类型 + * @return string 图片类型 + */ + public function type(){ + return $this->img->type(); + } + + /** + * 返回图像MIME类型 + * @return string 图像MIME类型 + */ + public function mime(){ + return $this->img->mime(); + } + + /** + * 返回图像尺寸数组 0 - 图片宽度,1 - 图片高度 + * @return array 图片尺寸 + */ + public function size(){ + return $this->img->size(); + } + + /** + * 裁剪图片 + * @param integer $w 裁剪区域宽度 + * @param integer $h 裁剪区域高度 + * @param integer $x 裁剪区域x坐标 + * @param integer $y 裁剪区域y坐标 + * @param integer $width 图片保存宽度 + * @param integer $height 图片保存高度 + * @return Object 当前图片处理库对象 + */ + public function crop($w, $h, $x = 0, $y = 0, $width = null, $height = null){ + $this->img->crop($w, $h, $x, $y, $width, $height); + return $this; + } + + /** + * 生成缩略图 + * @param integer $width 缩略图最大宽度 + * @param integer $height 缩略图最大高度 + * @param integer $type 缩略图裁剪类型 + * @return Object 当前图片处理库对象 + */ + public function thumb($width, $height, $type = self::IMAGE_THUMB_SCALE){ + $this->img->thumb($width, $height, $type); + return $this; + } + + /** + * 添加水印 + * @param string $source 水印图片路径 + * @param integer $locate 水印位置 + * @param integer $alpha 水印透明度 + * @return Object 当前图片处理库对象 + */ + public function water($source, $locate = self::IMAGE_WATER_SOUTHEAST){ + $this->img->water($source, $locate); + return $this; + } + + /** + * 图像添加文字 + * @param string $text 添加的文字 + * @param string $font 字体路径 + * @param integer $size 字号 + * @param string $color 文字颜色 + * @param integer $locate 文字写入位置 + * @param integer $offset 文字相对当前位置的偏移量 + * @param integer $angle 文字倾斜角度 + * @return Object 当前图片处理库对象 + */ + public function text($text, $font, $size, $color = '#00000000', + $locate = self::IMAGE_WATER_SOUTHEAST, $offset = 0, $angle = 0){ + $this->img->text($text, $font, $size, $color, $locate, $offset, $angle); + return $this; + } +} \ No newline at end of file diff --git a/ThinkPHP/Library/Think/Image/Driver/GIF.class.php b/ThinkPHP/Library/Think/Image/Driver/GIF.class.php new file mode 100644 index 000000000..2108e61d3 --- /dev/null +++ b/ThinkPHP/Library/Think/Image/Driver/GIF.class.php @@ -0,0 +1,570 @@ + +// +---------------------------------------------------------------------- +// | GIF.class.php 2013-03-09 +// +---------------------------------------------------------------------- +namespace Think\Image\Driver; +class GIF{ + /** + * GIF帧列表 + * @var array + */ + private $frames = array(); + + /** + * 每帧等待时间列表 + * @var array + */ + private $delays = array(); + + /** + * 构造方法,用于解码GIF图片 + * @param string $src GIF图片数据 + * @param string $mod 图片数据类型 + */ + public function __construct($src = null, $mod = 'url') { + if(!is_null($src)){ + if('url' == $mod && is_file($src)){ + $src = file_get_contents($src); + } + + /* 解码GIF图片 */ + try{ + $de = new GIFDecoder($src); + $this->frames = $de->GIFGetFrames(); + $this->delays = $de->GIFGetDelays(); + } catch(Exception $e){ + throw new Exception("解码GIF图片出错"); + } + } + } + + /** + * 设置或获取当前帧的数据 + * @param string $stream 二进制数据流 + * @return boolean 获取到的数据 + */ + public function image($stream = null){ + if(is_null($stream)){ + $current = current($this->frames); + return false === $current ? reset($this->frames) : $current; + } else { + $this->frames[key($this->frames)] = $stream; + } + } + + /** + * 将当前帧移动到下一帧 + * @return string 当前帧数据 + */ + public function nextImage(){ + return next($this->frames); + } + + /** + * 编码并保存当前GIF图片 + * @param string $gifname 图片名称 + */ + public function save($gifname){ + $gif = new GIFEncoder($this->frames, $this->delays, 0, 2, 0, 0, 0, 'bin'); + file_put_contents($gifname, $gif->GetAnimation()); + } + +} + + +/* +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:: +:: GIFEncoder Version 2.0 by László Zsidi, http://gifs.hu +:: +:: This class is a rewritten 'GifMerge.class.php' version. +:: +:: Modification: +:: - Simplified and easy code, +:: - Ultra fast encoding, +:: - Built-in errors, +:: - Stable working +:: +:: +:: Updated at 2007. 02. 13. '00.05.AM' +:: +:: +:: +:: Try on-line GIFBuilder Form demo based on GIFEncoder. +:: +:: http://gifs.hu/phpclasses/demos/GifBuilder/ +:: +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +*/ + +Class GIFEncoder { + var $GIF = "GIF89a"; /* GIF header 6 bytes */ + var $VER = "GIFEncoder V2.05"; /* Encoder version */ + + var $BUF = Array ( ); + var $LOP = 0; + var $DIS = 2; + var $COL = -1; + var $IMG = -1; + + var $ERR = Array ( + 'ERR00'=>"Does not supported function for only one image!", + 'ERR01'=>"Source is not a GIF image!", + 'ERR02'=>"Unintelligible flag ", + 'ERR03'=>"Does not make animation from animated GIF source", + ); + + /* + ::::::::::::::::::::::::::::::::::::::::::::::::::: + :: + :: GIFEncoder... + :: + */ + function GIFEncoder ( + $GIF_src, $GIF_dly, $GIF_lop, $GIF_dis, + $GIF_red, $GIF_grn, $GIF_blu, $GIF_mod + ) { + if ( ! is_array ( $GIF_src ) && ! is_array ( $GIF_tim ) ) { + printf ( "%s: %s", $this->VER, $this->ERR [ 'ERR00' ] ); + exit ( 0 ); + } + $this->LOP = ( $GIF_lop > -1 ) ? $GIF_lop : 0; + $this->DIS = ( $GIF_dis > -1 ) ? ( ( $GIF_dis < 3 ) ? $GIF_dis : 3 ) : 2; + $this->COL = ( $GIF_red > -1 && $GIF_grn > -1 && $GIF_blu > -1 ) ? + ( $GIF_red | ( $GIF_grn << 8 ) | ( $GIF_blu << 16 ) ) : -1; + + for ( $i = 0; $i < count ( $GIF_src ); $i++ ) { + if ( strToLower ( $GIF_mod ) == "url" ) { + $this->BUF [ ] = fread ( fopen ( $GIF_src [ $i ], "rb" ), filesize ( $GIF_src [ $i ] ) ); + } + else if ( strToLower ( $GIF_mod ) == "bin" ) { + $this->BUF [ ] = $GIF_src [ $i ]; + } + else { + printf ( "%s: %s ( %s )!", $this->VER, $this->ERR [ 'ERR02' ], $GIF_mod ); + exit ( 0 ); + } + if ( substr ( $this->BUF [ $i ], 0, 6 ) != "GIF87a" && substr ( $this->BUF [ $i ], 0, 6 ) != "GIF89a" ) { + printf ( "%s: %d %s", $this->VER, $i, $this->ERR [ 'ERR01' ] ); + exit ( 0 ); + } + for ( $j = ( 13 + 3 * ( 2 << ( ord ( $this->BUF [ $i ] { 10 } ) & 0x07 ) ) ), $k = TRUE; $k; $j++ ) { + switch ( $this->BUF [ $i ] { $j } ) { + case "!": + if ( ( substr ( $this->BUF [ $i ], ( $j + 3 ), 8 ) ) == "NETSCAPE" ) { + printf ( "%s: %s ( %s source )!", $this->VER, $this->ERR [ 'ERR03' ], ( $i + 1 ) ); + exit ( 0 ); + } + break; + case ";": + $k = FALSE; + break; + } + } + } + GIFEncoder::GIFAddHeader ( ); + for ( $i = 0; $i < count ( $this->BUF ); $i++ ) { + GIFEncoder::GIFAddFrames ( $i, $GIF_dly [ $i ] ); + } + GIFEncoder::GIFAddFooter ( ); + } + /* + ::::::::::::::::::::::::::::::::::::::::::::::::::: + :: + :: GIFAddHeader... + :: + */ + function GIFAddHeader ( ) { + $cmap = 0; + + if ( ord ( $this->BUF [ 0 ] { 10 } ) & 0x80 ) { + $cmap = 3 * ( 2 << ( ord ( $this->BUF [ 0 ] { 10 } ) & 0x07 ) ); + + $this->GIF .= substr ( $this->BUF [ 0 ], 6, 7 ); + $this->GIF .= substr ( $this->BUF [ 0 ], 13, $cmap ); + $this->GIF .= "!\377\13NETSCAPE2.0\3\1" . GIFEncoder::GIFWord ( $this->LOP ) . "\0"; + } + } + /* + ::::::::::::::::::::::::::::::::::::::::::::::::::: + :: + :: GIFAddFrames... + :: + */ + function GIFAddFrames ( $i, $d ) { + + $Locals_str = 13 + 3 * ( 2 << ( ord ( $this->BUF [ $i ] { 10 } ) & 0x07 ) ); + + $Locals_end = strlen ( $this->BUF [ $i ] ) - $Locals_str - 1; + $Locals_tmp = substr ( $this->BUF [ $i ], $Locals_str, $Locals_end ); + + $Global_len = 2 << ( ord ( $this->BUF [ 0 ] { 10 } ) & 0x07 ); + $Locals_len = 2 << ( ord ( $this->BUF [ $i ] { 10 } ) & 0x07 ); + + $Global_rgb = substr ( $this->BUF [ 0 ], 13, + 3 * ( 2 << ( ord ( $this->BUF [ 0 ] { 10 } ) & 0x07 ) ) ); + $Locals_rgb = substr ( $this->BUF [ $i ], 13, + 3 * ( 2 << ( ord ( $this->BUF [ $i ] { 10 } ) & 0x07 ) ) ); + + $Locals_ext = "!\xF9\x04" . chr ( ( $this->DIS << 2 ) + 0 ) . + chr ( ( $d >> 0 ) & 0xFF ) . chr ( ( $d >> 8 ) & 0xFF ) . "\x0\x0"; + + if ( $this->COL > -1 && ord ( $this->BUF [ $i ] { 10 } ) & 0x80 ) { + for ( $j = 0; $j < ( 2 << ( ord ( $this->BUF [ $i ] { 10 } ) & 0x07 ) ); $j++ ) { + if ( + ord ( $Locals_rgb { 3 * $j + 0 } ) == ( ( $this->COL >> 16 ) & 0xFF ) && + ord ( $Locals_rgb { 3 * $j + 1 } ) == ( ( $this->COL >> 8 ) & 0xFF ) && + ord ( $Locals_rgb { 3 * $j + 2 } ) == ( ( $this->COL >> 0 ) & 0xFF ) + ) { + $Locals_ext = "!\xF9\x04" . chr ( ( $this->DIS << 2 ) + 1 ) . + chr ( ( $d >> 0 ) & 0xFF ) . chr ( ( $d >> 8 ) & 0xFF ) . chr ( $j ) . "\x0"; + break; + } + } + } + switch ( $Locals_tmp { 0 } ) { + case "!": + $Locals_img = substr ( $Locals_tmp, 8, 10 ); + $Locals_tmp = substr ( $Locals_tmp, 18, strlen ( $Locals_tmp ) - 18 ); + break; + case ",": + $Locals_img = substr ( $Locals_tmp, 0, 10 ); + $Locals_tmp = substr ( $Locals_tmp, 10, strlen ( $Locals_tmp ) - 10 ); + break; + } + if ( ord ( $this->BUF [ $i ] { 10 } ) & 0x80 && $this->IMG > -1 ) { + if ( $Global_len == $Locals_len ) { + if ( GIFEncoder::GIFBlockCompare ( $Global_rgb, $Locals_rgb, $Global_len ) ) { + $this->GIF .= ( $Locals_ext . $Locals_img . $Locals_tmp ); + } + else { + $byte = ord ( $Locals_img { 9 } ); + $byte |= 0x80; + $byte &= 0xF8; + $byte |= ( ord ( $this->BUF [ 0 ] { 10 } ) & 0x07 ); + $Locals_img { 9 } = chr ( $byte ); + $this->GIF .= ( $Locals_ext . $Locals_img . $Locals_rgb . $Locals_tmp ); + } + } + else { + $byte = ord ( $Locals_img { 9 } ); + $byte |= 0x80; + $byte &= 0xF8; + $byte |= ( ord ( $this->BUF [ $i ] { 10 } ) & 0x07 ); + $Locals_img { 9 } = chr ( $byte ); + $this->GIF .= ( $Locals_ext . $Locals_img . $Locals_rgb . $Locals_tmp ); + } + } + else { + $this->GIF .= ( $Locals_ext . $Locals_img . $Locals_tmp ); + } + $this->IMG = 1; + } + /* + ::::::::::::::::::::::::::::::::::::::::::::::::::: + :: + :: GIFAddFooter... + :: + */ + function GIFAddFooter ( ) { + $this->GIF .= ";"; + } + /* + ::::::::::::::::::::::::::::::::::::::::::::::::::: + :: + :: GIFBlockCompare... + :: + */ + function GIFBlockCompare ( $GlobalBlock, $LocalBlock, $Len ) { + + for ( $i = 0; $i < $Len; $i++ ) { + if ( + $GlobalBlock { 3 * $i + 0 } != $LocalBlock { 3 * $i + 0 } || + $GlobalBlock { 3 * $i + 1 } != $LocalBlock { 3 * $i + 1 } || + $GlobalBlock { 3 * $i + 2 } != $LocalBlock { 3 * $i + 2 } + ) { + return ( 0 ); + } + } + + return ( 1 ); + } + /* + ::::::::::::::::::::::::::::::::::::::::::::::::::: + :: + :: GIFWord... + :: + */ + function GIFWord ( $int ) { + + return ( chr ( $int & 0xFF ) . chr ( ( $int >> 8 ) & 0xFF ) ); + } + /* + ::::::::::::::::::::::::::::::::::::::::::::::::::: + :: + :: GetAnimation... + :: + */ + function GetAnimation ( ) { + return ( $this->GIF ); + } +} + + +/* +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:: +:: GIFDecoder Version 2.0 by László Zsidi, http://gifs.hu +:: +:: Created at 2007. 02. 01. '07.47.AM' +:: +:: +:: +:: +:: Try on-line GIFBuilder Form demo based on GIFDecoder. +:: +:: http://gifs.hu/phpclasses/demos/GifBuilder/ +:: +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +*/ + +Class GIFDecoder { + var $GIF_buffer = Array ( ); + var $GIF_arrays = Array ( ); + var $GIF_delays = Array ( ); + var $GIF_stream = ""; + var $GIF_string = ""; + var $GIF_bfseek = 0; + + var $GIF_screen = Array ( ); + var $GIF_global = Array ( ); + var $GIF_sorted; + var $GIF_colorS; + var $GIF_colorC; + var $GIF_colorF; + + /* + ::::::::::::::::::::::::::::::::::::::::::::::::::: + :: + :: GIFDecoder ( $GIF_pointer ) + :: + */ + function GIFDecoder ( $GIF_pointer ) { + $this->GIF_stream = $GIF_pointer; + + GIFDecoder::GIFGetByte ( 6 ); // GIF89a + GIFDecoder::GIFGetByte ( 7 ); // Logical Screen Descriptor + + $this->GIF_screen = $this->GIF_buffer; + $this->GIF_colorF = $this->GIF_buffer [ 4 ] & 0x80 ? 1 : 0; + $this->GIF_sorted = $this->GIF_buffer [ 4 ] & 0x08 ? 1 : 0; + $this->GIF_colorC = $this->GIF_buffer [ 4 ] & 0x07; + $this->GIF_colorS = 2 << $this->GIF_colorC; + + if ( $this->GIF_colorF == 1 ) { + GIFDecoder::GIFGetByte ( 3 * $this->GIF_colorS ); + $this->GIF_global = $this->GIF_buffer; + } + /* + * + * 05.06.2007. + * Made a little modification + * + * + - for ( $cycle = 1; $cycle; ) { + + if ( GIFDecoder::GIFGetByte ( 1 ) ) { + - switch ( $this->GIF_buffer [ 0 ] ) { + - case 0x21: + - GIFDecoder::GIFReadExtensions ( ); + - break; + - case 0x2C: + - GIFDecoder::GIFReadDescriptor ( ); + - break; + - case 0x3B: + - $cycle = 0; + - break; + - } + - } + + else { + + $cycle = 0; + + } + - } + */ + for ( $cycle = 1; $cycle; ) { + if ( GIFDecoder::GIFGetByte ( 1 ) ) { + switch ( $this->GIF_buffer [ 0 ] ) { + case 0x21: + GIFDecoder::GIFReadExtensions ( ); + break; + case 0x2C: + GIFDecoder::GIFReadDescriptor ( ); + break; + case 0x3B: + $cycle = 0; + break; + } + } + else { + $cycle = 0; + } + } + } + /* + ::::::::::::::::::::::::::::::::::::::::::::::::::: + :: + :: GIFReadExtension ( ) + :: + */ + function GIFReadExtensions ( ) { + GIFDecoder::GIFGetByte ( 1 ); + for ( ; ; ) { + GIFDecoder::GIFGetByte ( 1 ); + if ( ( $u = $this->GIF_buffer [ 0 ] ) == 0x00 ) { + break; + } + GIFDecoder::GIFGetByte ( $u ); + /* + * 07.05.2007. + * Implemented a new line for a new function + * to determine the originaly delays between + * frames. + * + */ + if ( $u == 4 ) { + $this->GIF_delays [ ] = ( $this->GIF_buffer [ 1 ] | $this->GIF_buffer [ 2 ] << 8 ); + } + } + } + /* + ::::::::::::::::::::::::::::::::::::::::::::::::::: + :: + :: GIFReadExtension ( ) + :: + */ + function GIFReadDescriptor ( ) { + $GIF_screen = Array ( ); + + GIFDecoder::GIFGetByte ( 9 ); + $GIF_screen = $this->GIF_buffer; + $GIF_colorF = $this->GIF_buffer [ 8 ] & 0x80 ? 1 : 0; + if ( $GIF_colorF ) { + $GIF_code = $this->GIF_buffer [ 8 ] & 0x07; + $GIF_sort = $this->GIF_buffer [ 8 ] & 0x20 ? 1 : 0; + } + else { + $GIF_code = $this->GIF_colorC; + $GIF_sort = $this->GIF_sorted; + } + $GIF_size = 2 << $GIF_code; + $this->GIF_screen [ 4 ] &= 0x70; + $this->GIF_screen [ 4 ] |= 0x80; + $this->GIF_screen [ 4 ] |= $GIF_code; + if ( $GIF_sort ) { + $this->GIF_screen [ 4 ] |= 0x08; + } + $this->GIF_string = "GIF87a"; + GIFDecoder::GIFPutByte ( $this->GIF_screen ); + if ( $GIF_colorF == 1 ) { + GIFDecoder::GIFGetByte ( 3 * $GIF_size ); + GIFDecoder::GIFPutByte ( $this->GIF_buffer ); + } + else { + GIFDecoder::GIFPutByte ( $this->GIF_global ); + } + $this->GIF_string .= chr ( 0x2C ); + $GIF_screen [ 8 ] &= 0x40; + GIFDecoder::GIFPutByte ( $GIF_screen ); + GIFDecoder::GIFGetByte ( 1 ); + GIFDecoder::GIFPutByte ( $this->GIF_buffer ); + for ( ; ; ) { + GIFDecoder::GIFGetByte ( 1 ); + GIFDecoder::GIFPutByte ( $this->GIF_buffer ); + if ( ( $u = $this->GIF_buffer [ 0 ] ) == 0x00 ) { + break; + } + GIFDecoder::GIFGetByte ( $u ); + GIFDecoder::GIFPutByte ( $this->GIF_buffer ); + } + $this->GIF_string .= chr ( 0x3B ); + /* + Add frames into $GIF_stream array... + */ + $this->GIF_arrays [ ] = $this->GIF_string; + } + /* + ::::::::::::::::::::::::::::::::::::::::::::::::::: + :: + :: GIFGetByte ( $len ) + :: + */ + + /* + * + * 05.06.2007. + * Made a little modification + * + * + - function GIFGetByte ( $len ) { + - $this->GIF_buffer = Array ( ); + - + - for ( $i = 0; $i < $len; $i++ ) { + + if ( $this->GIF_bfseek > strlen ( $this->GIF_stream ) ) { + + return 0; + + } + - $this->GIF_buffer [ ] = ord ( $this->GIF_stream { $this->GIF_bfseek++ } ); + - } + + return 1; + - } + */ + function GIFGetByte ( $len ) { + $this->GIF_buffer = Array ( ); + + for ( $i = 0; $i < $len; $i++ ) { + if ( $this->GIF_bfseek > strlen ( $this->GIF_stream ) ) { + return 0; + } + $this->GIF_buffer [ ] = ord ( $this->GIF_stream { $this->GIF_bfseek++ } ); + } + return 1; + } + /* + ::::::::::::::::::::::::::::::::::::::::::::::::::: + :: + :: GIFPutByte ( $bytes ) + :: + */ + function GIFPutByte ( $bytes ) { + for ( $i = 0; $i < count ( $bytes ); $i++ ) { + $this->GIF_string .= chr ( $bytes [ $i ] ); + } + } + /* + ::::::::::::::::::::::::::::::::::::::::::::::::::: + :: + :: PUBLIC FUNCTIONS + :: + :: + :: GIFGetFrames ( ) + :: + */ + function GIFGetFrames ( ) { + return ( $this->GIF_arrays ); + } + /* + ::::::::::::::::::::::::::::::::::::::::::::::::::: + :: + :: GIFGetDelays ( ) + :: + */ + function GIFGetDelays ( ) { + return ( $this->GIF_delays ); + } +} diff --git a/ThinkPHP/Library/Think/Image/Driver/Gd.class.php b/ThinkPHP/Library/Think/Image/Driver/Gd.class.php new file mode 100644 index 000000000..dd32b8c4c --- /dev/null +++ b/ThinkPHP/Library/Think/Image/Driver/Gd.class.php @@ -0,0 +1,544 @@ + +// +---------------------------------------------------------------------- +// | ImageGd.class.php 2013-03-05 +// +---------------------------------------------------------------------- +namespace Think\Image\Driver; +use Think\Image; +class Gd{ + /** + * 图像资源对象 + * @var resource + */ + private $img; + + /** + * 图像信息,包括width,height,type,mime,size + * @var array + */ + private $info; + + /** + * 构造方法,可用于打开一张图像 + * @param string $imgname 图像路径 + */ + public function __construct($imgname = null) { + $imgname && $this->open($imgname); + } + + /** + * 打开一张图像 + * @param string $imgname 图像路径 + */ + public function open($imgname){ + //检测图像文件 + if(!is_file($imgname)) throw new Exception('不存在的图像文件'); + + //获取图像信息 + $info = getimagesize($imgname); + + //检测图像合法性 + if(false === $info || (IMAGETYPE_GIF === $info[2] && empty($info['bits']))){ + throw new Exception('非法图像文件'); + } + + //设置图像信息 + $this->info = array( + 'width' => $info[0], + 'height' => $info[1], + 'type' => image_type_to_extension($info[2], false), + 'mime' => $info['mime'], + ); + + //销毁已存在的图像 + empty($this->img) || imagedestroy($this->img); + + //打开图像 + if('gif' == $this->info['type']){ + $class = 'Think\\Image\\Driver\\GIF'; + $this->gif = new $class($imgname); + $this->img = imagecreatefromstring($this->gif->image()); + } else { + $fun = "imagecreatefrom{$this->info['type']}"; + $this->img = $fun($imgname); + } + } + + /** + * 保存图像 + * @param string $imgname 图像保存名称 + * @param string $type 图像类型 + * @param boolean $interlace 是否对JPEG类型图像设置隔行扫描 + */ + public function save($imgname, $type = null, $interlace = true){ + if(empty($this->img)) throw new Exception('没有可以被保存的图像资源'); + + //自动获取图像类型 + if(is_null($type)){ + $type = $this->info['type']; + } else { + $type = strtolower($type); + } + + //JPEG图像设置隔行扫描 + if('jpeg' == $type || 'jpg' == $type){ + $type = 'jpeg'; + imageinterlace($this->img, $interlace); + } + + //保存图像 + if('gif' == $type && !empty($this->gif)){ + $this->gif->save($imgname); + } else { + $fun = "image{$type}"; + $fun($this->img, $imgname); + } + } + + /** + * 返回图像宽度 + * @return integer 图像宽度 + */ + public function width(){ + if(empty($this->img)) throw new Exception('没有指定图像资源'); + return $this->info['width']; + } + + /** + * 返回图像高度 + * @return integer 图像高度 + */ + public function height(){ + if(empty($this->img)) throw new Exception('没有指定图像资源'); + return $this->info['height']; + } + + /** + * 返回图像类型 + * @return string 图像类型 + */ + public function type(){ + if(empty($this->img)) throw new Exception('没有指定图像资源'); + return $this->info['type']; + } + + /** + * 返回图像MIME类型 + * @return string 图像MIME类型 + */ + public function mime(){ + if(empty($this->img)) throw new Exception('没有指定图像资源'); + return $this->info['mime']; + } + + /** + * 返回图像尺寸数组 0 - 图像宽度,1 - 图像高度 + * @return array 图像尺寸 + */ + public function size(){ + if(empty($this->img)) throw new Exception('没有指定图像资源'); + return array($this->info['width'], $this->info['height']); + } + + /** + * 裁剪图像 + * @param integer $w 裁剪区域宽度 + * @param integer $h 裁剪区域高度 + * @param integer $x 裁剪区域x坐标 + * @param integer $y 裁剪区域y坐标 + * @param integer $width 图像保存宽度 + * @param integer $height 图像保存高度 + */ + public function crop($w, $h, $x = 0, $y = 0, $width = null, $height = null){ + if(empty($this->img)) throw new Exception('没有可以被裁剪的图像资源'); + + //设置保存尺寸 + empty($width) && $width = $w; + empty($height) && $height = $h; + + do { + //创建新图像 + $img = imagecreatetruecolor($width, $height); + // 调整默认颜色 + $color = imagecolorallocate($img, 255, 255, 255); + imagefill($img, 0, 0, $color); + + //裁剪 + imagecopyresampled($img, $this->img, 0, 0, $x, $y, $width, $height, $w, $h); + imagedestroy($this->img); //销毁原图 + + //设置新图像 + $this->img = $img; + } while(!empty($this->gif) && $this->gifNext()); + + $this->info['width'] = $width; + $this->info['height'] = $height; + } + + /** + * 生成缩略图 + * @param integer $width 缩略图最大宽度 + * @param integer $height 缩略图最大高度 + * @param integer $type 缩略图裁剪类型 + */ + public function thumb($width, $height, $type = Image::IMAGE_THUMB_SCALE){ + if(empty($this->img)) throw new Exception('没有可以被缩略的图像资源'); + + //原图宽度和高度 + $w = $this->info['width']; + $h = $this->info['height']; + + /* 计算缩略图生成的必要参数 */ + switch ($type) { + /* 等比例缩放 */ + case Image::IMAGE_THUMB_SCALING: + //原图尺寸小于缩略图尺寸则不进行缩略 + if($w < $width && $h < $height) return; + + //计算缩放比例 + $scale = min($width/$w, $height/$h); + + //设置缩略图的坐标及宽度和高度 + $x = $y = 0; + $width = $w * $scale; + $height = $h * $scale; + break; + + /* 居中裁剪 */ + case Image::IMAGE_THUMB_CENTER: + //计算缩放比例 + $scale = max($width/$w, $height/$h); + + //设置缩略图的坐标及宽度和高度 + $w = $width/$scale; + $h = $height/$scale; + $x = ($this->info['width'] - $w)/2; + $y = ($this->info['height'] - $h)/2; + break; + + /* 左上角裁剪 */ + case Image::IMAGE_THUMB_NORTHWEST: + //计算缩放比例 + $scale = max($width/$w, $height/$h); + + //设置缩略图的坐标及宽度和高度 + $x = $y = 0; + $w = $width/$scale; + $h = $height/$scale; + break; + + /* 右下角裁剪 */ + case Image::IMAGE_THUMB_SOUTHEAST: + //计算缩放比例 + $scale = max($width/$w, $height/$h); + + //设置缩略图的坐标及宽度和高度 + $w = $width/$scale; + $h = $height/$scale; + $x = $this->info['width'] - $w; + $y = $this->info['height'] - $h; + break; + + /* 填充 */ + case Image::IMAGE_THUMB_FILLED: + //计算缩放比例 + if($w < $width && $h < $height){ + $scale = 1; + } else { + $scale = min($width/$w, $height/$h); + } + + //设置缩略图的坐标及宽度和高度 + $neww = $w * $scale; + $newh = $h * $scale; + $posx = ($width - $w * $scale)/2; + $posy = ($height - $h * $scale)/2; + + do{ + //创建新图像 + $img = imagecreatetruecolor($width, $height); + // 调整默认颜色 + $color = imagecolorallocate($img, 255, 255, 255); + imagefill($img, 0, 0, $color); + + //裁剪 + imagecopyresampled($img, $this->img, $posx, $posy, $x, $y, $neww, $newh, $w, $h); + imagedestroy($this->img); //销毁原图 + $this->img = $img; + } while(!empty($this->gif) && $this->gifNext()); + + $this->info['width'] = $width; + $this->info['height'] = $height; + return; + + /* 固定 */ + case Image::IMAGE_THUMB_FIXED: + $x = $y = 0; + break; + + default: + throw new Exception('不支持的缩略图裁剪类型'); + } + + /* 裁剪图像 */ + $this->crop($w, $h, $x, $y, $width, $height); + } + + /** + * 添加水印 + * @param string $source 水印图片路径 + * @param integer $locate 水印位置 + * @param integer $alpha 水印透明度 + */ + public function water($source, $locate = Image::IMAGE_WATER_SOUTHEAST){ + //资源检测 + if(empty($this->img)) throw new Exception('没有可以被添加水印的图像资源'); + if(!is_file($source)) throw new Exception('水印图像不存在'); + + //获取水印图像信息 + $info = getimagesize($source); + if(false === $info || (IMAGETYPE_GIF === $info[2] && empty($info['bits']))){ + throw new Exception('非法水印文件'); + } + + //创建水印图像资源 + $fun = 'imagecreatefrom' . image_type_to_extension($info[2], false); + $water = $fun($source); + + //设定水印图像的混色模式 + imagealphablending($water, true); + + /* 设定水印位置 */ + switch ($locate) { + /* 右下角水印 */ + case Image::IMAGE_WATER_SOUTHEAST: + $x = $this->info['width'] - $info[0]; + $y = $this->info['height'] - $info[1]; + break; + + /* 左下角水印 */ + case Image::IMAGE_WATER_SOUTHWEST: + $x = 0; + $y = $this->info['height'] - $info[1]; + break; + + /* 左上角水印 */ + case Image::IMAGE_WATER_NORTHWEST: + $x = $y = 0; + break; + + /* 右上角水印 */ + case Image::IMAGE_WATER_NORTHEAST: + $x = $this->info['width'] - $info[0]; + $y = 0; + break; + + /* 居中水印 */ + case Image::IMAGE_WATER_CENTER: + $x = ($this->info['width'] - $info[0])/2; + $y = ($this->info['height'] - $info[1])/2; + break; + + /* 下居中水印 */ + case Image::IMAGE_WATER_SOUTH: + $x = ($this->info['width'] - $info[0])/2; + $y = $this->info['height'] - $info[1]; + break; + + /* 右居中水印 */ + case Image::IMAGE_WATER_EAST: + $x = $this->info['width'] - $info[0]; + $y = ($this->info['height'] - $info[1])/2; + break; + + /* 上居中水印 */ + case Image::IMAGE_WATER_NORTH: + $x = ($this->info['width'] - $info[0])/2; + $y = 0; + break; + + /* 左居中水印 */ + case Image::IMAGE_WATER_WEST: + $x = 0; + $y = ($this->info['height'] - $info[1])/2; + break; + + default: + /* 自定义水印坐标 */ + if(is_array($locate)){ + list($x, $y) = $locate; + } else { + throw new Exception('不支持的水印位置类型'); + } + } + + do{ + //添加水印 + $src = imagecreatetruecolor($info[0], $info[1]); + // 调整默认颜色 + $color = imagecolorallocate($src, 255, 255, 255); + imagefill($src, 0, 0, $color); + + imagecopy($src, $this->img, 0, 0, $x, $y, $info[0], $info[1]); + imagecopy($src, $water, 0, 0, 0, 0, $info[0], $info[1]); + imagecopymerge($this->img, $src, $x, $y, 0, 0, $info[0], $info[1], 100); + + //销毁零时图片资源 + imagedestroy($src); + } while(!empty($this->gif) && $this->gifNext()); + + //销毁水印资源 + imagedestroy($water); + } + + /** + * 图像添加文字 + * @param string $text 添加的文字 + * @param string $font 字体路径 + * @param integer $size 字号 + * @param string $color 文字颜色 + * @param integer $locate 文字写入位置 + * @param integer $offset 文字相对当前位置的偏移量 + * @param integer $angle 文字倾斜角度 + */ + public function text($text, $font, $size, $color = '#00000000', + $locate = Image::IMAGE_WATER_SOUTHEAST, $offset = 0, $angle = 0){ + //资源检测 + if(empty($this->img)) throw new Exception('没有可以被写入文字的图像资源'); + if(!is_file($font)) throw new Exception("不存在的字体文件:{$font}"); + + //获取文字信息 + $info = imagettfbbox($size, $angle, $font, $text); + $minx = min($info[0], $info[2], $info[4], $info[6]); + $maxx = max($info[0], $info[2], $info[4], $info[6]); + $miny = min($info[1], $info[3], $info[5], $info[7]); + $maxy = max($info[1], $info[3], $info[5], $info[7]); + + /* 计算文字初始坐标和尺寸 */ + $x = $minx; + $y = abs($miny); + $w = $maxx - $minx; + $h = $maxy - $miny; + + /* 设定文字位置 */ + switch ($locate) { + /* 右下角文字 */ + case Image::IMAGE_WATER_SOUTHEAST: + $x += $this->info['width'] - $w; + $y += $this->info['height'] - $h; + break; + + /* 左下角文字 */ + case Image::IMAGE_WATER_SOUTHWEST: + $y += $this->info['height'] - $h; + break; + + /* 左上角文字 */ + case Image::IMAGE_WATER_NORTHWEST: + // 起始坐标即为左上角坐标,无需调整 + break; + + /* 右上角文字 */ + case Image::IMAGE_WATER_NORTHEAST: + $x += $this->info['width'] - $w; + break; + + /* 居中文字 */ + case Image::IMAGE_WATER_CENTER: + $x += ($this->info['width'] - $w)/2; + $y += ($this->info['height'] - $h)/2; + break; + + /* 下居中文字 */ + case Image::IMAGE_WATER_SOUTH: + $x += ($this->info['width'] - $w)/2; + $y += $this->info['height'] - $h; + break; + + /* 右居中文字 */ + case Image::IMAGE_WATER_EAST: + $x += $this->info['width'] - $w; + $y += ($this->info['height'] - $h)/2; + break; + + /* 上居中文字 */ + case Image::IMAGE_WATER_NORTH: + $x += ($this->info['width'] - $w)/2; + break; + + /* 左居中文字 */ + case Image::IMAGE_WATER_WEST: + $y += ($this->info['height'] - $h)/2; + break; + + default: + /* 自定义文字坐标 */ + if(is_array($locate)){ + list($posx, $posy) = $locate; + $x += $posx; + $y += $posy; + } else { + throw new Exception('不支持的文字位置类型'); + } + } + + /* 设置偏移量 */ + if(is_array($offset)){ + $offset = array_map('intval', $offset); + list($ox, $oy) = $offset; + } else{ + $offset = intval($offset); + $ox = $oy = $offset; + } + + /* 设置颜色 */ + if(is_string($color) && 0 === strpos($color, '#')){ + $color = str_split(substr($color, 1), 2); + $color = array_map('hexdec', $color); + if(empty($color[3]) || $color[3] > 127){ + $color[3] = 0; + } + } elseif (!is_array($color)) { + throw new Exception('错误的颜色值'); + } + + do{ + /* 写入文字 */ + $col = imagecolorallocatealpha($this->img, $color[0], $color[1], $color[2], $color[3]); + imagettftext($this->img, $size, $angle, $x + $ox, $y + $oy, $col, $font, $text); + } while(!empty($this->gif) && $this->gifNext()); + } + + /* 切换到GIF的下一帧并保存当前帧,内部使用 */ + private function gifNext(){ + ob_start(); + ob_implicit_flush(0); + imagegif($this->img); + $img = ob_get_clean(); + + $this->gif->image($img); + $next = $this->gif->nextImage(); + + if($next){ + $this->img = imagecreatefromstring($next); + return $next; + } else { + $this->img = imagecreatefromstring($this->gif->image()); + return false; + } + } + + /** + * 析构方法,用于销毁图像资源 + */ + public function __destruct() { + empty($this->img) || imagedestroy($this->img); + } +} \ No newline at end of file diff --git a/ThinkPHP/Library/Think/Image/Driver/Imagick.class.php b/ThinkPHP/Library/Think/Image/Driver/Imagick.class.php new file mode 100644 index 000000000..50200905e --- /dev/null +++ b/ThinkPHP/Library/Think/Image/Driver/Imagick.class.php @@ -0,0 +1,589 @@ + +// +---------------------------------------------------------------------- +// | ImageImagick.class.php 2013-03-06 +// +---------------------------------------------------------------------- +namespace Think\Image\Driver; +use Think\Image; +class Imagick{ + /** + * 图像资源对象 + * @var resource + */ + private $img; + + /** + * 图像信息,包括width,height,type,mime,size + * @var array + */ + private $info; + + /** + * 构造方法,可用于打开一张图像 + * @param string $imgname 图像路径 + */ + public function __construct($imgname = null) { + $imgname && $this->open($imgname); + } + + /** + * 打开一张图像 + * @param string $imgname 图像路径 + */ + public function open($imgname){ + //检测图像文件 + if(!is_file($imgname)) throw new Exception('不存在的图像文件'); + + //销毁已存在的图像 + empty($this->img) || $this->img->destroy(); + + //载入图像 + $this->img = new \Imagick(realpath($imgname)); + + //设置图像信息 + $this->info = array( + 'width' => $this->img->getImageWidth(), + 'height' => $this->img->getImageHeight(), + 'type' => strtolower($this->img->getImageFormat()), + 'mime' => $this->img->getImageMimeType(), + ); + } + + /** + * 保存图像 + * @param string $imgname 图像保存名称 + * @param string $type 图像类型 + * @param boolean $interlace 是否对JPEG类型图像设置隔行扫描 + */ + public function save($imgname, $type = null, $interlace = true){ + if(empty($this->img)) throw new Exception('没有可以被保存的图像资源'); + + //设置图片类型 + if(is_null($type)){ + $type = $this->info['type']; + } else { + $type = strtolower($type); + $this->img->setImageFormat($type); + } + + //JPEG图像设置隔行扫描 + if('jpeg' == $type || 'jpg' == $type){ + $this->img->setImageInterlaceScheme(1); + } + + //去除图像配置信息 + $this->img->stripImage(); + + //保存图像 + $imgname = realpath(dirname($imgname)) . '/' . basename($imgname); //强制绝对路径 + if ('gif' == $type) { + $this->img->writeImages($imgname, true); + } else { + $this->img->writeImage($imgname); + } + } + + /** + * 返回图像宽度 + * @return integer 图像宽度 + */ + public function width(){ + if(empty($this->img)) throw new Exception('没有指定图像资源'); + return $this->info['width']; + } + + /** + * 返回图像高度 + * @return integer 图像高度 + */ + public function height(){ + if(empty($this->img)) throw new Exception('没有指定图像资源'); + return $this->info['height']; + } + + /** + * 返回图像类型 + * @return string 图像类型 + */ + public function type(){ + if(empty($this->img)) throw new Exception('没有指定图像资源'); + return $this->info['type']; + } + + /** + * 返回图像MIME类型 + * @return string 图像MIME类型 + */ + public function mime(){ + if(empty($this->img)) throw new Exception('没有指定图像资源'); + return $this->info['mime']; + } + + /** + * 返回图像尺寸数组 0 - 图像宽度,1 - 图像高度 + * @return array 图像尺寸 + */ + public function size(){ + if(empty($this->img)) throw new Exception('没有指定图像资源'); + return array($this->info['width'], $this->info['height']); + } + + /** + * 裁剪图像 + * @param integer $w 裁剪区域宽度 + * @param integer $h 裁剪区域高度 + * @param integer $x 裁剪区域x坐标 + * @param integer $y 裁剪区域y坐标 + * @param integer $width 图像保存宽度 + * @param integer $height 图像保存高度 + */ + public function crop($w, $h, $x = 0, $y = 0, $width = null, $height = null){ + if(empty($this->img)) throw new Exception('没有可以被裁剪的图像资源'); + + //设置保存尺寸 + empty($width) && $width = $w; + empty($height) && $height = $h; + + //裁剪图片 + if('gif' == $this->info['type']){ + $img = $this->img->coalesceImages(); + $this->img->destroy(); //销毁原图 + + //循环裁剪每一帧 + do { + $this->_crop($w, $h, $x, $y, $width, $height, $img); + } while ($img->nextImage()); + + //压缩图片 + $this->img = $img->deconstructImages(); + $img->destroy(); //销毁零时图片 + } else { + $this->_crop($w, $h, $x, $y, $width, $height); + } + } + + /* 裁剪图片,内部调用 */ + private function _crop($w, $h, $x, $y, $width, $height, $img = null){ + is_null($img) && $img = $this->img; + + //裁剪 + $info = $this->info; + if($x != 0 || $y != 0 || $w != $info['width'] || $h != $info['height']){ + $img->cropImage($w, $h, $x, $y); + $img->setImagePage($w, $h, 0, 0); //调整画布和图片一致 + } + + //调整大小 + if($w != $width || $h != $height){ + $img->sampleImage($width, $height); + } + + //设置缓存尺寸 + $this->info['width'] = $w; + $this->info['height'] = $h; + } + + /** + * 生成缩略图 + * @param integer $width 缩略图最大宽度 + * @param integer $height 缩略图最大高度 + * @param integer $type 缩略图裁剪类型 + */ + public function thumb($width, $height, $type = Image::IMAGE_THUMB_SCALE){ + if(empty($this->img)) throw new Exception('没有可以被缩略的图像资源'); + + //原图宽度和高度 + $w = $this->info['width']; + $h = $this->info['height']; + + /* 计算缩略图生成的必要参数 */ + switch ($type) { + /* 等比例缩放 */ + case Image::IMAGE_THUMB_SCALING: + //原图尺寸小于缩略图尺寸则不进行缩略 + if($w < $width && $h < $height) return; + + //计算缩放比例 + $scale = min($width/$w, $height/$h); + + //设置缩略图的坐标及宽度和高度 + $x = $y = 0; + $width = $w * $scale; + $height = $h * $scale; + break; + + /* 居中裁剪 */ + case Image::IMAGE_THUMB_CENTER: + //计算缩放比例 + $scale = max($width/$w, $height/$h); + + //设置缩略图的坐标及宽度和高度 + $w = $width/$scale; + $h = $height/$scale; + $x = ($this->info['width'] - $w)/2; + $y = ($this->info['height'] - $h)/2; + break; + + /* 左上角裁剪 */ + case Image::IMAGE_THUMB_NORTHWEST: + //计算缩放比例 + $scale = max($width/$w, $height/$h); + + //设置缩略图的坐标及宽度和高度 + $x = $y = 0; + $w = $width/$scale; + $h = $height/$scale; + break; + + /* 右下角裁剪 */ + case Image::IMAGE_THUMB_SOUTHEAST: + //计算缩放比例 + $scale = max($width/$w, $height/$h); + + //设置缩略图的坐标及宽度和高度 + $w = $width/$scale; + $h = $height/$scale; + $x = $this->info['width'] - $w; + $y = $this->info['height'] - $h; + break; + + /* 填充 */ + case Image::IMAGE_THUMB_FILLED: + //计算缩放比例 + if($w < $width && $h < $height){ + $scale = 1; + } else { + $scale = min($width/$w, $height/$h); + } + + //设置缩略图的坐标及宽度和高度 + $neww = $w * $scale; + $newh = $h * $scale; + $posx = ($width - $w * $scale)/2; + $posy = ($height - $h * $scale)/2; + + //创建一张新图像 + $newimg = new Imagick(); + $newimg->newImage($width, $height, 'white', $this->info['type']); + + + if('gif' == $this->info['type']){ + $imgs = $this->img->coalesceImages(); + $img = new Imagick(); + $this->img->destroy(); //销毁原图 + + //循环填充每一帧 + do { + //填充图像 + $image = $this->_fill($newimg, $posx, $posy, $neww, $newh, $imgs); + + $img->addImage($image); + $img->setImageDelay($imgs->getImageDelay()); + $img->setImagePage($width, $height, 0, 0); + + $image->destroy(); //销毁零时图片 + + } while ($imgs->nextImage()); + + //压缩图片 + $this->img->destroy(); + $this->img = $img->deconstructImages(); + $imgs->destroy(); //销毁零时图片 + $img->destroy(); //销毁零时图片 + + } else { + //填充图像 + $img = $this->_fill($newimg, $posx, $posy, $neww, $newh); + //销毁原图 + $this->img->destroy(); + $this->img = $img; + } + + //设置新图像属性 + $this->info['width'] = $width; + $this->info['height'] = $height; + return; + + /* 固定 */ + case Image::IMAGE_THUMB_FIXED: + $x = $y = 0; + break; + + default: + throw new Exception('不支持的缩略图裁剪类型'); + } + + /* 裁剪图像 */ + $this->crop($w, $h, $x, $y, $width, $height); + } + + /* 填充指定图像,内部使用 */ + private function _fill($newimg, $posx, $posy, $neww, $newh, $img = null){ + is_null($img) && $img = $this->img; + + /* 将指定图片绘入空白图片 */ + $draw = new ImagickDraw(); + $draw->composite($img->getImageCompose(), $posx, $posy, $neww, $newh, $img); + $image = $newimg->clone(); + $image->drawImage($draw); + $draw->destroy(); + + return $image; + } + + /** + * 添加水印 + * @param string $source 水印图片路径 + * @param integer $locate 水印位置 + * @param integer $alpha 水印透明度 + */ + public function water($source, $locate = Image::IMAGE_WATER_SOUTHEAST){ + //资源检测 + if(empty($this->img)) throw new Exception('没有可以被添加水印的图像资源'); + if(!is_file($source)) throw new Exception('水印图像不存在'); + + //创建水印图像资源 + $water = new Imagick(realpath($source)); + $info = array($water->getImageWidth(), $water->getImageHeight()); + + /* 设定水印位置 */ + switch ($locate) { + /* 右下角水印 */ + case Image::IMAGE_WATER_SOUTHEAST: + $x = $this->info['width'] - $info[0]; + $y = $this->info['height'] - $info[1]; + break; + + /* 左下角水印 */ + case Image::IMAGE_WATER_SOUTHWEST: + $x = 0; + $y = $this->info['height'] - $info[1]; + break; + + /* 左上角水印 */ + case Image::IMAGE_WATER_NORTHWEST: + $x = $y = 0; + break; + + /* 右上角水印 */ + case Image::IMAGE_WATER_NORTHEAST: + $x = $this->info['width'] - $info[0]; + $y = 0; + break; + + /* 居中水印 */ + case Image::IMAGE_WATER_CENTER: + $x = ($this->info['width'] - $info[0])/2; + $y = ($this->info['height'] - $info[1])/2; + break; + + /* 下居中水印 */ + case Image::IMAGE_WATER_SOUTH: + $x = ($this->info['width'] - $info[0])/2; + $y = $this->info['height'] - $info[1]; + break; + + /* 右居中水印 */ + case Image::IMAGE_WATER_EAST: + $x = $this->info['width'] - $info[0]; + $y = ($this->info['height'] - $info[1])/2; + break; + + /* 上居中水印 */ + case Image::IMAGE_WATER_NORTH: + $x = ($this->info['width'] - $info[0])/2; + $y = 0; + break; + + /* 左居中水印 */ + case Image::IMAGE_WATER_WEST: + $x = 0; + $y = ($this->info['height'] - $info[1])/2; + break; + + default: + /* 自定义水印坐标 */ + if(is_array($locate)){ + list($x, $y) = $locate; + } else { + throw new Exception('不支持的水印位置类型'); + } + } + + //创建绘图资源 + $draw = new ImagickDraw(); + $draw->composite($water->getImageCompose(), $x, $y, $info[0], $info[1], $water); + + if('gif' == $this->info['type']){ + $img = $this->img->coalesceImages(); + $this->img->destroy(); //销毁原图 + + do{ + //添加水印 + $img->drawImage($draw); + } while ($img->nextImage()); + + //压缩图片 + $this->img = $img->deconstructImages(); + $img->destroy(); //销毁零时图片 + + } else { + //添加水印 + $this->img->drawImage($draw); + } + + //销毁水印资源 + $draw->destroy(); + $water->destroy(); + } + + /** + * 图像添加文字 + * @param string $text 添加的文字 + * @param string $font 字体路径 + * @param integer $size 字号 + * @param string $color 文字颜色 + * @param integer $locate 文字写入位置 + * @param integer $offset 文字相对当前位置的偏移量 + * @param integer $angle 文字倾斜角度 + */ + public function text($text, $font, $size, $color = '#00000000', + $locate = Image::IMAGE_WATER_SOUTHEAST, $offset = 0, $angle = 0){ + //资源检测 + if(empty($this->img)) throw new Exception('没有可以被写入文字的图像资源'); + if(!is_file($font)) throw new Exception("不存在的字体文件:{$font}"); + + //获取颜色和透明度 + if(is_array($color)){ + $color = array_map('dechex', $color); + foreach ($color as &$value) { + $value = str_pad($value, 2, '0', STR_PAD_LEFT); + } + $color = '#' . implode('', $color); + } elseif(!is_string($color) || 0 !== strpos($color, '#')) { + throw new Exception('错误的颜色值'); + } + $col = substr($color, 0, 7); + $alp = strlen($color) == 9 ? substr($color, -2) : 0; + + + //获取文字信息 + $draw = new ImagickDraw(); + $draw->setFont(realpath($font)); + $draw->setFontSize($size); + $draw->setFillColor($col); + $draw->setFillAlpha(1-hexdec($alp)/127); + $draw->setTextAntialias(true); + $draw->setStrokeAntialias(true); + + $metrics = $this->img->queryFontMetrics($draw, $text); + + /* 计算文字初始坐标和尺寸 */ + $x = 0; + $y = $metrics['ascender']; + $w = $metrics['textWidth']; + $h = $metrics['textHeight']; + + /* 设定文字位置 */ + switch ($locate) { + /* 右下角文字 */ + case Image::IMAGE_WATER_SOUTHEAST: + $x += $this->info['width'] - $w; + $y += $this->info['height'] - $h; + break; + + /* 左下角文字 */ + case Image::IMAGE_WATER_SOUTHWEST: + $y += $this->info['height'] - $h; + break; + + /* 左上角文字 */ + case Image::IMAGE_WATER_NORTHWEST: + // 起始坐标即为左上角坐标,无需调整 + break; + + /* 右上角文字 */ + case Image::IMAGE_WATER_NORTHEAST: + $x += $this->info['width'] - $w; + break; + + /* 居中文字 */ + case Image::IMAGE_WATER_CENTER: + $x += ($this->info['width'] - $w)/2; + $y += ($this->info['height'] - $h)/2; + break; + + /* 下居中文字 */ + case Image::IMAGE_WATER_SOUTH: + $x += ($this->info['width'] - $w)/2; + $y += $this->info['height'] - $h; + break; + + /* 右居中文字 */ + case Image::IMAGE_WATER_EAST: + $x += $this->info['width'] - $w; + $y += ($this->info['height'] - $h)/2; + break; + + /* 上居中文字 */ + case Image::IMAGE_WATER_NORTH: + $x += ($this->info['width'] - $w)/2; + break; + + /* 左居中文字 */ + case Image::IMAGE_WATER_WEST: + $y += ($this->info['height'] - $h)/2; + break; + + default: + /* 自定义文字坐标 */ + if(is_array($locate)){ + list($posx, $posy) = $locate; + $x += $posx; + $y += $posy; + } else { + throw new Exception('不支持的文字位置类型'); + } + } + + /* 设置偏移量 */ + if(is_array($offset)){ + $offset = array_map('intval', $offset); + list($ox, $oy) = $offset; + } else{ + $offset = intval($offset); + $ox = $oy = $offset; + } + + /* 写入文字 */ + if('gif' == $this->info['type']){ + $img = $this->img->coalesceImages(); + $this->img->destroy(); //销毁原图 + do{ + $img->annotateImage($draw, $x + $ox, $y + $oy, $angle, $text); + } while ($img->nextImage()); + + //压缩图片 + $this->img = $img->deconstructImages(); + $img->destroy(); //销毁零时图片 + + } else { + $this->img->annotateImage($draw, $x + $ox, $y + $oy, $angle, $text); + } + $draw->destroy(); + } + + /** + * 析构方法,用于销毁图像资源 + */ + public function __destruct() { + empty($this->img) || $this->img->destroy(); + } +} \ No newline at end of file diff --git a/ThinkPHP/Lib/Core/Log.class.php b/ThinkPHP/Library/Think/Log.class.php similarity index 54% rename from ThinkPHP/Lib/Core/Log.class.php rename to ThinkPHP/Library/Think/Log.class.php index bf85d6022..1dd36e2e9 100644 --- a/ThinkPHP/Lib/Core/Log.class.php +++ b/ThinkPHP/Library/Think/Log.class.php @@ -2,19 +2,15 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK IT ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006-2013 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- - +namespace Think; /** * 日志处理类 - * @category Think - * @package Think - * @subpackage Core - * @author liu21st */ class Log { @@ -29,17 +25,23 @@ class Log { const DEBUG = 'DEBUG'; // 调试: 调试信息 const SQL = 'SQL'; // SQL:SQL语句 注意只在调试模式开启时有效 - // 日志记录方式 - const SYSTEM = 0; - const MAIL = 1; - const FILE = 3; - const SAPI = 4; - // 日志信息 - static $log = array(); + static protected $log = array(); - // 日期格式 - static $format = '[ c ]'; + // 日志存储 + static protected $storage = null; + + // 日志初始化 + static public function init($config=array()){ + $type = isset($config['type'])?$config['type']:'File'; + if(strpos($type,'\\')){ + $class = $type; + }else{ + $class = 'Think\\Log\\Driver\\'. ucwords(strtolower($type)); + } + unset($config['type']); + self::$storage = new $class($config); + } /** * 记录日志 并且会过滤未经设置的级别 @@ -62,27 +64,22 @@ static function record($message,$level=self::ERR,$record=false) { * @access public * @param integer $type 日志记录方式 * @param string $destination 写入目标 - * @param string $extra 额外参数 * @return void */ - static function save($type='',$destination='',$extra='') { + static function save($type='',$destination='') { if(empty(self::$log)) return ; - $type = $type?$type:C('LOG_TYPE'); - if(self::FILE == $type) { // 文件方式记录日志信息 - if(empty($destination)) - $destination = C('LOG_PATH').date('y_m_d').'.log'; - //检测日志文件大小,超过配置大小则备份日志文件重新生成 - if(is_file($destination) && floor(C('LOG_FILE_SIZE')) <= filesize($destination) ) - rename($destination,dirname($destination).'/'.time().'-'.basename($destination)); - }else{ - $destination = $destination?$destination:C('LOG_DEST'); - $extra = $extra?$extra:C('LOG_EXTRA'); + + if(empty($destination)) + $destination = C('LOG_PATH').date('y_m_d').'.log'; + if(!self::$storage){ + $type = $type?$type:C('LOG_TYPE'); + $class = 'Think\\Log\\Driver\\'. ucwords($type); + self::$storage = new $class(); } - $now = date(self::$format); - error_log($now.' '.get_client_ip().' '.$_SERVER['REQUEST_URI']."\r\n".implode('',self::$log)."\r\n", $type,$destination ,$extra); + $message = implode('',self::$log); + self::$storage->write($message,$destination); // 保存后清空日志缓存 self::$log = array(); - //clearstatcache(); } /** @@ -93,23 +90,16 @@ static function save($type='',$destination='',$extra='') { * @param string $level 日志级别 * @param integer $type 日志记录方式 * @param string $destination 写入目标 - * @param string $extra 额外参数 * @return void */ - static function write($message,$level=self::ERR,$type='',$destination='',$extra='') { - $now = date(self::$format); - $type = $type?$type:C('LOG_TYPE'); - if(self::FILE == $type) { // 文件方式记录日志 - if(empty($destination)) - $destination = C('LOG_PATH').date('y_m_d').'.log'; - //检测日志文件大小,超过配置大小则备份日志文件重新生成 - if(is_file($destination) && floor(C('LOG_FILE_SIZE')) <= filesize($destination) ) - rename($destination,dirname($destination).'/'.time().'-'.basename($destination)); - }else{ - $destination = $destination?$destination:C('LOG_DEST'); - $extra = $extra?$extra:C('LOG_EXTRA'); + static function write($message,$level=self::ERR,$type='',$destination='') { + if(!self::$storage){ + $type = $type?$type:C('LOG_TYPE'); + $class = 'Think\\Log\\Driver\\'. ucwords($type); + self::$storage = new $class(); } - error_log("{$now} {$level}: {$message}\r\n", $type,$destination,$extra ); - //clearstatcache(); + if(empty($destination)) + $destination = C('LOG_PATH').date('y_m_d').'.log'; + self::$storage->write("{$level}: {$message}", $destination); } } \ No newline at end of file diff --git a/ThinkPHP/Library/Think/Log/Driver/File.class.php b/ThinkPHP/Library/Think/Log/Driver/File.class.php new file mode 100644 index 000000000..677edadb3 --- /dev/null +++ b/ThinkPHP/Library/Think/Log/Driver/File.class.php @@ -0,0 +1,43 @@ + +// +---------------------------------------------------------------------- + +namespace Think\Log\Driver; + +class File { + + protected $config = array( + 'log_time_format' => ' c ', + 'log_file_size' => 2097152, + 'log_path' => '', + ); + + // 实例化并传入参数 + public function __construct($config=array()){ + $this->config = array_merge($this->config,$config); + } + + /** + * 日志写入接口 + * @access public + * @param string $log 日志信息 + * @param string $destination 写入目标 + * @return void + */ + public function write($log,$destination='') { + $now = date($this->config['log_time_format']); + if(empty($destination)) + $destination = $this->config['log_path'].date('y_m_d').'.log'; + //检测日志文件大小,超过配置大小则备份日志文件重新生成 + if(is_file($destination) && floor($this->config['log_file_size']) <= filesize($destination) ) + rename($destination,dirname($destination).'/'.time().'-'.basename($destination)); + error_log("[{$now}] ".$_SERVER['REMOTE_ADDR'].' '.$_SERVER['REQUEST_URI']."\r\n{$log}\r\n", 3,$destination); + } +} diff --git a/ThinkPHP/Library/Think/Log/Driver/Sae.class.php b/ThinkPHP/Library/Think/Log/Driver/Sae.class.php new file mode 100644 index 000000000..64c0ca9c8 --- /dev/null +++ b/ThinkPHP/Library/Think/Log/Driver/Sae.class.php @@ -0,0 +1,47 @@ + +// +---------------------------------------------------------------------- + +namespace Think\Log\Driver; + +class Sae { + + protected $config = array( + 'log_time_format' => ' c ', + ); + + // 实例化并传入参数 + public function __construct($config=array()){ + $this->config = array_merge($this->config,$config); + } + + /** + * 日志写入接口 + * @access public + * @param string $log 日志信息 + * @param string $destination 写入目标 + * @return void + */ + public function write($log,$destination='') { + static $is_debug=null; + $now = date($this->config['log_time_format']); + $logstr="[{$now}] ".$_SERVER['REMOTE_ADDR'].' '.$_SERVER['REQUEST_URI']."\r\n{$log}\r\n"; + if(is_null($is_debug)){ + preg_replace('@(\w+)\=([^;]*)@e', '$appSettings[\'\\1\']="\\2";', $_SERVER['HTTP_APPCOOKIE']); + $is_debug = in_array($_SERVER['HTTP_APPVERSION'], explode(',', $appSettings['debug'])) ? true : false; + } + if($is_debug) + sae_set_display_errors(false);//记录日志不将日志打印出来 + sae_debug($logstr); + if($is_debug) + sae_set_display_errors(true); + + } +} diff --git a/ThinkPHP/Lib/Core/Model.class.php b/ThinkPHP/Library/Think/Model.class.php similarity index 90% rename from ThinkPHP/Lib/Core/Model.class.php rename to ThinkPHP/Library/Think/Model.class.php index d4fe85c2b..012b77293 100644 --- a/ThinkPHP/Lib/Core/Model.class.php +++ b/ThinkPHP/Library/Think/Model.class.php @@ -1,1553 +1,1598 @@ - -// +---------------------------------------------------------------------- - -/** - * ThinkPHP Model模型类 - * 实现了ORM和ActiveRecords模式 - * @category Think - * @package Think - * @subpackage Core - * @author liu21st - */ -class Model { - // 操作状态 - const MODEL_INSERT = 1; // 插入模型数据 - const MODEL_UPDATE = 2; // 更新模型数据 - const MODEL_BOTH = 3; // 包含上面两种方式 - const MUST_VALIDATE = 1;// 必须验证 - const EXISTS_VALIDATE = 0;// 表单存在字段则验证 - const VALUE_VALIDATE = 2;// 表单值不为空则验证 - // 当前使用的扩展模型 - private $_extModel = null; - // 当前数据库操作对象 - protected $db = null; - // 主键名称 - protected $pk = 'id'; - // 数据表前缀 - protected $tablePrefix = ''; - // 模型名称 - protected $name = ''; - // 数据库名称 - protected $dbName = ''; - //数据库配置 - protected $connection = ''; - // 数据表名(不包含表前缀) - protected $tableName = ''; - // 实际数据表名(包含表前缀) - protected $trueTableName = ''; - // 最近错误信息 - protected $error = ''; - // 字段信息 - protected $fields = array(); - // 数据信息 - protected $data = array(); - // 查询表达式参数 - protected $options = array(); - protected $_validate = array(); // 自动验证定义 - protected $_auto = array(); // 自动完成定义 - protected $_map = array(); // 字段映射定义 - protected $_scope = array(); // 命名范围定义 - // 是否自动检测数据表字段信息 - protected $autoCheckFields = true; - // 是否批处理验证 - protected $patchValidate = false; - // 链操作方法列表 - protected $methods = array('table','order','alias','having','group','lock','distinct','auto','filter','validate','result','bind','token'); - - /** - * 架构函数 - * 取得DB类的实例对象 字段检查 - * @access public - * @param string $name 模型名称 - * @param string $tablePrefix 表前缀 - * @param mixed $connection 数据库连接信息 - */ - public function __construct($name='',$tablePrefix='',$connection='') { - // 模型初始化 - $this->_initialize(); - // 获取模型名称 - if(!empty($name)) { - if(strpos($name,'.')) { // 支持 数据库名.模型名的 定义 - list($this->dbName,$this->name) = explode('.',$name); - }else{ - $this->name = $name; - } - }elseif(empty($this->name)){ - $this->name = $this->getModelName(); - } - // 设置表前缀 - if(is_null($tablePrefix)) {// 前缀为Null表示没有前缀 - $this->tablePrefix = ''; - }elseif('' != $tablePrefix) { - $this->tablePrefix = $tablePrefix; - }else{ - $this->tablePrefix = $this->tablePrefix?$this->tablePrefix:C('DB_PREFIX'); - } - - // 数据库初始化操作 - // 获取数据库操作对象 - // 当前模型有独立的数据库连接信息 - $this->db(0,empty($this->connection)?$connection:$this->connection); - } - - /** - * 自动检测数据表信息 - * @access protected - * @return void - */ - protected function _checkTableInfo() { - // 如果不是Model类 自动记录数据表信息 - // 只在第一次执行记录 - if(empty($this->fields)) { - // 如果数据表字段没有定义则自动获取 - if(C('DB_FIELDS_CACHE')) { - $db = $this->dbName?$this->dbName:C('DB_NAME'); - $fields = F('_fields/'.strtolower($db.'.'.$this->name)); - if($fields) { - $version = C('DB_FIELD_VERSION'); - if(empty($version) || $fields['_version']== $version) { - $this->fields = $fields; - return ; - } - } - } - // 每次都会读取数据表信息 - $this->flush(); - } - } - - /** - * 获取字段信息并缓存 - * @access public - * @return void - */ - public function flush() { - // 缓存不存在则查询数据表信息 - $this->db->setModel($this->name); - $fields = $this->db->getFields($this->getTableName()); - if(!$fields) { // 无法获取字段信息 - return false; - } - $this->fields = array_keys($fields); - $this->fields['_autoinc'] = false; - foreach ($fields as $key=>$val){ - // 记录字段类型 - $type[$key] = $val['type']; - if($val['primary']) { - $this->fields['_pk'] = $key; - if($val['autoinc']) $this->fields['_autoinc'] = true; - } - } - // 记录字段类型信息 - $this->fields['_type'] = $type; - if(C('DB_FIELD_VERSION')) $this->fields['_version'] = C('DB_FIELD_VERSION'); - - // 2008-3-7 增加缓存开关控制 - if(C('DB_FIELDS_CACHE')){ - // 永久缓存数据表信息 - $db = $this->dbName?$this->dbName:C('DB_NAME'); - F('_fields/'.strtolower($db.'.'.$this->name),$this->fields); - } - } - - /** - * 动态切换扩展模型 - * @access public - * @param string $type 模型类型名称 - * @param mixed $vars 要传入扩展模型的属性变量 - * @return Model - */ - public function switchModel($type,$vars=array()) { - $class = ucwords(strtolower($type)).'Model'; - if(!class_exists($class)) - throw_exception($class.L('_MODEL_NOT_EXIST_')); - // 实例化扩展模型 - $this->_extModel = new $class($this->name); - if(!empty($vars)) { - // 传入当前模型的属性到扩展模型 - foreach ($vars as $var) - $this->_extModel->setProperty($var,$this->$var); - } - return $this->_extModel; - } - - /** - * 设置数据对象的值 - * @access public - * @param string $name 名称 - * @param mixed $value 值 - * @return void - */ - public function __set($name,$value) { - // 设置数据对象属性 - $this->data[$name] = $value; - } - - /** - * 获取数据对象的值 - * @access public - * @param string $name 名称 - * @return mixed - */ - public function __get($name) { - return isset($this->data[$name])?$this->data[$name]:null; - } - - /** - * 检测数据对象的值 - * @access public - * @param string $name 名称 - * @return boolean - */ - public function __isset($name) { - return isset($this->data[$name]); - } - - /** - * 销毁数据对象的值 - * @access public - * @param string $name 名称 - * @return void - */ - public function __unset($name) { - unset($this->data[$name]); - } - - /** - * 利用__call方法实现一些特殊的Model方法 - * @access public - * @param string $method 方法名称 - * @param array $args 调用参数 - * @return mixed - */ - public function __call($method,$args) { - if(in_array(strtolower($method),$this->methods,true)) { - // 连贯操作的实现 - $this->options[strtolower($method)] = $args[0]; - return $this; - }elseif(in_array(strtolower($method),array('count','sum','min','max','avg'),true)){ - // 统计查询的实现 - $field = isset($args[0])?$args[0]:'*'; - return $this->getField(strtoupper($method).'('.$field.') AS tp_'.$method); - }elseif(strtolower(substr($method,0,5))=='getby') { - // 根据某个字段获取记录 - $field = parse_name(substr($method,5)); - $where[$field] = $args[0]; - return $this->where($where)->find(); - }elseif(strtolower(substr($method,0,10))=='getfieldby') { - // 根据某个字段获取记录的某个值 - $name = parse_name(substr($method,10)); - $where[$name] =$args[0]; - return $this->where($where)->getField($args[1]); - }elseif(isset($this->_scope[$method])){// 命名范围的单独调用支持 - return $this->scope($method,$args[0]); - }else{ - throw_exception(__CLASS__.':'.$method.L('_METHOD_NOT_EXIST_')); - return; - } - } - // 回调方法 初始化模型 - protected function _initialize() {} - - /** - * 对保存到数据库的数据进行处理 - * @access protected - * @param mixed $data 要操作的数据 - * @return boolean - */ - protected function _facade($data) { - // 检查非数据字段 - if(!empty($this->fields)) { - foreach ($data as $key=>$val){ - if(!in_array($key,$this->fields,true)){ - unset($data[$key]); - }elseif(is_scalar($val)) { - // 字段类型检查 - $this->_parseType($data,$key); - } - } - } - // 安全过滤 - if(!empty($this->options['filter'])) { - $data = array_map($this->options['filter'],$data); - unset($this->options['filter']); - } - $this->_before_write($data); - return $data; - } - - // 写入数据前的回调方法 包括新增和更新 - protected function _before_write(&$data) {} - - /** - * 新增数据 - * @access public - * @param mixed $data 数据 - * @param array $options 表达式 - * @param boolean $replace 是否replace - * @return mixed - */ - public function add($data='',$options=array(),$replace=false) { - if(empty($data)) { - // 没有传递数据,获取当前数据对象的值 - if(!empty($this->data)) { - $data = $this->data; - // 重置数据 - $this->data = array(); - }else{ - $this->error = L('_DATA_TYPE_INVALID_'); - return false; - } - } - // 分析表达式 - $options = $this->_parseOptions($options); - // 数据处理 - $data = $this->_facade($data); - if(false === $this->_before_insert($data,$options)) { - return false; - } - // 写入数据到数据库 - $result = $this->db->insert($data,$options,$replace); - if(false !== $result ) { - $insertId = $this->getLastInsID(); - if($insertId) { - // 自增主键返回插入ID - $data[$this->getPk()] = $insertId; - $this->_after_insert($data,$options); - return $insertId; - } - $this->_after_insert($data,$options); - } - return $result; - } - // 插入数据前的回调方法 - protected function _before_insert(&$data,$options) {} - // 插入成功后的回调方法 - protected function _after_insert($data,$options) {} - - public function addAll($dataList,$options=array(),$replace=false){ - if(empty($dataList)) { - $this->error = L('_DATA_TYPE_INVALID_'); - return false; - } - // 分析表达式 - $options = $this->_parseOptions($options); - // 数据处理 - foreach ($dataList as $key=>$data){ - $dataList[$key] = $this->_facade($data); - } - // 写入数据到数据库 - $result = $this->db->insertAll($dataList,$options,$replace); - if(false !== $result ) { - $insertId = $this->getLastInsID(); - if($insertId) { - return $insertId; - } - } - return $result; - } - - /** - * 通过Select方式添加记录 - * @access public - * @param string $fields 要插入的数据表字段名 - * @param string $table 要插入的数据表名 - * @param array $options 表达式 - * @return boolean - */ - public function selectAdd($fields='',$table='',$options=array()) { - // 分析表达式 - $options = $this->_parseOptions($options); - // 写入数据到数据库 - if(false === $result = $this->db->selectInsert($fields?$fields:$options['field'],$table?$table:$this->getTableName(),$options)){ - // 数据库插入操作失败 - $this->error = L('_OPERATION_WRONG_'); - return false; - }else { - // 插入成功 - return $result; - } - } - - /** - * 保存数据 - * @access public - * @param mixed $data 数据 - * @param array $options 表达式 - * @return boolean - */ - public function save($data='',$options=array()) { - if(empty($data)) { - // 没有传递数据,获取当前数据对象的值 - if(!empty($this->data)) { - $data = $this->data; - // 重置数据 - $this->data = array(); - }else{ - $this->error = L('_DATA_TYPE_INVALID_'); - return false; - } - } - // 数据处理 - $data = $this->_facade($data); - // 分析表达式 - $options = $this->_parseOptions($options); - $pk = $this->getPk(); - if(!isset($options['where']) ) { - // 如果存在主键数据 则自动作为更新条件 - if(isset($data[$pk])) { - $where[$pk] = $data[$pk]; - $options['where'] = $where; - unset($data[$pk]); - }else{ - // 如果没有任何更新条件则不执行 - $this->error = L('_OPERATION_WRONG_'); - return false; - } - } - if(is_array($options['where']) && isset($options['where'][$pk])){ - $pkValue = $options['where'][$pk]; - } - if(false === $this->_before_update($data,$options)) { - return false; - } - $result = $this->db->update($data,$options); - if(false !== $result) { - if(isset($pkValue)) $data[$pk] = $pkValue; - $this->_after_update($data,$options); - } - return $result; - } - // 更新数据前的回调方法 - protected function _before_update(&$data,$options) {} - // 更新成功后的回调方法 - protected function _after_update($data,$options) {} - - /** - * 删除数据 - * @access public - * @param mixed $options 表达式 - * @return mixed - */ - public function delete($options=array()) { - if(empty($options) && empty($this->options['where'])) { - // 如果删除条件为空 则删除当前数据对象所对应的记录 - if(!empty($this->data) && isset($this->data[$this->getPk()])) - return $this->delete($this->data[$this->getPk()]); - else - return false; - } - $pk = $this->getPk(); - if(is_numeric($options) || is_string($options)) { - // 根据主键删除记录 - if(strpos($options,',')) { - $where[$pk] = array('IN', $options); - }else{ - $where[$pk] = $options; - } - $options = array(); - $options['where'] = $where; - } - // 分析表达式 - $options = $this->_parseOptions($options); - if(is_array($options['where']) && isset($options['where'][$pk])){ - $pkValue = $options['where'][$pk]; - } - $result = $this->db->delete($options); - if(false !== $result) { - $data = array(); - if(isset($pkValue)) $data[$pk] = $pkValue; - $this->_after_delete($data,$options); - } - // 返回删除记录个数 - return $result; - } - // 删除成功后的回调方法 - protected function _after_delete($data,$options) {} - - /** - * 查询数据集 - * @access public - * @param array $options 表达式参数 - * @return mixed - */ - public function select($options=array()) { - if(is_string($options) || is_numeric($options)) { - // 根据主键查询 - $pk = $this->getPk(); - if(strpos($options,',')) { - $where[$pk] = array('IN',$options); - }else{ - $where[$pk] = $options; - } - $options = array(); - $options['where'] = $where; - }elseif(false === $options){ // 用于子查询 不查询只返回SQL - $options = array(); - // 分析表达式 - $options = $this->_parseOptions($options); - return '( '.$this->db->buildSelectSql($options).' )'; - } - // 分析表达式 - $options = $this->_parseOptions($options); - $resultSet = $this->db->select($options); - if(false === $resultSet) { - return false; - } - if(empty($resultSet)) { // 查询结果为空 - return null; - } - $this->_after_select($resultSet,$options); - return $resultSet; - } - // 查询成功后的回调方法 - protected function _after_select(&$resultSet,$options) {} - - /** - * 生成查询SQL 可用于子查询 - * @access public - * @param array $options 表达式参数 - * @return string - */ - public function buildSql($options=array()) { - // 分析表达式 - $options = $this->_parseOptions($options); - return '( '.$this->db->buildSelectSql($options).' )'; - } - - /** - * 分析表达式 - * @access protected - * @param array $options 表达式参数 - * @return array - */ - protected function _parseOptions($options=array()) { - if(is_array($options)) - $options = array_merge($this->options,$options); - // 查询过后清空sql表达式组装 避免影响下次查询 - $this->options = array(); - if(!isset($options['table'])){ - // 自动获取表名 - $options['table'] = $this->getTableName(); - $fields = $this->fields; - }else{ - // 指定数据表 则重新获取字段列表 但不支持类型检测 - $fields = $this->getDbFields(); - } - - if(!empty($options['alias'])) { - $options['table'] .= ' '.$options['alias']; - } - // 记录操作的模型名称 - $options['model'] = $this->name; - - // 字段类型验证 - if(isset($options['where']) && is_array($options['where']) && !empty($fields) && !isset($options['join'])) { - // 对数组查询条件进行字段类型检查 - foreach ($options['where'] as $key=>$val){ - $key = trim($key); - if(in_array($key,$fields,true)){ - if(is_scalar($val)) { - $this->_parseType($options['where'],$key); - } - }elseif(!is_numeric($key) && '_' != substr($key,0,1) && false === strpos($key,'.') && false === strpos($key,'(') && false === strpos($key,'|') && false === strpos($key,'&')){ - unset($options['where'][$key]); - } - } - } - - // 表达式过滤 - $this->_options_filter($options); - return $options; - } - // 表达式过滤回调方法 - protected function _options_filter(&$options) {} - - /** - * 数据类型检测 - * @access protected - * @param mixed $data 数据 - * @param string $key 字段名 - * @return void - */ - protected function _parseType(&$data,$key) { - if(empty($this->options['bind'][':'.$key])){ - $fieldType = strtolower($this->fields['_type'][$key]); - if(false !== strpos($fieldType,'enum')){ - // 支持ENUM类型优先检测 - }elseif(false === strpos($fieldType,'bigint') && false !== strpos($fieldType,'int')) { - $data[$key] = intval($data[$key]); - }elseif(false !== strpos($fieldType,'float') || false !== strpos($fieldType,'double')){ - $data[$key] = floatval($data[$key]); - }elseif(false !== strpos($fieldType,'bool')){ - $data[$key] = (bool)$data[$key]; - } - } - } - - /** - * 查询数据 - * @access public - * @param mixed $options 表达式参数 - * @return mixed - */ - public function find($options=array()) { - if(is_numeric($options) || is_string($options)) { - $where[$this->getPk()] = $options; - $options = array(); - $options['where'] = $where; - } - // 总是查找一条记录 - $options['limit'] = 1; - // 分析表达式 - $options = $this->_parseOptions($options); - $resultSet = $this->db->select($options); - if(false === $resultSet) { - return false; - } - if(empty($resultSet)) {// 查询结果为空 - return null; - } - $this->data = $resultSet[0]; - $this->_after_find($this->data,$options); - if(!empty($this->options['result'])) { - return $this->returnResult($this->data,$this->options['result']); - } - return $this->data; - } - // 查询成功的回调方法 - protected function _after_find(&$result,$options) {} - - protected function returnResult($data,$type=''){ - if ($type){ - if(is_callable($type)){ - return call_user_func($type,$data); - } - switch (strtolower($type)){ - case 'json': - return json_encode($data); - case 'xml': - return xml_encode($data); - } - } - return $data; - } - - /** - * 处理字段映射 - * @access public - * @param array $data 当前数据 - * @param integer $type 类型 0 写入 1 读取 - * @return array - */ - public function parseFieldsMap($data,$type=1) { - // 检查字段映射 - if(!empty($this->_map)) { - foreach ($this->_map as $key=>$val){ - if($type==1) { // 读取 - if(isset($data[$val])) { - $data[$key] = $data[$val]; - unset($data[$val]); - } - }else{ - if(isset($data[$key])) { - $data[$val] = $data[$key]; - unset($data[$key]); - } - } - } - } - return $data; - } - - /** - * 设置记录的某个字段值 - * 支持使用数据库字段和方法 - * @access public - * @param string|array $field 字段名 - * @param string $value 字段值 - * @return boolean - */ - public function setField($field,$value='') { - if(is_array($field)) { - $data = $field; - }else{ - $data[$field] = $value; - } - return $this->save($data); - } - - /** - * 字段值增长 - * @access public - * @param string $field 字段名 - * @param integer $step 增长值 - * @return boolean - */ - public function setInc($field,$step=1) { - return $this->setField($field,array('exp',$field.'+'.$step)); - } - - /** - * 字段值减少 - * @access public - * @param string $field 字段名 - * @param integer $step 减少值 - * @return boolean - */ - public function setDec($field,$step=1) { - return $this->setField($field,array('exp',$field.'-'.$step)); - } - - /** - * 获取一条记录的某个字段值 - * @access public - * @param string $field 字段名 - * @param string $spea 字段数据间隔符号 NULL返回数组 - * @return mixed - */ - public function getField($field,$sepa=null) { - $options['field'] = $field; - $options = $this->_parseOptions($options); - $field = trim($field); - if(strpos($field,',')) { // 多字段 - if(!isset($options['limit'])){ - $options['limit'] = is_numeric($sepa)?$sepa:''; - } - $resultSet = $this->db->select($options); - if(!empty($resultSet)) { - $_field = explode(',', $field); - $field = array_keys($resultSet[0]); - $key = array_shift($field); - $key2 = array_shift($field); - $cols = array(); - $count = count($_field); - foreach ($resultSet as $result){ - $name = $result[$key]; - if(2==$count) { - $cols[$name] = $result[$key2]; - }else{ - $cols[$name] = is_string($sepa)?implode($sepa,$result):$result; - } - } - return $cols; - } - }else{ // 查找一条记录 - // 返回数据个数 - if(true !== $sepa) {// 当sepa指定为true的时候 返回所有数据 - $options['limit'] = is_numeric($sepa)?$sepa:1; - } - $result = $this->db->select($options); - if(!empty($result)) { - if(true !== $sepa && 1==$options['limit']) return reset($result[0]); - foreach ($result as $val){ - $array[] = $val[$field]; - } - return $array; - } - } - return null; - } - - /** - * 创建数据对象 但不保存到数据库 - * @access public - * @param mixed $data 创建数据 - * @param string $type 状态 - * @return mixed - */ - public function create($data='',$type='') { - // 如果没有传值默认取POST数据 - if(empty($data)) { - $data = $_POST; - }elseif(is_object($data)){ - $data = get_object_vars($data); - } - // 验证数据 - if(empty($data) || !is_array($data)) { - $this->error = L('_DATA_TYPE_INVALID_'); - return false; - } - - // 检查字段映射 - $data = $this->parseFieldsMap($data,0); - - // 状态 - $type = $type?$type:(!empty($data[$this->getPk()])?self::MODEL_UPDATE:self::MODEL_INSERT); - - // 检测提交字段的合法性 - if(isset($this->options['field'])) { // $this->field('field1,field2...')->create() - $fields = $this->options['field']; - unset($this->options['field']); - }elseif($type == self::MODEL_INSERT && isset($this->insertFields)) { - $fields = $this->insertFields; - }elseif($type == self::MODEL_UPDATE && isset($this->updateFields)) { - $fields = $this->updateFields; - } - if(isset($fields)) { - if(is_string($fields)) { - $fields = explode(',',$fields); - } - // 判断令牌验证字段 - if(C('TOKEN_ON')) $fields[] = C('TOKEN_NAME'); - foreach ($data as $key=>$val){ - if(!in_array($key,$fields)) { - unset($data[$key]); - } - } - } - - // 数据自动验证 - if(!$this->autoValidation($data,$type)) return false; - - // 表单令牌验证 - if(!$this->autoCheckToken($data)) { - $this->error = L('_TOKEN_ERROR_'); - return false; - } - - // 验证完成生成数据对象 - if($this->autoCheckFields) { // 开启字段检测 则过滤非法字段数据 - $fields = $this->getDbFields(); - foreach ($data as $key=>$val){ - if(!in_array($key,$fields)) { - unset($data[$key]); - }elseif(MAGIC_QUOTES_GPC && is_string($val)){ - $data[$key] = stripslashes($val); - } - } - } - - // 创建完成对数据进行自动处理 - $this->autoOperation($data,$type); - // 赋值当前数据对象 - $this->data = $data; - // 返回创建的数据以供其他调用 - return $data; - } - - // 自动表单令牌验证 - // 如果是 ajax 提交时携带页面meta 中的token - public function autoCheckToken($data) { - // 支持使用token(false) 关闭令牌验证 - if(isset($this->options['token']) && !$this->options['token']) return true; - if(C('TOKEN_ON')){ - $name = C('TOKEN_NAME'); - if(!isset($data[$name]) || !isset($_SESSION[$name])) { // 令牌数据无效 - return false; - } - - // 令牌验证 - list($key,$value) = explode('_',$data[$name]); - if($value && $_SESSION[$name][$key] === $value) { // 防止重复提交 - unset($_SESSION[$name][$key]); // 验证完成销毁session - return true; - } - // 开启TOKEN重置 - if(C('TOKEN_RESET')) unset($_SESSION[$name][$key]); - return false; - } - return true; - } - - /** - * 使用正则验证数据 - * @access public - * @param string $value 要验证的数据 - * @param string $rule 验证规则 - * @return boolean - */ - public function regex($value,$rule) { - $validate = array( - 'require' => '/.+/', - 'email' => '/^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/', - 'url' => '/^http(s?):\/\/(?:[A-za-z0-9-]+\.)+[A-za-z]{2,4}(?:[\/\?#][\/=\?%\-&~`@[\]\':+!\.#\w]*)?$/', - 'currency' => '/^\d+(\.\d+)?$/', - 'number' => '/^\d+$/', - 'zip' => '/^\d{6}$/', - 'integer' => '/^[-\+]?\d+$/', - 'double' => '/^[-\+]?\d+(\.\d+)?$/', - 'english' => '/^[A-Za-z]+$/', - ); - // 检查是否有内置的正则表达式 - if(isset($validate[strtolower($rule)])) - $rule = $validate[strtolower($rule)]; - return preg_match($rule,$value)===1; - } - - /** - * 自动表单处理 - * @access public - * @param array $data 创建数据 - * @param string $type 创建类型 - * @return mixed - */ - private function autoOperation(&$data,$type) { - if(!empty($this->options['auto'])) { - $_auto = $this->options['auto']; - unset($this->options['auto']); - }elseif(!empty($this->_auto)){ - $_auto = $this->_auto; - } - // 自动填充 - if(isset($_auto)) { - foreach ($_auto as $auto){ - // 填充因子定义格式 - // array('field','填充内容','填充条件','附加规则',[额外参数]) - if(empty($auto[2])) $auto[2] = self::MODEL_INSERT; // 默认为新增的时候自动填充 - if( $type == $auto[2] || $auto[2] == self::MODEL_BOTH) { - switch(trim($auto[3])) { - case 'function': // 使用函数进行填充 字段的值作为参数 - case 'callback': // 使用回调方法 - $args = isset($auto[4])?(array)$auto[4]:array(); - if(isset($data[$auto[0]])) { - array_unshift($args,$data[$auto[0]]); - } - if('function'==$auto[3]) { - $data[$auto[0]] = call_user_func_array($auto[1], $args); - }else{ - $data[$auto[0]] = call_user_func_array(array(&$this,$auto[1]), $args); - } - break; - case 'field': // 用其它字段的值进行填充 - $data[$auto[0]] = $data[$auto[1]]; - break; - case 'ignore': // 为空忽略 - if(''===$data[$auto[0]]) - unset($data[$auto[0]]); - break; - case 'string': - default: // 默认作为字符串填充 - $data[$auto[0]] = $auto[1]; - } - if(false === $data[$auto[0]] ) unset($data[$auto[0]]); - } - } - } - return $data; - } - - /** - * 自动表单验证 - * @access protected - * @param array $data 创建数据 - * @param string $type 创建类型 - * @return boolean - */ - protected function autoValidation($data,$type) { - if(!empty($this->options['validate'])) { - $_validate = $this->options['validate']; - unset($this->options['validate']); - }elseif(!empty($this->_validate)){ - $_validate = $this->_validate; - } - // 属性验证 - if(isset($_validate)) { // 如果设置了数据自动验证则进行数据验证 - if($this->patchValidate) { // 重置验证错误信息 - $this->error = array(); - } - foreach($_validate as $key=>$val) { - // 验证因子定义格式 - // array(field,rule,message,condition,type,when,params) - // 判断是否需要执行验证 - if(empty($val[5]) || $val[5]== self::MODEL_BOTH || $val[5]== $type ) { - if(0==strpos($val[2],'{%') && strpos($val[2],'}')) - // 支持提示信息的多语言 使用 {%语言定义} 方式 - $val[2] = L(substr($val[2],2,-1)); - $val[3] = isset($val[3])?$val[3]:self::EXISTS_VALIDATE; - $val[4] = isset($val[4])?$val[4]:'regex'; - // 判断验证条件 - switch($val[3]) { - case self::MUST_VALIDATE: // 必须验证 不管表单是否有设置该字段 - if(false === $this->_validationField($data,$val)) - return false; - break; - case self::VALUE_VALIDATE: // 值不为空的时候才验证 - if('' != trim($data[$val[0]])) - if(false === $this->_validationField($data,$val)) - return false; - break; - default: // 默认表单存在该字段就验证 - if(isset($data[$val[0]])) - if(false === $this->_validationField($data,$val)) - return false; - } - } - } - // 批量验证的时候最后返回错误 - if(!empty($this->error)) return false; - } - return true; - } - - /** - * 验证表单字段 支持批量验证 - * 如果批量验证返回错误的数组信息 - * @access protected - * @param array $data 创建数据 - * @param array $val 验证因子 - * @return boolean - */ - protected function _validationField($data,$val) { - if(false === $this->_validationFieldItem($data,$val)){ - if($this->patchValidate) { - $this->error[$val[0]] = $val[2]; - }else{ - $this->error = $val[2]; - return false; - } - } - return ; - } - - /** - * 根据验证因子验证字段 - * @access protected - * @param array $data 创建数据 - * @param array $val 验证因子 - * @return boolean - */ - protected function _validationFieldItem($data,$val) { - switch(strtolower(trim($val[4]))) { - case 'function':// 使用函数进行验证 - case 'callback':// 调用方法进行验证 - $args = isset($val[6])?(array)$val[6]:array(); - if(is_string($val[0]) && strpos($val[0], ',')) - $val[0] = explode(',', $val[0]); - if(is_array($val[0])){ - // 支持多个字段验证 - foreach($val[0] as $field) - $_data[$field] = $data[$field]; - array_unshift($args, $_data); - }else{ - array_unshift($args, $data[$val[0]]); - } - if('function'==$val[4]) { - return call_user_func_array($val[1], $args); - }else{ - return call_user_func_array(array(&$this, $val[1]), $args); - } - case 'confirm': // 验证两个字段是否相同 - return $data[$val[0]] == $data[$val[1]]; - case 'unique': // 验证某个值是否唯一 - if(is_string($val[0]) && strpos($val[0],',')) - $val[0] = explode(',',$val[0]); - $map = array(); - if(is_array($val[0])) { - // 支持多个字段验证 - foreach ($val[0] as $field) - $map[$field] = $data[$field]; - }else{ - $map[$val[0]] = $data[$val[0]]; - } - if(!empty($data[$this->getPk()])) { // 完善编辑的时候验证唯一 - $map[$this->getPk()] = array('neq',$data[$this->getPk()]); - } - if($this->where($map)->find()) return false; - return true; - default: // 检查附加规则 - return $this->check($data[$val[0]],$val[1],$val[4]); - } - } - - /** - * 验证数据 支持 in between equal length regex expire ip_allow ip_deny - * @access public - * @param string $value 验证数据 - * @param mixed $rule 验证表达式 - * @param string $type 验证方式 默认为正则验证 - * @return boolean - */ - public function check($value,$rule,$type='regex'){ - $type = strtolower(trim($type)); - switch($type) { - case 'in': // 验证是否在某个指定范围之内 逗号分隔字符串或者数组 - case 'notin': - $range = is_array($rule)? $rule : explode(',',$rule); - return $type == 'in' ? in_array($value ,$range) : !in_array($value ,$range); - case 'between': // 验证是否在某个范围 - case 'notbetween': // 验证是否不在某个范围 - if (is_array($rule)){ - $min = $rule[0]; - $max = $rule[1]; - }else{ - list($min,$max) = explode(',',$rule); - } - return $type == 'between' ? $value>=$min && $value<=$max : $value<$min || $value>$max; - case 'equal': // 验证是否等于某个值 - case 'notequal': // 验证是否等于某个值 - return $type == 'equal' ? $value == $rule : $value != $rule; - case 'length': // 验证长度 - $length = mb_strlen($value,'utf-8'); // 当前数据长度 - if(strpos($rule,',')) { // 长度区间 - list($min,$max) = explode(',',$rule); - return $length >= $min && $length <= $max; - }else{// 指定长度 - return $length == $rule; - } - case 'expire': - list($start,$end) = explode(',',$rule); - if(!is_numeric($start)) $start = strtotime($start); - if(!is_numeric($end)) $end = strtotime($end); - return NOW_TIME >= $start && NOW_TIME <= $end; - case 'ip_allow': // IP 操作许可验证 - return in_array(get_client_ip(),explode(',',$rule)); - case 'ip_deny': // IP 操作禁止验证 - return !in_array(get_client_ip(),explode(',',$rule)); - case 'regex': - default: // 默认使用正则验证 可以使用验证类中定义的验证名称 - // 检查附加规则 - return $this->regex($value,$rule); - } - } - - /** - * SQL查询 - * @access public - * @param string $sql SQL指令 - * @param mixed $parse 是否需要解析SQL - * @return mixed - */ - public function query($sql,$parse=false) { - if(!is_bool($parse) && !is_array($parse)) { - $parse = func_get_args(); - array_shift($parse); - } - $sql = $this->parseSql($sql,$parse); - return $this->db->query($sql); - } - - /** - * 执行SQL语句 - * @access public - * @param string $sql SQL指令 - * @param mixed $parse 是否需要解析SQL - * @return false | integer - */ - public function execute($sql,$parse=false) { - if(!is_bool($parse) && !is_array($parse)) { - $parse = func_get_args(); - array_shift($parse); - } - $sql = $this->parseSql($sql,$parse); - return $this->db->execute($sql); - } - - /** - * 解析SQL语句 - * @access public - * @param string $sql SQL指令 - * @param boolean $parse 是否需要解析SQL - * @return string - */ - protected function parseSql($sql,$parse) { - // 分析表达式 - if(true === $parse) { - $options = $this->_parseOptions(); - $sql = $this->db->parseSql($sql,$options); - }elseif(is_array($parse)){ // SQL预处理 - $parse = array_map(array($this->db,'escapeString'),$parse); - $sql = vsprintf($sql,$parse); - }else{ - $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX'))); - } - $this->db->setModel($this->name); - return $sql; - } - - /** - * 切换当前的数据库连接 - * @access public - * @param integer $linkNum 连接序号 - * @param mixed $config 数据库连接信息 - * @param array $params 模型参数 - * @return Model - */ - public function db($linkNum='',$config='',$params=array()){ - if(''===$linkNum && $this->db) { - return $this->db; - } - static $_linkNum = array(); - static $_db = array(); - if(!isset($_db[$linkNum]) || (isset($_db[$linkNum]) && $config && $_linkNum[$linkNum]!=$config) ) { - // 创建一个新的实例 - if(!empty($config) && is_string($config) && false === strpos($config,'/')) { // 支持读取配置参数 - $config = C($config); - } - $_db[$linkNum] = Db::getInstance($config); - }elseif(NULL === $config){ - $_db[$linkNum]->close(); // 关闭数据库连接 - unset($_db[$linkNum]); - return ; - } - if(!empty($params)) { - if(is_string($params)) parse_str($params,$params); - foreach ($params as $name=>$value){ - $this->setProperty($name,$value); - } - } - // 记录连接信息 - $_linkNum[$linkNum] = $config; - // 切换数据库连接 - $this->db = $_db[$linkNum]; - $this->_after_db(); - // 字段检测 - if(!empty($this->name) && $this->autoCheckFields) $this->_checkTableInfo(); - return $this; - } - // 数据库切换后回调方法 - protected function _after_db() {} - - /** - * 得到当前的数据对象名称 - * @access public - * @return string - */ - public function getModelName() { - if(empty($this->name)) - $this->name = substr(get_class($this),0,-5); - return $this->name; - } - - /** - * 得到完整的数据表名 - * @access public - * @return string - */ - public function getTableName() { - if(empty($this->trueTableName)) { - $tableName = !empty($this->tablePrefix) ? $this->tablePrefix : ''; - if(!empty($this->tableName)) { - $tableName .= $this->tableName; - }else{ - $tableName .= parse_name($this->name); - } - $this->trueTableName = strtolower($tableName); - } - return (!empty($this->dbName)?$this->dbName.'.':'').$this->trueTableName; - } - - /** - * 启动事务 - * @access public - * @return void - */ - public function startTrans() { - $this->commit(); - $this->db->startTrans(); - return ; - } - - /** - * 提交事务 - * @access public - * @return boolean - */ - public function commit() { - return $this->db->commit(); - } - - /** - * 事务回滚 - * @access public - * @return boolean - */ - public function rollback() { - return $this->db->rollback(); - } - - /** - * 返回模型的错误信息 - * @access public - * @return string - */ - public function getError(){ - return $this->error; - } - - /** - * 返回数据库的错误信息 - * @access public - * @return string - */ - public function getDbError() { - return $this->db->getError(); - } - - /** - * 返回最后插入的ID - * @access public - * @return string - */ - public function getLastInsID() { - return $this->db->getLastInsID(); - } - - /** - * 返回最后执行的sql语句 - * @access public - * @return string - */ - public function getLastSql() { - return $this->db->getLastSql($this->name); - } - // 鉴于getLastSql比较常用 增加_sql 别名 - public function _sql(){ - return $this->getLastSql(); - } - - /** - * 获取主键名称 - * @access public - * @return string - */ - public function getPk() { - return isset($this->fields['_pk'])?$this->fields['_pk']:$this->pk; - } - - /** - * 获取数据表字段信息 - * @access public - * @return array - */ - public function getDbFields(){ - if(isset($this->options['table'])) {// 动态指定表名 - $fields = $this->db->getFields($this->options['table']); - return $fields?array_keys($fields):false; - } - if($this->fields) { - $fields = $this->fields; - unset($fields['_autoinc'],$fields['_pk'],$fields['_type'],$fields['_version']); - return $fields; - } - return false; - } - - /** - * 设置数据对象值 - * @access public - * @param mixed $data 数据 - * @return Model - */ - public function data($data=''){ - if('' === $data && !empty($this->data)) { - return $this->data; - } - if(is_object($data)){ - $data = get_object_vars($data); - }elseif(is_string($data)){ - parse_str($data,$data); - }elseif(!is_array($data)){ - throw_exception(L('_DATA_TYPE_INVALID_')); - } - $this->data = $data; - return $this; - } - - /** - * 查询SQL组装 join - * @access public - * @param mixed $join - * @return Model - */ - public function join($join) { - if(is_array($join)) { - $this->options['join'] = $join; - }elseif(!empty($join)) { - $this->options['join'][] = $join; - } - return $this; - } - - /** - * 查询SQL组装 union - * @access public - * @param mixed $union - * @param boolean $all - * @return Model - */ - public function union($union,$all=false) { - if(empty($union)) return $this; - if($all) { - $this->options['union']['_all'] = true; - } - if(is_object($union)) { - $union = get_object_vars($union); - } - // 转换union表达式 - if(is_string($union) ) { - $options = $union; - }elseif(is_array($union)){ - if(isset($union[0])) { - $this->options['union'] = array_merge($this->options['union'],$union); - return $this; - }else{ - $options = $union; - } - }else{ - throw_exception(L('_DATA_TYPE_INVALID_')); - } - $this->options['union'][] = $options; - return $this; - } - - /** - * 查询缓存 - * @access public - * @param mixed $key - * @param integer $expire - * @param string $type - * @return Model - */ - public function cache($key=true,$expire=null,$type=''){ - if(false !== $key) - $this->options['cache'] = array('key'=>$key,'expire'=>$expire,'type'=>$type); - return $this; - } - - /** - * 指定查询字段 支持字段排除 - * @access public - * @param mixed $field - * @param boolean $except 是否排除 - * @return Model - */ - public function field($field,$except=false){ - if(true === $field) {// 获取全部字段 - $fields = $this->getDbFields(); - $field = $fields?$fields:'*'; - }elseif($except) {// 字段排除 - if(is_string($field)) { - $field = explode(',',$field); - } - $fields = $this->getDbFields(); - $field = $fields?array_diff($fields,$field):$field; - } - $this->options['field'] = $field; - return $this; - } - - /** - * 调用命名范围 - * @access public - * @param mixed $scope 命名范围名称 支持多个 和直接定义 - * @param array $args 参数 - * @return Model - */ - public function scope($scope='',$args=NULL){ - if('' === $scope) { - if(isset($this->_scope['default'])) { - // 默认的命名范围 - $options = $this->_scope['default']; - }else{ - return $this; - } - }elseif(is_string($scope)){ // 支持多个命名范围调用 用逗号分割 - $scopes = explode(',',$scope); - $options = array(); - foreach ($scopes as $name){ - if(!isset($this->_scope[$name])) continue; - $options = array_merge($options,$this->_scope[$name]); - } - if(!empty($args) && is_array($args)) { - $options = array_merge($options,$args); - } - }elseif(is_array($scope)){ // 直接传入命名范围定义 - $options = $scope; - } - - if(is_array($options) && !empty($options)){ - $this->options = array_merge($this->options,array_change_key_case($options)); - } - return $this; - } - - /** - * 指定查询条件 支持安全过滤 - * @access public - * @param mixed $where 条件表达式 - * @param mixed $parse 预处理参数 - * @return Model - */ - public function where($where,$parse=null){ - if(!is_null($parse) && is_string($where)) { - if(!is_array($parse)) { - $parse = func_get_args(); - array_shift($parse); - } - $parse = array_map(array($this->db,'escapeString'),$parse); - $where = vsprintf($where,$parse); - }elseif(is_object($where)){ - $where = get_object_vars($where); - } - if(is_string($where) && '' != $where){ - $map = array(); - $map['_string'] = $where; - $where = $map; - } - if(isset($this->options['where'])){ - $this->options['where'] = array_merge($this->options['where'],$where); - }else{ - $this->options['where'] = $where; - } - - return $this; - } - - /** - * 指定查询数量 - * @access public - * @param mixed $offset 起始位置 - * @param mixed $length 查询数量 - * @return Model - */ - public function limit($offset,$length=null){ - $this->options['limit'] = is_null($length)?$offset:$offset.','.$length; - return $this; - } - - /** - * 指定分页 - * @access public - * @param mixed $page 页数 - * @param mixed $listRows 每页数量 - * @return Model - */ - public function page($page,$listRows=null){ - $this->options['page'] = is_null($listRows)?$page:$page.','.$listRows; - return $this; - } - - /** - * 查询注释 - * @access public - * @param string $comment 注释 - * @return Model - */ - public function comment($comment){ - $this->options['comment'] = $comment; - return $this; - } - - /** - * 设置模型的属性值 - * @access public - * @param string $name 名称 - * @param mixed $value 值 - * @return Model - */ - public function setProperty($name,$value) { - if(property_exists($this,$name)) - $this->$name = $value; - return $this; - } - -} + +// +---------------------------------------------------------------------- +namespace Think; +/** + * ThinkPHP Model模型类 + * 实现了ORM和ActiveRecords模式 + */ +class Model { + // 操作状态 + const MODEL_INSERT = 1; // 插入模型数据 + const MODEL_UPDATE = 2; // 更新模型数据 + const MODEL_BOTH = 3; // 包含上面两种方式 + const MUST_VALIDATE = 1; // 必须验证 + const EXISTS_VALIDATE = 0; // 表单存在字段则验证 + const VALUE_VALIDATE = 2; // 表单值不为空则验证 + + // 当前数据库操作对象 + protected $db = null; + // 主键名称 + protected $pk = 'id'; + // 主键是否自动增长 + protected $autoinc = false; + // 数据表前缀 + protected $tablePrefix = null; + // 模型名称 + protected $name = ''; + // 数据库名称 + protected $dbName = ''; + //数据库配置 + protected $connection = ''; + // 数据表名(不包含表前缀) + protected $tableName = ''; + // 实际数据表名(包含表前缀) + protected $trueTableName = ''; + // 最近错误信息 + protected $error = ''; + // 字段信息 + protected $fields = array(); + // 数据信息 + protected $data = array(); + // 查询表达式参数 + protected $options = array(); + protected $_validate = array(); // 自动验证定义 + protected $_auto = array(); // 自动完成定义 + protected $_map = array(); // 字段映射定义 + protected $_scope = array(); // 命名范围定义 + // 是否自动检测数据表字段信息 + protected $autoCheckFields = true; + // 是否批处理验证 + protected $patchValidate = false; + // 链操作方法列表 + protected $methods = array('table','order','alias','having','group','lock','distinct','auto','filter','validate','result','token'); + + /** + * 架构函数 + * 取得DB类的实例对象 字段检查 + * @access public + * @param string $name 模型名称 + * @param string $tablePrefix 表前缀 + * @param mixed $connection 数据库连接信息 + */ + public function __construct($name='',$tablePrefix='',$connection='') { + // 模型初始化 + $this->_initialize(); + // 获取模型名称 + if(!empty($name)) { + if(strpos($name,'.')) { // 支持 数据库名.模型名的 定义 + list($this->dbName,$this->name) = explode('.',$name); + }else{ + $this->name = $name; + } + }elseif(empty($this->name)){ + $this->name = $this->getModelName(); + } + // 设置表前缀 + if(is_null($tablePrefix)) {// 前缀为Null表示没有前缀 + $this->tablePrefix = ''; + }elseif('' != $tablePrefix) { + $this->tablePrefix = $tablePrefix; + }elseif(!isset($this->tablePrefix)){ + $this->tablePrefix = C('DB_PREFIX'); + } + + // 数据库初始化操作 + // 获取数据库操作对象 + // 当前模型有独立的数据库连接信息 + $this->db(0,empty($this->connection)?$connection:$this->connection,true); + } + + /** + * 自动检测数据表信息 + * @access protected + * @return void + */ + protected function _checkTableInfo() { + // 如果不是Model类 自动记录数据表信息 + // 只在第一次执行记录 + if(empty($this->fields)) { + // 如果数据表字段没有定义则自动获取 + if(C('DB_FIELDS_CACHE')) { + $db = $this->dbName?$this->dbName:C('DB_NAME'); + $fields = F('_fields/'.strtolower($db.'.'.$this->name)); + if($fields) { + $this->fields = $fields; + $this->pk = $fields['_pk']; + return ; + } + } + // 每次都会读取数据表信息 + $this->flush(); + } + } + + /** + * 获取字段信息并缓存 + * @access public + * @return void + */ + public function flush() { + // 缓存不存在则查询数据表信息 + $this->db->setModel($this->name); + $fields = $this->db->getFields($this->getTableName()); + if(!$fields) { // 无法获取字段信息 + return false; + } + $this->fields = array_keys($fields); + foreach ($fields as $key=>$val){ + // 记录字段类型 + $type[$key] = $val['type']; + if($val['primary']) { + $this->pk = $key; + $this->fields['_pk'] = $key; + if($val['autoinc']) $this->autoinc = true; + } + } + // 记录字段类型信息 + $this->fields['_type'] = $type; + + // 2008-3-7 增加缓存开关控制 + if(C('DB_FIELDS_CACHE')){ + // 永久缓存数据表信息 + $db = $this->dbName?$this->dbName:C('DB_NAME'); + F('_fields/'.strtolower($db.'.'.$this->name),$this->fields); + } + } + + /** + * 设置数据对象的值 + * @access public + * @param string $name 名称 + * @param mixed $value 值 + * @return void + */ + public function __set($name,$value) { + // 设置数据对象属性 + $this->data[$name] = $value; + } + + /** + * 获取数据对象的值 + * @access public + * @param string $name 名称 + * @return mixed + */ + public function __get($name) { + return isset($this->data[$name])?$this->data[$name]:null; + } + + /** + * 检测数据对象的值 + * @access public + * @param string $name 名称 + * @return boolean + */ + public function __isset($name) { + return isset($this->data[$name]); + } + + /** + * 销毁数据对象的值 + * @access public + * @param string $name 名称 + * @return void + */ + public function __unset($name) { + unset($this->data[$name]); + } + + /** + * 利用__call方法实现一些特殊的Model方法 + * @access public + * @param string $method 方法名称 + * @param array $args 调用参数 + * @return mixed + */ + public function __call($method,$args) { + if(in_array(strtolower($method),$this->methods,true)) { + // 连贯操作的实现 + $this->options[strtolower($method)] = $args[0]; + return $this; + }elseif(in_array(strtolower($method),array('count','sum','min','max','avg'),true)){ + // 统计查询的实现 + $field = isset($args[0])?$args[0]:'*'; + return $this->getField(strtoupper($method).'('.$field.') AS tp_'.$method); + }elseif(strtolower(substr($method,0,5))=='getby') { + // 根据某个字段获取记录 + $field = parse_name(substr($method,5)); + $where[$field] = $args[0]; + return $this->where($where)->find(); + }elseif(strtolower(substr($method,0,10))=='getfieldby') { + // 根据某个字段获取记录的某个值 + $name = parse_name(substr($method,10)); + $where[$name] =$args[0]; + return $this->where($where)->getField($args[1]); + }elseif(isset($this->_scope[$method])){// 命名范围的单独调用支持 + return $this->scope($method,$args[0]); + }else{ + E(__CLASS__.':'.$method.L('_METHOD_NOT_EXIST_')); + return; + } + } + // 回调方法 初始化模型 + protected function _initialize() {} + + /** + * 对保存到数据库的数据进行处理 + * @access protected + * @param mixed $data 要操作的数据 + * @return boolean + */ + protected function _facade($data) { + + // 检查数据字段合法性 + if(!empty($this->fields)) { + if(!empty($this->options['field'])) { + $fields = $this->options['field']; + unset($this->options['field']); + if(is_string($fields)) { + $fields = explode(',',$fields); + } + }else{ + $fields = $this->fields; + } + foreach ($data as $key=>$val){ + if(!in_array($key,$fields,true)){ + unset($data[$key]); + }elseif(is_scalar($val)) { + // 字段类型检查 和 强制转换 + $this->_parseType($data,$key); + } + } + } + + // 安全过滤 + if(!empty($this->options['filter'])) { + $data = array_map($this->options['filter'],$data); + unset($this->options['filter']); + } + $this->_before_write($data); + return $data; + } + + // 写入数据前的回调方法 包括新增和更新 + protected function _before_write(&$data) {} + + /** + * 新增数据 + * @access public + * @param mixed $data 数据 + * @param array $options 表达式 + * @param boolean $replace 是否replace + * @return mixed + */ + public function add($data='',$options=array(),$replace=false) { + if(empty($data)) { + // 没有传递数据,获取当前数据对象的值 + if(!empty($this->data)) { + $data = $this->data; + // 重置数据 + $this->data = array(); + }else{ + $this->error = L('_DATA_TYPE_INVALID_'); + return false; + } + } + // 分析表达式 + $options = $this->_parseOptions($options); + // 数据处理 + $data = $this->_facade($data); + if(false === $this->_before_insert($data,$options)) { + return false; + } + // 写入数据到数据库 + $result = $this->db->insert($data,$options,$replace); + if(false !== $result ) { + $insertId = $this->getLastInsID(); + if($insertId) { + // 自增主键返回插入ID + $data[$this->getPk()] = $insertId; + $this->_after_insert($data,$options); + return $insertId; + } + $this->_after_insert($data,$options); + } + return $result; + } + // 插入数据前的回调方法 + protected function _before_insert(&$data,$options) {} + // 插入成功后的回调方法 + protected function _after_insert($data,$options) {} + + public function addAll($dataList,$options=array(),$replace=false){ + if(empty($dataList)) { + $this->error = L('_DATA_TYPE_INVALID_'); + return false; + } + // 分析表达式 + $options = $this->_parseOptions($options); + // 数据处理 + foreach ($dataList as $key=>$data){ + $dataList[$key] = $this->_facade($data); + } + // 写入数据到数据库 + $result = $this->db->insertAll($dataList,$options,$replace); + if(false !== $result ) { + $insertId = $this->getLastInsID(); + if($insertId) { + return $insertId; + } + } + return $result; + } + + /** + * 通过Select方式添加记录 + * @access public + * @param string $fields 要插入的数据表字段名 + * @param string $table 要插入的数据表名 + * @param array $options 表达式 + * @return boolean + */ + public function selectAdd($fields='',$table='',$options=array()) { + // 分析表达式 + $options = $this->_parseOptions($options); + // 写入数据到数据库 + if(false === $result = $this->db->selectInsert($fields?$fields:$options['field'],$table?$table:$this->getTableName(),$options)){ + // 数据库插入操作失败 + $this->error = L('_OPERATION_WRONG_'); + return false; + }else { + // 插入成功 + return $result; + } + } + + /** + * 保存数据 + * @access public + * @param mixed $data 数据 + * @param array $options 表达式 + * @return boolean + */ + public function save($data='',$options=array()) { + if(empty($data)) { + // 没有传递数据,获取当前数据对象的值 + if(!empty($this->data)) { + $data = $this->data; + // 重置数据 + $this->data = array(); + }else{ + $this->error = L('_DATA_TYPE_INVALID_'); + return false; + } + } + // 数据处理 + $data = $this->_facade($data); + // 分析表达式 + $options = $this->_parseOptions($options); + $pk = $this->getPk(); + if(!isset($options['where']) ) { + // 如果存在主键数据 则自动作为更新条件 + if(isset($data[$pk])) { + $where[$pk] = $data[$pk]; + $options['where'] = $where; + unset($data[$pk]); + }else{ + // 如果没有任何更新条件则不执行 + $this->error = L('_OPERATION_WRONG_'); + return false; + } + } + if(is_array($options['where']) && isset($options['where'][$pk])){ + $pkValue = $options['where'][$pk]; + } + if(false === $this->_before_update($data,$options)) { + return false; + } + $result = $this->db->update($data,$options); + if(false !== $result) { + if(isset($pkValue)) $data[$pk] = $pkValue; + $this->_after_update($data,$options); + } + return $result; + } + // 更新数据前的回调方法 + protected function _before_update(&$data,$options) {} + // 更新成功后的回调方法 + protected function _after_update($data,$options) {} + + /** + * 删除数据 + * @access public + * @param mixed $options 表达式 + * @return mixed + */ + public function delete($options=array()) { + if(empty($options) && empty($this->options['where'])) { + // 如果删除条件为空 则删除当前数据对象所对应的记录 + if(!empty($this->data) && isset($this->data[$this->getPk()])) + return $this->delete($this->data[$this->getPk()]); + else + return false; + } + $pk = $this->getPk(); + if(is_numeric($options) || is_string($options)) { + // 根据主键删除记录 + if(strpos($options,',')) { + $where[$pk] = array('IN', $options); + }else{ + $where[$pk] = $options; + } + $options = array(); + $options['where'] = $where; + } + // 分析表达式 + $options = $this->_parseOptions($options); + if(is_array($options['where']) && isset($options['where'][$pk])){ + $pkValue = $options['where'][$pk]; + } + if(false === $this->_before_delete($options)) { + return false; + } + $result = $this->db->delete($options); + if(false !== $result) { + $data = array(); + if(isset($pkValue)) $data[$pk] = $pkValue; + $this->_after_delete($data,$options); + } + // 返回删除记录个数 + return $result; + } + // 删除数据前的回调方法 + protected function _before_delete($options) {} + // 删除成功后的回调方法 + protected function _after_delete($data,$options) {} + + /** + * 查询数据集 + * @access public + * @param array $options 表达式参数 + * @return mixed + */ + public function select($options=array()) { + if(is_string($options) || is_numeric($options)) { + // 根据主键查询 + $pk = $this->getPk(); + if(strpos($options,',')) { + $where[$pk] = array('IN',$options); + }else{ + $where[$pk] = $options; + } + $options = array(); + $options['where'] = $where; + }elseif(false === $options){ // 用于子查询 不查询只返回SQL + $options = array(); + // 分析表达式 + $options = $this->_parseOptions($options); + return '( '.$this->db->buildSelectSql($options).' )'; + } + // 分析表达式 + $options = $this->_parseOptions($options); + $resultSet = $this->db->select($options); + if(false === $resultSet) { + return false; + } + if(empty($resultSet)) { // 查询结果为空 + return null; + } + $resultSet = array_map(array($this,'_read_data'),$resultSet); + $this->_after_select($resultSet,$options); + return $resultSet; + } + // 查询成功后的回调方法 + protected function _after_select(&$resultSet,$options) {} + + /** + * 生成查询SQL 可用于子查询 + * @access public + * @param array $options 表达式参数 + * @return string + */ + public function buildSql($options=array()) { + // 分析表达式 + $options = $this->_parseOptions($options); + return '( '.$this->db->buildSelectSql($options).' )'; + } + + /** + * 分析表达式 + * @access protected + * @param array $options 表达式参数 + * @return array + */ + protected function _parseOptions($options=array()) { + if(is_array($options)) + $options = array_merge($this->options,$options); + // 查询过后清空sql表达式组装 避免影响下次查询 + $this->options = array(); + if(!isset($options['table'])){ + // 自动获取表名 + $options['table'] = $this->getTableName(); + $fields = $this->fields; + }else{ + // 指定数据表 则重新获取字段列表 但不支持类型检测 + $fields = $this->getDbFields(); + } + + if(!empty($options['alias'])) { + $options['table'] .= ' '.$options['alias']; + } + // 记录操作的模型名称 + $options['model'] = $this->name; + + // 字段类型验证 + if(isset($options['where']) && is_array($options['where']) && !empty($fields) && !isset($options['join'])) { + // 对数组查询条件进行字段类型检查 + foreach ($options['where'] as $key=>$val){ + $key = trim($key); + if(in_array($key,$fields,true)){ + if(is_scalar($val)) { + $this->_parseType($options['where'],$key); + } + }elseif(!is_numeric($key) && '_' != substr($key,0,1) && false === strpos($key,'.') && false === strpos($key,'(') && false === strpos($key,'|') && false === strpos($key,'&')){ + unset($options['where'][$key]); + } + } + } + + // 表达式过滤 + $this->_options_filter($options); + return $options; + } + // 表达式过滤回调方法 + protected function _options_filter(&$options) {} + + /** + * 数据类型检测 + * @access protected + * @param mixed $data 数据 + * @param string $key 字段名 + * @return void + */ + protected function _parseType(&$data,$key) { + if(empty($this->options['bind'][':'.$key]) && isset($this->fields['_type'][$key])){ + $fieldType = strtolower($this->fields['_type'][$key]); + if(false !== strpos($fieldType,'enum')){ + // 支持ENUM类型优先检测 + }elseif(false === strpos($fieldType,'bigint') && false !== strpos($fieldType,'int')) { + $data[$key] = intval($data[$key]); + }elseif(false !== strpos($fieldType,'float') || false !== strpos($fieldType,'double')){ + $data[$key] = floatval($data[$key]); + }elseif(false !== strpos($fieldType,'bool')){ + $data[$key] = (bool)$data[$key]; + } + } + } + + /** + * 数据读取后的处理 + * @access protected + * @param array $data 当前数据 + * @return array + */ + protected function _read_data($data) { + // 检查字段映射 + if(!empty($this->_map) && C('READ_DATA_MAP')) { + foreach ($this->_map as $key=>$val){ + if(isset($data[$val])) { + $data[$key] = $data[$val]; + unset($data[$val]); + } + } + } + return $data; + } + + /** + * 查询数据 + * @access public + * @param mixed $options 表达式参数 + * @return mixed + */ + public function find($options=array()) { + if(is_numeric($options) || is_string($options)) { + $where[$this->getPk()] = $options; + $options = array(); + $options['where'] = $where; + } + // 总是查找一条记录 + $options['limit'] = 1; + // 分析表达式 + $options = $this->_parseOptions($options); + $resultSet = $this->db->select($options); + if(false === $resultSet) { + return false; + } + if(empty($resultSet)) {// 查询结果为空 + return null; + } + // 读取数据后的处理 + $data = $this->_read_data($resultSet[0]); + $this->_after_find($data,$options); + if(!empty($this->options['result'])) { + return $this->returnResult($data,$this->options['result']); + } + $this->data = $data; + return $this->data; + } + // 查询成功的回调方法 + protected function _after_find(&$result,$options) {} + + protected function returnResult($data,$type=''){ + if ($type){ + if(is_callable($type)){ + return call_user_func($type,$data); + } + switch (strtolower($type)){ + case 'json': + return json_encode($data); + case 'xml': + return xml_encode($data); + } + } + return $data; + } + + /** + * 处理字段映射 + * @access public + * @param array $data 当前数据 + * @param integer $type 类型 0 写入 1 读取 + * @return array + */ + public function parseFieldsMap($data,$type=1) { + // 检查字段映射 + if(!empty($this->_map)) { + foreach ($this->_map as $key=>$val){ + if($type==1) { // 读取 + if(isset($data[$val])) { + $data[$key] = $data[$val]; + unset($data[$val]); + } + }else{ + if(isset($data[$key])) { + $data[$val] = $data[$key]; + unset($data[$key]); + } + } + } + } + return $data; + } + + /** + * 设置记录的某个字段值 + * 支持使用数据库字段和方法 + * @access public + * @param string|array $field 字段名 + * @param string $value 字段值 + * @return boolean + */ + public function setField($field,$value='') { + if(is_array($field)) { + $data = $field; + }else{ + $data[$field] = $value; + } + return $this->save($data); + } + + /** + * 字段值增长 + * @access public + * @param string $field 字段名 + * @param integer $step 增长值 + * @return boolean + */ + public function setInc($field,$step=1) { + return $this->setField($field,array('exp',$field.'+'.$step)); + } + + /** + * 字段值减少 + * @access public + * @param string $field 字段名 + * @param integer $step 减少值 + * @return boolean + */ + public function setDec($field,$step=1) { + return $this->setField($field,array('exp',$field.'-'.$step)); + } + + /** + * 获取一条记录的某个字段值 + * @access public + * @param string $field 字段名 + * @param string $spea 字段数据间隔符号 NULL返回数组 + * @return mixed + */ + public function getField($field,$sepa=null) { + $options['field'] = $field; + $options = $this->_parseOptions($options); + $field = trim($field); + if(strpos($field,',')) { // 多字段 + if(!isset($options['limit'])){ + $options['limit'] = is_numeric($sepa)?$sepa:''; + } + $resultSet = $this->db->select($options); + if(!empty($resultSet)) { + $_field = explode(',', $field); + $field = array_keys($resultSet[0]); + $key = array_shift($field); + $key2 = array_shift($field); + $cols = array(); + $count = count($_field); + foreach ($resultSet as $result){ + $name = $result[$key]; + if(2==$count) { + $cols[$name] = $result[$key2]; + }else{ + $cols[$name] = is_string($sepa)?implode($sepa,$result):$result; + } + } + return $cols; + } + }else{ // 查找一条记录 + // 返回数据个数 + if(true !== $sepa) {// 当sepa指定为true的时候 返回所有数据 + $options['limit'] = is_numeric($sepa)?$sepa:1; + } + $result = $this->db->select($options); + if(!empty($result)) { + if(true !== $sepa && 1==$options['limit']) return reset($result[0]); + foreach ($result as $val){ + $array[] = $val[$field]; + } + return $array; + } + } + return null; + } + + /** + * 创建数据对象 但不保存到数据库 + * @access public + * @param mixed $data 创建数据 + * @param string $type 状态 + * @return mixed + */ + public function create($data='',$type='') { + // 如果没有传值默认取POST数据 + if(empty($data)) { + $data = I('post.'); + }elseif(is_object($data)){ + $data = get_object_vars($data); + } + // 验证数据 + if(empty($data) || !is_array($data)) { + $this->error = L('_DATA_TYPE_INVALID_'); + return false; + } + + // 状态 + $type = $type?$type:(!empty($data[$this->getPk()])?self::MODEL_UPDATE:self::MODEL_INSERT); + + // 检查字段映射 + if(!empty($this->_map)) { + foreach ($this->_map as $key=>$val){ + if(isset($data[$key])) { + $data[$val] = $data[$key]; + unset($data[$key]); + } + } + } + + // 检测提交字段的合法性 + if(isset($this->options['field'])) { // $this->field('field1,field2...')->create() + $fields = $this->options['field']; + unset($this->options['field']); + }elseif($type == self::MODEL_INSERT && isset($this->insertFields)) { + $fields = $this->insertFields; + }elseif($type == self::MODEL_UPDATE && isset($this->updateFields)) { + $fields = $this->updateFields; + } + if(isset($fields)) { + if(is_string($fields)) { + $fields = explode(',',$fields); + } + // 判断令牌验证字段 + if(C('TOKEN_ON')) $fields[] = C('TOKEN_NAME'); + foreach ($data as $key=>$val){ + if(!in_array($key,$fields)) { + unset($data[$key]); + } + } + } + + // 数据自动验证 + if(!$this->autoValidation($data,$type)) return false; + + // 表单令牌验证 + if(!$this->autoCheckToken($data)) { + $this->error = L('_TOKEN_ERROR_'); + return false; + } + + // 验证完成生成数据对象 + if($this->autoCheckFields) { // 开启字段检测 则过滤非法字段数据 + $fields = $this->getDbFields(); + foreach ($data as $key=>$val){ + if(!in_array($key,$fields)) { + unset($data[$key]); + }elseif(MAGIC_QUOTES_GPC && is_string($val)){ + $data[$key] = stripslashes($val); + } + } + } + + // 创建完成对数据进行自动处理 + $this->autoOperation($data,$type); + // 赋值当前数据对象 + $this->data = $data; + // 返回创建的数据以供其他调用 + return $data; + } + + // 自动表单令牌验证 + // TODO ajax无刷新多次提交暂不能满足 + public function autoCheckToken($data) { + // 支持使用token(false) 关闭令牌验证 + if(isset($this->options['token']) && !$this->options['token']) return true; + if(C('TOKEN_ON')){ + $name = C('TOKEN_NAME'); + if(!isset($data[$name]) || !isset($_SESSION[$name])) { // 令牌数据无效 + return false; + } + + // 令牌验证 + list($key,$value) = explode('_',$data[$name]); + if($value && $_SESSION[$name][$key] === $value) { // 防止重复提交 + unset($_SESSION[$name][$key]); // 验证完成销毁session + return true; + } + // 开启TOKEN重置 + if(C('TOKEN_RESET')) unset($_SESSION[$name][$key]); + return false; + } + return true; + } + + /** + * 使用正则验证数据 + * @access public + * @param string $value 要验证的数据 + * @param string $rule 验证规则 + * @return boolean + */ + public function regex($value,$rule) { + $validate = array( + 'require' => '/\S+/', + 'email' => '/^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/', + 'url' => '/^http(s?):\/\/(?:[A-za-z0-9-]+\.)+[A-za-z]{2,4}(?:[\/\?#][\/=\?%\-&~`@[\]\':+!\.#\w]*)?$/', + 'currency' => '/^\d+(\.\d+)?$/', + 'number' => '/^\d+$/', + 'zip' => '/^\d{6}$/', + 'integer' => '/^[-\+]?\d+$/', + 'double' => '/^[-\+]?\d+(\.\d+)?$/', + 'english' => '/^[A-Za-z]+$/', + ); + // 检查是否有内置的正则表达式 + if(isset($validate[strtolower($rule)])) + $rule = $validate[strtolower($rule)]; + return preg_match($rule,$value)===1; + } + + /** + * 自动表单处理 + * @access public + * @param array $data 创建数据 + * @param string $type 创建类型 + * @return mixed + */ + private function autoOperation(&$data,$type) { + if(!empty($this->options['auto'])) { + $_auto = $this->options['auto']; + unset($this->options['auto']); + }elseif(!empty($this->_auto)){ + $_auto = $this->_auto; + } + // 自动填充 + if(isset($_auto)) { + foreach ($_auto as $auto){ + // 填充因子定义格式 + // array('field','填充内容','填充条件','附加规则',[额外参数]) + if(empty($auto[2])) $auto[2] = self::MODEL_INSERT; // 默认为新增的时候自动填充 + if( $type == $auto[2] || $auto[2] == self::MODEL_BOTH) { + if(empty($auto[3])) $auto[3] = 'string'; + switch(trim($auto[3])) { + case 'function': // 使用函数进行填充 字段的值作为参数 + case 'callback': // 使用回调方法 + $args = isset($auto[4])?(array)$auto[4]:array(); + if(isset($data[$auto[0]])) { + array_unshift($args,$data[$auto[0]]); + } + if('function'==$auto[3]) { + $data[$auto[0]] = call_user_func_array($auto[1], $args); + }else{ + $data[$auto[0]] = call_user_func_array(array(&$this,$auto[1]), $args); + } + break; + case 'field': // 用其它字段的值进行填充 + $data[$auto[0]] = $data[$auto[1]]; + break; + case 'ignore': // 为空忽略 + if($auto[1]===$data[$auto[0]]) + unset($data[$auto[0]]); + break; + case 'string': + default: // 默认作为字符串填充 + $data[$auto[0]] = $auto[1]; + } + if(isset($data[$auto[0]]) && false === $data[$auto[0]] ) unset($data[$auto[0]]); + } + } + } + return $data; + } + + /** + * 自动表单验证 + * @access protected + * @param array $data 创建数据 + * @param string $type 创建类型 + * @return boolean + */ + protected function autoValidation($data,$type) { + if(!empty($this->options['validate'])) { + $_validate = $this->options['validate']; + unset($this->options['validate']); + }elseif(!empty($this->_validate)){ + $_validate = $this->_validate; + } + // 属性验证 + if(isset($_validate)) { // 如果设置了数据自动验证则进行数据验证 + if($this->patchValidate) { // 重置验证错误信息 + $this->error = array(); + } + foreach($_validate as $key=>$val) { + // 验证因子定义格式 + // array(field,rule,message,condition,type,when,params) + // 判断是否需要执行验证 + if(empty($val[5]) || $val[5]== self::MODEL_BOTH || $val[5]== $type ) { + if(0==strpos($val[2],'{%') && strpos($val[2],'}')) + // 支持提示信息的多语言 使用 {%语言定义} 方式 + $val[2] = L(substr($val[2],2,-1)); + $val[3] = isset($val[3])?$val[3]:self::EXISTS_VALIDATE; + $val[4] = isset($val[4])?$val[4]:'regex'; + // 判断验证条件 + switch($val[3]) { + case self::MUST_VALIDATE: // 必须验证 不管表单是否有设置该字段 + if(false === $this->_validationField($data,$val)) + return false; + break; + case self::VALUE_VALIDATE: // 值不为空的时候才验证 + if('' != trim($data[$val[0]])) + if(false === $this->_validationField($data,$val)) + return false; + break; + default: // 默认表单存在该字段就验证 + if(isset($data[$val[0]])) + if(false === $this->_validationField($data,$val)) + return false; + } + } + } + // 批量验证的时候最后返回错误 + if(!empty($this->error)) return false; + } + return true; + } + + /** + * 验证表单字段 支持批量验证 + * 如果批量验证返回错误的数组信息 + * @access protected + * @param array $data 创建数据 + * @param array $val 验证因子 + * @return boolean + */ + protected function _validationField($data,$val) { + if($this->patchValidate && isset($this->error[$val[0]])) + return ; //当前字段已经有规则验证没有通过 + if(false === $this->_validationFieldItem($data,$val)){ + if($this->patchValidate) { + $this->error[$val[0]] = $val[2]; + }else{ + $this->error = $val[2]; + return false; + } + } + return ; + } + + /** + * 根据验证因子验证字段 + * @access protected + * @param array $data 创建数据 + * @param array $val 验证因子 + * @return boolean + */ + protected function _validationFieldItem($data,$val) { + switch(strtolower(trim($val[4]))) { + case 'function':// 使用函数进行验证 + case 'callback':// 调用方法进行验证 + $args = isset($val[6])?(array)$val[6]:array(); + if(is_string($val[0]) && strpos($val[0], ',')) + $val[0] = explode(',', $val[0]); + if(is_array($val[0])){ + // 支持多个字段验证 + foreach($val[0] as $field) + $_data[$field] = $data[$field]; + array_unshift($args, $_data); + }else{ + array_unshift($args, $data[$val[0]]); + } + if('function'==$val[4]) { + return call_user_func_array($val[1], $args); + }else{ + return call_user_func_array(array(&$this, $val[1]), $args); + } + case 'confirm': // 验证两个字段是否相同 + return $data[$val[0]] == $data[$val[1]]; + case 'unique': // 验证某个值是否唯一 + if(is_string($val[0]) && strpos($val[0],',')) + $val[0] = explode(',',$val[0]); + $map = array(); + if(is_array($val[0])) { + // 支持多个字段验证 + foreach ($val[0] as $field) + $map[$field] = $data[$field]; + }else{ + $map[$val[0]] = $data[$val[0]]; + } + if(!empty($data[$this->getPk()])) { // 完善编辑的时候验证唯一 + $map[$this->getPk()] = array('neq',$data[$this->getPk()]); + } + if($this->where($map)->find()) return false; + return true; + default: // 检查附加规则 + return $this->check($data[$val[0]],$val[1],$val[4]); + } + } + + /** + * 验证数据 支持 in between equal length regex expire ip_allow ip_deny + * @access public + * @param string $value 验证数据 + * @param mixed $rule 验证表达式 + * @param string $type 验证方式 默认为正则验证 + * @return boolean + */ + public function check($value,$rule,$type='regex'){ + $type = strtolower(trim($type)); + switch($type) { + case 'in': // 验证是否在某个指定范围之内 逗号分隔字符串或者数组 + case 'notin': + $range = is_array($rule)? $rule : explode(',',$rule); + return $type == 'in' ? in_array($value ,$range) : !in_array($value ,$range); + case 'between': // 验证是否在某个范围 + case 'notbetween': // 验证是否不在某个范围 + if (is_array($rule)){ + $min = $rule[0]; + $max = $rule[1]; + }else{ + list($min,$max) = explode(',',$rule); + } + return $type == 'between' ? $value>=$min && $value<=$max : $value<$min || $value>$max; + case 'equal': // 验证是否等于某个值 + case 'notequal': // 验证是否等于某个值 + return $type == 'equal' ? $value == $rule : $value != $rule; + case 'length': // 验证长度 + $length = mb_strlen($value,'utf-8'); // 当前数据长度 + if(strpos($rule,',')) { // 长度区间 + list($min,$max) = explode(',',$rule); + return $length >= $min && $length <= $max; + }else{// 指定长度 + return $length == $rule; + } + case 'expire': + list($start,$end) = explode(',',$rule); + if(!is_numeric($start)) $start = strtotime($start); + if(!is_numeric($end)) $end = strtotime($end); + return NOW_TIME >= $start && NOW_TIME <= $end; + case 'ip_allow': // IP 操作许可验证 + return in_array(get_client_ip(),explode(',',$rule)); + case 'ip_deny': // IP 操作禁止验证 + return !in_array(get_client_ip(),explode(',',$rule)); + case 'regex': + default: // 默认使用正则验证 可以使用验证类中定义的验证名称 + // 检查附加规则 + return $this->regex($value,$rule); + } + } + + /** + * SQL查询 + * @access public + * @param string $sql SQL指令 + * @param mixed $parse 是否需要解析SQL + * @return mixed + */ + public function query($sql,$parse=false) { + if(!is_bool($parse) && !is_array($parse)) { + $parse = func_get_args(); + array_shift($parse); + } + $sql = $this->parseSql($sql,$parse); + return $this->db->query($sql); + } + + /** + * 执行SQL语句 + * @access public + * @param string $sql SQL指令 + * @param mixed $parse 是否需要解析SQL + * @return false | integer + */ + public function execute($sql,$parse=false) { + if(!is_bool($parse) && !is_array($parse)) { + $parse = func_get_args(); + array_shift($parse); + } + $sql = $this->parseSql($sql,$parse); + return $this->db->execute($sql); + } + + /** + * 解析SQL语句 + * @access public + * @param string $sql SQL指令 + * @param boolean $parse 是否需要解析SQL + * @return string + */ + protected function parseSql($sql,$parse) { + // 分析表达式 + if(true === $parse) { + $options = $this->_parseOptions(); + $sql = $this->db->parseSql($sql,$options); + }elseif(is_array($parse)){ // SQL预处理 + $parse = array_map(array($this->db,'escapeString'),$parse); + $sql = vsprintf($sql,$parse); + }else{ + $sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>C('DB_PREFIX'))); + } + $this->db->setModel($this->name); + return $sql; + } + + /** + * 切换当前的数据库连接 + * @access public + * @param integer $linkNum 连接序号 + * @param mixed $config 数据库连接信息 + * @param boolean $force 强制重新连接 + * @return Model + */ + public function db($linkNum='',$config='',$force=false) { + if('' === $linkNum && $this->db) { + return $this->db; + } + + static $_db = array(); + if(!isset($_db[$linkNum]) || $force ) { + // 创建一个新的实例 + if(!empty($config) && is_string($config) && false === strpos($config,'/')) { // 支持读取配置参数 + $config = C($config); + } + $_db[$linkNum] = Db::getInstance($config); + }elseif(NULL === $config){ + $_db[$linkNum]->close(); // 关闭数据库连接 + unset($_db[$linkNum]); + return ; + } + + // 切换数据库连接 + $this->db = $_db[$linkNum]; + $this->_after_db(); + // 字段检测 + if(!empty($this->name) && $this->autoCheckFields) $this->_checkTableInfo(); + return $this; + } + // 数据库切换后回调方法 + protected function _after_db() {} + + /** + * 得到当前的数据对象名称 + * @access public + * @return string + */ + public function getModelName() { + if(empty($this->name)){ + $name = substr(get_class($this),0,-5); + if ( $pos = strrpos($name,'\\') ) {//有命名空间 + $this->name = substr($name,$pos+1); + }else{ + $this->name = $name; + } + } + return $this->name; + } + + /** + * 得到完整的数据表名 + * @access public + * @return string + */ + public function getTableName() { + if(empty($this->trueTableName)) { + $tableName = !empty($this->tablePrefix) ? $this->tablePrefix : ''; + if(!empty($this->tableName)) { + $tableName .= $this->tableName; + }else{ + $tableName .= parse_name($this->name); + } + $this->trueTableName = strtolower($tableName); + } + return (!empty($this->dbName)?$this->dbName.'.':'').$this->trueTableName; + } + + /** + * 启动事务 + * @access public + * @return void + */ + public function startTrans() { + $this->commit(); + $this->db->startTrans(); + return ; + } + + /** + * 提交事务 + * @access public + * @return boolean + */ + public function commit() { + return $this->db->commit(); + } + + /** + * 事务回滚 + * @access public + * @return boolean + */ + public function rollback() { + return $this->db->rollback(); + } + + /** + * 返回模型的错误信息 + * @access public + * @return string + */ + public function getError(){ + return $this->error; + } + + /** + * 返回数据库的错误信息 + * @access public + * @return string + */ + public function getDbError() { + return $this->db->getError(); + } + + /** + * 返回最后插入的ID + * @access public + * @return string + */ + public function getLastInsID() { + return $this->db->getLastInsID(); + } + + /** + * 返回最后执行的sql语句 + * @access public + * @return string + */ + public function getLastSql() { + return $this->db->getLastSql($this->name); + } + // 鉴于getLastSql比较常用 增加_sql 别名 + public function _sql(){ + return $this->getLastSql(); + } + + /** + * 获取主键名称 + * @access public + * @return string + */ + public function getPk() { + return $this->pk; + } + + /** + * 获取数据表字段信息 + * @access public + * @return array + */ + public function getDbFields(){ + if(isset($this->options['table'])) {// 动态指定表名 + $array = explode(' ',$this->options['table']); + $fields = $this->db->getFields($array[0]); + return $fields?array_keys($fields):false; + } + if($this->fields) { + $fields = $this->fields; + unset($fields['_type'],$fields['_pk']); + return $fields; + } + return false; + } + + /** + * 设置数据对象值 + * @access public + * @param mixed $data 数据 + * @return Model + */ + public function data($data=''){ + if('' === $data && !empty($this->data)) { + return $this->data; + } + if(is_object($data)){ + $data = get_object_vars($data); + }elseif(is_string($data)){ + parse_str($data,$data); + }elseif(!is_array($data)){ + E(L('_DATA_TYPE_INVALID_')); + } + $this->data = $data; + return $this; + } + + /** + * 查询SQL组装 join + * @access public + * @param mixed $join + * @param string $type JOIN类型 + * @return Model + */ + public function join($join,$type='INNER') { + if(is_array($join)) { + $this->options['join'] = $join; + }elseif(!empty($join)) { + $this->options['join'][] = false !== stripos($join,'JOIN')? $join : $type.' JOIN '.$join; + } + return $this; + } + + /** + * 查询SQL组装 union + * @access public + * @param mixed $union + * @param boolean $all + * @return Model + */ + public function union($union,$all=false) { + if(empty($union)) return $this; + if($all) { + $this->options['union']['_all'] = true; + } + if(is_object($union)) { + $union = get_object_vars($union); + } + // 转换union表达式 + if(is_string($union) ) { + $options = $union; + }elseif(is_array($union)){ + if(isset($union[0])) { + $this->options['union'] = array_merge($this->options['union'],$union); + return $this; + }else{ + $options = $union; + } + }else{ + E(L('_DATA_TYPE_INVALID_')); + } + $this->options['union'][] = $options; + return $this; + } + + /** + * 查询缓存 + * @access public + * @param mixed $key + * @param integer $expire + * @param string $type + * @return Model + */ + public function cache($key=true,$expire=null,$type=''){ + if(false !== $key) + $this->options['cache'] = array('key'=>$key,'expire'=>$expire,'type'=>$type); + return $this; + } + + /** + * 指定查询字段 支持字段排除 + * @access public + * @param mixed $field + * @param boolean $except 是否排除 + * @return Model + */ + public function field($field,$except=false){ + if(true === $field) {// 获取全部字段 + $fields = $this->getDbFields(); + $field = $fields?$fields:'*'; + }elseif($except) {// 字段排除 + if(is_string($field)) { + $field = explode(',',$field); + } + $fields = $this->getDbFields(); + $field = $fields?array_diff($fields,$field):$field; + } + $this->options['field'] = $field; + return $this; + } + + /** + * 调用命名范围 + * @access public + * @param mixed $scope 命名范围名称 支持多个 和直接定义 + * @param array $args 参数 + * @return Model + */ + public function scope($scope='',$args=NULL){ + if('' === $scope) { + if(isset($this->_scope['default'])) { + // 默认的命名范围 + $options = $this->_scope['default']; + }else{ + return $this; + } + }elseif(is_string($scope)){ // 支持多个命名范围调用 用逗号分割 + $scopes = explode(',',$scope); + $options = array(); + foreach ($scopes as $name){ + if(!isset($this->_scope[$name])) continue; + $options = array_merge($options,$this->_scope[$name]); + } + if(!empty($args) && is_array($args)) { + $options = array_merge($options,$args); + } + }elseif(is_array($scope)){ // 直接传入命名范围定义 + $options = $scope; + } + + if(is_array($options) && !empty($options)){ + $this->options = array_merge($this->options,array_change_key_case($options)); + } + return $this; + } + + /** + * 指定查询条件 支持安全过滤 + * @access public + * @param mixed $where 条件表达式 + * @param mixed $parse 预处理参数 + * @return Model + */ + public function where($where,$parse=null){ + if(!is_null($parse) && is_string($where)) { + if(!is_array($parse)) { + $parse = func_get_args(); + array_shift($parse); + } + $parse = array_map(array($this->db,'escapeString'),$parse); + $where = vsprintf($where,$parse); + }elseif(is_object($where)){ + $where = get_object_vars($where); + } + if(is_string($where) && '' != $where){ + $map = array(); + $map['_string'] = $where; + $where = $map; + } + if(isset($this->options['where'])){ + $this->options['where'] = array_merge($this->options['where'],$where); + }else{ + $this->options['where'] = $where; + } + + return $this; + } + + /** + * 指定查询数量 + * @access public + * @param mixed $offset 起始位置 + * @param mixed $length 查询数量 + * @return Model + */ + public function limit($offset,$length=null){ + $this->options['limit'] = is_null($length)?$offset:$offset.','.$length; + return $this; + } + + /** + * 指定分页 + * @access public + * @param mixed $page 页数 + * @param mixed $listRows 每页数量 + * @return Model + */ + public function page($page,$listRows=null){ + $this->options['page'] = is_null($listRows)?$page:$page.','.$listRows; + return $this; + } + + /** + * 查询注释 + * @access public + * @param string $comment 注释 + * @return Model + */ + public function comment($comment){ + $this->options['comment'] = $comment; + return $this; + } + + /** + * 参数绑定 + * @access public + * @param string $key 参数名 + * @param mixed $value 绑定的变量及绑定参数 + * @return Model + */ + public function bind($key,$value=false) { + if(is_array($key)){ + $this->options['bind'] = $key; + }else{ + $num = func_num_args(); + if($num>2){ + $params = func_get_args(); + array_shift($params); + $this->options['bind'][$key] = $params; + }else{ + $this->options['bind'][$key] = $value; + } + } + return $this; + } + + /** + * 设置模型的属性值 + * @access public + * @param string $name 名称 + * @param mixed $value 值 + * @return Model + */ + public function setProperty($name,$value) { + if(property_exists($this,$name)) + $this->$name = $value; + return $this; + } + +} \ No newline at end of file diff --git a/ThinkPHP/Library/Think/Model/AdvModel.class.php b/ThinkPHP/Library/Think/Model/AdvModel.class.php new file mode 100644 index 000000000..32f92a52f --- /dev/null +++ b/ThinkPHP/Library/Think/Model/AdvModel.class.php @@ -0,0 +1,668 @@ + +// +---------------------------------------------------------------------- + +namespace Think\Model; +use Think\Model; +/** + * 高级模型扩展 + * @category Extend + * @package Extend + * @subpackage Model + * @author liu21st + */ +class AdvModel extends Model { + protected $optimLock = 'lock_version'; + protected $returnType = 'array'; + protected $blobFields = array(); + protected $blobValues = null; + protected $serializeField = array(); + protected $readonlyField = array(); + protected $_filter = array(); + protected $partition = array(); + + public function __construct($name='',$tablePrefix='',$connection='') { + if('' !== $name || is_subclass_of($this,'AdvModel') ){ + // 如果是AdvModel子类或者有传入模型名称则获取字段缓存 + }else{ + // 空的模型 关闭字段缓存 + $this->autoCheckFields = false; + } + parent::__construct($name,$tablePrefix,$connection); + } + + /** + * 利用__call方法重载 实现一些特殊的Model方法 (魔术方法) + * @access public + * @param string $method 方法名称 + * @param mixed $args 调用参数 + * @return mixed + */ + public function __call($method,$args) { + if(strtolower(substr($method,0,3))=='top'){ + // 获取前N条记录 + $count = substr($method,3); + array_unshift($args,$count); + return call_user_func_array(array(&$this, 'topN'), $args); + }else{ + return parent::__call($method,$args); + } + } + + /** + * 对保存到数据库的数据进行处理 + * @access protected + * @param mixed $data 要操作的数据 + * @return boolean + */ + protected function _facade($data) { + // 检查序列化字段 + $data = $this->serializeField($data); + return parent::_facade($data); + } + + // 查询成功后的回调方法 + protected function _after_find(&$result,$options='') { + // 检查序列化字段 + $this->checkSerializeField($result); + // 获取文本字段 + $this->getBlobFields($result); + // 检查字段过滤 + $result = $this->getFilterFields($result); + // 缓存乐观锁 + $this->cacheLockVersion($result); + } + + // 查询数据集成功后的回调方法 + protected function _after_select(&$resultSet,$options='') { + // 检查序列化字段 + $resultSet = $this->checkListSerializeField($resultSet); + // 获取文本字段 + $resultSet = $this->getListBlobFields($resultSet); + // 检查列表字段过滤 + $resultSet = $this->getFilterListFields($resultSet); + } + + // 写入前的回调方法 + protected function _before_insert(&$data,$options='') { + // 记录乐观锁 + $data = $this->recordLockVersion($data); + // 检查文本字段 + $data = $this->checkBlobFields($data); + // 检查字段过滤 + $data = $this->setFilterFields($data); + } + + protected function _after_insert($data,$options) { + // 保存文本字段 + $this->saveBlobFields($data); + } + + // 更新前的回调方法 + protected function _before_update(&$data,$options='') { + // 检查乐观锁 + if(!$this->checkLockVersion($data,$options)) { + return false; + } + // 检查文本字段 + $data = $this->checkBlobFields($data); + // 检查只读字段 + $data = $this->checkReadonlyField($data); + // 检查字段过滤 + $data = $this->setFilterFields($data); + } + + protected function _after_update($data,$options) { + // 保存文本字段 + $this->saveBlobFields($data); + } + + protected function _after_delete($data,$options) { + // 删除Blob数据 + $this->delBlobFields($data); + } + + /** + * 记录乐观锁 + * @access protected + * @param array $data 数据对象 + * @return array + */ + protected function recordLockVersion($data) { + // 记录乐观锁 + if($this->optimLock && !isset($data[$this->optimLock]) ) { + if(in_array($this->optimLock,$this->fields,true)) { + $data[$this->optimLock] = 0; + } + } + return $data; + } + + /** + * 缓存乐观锁 + * @access protected + * @param array $data 数据对象 + * @return void + */ + protected function cacheLockVersion($data) { + if($this->optimLock) { + if(isset($data[$this->optimLock]) && isset($data[$this->getPk()])) { + // 只有当存在乐观锁字段和主键有值的时候才记录乐观锁 + $_SESSION[$this->name.'_'.$data[$this->getPk()].'_lock_version'] = $data[$this->optimLock]; + } + } + } + + /** + * 检查乐观锁 + * @access protected + * @param array $data 当前数据 + * @param array $options 查询表达式 + * @return mixed + */ + protected function checkLockVersion(&$data,$options) { + $id = $data[$this->getPk()]; + // 检查乐观锁 + $identify = $this->name.'_'.$id.'_lock_version'; + if($this->optimLock && isset($_SESSION[$identify])) { + $lock_version = $_SESSION[$identify]; + $vo = $this->field($this->optimLock)->find($id); + $_SESSION[$identify] = $lock_version; + $curr_version = $vo[$this->optimLock]; + if(isset($curr_version)) { + if($curr_version>0 && $lock_version != $curr_version) { + // 记录已经更新 + $this->error = L('_RECORD_HAS_UPDATE_'); + return false; + }else{ + // 更新乐观锁 + $save_version = $data[$this->optimLock]; + if($save_version != $lock_version+1) { + $data[$this->optimLock] = $lock_version+1; + } + $_SESSION[$identify] = $lock_version+1; + } + } + } + return true; + } + + /** + * 查找前N个记录 + * @access public + * @param integer $count 记录个数 + * @param array $options 查询表达式 + * @return array + */ + public function topN($count,$options=array()) { + $options['limit'] = $count; + return $this->select($options); + } + + /** + * 查询符合条件的第N条记录 + * 0 表示第一条记录 -1 表示最后一条记录 + * @access public + * @param integer $position 记录位置 + * @param array $options 查询表达式 + * @return mixed + */ + public function getN($position=0,$options=array()) { + if($position>=0) { // 正向查找 + $options['limit'] = $position.',1'; + $list = $this->select($options); + return $list?$list[0]:false; + }else{ // 逆序查找 + $list = $this->select($options); + return $list?$list[count($list)-abs($position)]:false; + } + } + + /** + * 获取满足条件的第一条记录 + * @access public + * @param array $options 查询表达式 + * @return mixed + */ + public function first($options=array()) { + return $this->getN(0,$options); + } + + /** + * 获取满足条件的最后一条记录 + * @access public + * @param array $options 查询表达式 + * @return mixed + */ + public function last($options=array()) { + return $this->getN(-1,$options); + } + + /** + * 返回数据 + * @access public + * @param array $data 数据 + * @param string $type 返回类型 默认为数组 + * @return mixed + */ + public function returnResult($data,$type='') { + if('' === $type) + $type = $this->returnType; + switch($type) { + case 'array' : return $data; + case 'object': return (object)$data; + default:// 允许用户自定义返回类型 + if(class_exists($type)) + return new $type($data); + else + throw_exception(L('_CLASS_NOT_EXIST_').':'.$type); + } + } + + /** + * 获取数据的时候过滤数据字段 + * @access protected + * @param mixed $result 查询的数据 + * @return array + */ + protected function getFilterFields(&$result) { + if(!empty($this->_filter)) { + foreach ($this->_filter as $field=>$filter){ + if(isset($result[$field])) { + $fun = $filter[1]; + if(!empty($fun)) { + if(isset($filter[2]) && $filter[2]){ + // 传递整个数据对象作为参数 + $result[$field] = call_user_func($fun,$result); + }else{ + // 传递字段的值作为参数 + $result[$field] = call_user_func($fun,$result[$field]); + } + } + } + } + } + return $result; + } + + protected function getFilterListFields(&$resultSet) { + if(!empty($this->_filter)) { + foreach ($resultSet as $key=>$result) + $resultSet[$key] = $this->getFilterFields($result); + } + return $resultSet; + } + + /** + * 写入数据的时候过滤数据字段 + * @access protected + * @param mixed $result 查询的数据 + * @return array + */ + protected function setFilterFields($data) { + if(!empty($this->_filter)) { + foreach ($this->_filter as $field=>$filter){ + if(isset($data[$field])) { + $fun = $filter[0]; + if(!empty($fun)) { + if(isset($filter[2]) && $filter[2]) { + // 传递整个数据对象作为参数 + $data[$field] = call_user_func($fun,$data); + }else{ + // 传递字段的值作为参数 + $data[$field] = call_user_func($fun,$data[$field]); + } + } + } + } + } + return $data; + } + + /** + * 返回数据列表 + * @access protected + * @param array $resultSet 数据 + * @param string $type 返回类型 默认为数组 + * @return void + */ + protected function returnResultSet(&$resultSet,$type='') { + foreach ($resultSet as $key=>$data) + $resultSet[$key] = $this->returnResult($data,$type); + return $resultSet; + } + + protected function checkBlobFields(&$data) { + // 检查Blob文件保存字段 + if(!empty($this->blobFields)) { + foreach ($this->blobFields as $field){ + if(isset($data[$field])) { + if(isset($data[$this->getPk()])) + $this->blobValues[$this->name.'/'.$data[$this->getPk()].'_'.$field] = $data[$field]; + else + $this->blobValues[$this->name.'/@?id@_'.$field] = $data[$field]; + unset($data[$field]); + } + } + } + return $data; + } + + /** + * 获取数据集的文本字段 + * @access protected + * @param mixed $resultSet 查询的数据 + * @param string $field 查询的字段 + * @return void + */ + protected function getListBlobFields(&$resultSet,$field='') { + if(!empty($this->blobFields)) { + foreach ($resultSet as $key=>$result){ + $result = $this->getBlobFields($result,$field); + $resultSet[$key] = $result; + } + } + return $resultSet; + } + + /** + * 获取数据的文本字段 + * @access protected + * @param mixed $data 查询的数据 + * @param string $field 查询的字段 + * @return void + */ + protected function getBlobFields(&$data,$field='') { + if(!empty($this->blobFields)) { + $pk = $this->getPk(); + $id = $data[$pk]; + if(empty($field)) { + foreach ($this->blobFields as $field){ + $identify = $this->name.'/'.$id.'_'.$field; + $data[$field] = F($identify); + } + return $data; + }else{ + $identify = $this->name.'/'.$id.'_'.$field; + return F($identify); + } + } + } + + /** + * 保存File方式的字段 + * @access protected + * @param mixed $data 保存的数据 + * @return void + */ + protected function saveBlobFields(&$data) { + if(!empty($this->blobFields)) { + foreach ($this->blobValues as $key=>$val){ + if(strpos($key,'@?id@')) + $key = str_replace('@?id@',$data[$this->getPk()],$key); + F($key,$val); + } + } + } + + /** + * 删除File方式的字段 + * @access protected + * @param mixed $data 保存的数据 + * @param string $field 查询的字段 + * @return void + */ + protected function delBlobFields(&$data,$field='') { + if(!empty($this->blobFields)) { + $pk = $this->getPk(); + $id = $data[$pk]; + if(empty($field)) { + foreach ($this->blobFields as $field){ + $identify = $this->name.'/'.$id.'_'.$field; + F($identify,null); + } + }else{ + $identify = $this->name.'/'.$id.'_'.$field; + F($identify,null); + } + } + } + + /** + * 字段值延迟增长 + * @access public + * @param string $field 字段名 + * @param integer $step 增长值 + * @param integer $lazyTime 延时时间(s) + * @return boolean + */ + public function setLazyInc($field,$step=1,$lazyTime=0) { + $condition = $this->options['where']; + if(empty($condition)) { // 没有条件不做任何更新 + return false; + } + if($lazyTime>0) {// 延迟写入 + $guid = md5($this->name.'_'.$field.'_'.serialize($condition)); + $step = $this->lazyWrite($guid,$step,$lazyTime); + if(false === $step ) return true; // 等待下次写入 + } + return $this->setField($field,array('exp',$field.'+'.$step)); + } + + /** + * 字段值延迟减少 + * @access public + * @param string $field 字段名 + * @param integer $step 减少值 + * @param integer $lazyTime 延时时间(s) + * @return boolean + */ + public function setLazyDec($field,$step=1,$lazyTime=0) { + $condition = $this->options['where']; + if(empty($condition)) { // 没有条件不做任何更新 + return false; + } + if($lazyTime>0) {// 延迟写入 + $guid = md5($this->name.'_'.$field.'_'.serialize($condition)); + $step = $this->lazyWrite($guid,$step,$lazyTime); + if(false === $step ) return true; // 等待下次写入 + } + return $this->setField($field,array('exp',$field.'-'.$step)); + } + + /** + * 延时更新检查 返回false表示需要延时 + * 否则返回实际写入的数值 + * @access public + * @param string $guid 写入标识 + * @param integer $step 写入步进值 + * @param integer $lazyTime 延时时间(s) + * @return false|integer + */ + protected function lazyWrite($guid,$step,$lazyTime) { + if(false !== ($value = F($guid))) { // 存在缓存写入数据 + if(time()>F($guid.'_time')+$lazyTime) { + // 延时更新时间到了,删除缓存数据 并实际写入数据库 + F($guid,NULL); + F($guid.'_time',NULL); + return $value+$step; + }else{ + // 追加数据到缓存 + F($guid,$value+$step); + return false; + } + }else{ // 没有缓存数据 + F($guid,$step); + // 计时开始 + F($guid.'_time',time()); + return false; + } + } + + /** + * 检查序列化数据字段 + * @access protected + * @param array $data 数据 + * @return array + */ + protected function serializeField(&$data) { + // 检查序列化字段 + if(!empty($this->serializeField)) { + // 定义方式 $this->serializeField = array('ser'=>array('name','email')); + foreach ($this->serializeField as $key=>$val){ + if(empty($data[$key])) { + $serialize = array(); + foreach ($val as $name){ + if(isset($data[$name])) { + $serialize[$name] = $data[$name]; + unset($data[$name]); + } + } + if(!empty($serialize)) { + $data[$key] = serialize($serialize); + } + } + } + } + return $data; + } + + // 检查返回数据的序列化字段 + protected function checkSerializeField(&$result) { + // 检查序列化字段 + if(!empty($this->serializeField)) { + foreach ($this->serializeField as $key=>$val){ + if(isset($result[$key])) { + $serialize = unserialize($result[$key]); + foreach ($serialize as $name=>$value) + $result[$name] = $value; + unset($serialize,$result[$key]); + } + } + } + return $result; + } + + // 检查数据集的序列化字段 + protected function checkListSerializeField(&$resultSet) { + // 检查序列化字段 + if(!empty($this->serializeField)) { + foreach ($this->serializeField as $key=>$val){ + foreach ($resultSet as $k=>$result){ + if(isset($result[$key])) { + $serialize = unserialize($result[$key]); + foreach ($serialize as $name=>$value) + $result[$name] = $value; + unset($serialize,$result[$key]); + $resultSet[$k] = $result; + } + } + } + } + return $resultSet; + } + + /** + * 检查只读字段 + * @access protected + * @param array $data 数据 + * @return array + */ + protected function checkReadonlyField(&$data) { + if(!empty($this->readonlyField)) { + foreach ($this->readonlyField as $key=>$field){ + if(isset($data[$field])) + unset($data[$field]); + } + } + return $data; + } + + /** + * 批处理执行SQL语句 + * 批处理的指令都认为是execute操作 + * @access public + * @param array $sql SQL批处理指令 + * @return boolean + */ + public function patchQuery($sql=array()) { + if(!is_array($sql)) return false; + // 自动启动事务支持 + $this->startTrans(); + try{ + foreach ($sql as $_sql){ + $result = $this->execute($_sql); + if(false === $result) { + // 发生错误自动回滚事务 + $this->rollback(); + return false; + } + } + // 提交事务 + $this->commit(); + } catch (ThinkException $e) { + $this->rollback(); + } + return true; + } + + /** + * 得到分表的的数据表名 + * @access public + * @param array $data 操作的数据 + * @return string + */ + public function getPartitionTableName($data=array()) { + // 对数据表进行分区 + if(isset($data[$this->partition['field']])) { + $field = $data[$this->partition['field']]; + switch($this->partition['type']) { + case 'id': + // 按照id范围分表 + $step = $this->partition['expr']; + $seq = floor($field / $step)+1; + break; + case 'year': + // 按照年份分表 + if(!is_numeric($field)) { + $field = strtotime($field); + } + $seq = date('Y',$field)-$this->partition['expr']+1; + break; + case 'mod': + // 按照id的模数分表 + $seq = ($field % $this->partition['num'])+1; + break; + case 'md5': + // 按照md5的序列分表 + $seq = (ord(substr(md5($field),0,1)) % $this->partition['num'])+1; + break; + default : + if(function_exists($this->partition['type'])) { + // 支持指定函数哈希 + $fun = $this->partition['type']; + $seq = (ord(substr($fun($field),0,1)) % $this->partition['num'])+1; + }else{ + // 按照字段的首字母的值分表 + $seq = (ord($field{0}) % $this->partition['num'])+1; + } + } + return $this->getTableName().'_'.$seq; + }else{ + // 当设置的分表字段不在查询条件或者数据中 + // 进行联合查询,必须设定 partition['num'] + $tableName = array(); + for($i=0;$i<$this->partition['num'];$i++) + $tableName[] = 'SELECT * FROM '.$this->getTableName().'_'.($i+1); + $tableName = '( '.implode(" UNION ",$tableName).') AS '.$this->name; + return $tableName; + } + } +} \ No newline at end of file diff --git a/ThinkPHP/Library/Think/Model/MongoModel.class.php b/ThinkPHP/Library/Think/Model/MongoModel.class.php new file mode 100644 index 000000000..394777fbd --- /dev/null +++ b/ThinkPHP/Library/Think/Model/MongoModel.class.php @@ -0,0 +1,310 @@ + +// +---------------------------------------------------------------------- +namespace Think\Model; +use Think\Model; +/** + * MongoModel模型类 + * 实现了ODM和ActiveRecords模式 + * @category Extend + * @package Extend + * @subpackage Model + * @author liu21st + */ +class MongoModel extends Model{ + // 主键类型 + const TYPE_OBJECT = 1; + const TYPE_INT = 2; + const TYPE_STRING = 3; + + // 主键名称 + protected $pk = '_id'; + // _id 类型 1 Object 采用MongoId对象 2 Int 整形 支持自动增长 3 String 字符串Hash + protected $_idType = self::TYPE_OBJECT; + // Mongo默认关闭字段检测 可以动态追加字段 + protected $autoCheckFields = false; + // 链操作方法列表 + protected $methods = array('table','order','auto','filter','validate'); + + /** + * 利用__call方法实现一些特殊的Model方法 + * @access public + * @param string $method 方法名称 + * @param array $args 调用参数 + * @return mixed + */ + public function __call($method,$args) { + if(in_array(strtolower($method),$this->methods,true)) { + // 连贯操作的实现 + $this->options[strtolower($method)] = $args[0]; + return $this; + }elseif(strtolower(substr($method,0,5))=='getby') { + // 根据某个字段获取记录 + $field = parse_name(substr($method,5)); + $where[$field] =$args[0]; + return $this->where($where)->find(); + }elseif(strtolower(substr($method,0,10))=='getfieldby') { + // 根据某个字段获取记录的某个值 + $name = parse_name(substr($method,10)); + $where[$name] =$args[0]; + return $this->where($where)->getField($args[1]); + }else{ + throw_exception(__CLASS__.':'.$method.L('_METHOD_NOT_EXIST_')); + return; + } + } + + /** + * 获取字段信息并缓存 主键和自增信息直接配置 + * @access public + * @return void + */ + public function flush() { + // 缓存不存在则查询数据表信息 + $fields = $this->db->getFields(); + if(!$fields) { // 暂时没有数据无法获取字段信息 下次查询 + return false; + } + $this->fields = array_keys($fields); + foreach ($fields as $key=>$val){ + // 记录字段类型 + $type[$key] = $val['type']; + } + // 记录字段类型信息 + if(C('DB_FIELDTYPE_CHECK')) $this->fields['_type'] = $type; + + // 2008-3-7 增加缓存开关控制 + if(C('DB_FIELDS_CACHE')){ + // 永久缓存数据表信息 + $db = $this->dbName?$this->dbName:C('DB_NAME'); + F('_fields/'.$db.'.'.$this->name,$this->fields); + } + } + + // 写入数据前的回调方法 包括新增和更新 + protected function _before_write(&$data) { + $pk = $this->getPk(); + // 根据主键类型处理主键数据 + if(isset($data[$pk]) && $this->_idType == self::TYPE_OBJECT) { + $data[$pk] = new MongoId($data[$pk]); + } + } + + /** + * count统计 配合where连贯操作 + * @access public + * @return integer + */ + public function count(){ + // 分析表达式 + $options = $this->_parseOptions(); + return $this->db->count($options); + } + + /** + * 获取下一ID 用于自动增长型 + * @access public + * @param string $pk 字段名 默认为主键 + * @return mixed + */ + public function getMongoNextId($pk=''){ + if(empty($pk)) { + $pk = $this->getPk(); + } + return $this->db->mongo_next_id($pk); + } + + // 插入数据前的回调方法 + protected function _before_insert(&$data,$options) { + // 写入数据到数据库 + if($this->autoinc && $this->_idType== self::TYPE_INT) { // 主键自动增长 + $pk = $this->getPk(); + if(!isset($data[$pk])) { + $data[$pk] = $this->db->mongo_next_id($pk); + } + } + } + + public function clear(){ + return $this->db->clear(); + } + + // 查询成功后的回调方法 + protected function _after_select(&$resultSet,$options) { + array_walk($resultSet,array($this,'checkMongoId')); + } + + /** + * 获取MongoId + * @access protected + * @param array $result 返回数据 + * @return array + */ + protected function checkMongoId(&$result){ + if(is_object($result['_id'])) { + $result['_id'] = $result['_id']->__toString(); + } + return $result; + } + + // 表达式过滤回调方法 + protected function _options_filter(&$options) { + $id = $this->getPk(); + if(isset($options['where'][$id]) && is_scalar($options['where'][$id]) && $this->_idType== self::TYPE_OBJECT) { + $options['where'][$id] = new MongoId($options['where'][$id]); + } + } + + /** + * 查询数据 + * @access public + * @param mixed $options 表达式参数 + * @return mixed + */ + public function find($options=array()) { + if( is_numeric($options) || is_string($options)) { + $id = $this->getPk(); + $where[$id] = $options; + $options = array(); + $options['where'] = $where; + } + // 分析表达式 + $options = $this->_parseOptions($options); + $result = $this->db->find($options); + if(false === $result) { + return false; + } + if(empty($result)) {// 查询结果为空 + return null; + }else{ + $this->checkMongoId($result); + } + $this->data = $result; + $this->_after_find($this->data,$options); + return $this->data; + } + + /** + * 字段值增长 + * @access public + * @param string $field 字段名 + * @param integer $step 增长值 + * @return boolean + */ + public function setInc($field,$step=1) { + return $this->setField($field,array('inc',$step)); + } + + /** + * 字段值减少 + * @access public + * @param string $field 字段名 + * @param integer $step 减少值 + * @return boolean + */ + public function setDec($field,$step=1) { + return $this->setField($field,array('inc','-'.$step)); + } + + /** + * 获取一条记录的某个字段值 + * @access public + * @param string $field 字段名 + * @param string $spea 字段数据间隔符号 + * @return mixed + */ + public function getField($field,$sepa=null) { + $options['field'] = $field; + $options = $this->_parseOptions($options); + if(strpos($field,',')) { // 多字段 + if(is_numeric($sepa)) {// 限定数量 + $options['limit'] = $sepa; + $sepa = null;// 重置为null 返回数组 + } + $resultSet = $this->db->select($options); + if(!empty($resultSet)) { + $_field = explode(',', $field); + $field = array_keys($resultSet[0]); + $key = array_shift($field); + $key2 = array_shift($field); + $cols = array(); + $count = count($_field); + foreach ($resultSet as $result){ + $name = $result[$key]; + if(2==$count) { + $cols[$name] = $result[$key2]; + }else{ + $cols[$name] = is_null($sepa)?$result:implode($sepa,$result); + } + } + return $cols; + } + }else{ + // 返回数据个数 + if(true !== $sepa) {// 当sepa指定为true的时候 返回所有数据 + $options['limit'] = is_numeric($sepa)?$sepa:1; + } // 查找一条记录 + $result = $this->db->find($options); + if(!empty($result)) { + if(1==$options['limit']) return reset($result[0]); + foreach ($result as $val){ + $array[] = $val[$field]; + } + return $array; + } + } + return null; + } + + /** + * 执行Mongo指令 + * @access public + * @param array $command 指令 + * @return mixed + */ + public function command($command) { + return $this->db->command($command); + } + + /** + * 执行MongoCode + * @access public + * @param string $code MongoCode + * @param array $args 参数 + * @return mixed + */ + public function mongoCode($code,$args=array()) { + return $this->db->execute($code,$args); + } + + // 数据库切换后回调方法 + protected function _after_db() { + // 切换Collection + $this->db->switchCollection($this->getTableName(),$this->dbName?$this->dbName:C('db_name')); + } + + /** + * 得到完整的数据表名 Mongo表名不带dbName + * @access public + * @return string + */ + public function getTableName() { + if(empty($this->trueTableName)) { + $tableName = !empty($this->tablePrefix) ? $this->tablePrefix : ''; + if(!empty($this->tableName)) { + $tableName .= $this->tableName; + }else{ + $tableName .= parse_name($this->name); + } + $this->trueTableName = strtolower($tableName); + } + return $this->trueTableName; + } +} \ No newline at end of file diff --git a/ThinkPHP/Library/Think/Model/RelationModel.class.php b/ThinkPHP/Library/Think/Model/RelationModel.class.php new file mode 100644 index 000000000..40791c06a --- /dev/null +++ b/ThinkPHP/Library/Think/Model/RelationModel.class.php @@ -0,0 +1,393 @@ + +// +---------------------------------------------------------------------- + +namespace Think\Model; +use Think\Model; +/** + * ThinkPHP关联模型扩展 + * @category Extend + * @package Extend + * @subpackage Model + * @author liu21st + */ +define('HAS_ONE',1); +define('BELONGS_TO',2); +define('HAS_MANY',3); +define('MANY_TO_MANY',4); + +class RelationModel extends Model { + // 关联定义 + protected $_link = array(); + + /** + * 动态方法实现 + * @access public + * @param string $method 方法名称 + * @param array $args 调用参数 + * @return mixed + */ + public function __call($method,$args) { + if(strtolower(substr($method,0,8))=='relation'){ + $type = strtoupper(substr($method,8)); + if(in_array($type,array('ADD','SAVE','DEL'),true)) { + array_unshift($args,$type); + return call_user_func_array(array(&$this, 'opRelation'), $args); + } + }else{ + return parent::__call($method,$args); + } + } + + /** + * 得到关联的数据表名 + * @access public + * @return string + */ + public function getRelationTableName($relation) { + $relationTable = !empty($this->tablePrefix) ? $this->tablePrefix : ''; + $relationTable .= $this->tableName?$this->tableName:$this->name; + $relationTable .= '_'.$relation->getModelName(); + return strtolower($relationTable); + } + + // 查询成功后的回调方法 + protected function _after_find(&$result,$options) { + // 获取关联数据 并附加到结果中 + if(!empty($options['link'])) + $this->getRelation($result,$options['link']); + } + + // 查询数据集成功后的回调方法 + protected function _after_select(&$result,$options) { + // 获取关联数据 并附加到结果中 + if(!empty($options['link'])) + $this->getRelations($result,$options['link']); + } + + // 写入成功后的回调方法 + protected function _after_insert($data,$options) { + // 关联写入 + if(!empty($options['link'])) + $this->opRelation('ADD',$data,$options['link']); + } + + // 更新成功后的回调方法 + protected function _after_update($data,$options) { + // 关联更新 + if(!empty($options['link'])) + $this->opRelation('SAVE',$data,$options['link']); + } + + // 删除成功后的回调方法 + protected function _after_delete($data,$options) { + // 关联删除 + if(!empty($options['link'])) + $this->opRelation('DEL',$data,$options['link']); + } + + /** + * 对保存到数据库的数据进行处理 + * @access protected + * @param mixed $data 要操作的数据 + * @return boolean + */ + protected function _facade($data) { + $this->_before_write($data); + return $data; + } + + /** + * 获取返回数据集的关联记录 + * @access protected + * @param array $resultSet 返回数据 + * @param string|array $name 关联名称 + * @return array + */ + protected function getRelations(&$resultSet,$name='') { + // 获取记录集的主键列表 + foreach($resultSet as $key=>$val) { + $val = $this->getRelation($val,$name); + $resultSet[$key] = $val; + } + return $resultSet; + } + + /** + * 获取返回数据的关联记录 + * @access protected + * @param mixed $result 返回数据 + * @param string|array $name 关联名称 + * @param boolean $return 是否返回关联数据本身 + * @return array + */ + protected function getRelation(&$result,$name='',$return=false) { + if(!empty($this->_link)) { + foreach($this->_link as $key=>$val) { + $mappingName = !empty($val['mapping_name'])?$val['mapping_name']:$key; // 映射名称 + if(empty($name) || true === $name || $mappingName == $name || (is_array($name) && in_array($mappingName,$name))) { + $mappingType = !empty($val['mapping_type'])?$val['mapping_type']:$val; // 关联类型 + $mappingClass = !empty($val['class_name'])?$val['class_name']:$key; // 关联类名 + $mappingFields = !empty($val['mapping_fields'])?$val['mapping_fields']:'*'; // 映射字段 + $mappingCondition = !empty($val['condition'])?$val['condition']:'1=1'; // 关联条件 + $mappingKey =!empty($val['mapping_key'])? $val['mapping_key'] : $this->getPk(); // 关联键名 + if(strtoupper($mappingClass)==strtoupper($this->name)) { + // 自引用关联 获取父键名 + $mappingFk = !empty($val['parent_key'])? $val['parent_key'] : 'parent_id'; + }else{ + $mappingFk = !empty($val['foreign_key'])?$val['foreign_key']:strtolower($this->name).'_id'; // 关联外键 + } + // 获取关联模型对象 + $model = D($mappingClass); + switch($mappingType) { + case HAS_ONE: + $pk = $result[$mappingKey]; + $mappingCondition .= " AND {$mappingFk}='{$pk}'"; + $relationData = $model->where($mappingCondition)->field($mappingFields)->find(); + if (!empty($val['relation_deep'])){ + $model->getRelation($relationData,$val['relation_deep']); + } + break; + case BELONGS_TO: + if(strtoupper($mappingClass)==strtoupper($this->name)) { + // 自引用关联 获取父键名 + $mappingFk = !empty($val['parent_key'])? $val['parent_key'] : 'parent_id'; + }else{ + $mappingFk = !empty($val['foreign_key'])?$val['foreign_key']:strtolower($model->getModelName()).'_id'; // 关联外键 + } + $fk = $result[$mappingFk]; + $mappingCondition .= " AND {$model->getPk()}='{$fk}'"; + $relationData = $model->where($mappingCondition)->field($mappingFields)->find(); + if (!empty($val['relation_deep'])){ + $model->getRelation($relationData,$val['relation_deep']); + } + break; + case HAS_MANY: + $pk = $result[$mappingKey]; + $mappingCondition .= " AND {$mappingFk}='{$pk}'"; + $mappingOrder = !empty($val['mapping_order'])?$val['mapping_order']:''; + $mappingLimit = !empty($val['mapping_limit'])?$val['mapping_limit']:''; + // 延时获取关联记录 + $relationData = $model->where($mappingCondition)->field($mappingFields)->order($mappingOrder)->limit($mappingLimit)->select(); + if (!empty($val['relation_deep'])){ + foreach($relationData as $key=>$data){ + $model->getRelation($data,$val['relation_deep']); + $relationData[$key] = $data; + } + } + break; + case MANY_TO_MANY: + $pk = $result[$mappingKey]; + $mappingCondition = " {$mappingFk}='{$pk}'"; + $mappingOrder = $val['mapping_order']; + $mappingLimit = $val['mapping_limit']; + $mappingRelationFk = $val['relation_foreign_key']?$val['relation_foreign_key']:$model->getModelName().'_id'; + $mappingRelationTable = $val['relation_table']?$val['relation_table']:$this->getRelationTableName($model); + $sql = "SELECT b.{$mappingFields} FROM {$mappingRelationTable} AS a, ".$model->getTableName()." AS b WHERE a.{$mappingRelationFk} = b.{$model->getPk()} AND a.{$mappingCondition}"; + if(!empty($val['condition'])) { + $sql .= ' AND '.$val['condition']; + } + if(!empty($mappingOrder)) { + $sql .= ' ORDER BY '.$mappingOrder; + } + if(!empty($mappingLimit)) { + $sql .= ' LIMIT '.$mappingLimit; + } + $relationData = $this->query($sql); + if (!empty($val['relation_deep'])){ + foreach($relationData as $key=>$data){ + $model->getRelation($data,$val['relation_deep']); + $relationData[$key] = $data; + } + } + break; + } + if(!$return){ + if(isset($val['as_fields']) && in_array($mappingType,array(HAS_ONE,BELONGS_TO)) ) { + // 支持直接把关联的字段值映射成数据对象中的某个字段 + // 仅仅支持HAS_ONE BELONGS_TO + $fields = explode(',',$val['as_fields']); + foreach ($fields as $field){ + if(strpos($field,':')) { + list($relationName,$nick) = explode(':',$field); + $result[$nick] = $relationData[$relationName]; + }else{ + $result[$field] = $relationData[$field]; + } + } + }else{ + $result[$mappingName] = $relationData; + } + unset($relationData); + }else{ + return $relationData; + } + } + } + } + return $result; + } + + /** + * 操作关联数据 + * @access protected + * @param string $opType 操作方式 ADD SAVE DEL + * @param mixed $data 数据对象 + * @param string $name 关联名称 + * @return mixed + */ + protected function opRelation($opType,$data='',$name='') { + $result = false; + if(empty($data) && !empty($this->data)){ + $data = $this->data; + }elseif(!is_array($data)){ + // 数据无效返回 + return false; + } + if(!empty($this->_link)) { + // 遍历关联定义 + foreach($this->_link as $key=>$val) { + // 操作制定关联类型 + $mappingName = $val['mapping_name']?$val['mapping_name']:$key; // 映射名称 + if(empty($name) || true === $name || $mappingName == $name || (is_array($name) && in_array($mappingName,$name)) ) { + // 操作制定的关联 + $mappingType = !empty($val['mapping_type'])?$val['mapping_type']:$val; // 关联类型 + $mappingClass = !empty($val['class_name'])?$val['class_name']:$key; // 关联类名 + $mappingKey =!empty($val['mapping_key'])? $val['mapping_key'] : $this->getPk(); // 关联键名 + // 当前数据对象主键值 + $pk = $data[$mappingKey]; + if(strtoupper($mappingClass)==strtoupper($this->name)) { + // 自引用关联 获取父键名 + $mappingFk = !empty($val['parent_key'])? $val['parent_key'] : 'parent_id'; + }else{ + $mappingFk = !empty($val['foreign_key'])?$val['foreign_key']:strtolower($this->name).'_id'; // 关联外键 + } + if(!empty($val['condition'])) { + $mappingCondition = $val['condition']; + }else{ + $mappingCondition = array(); + $mappingCondition[$mappingFk] = $pk; + } + // 获取关联model对象 + $model = D($mappingClass); + $mappingData = isset($data[$mappingName])?$data[$mappingName]:false; + if(!empty($mappingData) || $opType == 'DEL') { + switch($mappingType) { + case HAS_ONE: + switch (strtoupper($opType)){ + case 'ADD': // 增加关联数据 + $mappingData[$mappingFk] = $pk; + $result = $model->add($mappingData); + break; + case 'SAVE': // 更新关联数据 + $result = $model->where($mappingCondition)->save($mappingData); + break; + case 'DEL': // 根据外键删除关联数据 + $result = $model->where($mappingCondition)->delete(); + break; + } + break; + case BELONGS_TO: + break; + case HAS_MANY: + switch (strtoupper($opType)){ + case 'ADD' : // 增加关联数据 + $model->startTrans(); + foreach ($mappingData as $val){ + $val[$mappingFk] = $pk; + $result = $model->add($val); + } + $model->commit(); + break; + case 'SAVE' : // 更新关联数据 + $model->startTrans(); + $pk = $model->getPk(); + foreach ($mappingData as $vo){ + if(isset($vo[$pk])) {// 更新数据 + $mappingCondition = "$pk ={$vo[$pk]}"; + $result = $model->where($mappingCondition)->save($vo); + }else{ // 新增数据 + $vo[$mappingFk] = $data[$mappingKey]; + $result = $model->add($vo); + } + } + $model->commit(); + break; + case 'DEL' : // 删除关联数据 + $result = $model->where($mappingCondition)->delete(); + break; + } + break; + case MANY_TO_MANY: + $mappingRelationFk = $val['relation_foreign_key']?$val['relation_foreign_key']:$model->getModelName().'_id';// 关联 + $mappingRelationTable = $val['relation_table']?$val['relation_table']:$this->getRelationTableName($model); + if(is_array($mappingData)) { + $ids = array(); + foreach ($mappingData as $vo) + $ids[] = $vo[$mappingKey]; + $relationId = implode(',',$ids); + } + switch (strtoupper($opType)){ + case 'ADD': // 增加关联数据 + case 'SAVE': // 更新关联数据 + if(isset($relationId)) { + $this->startTrans(); + // 删除关联表数据 + $this->table($mappingRelationTable)->where($mappingCondition)->delete(); + // 插入关联表数据 + $sql = 'INSERT INTO '.$mappingRelationTable.' ('.$mappingFk.','.$mappingRelationFk.') SELECT a.'.$this->getPk().',b.'.$model->getPk().' FROM '.$this->getTableName().' AS a ,'.$model->getTableName()." AS b where a.".$this->getPk().' ='. $pk.' AND b.'.$model->getPk().' IN ('.$relationId.") "; + $result = $model->execute($sql); + if(false !== $result) + // 提交事务 + $this->commit(); + else + // 事务回滚 + $this->rollback(); + } + break; + case 'DEL': // 根据外键删除中间表关联数据 + $result = $this->table($mappingRelationTable)->where($mappingCondition)->delete(); + break; + } + break; + } + if (!empty($val['relation_deep'])){ + $model->opRelation($opType,$mappingData,$val['relation_deep']); + } + } + } + } + } + return $result; + } + + /** + * 进行关联查询 + * @access public + * @param mixed $name 关联名称 + * @return Model + */ + public function relation($name) { + $this->options['link'] = $name; + return $this; + } + + /** + * 关联数据获取 仅用于查询后 + * @access public + * @param string $name 关联名称 + * @return array + */ + public function relationGet($name) { + if(empty($this->data)) + return false; + return $this->getRelation($this->data,$name,true); + } +} \ No newline at end of file diff --git a/ThinkPHP/Library/Think/Model/ViewModel.class.php b/ThinkPHP/Library/Think/Model/ViewModel.class.php new file mode 100644 index 000000000..abdf76aa3 --- /dev/null +++ b/ThinkPHP/Library/Think/Model/ViewModel.class.php @@ -0,0 +1,246 @@ + +// +---------------------------------------------------------------------- + +namespace Think\Model; +use Think\Model; +/** + * ThinkPHP视图模型扩展 + * @category Extend + * @package Extend + * @subpackage Model + * @author liu21st + */ +class ViewModel extends Model { + + protected $viewFields = array(); + + /** + * 自动检测数据表信息 + * @access protected + * @return void + */ + protected function _checkTableInfo() {} + + /** + * 得到完整的数据表名 + * @access public + * @return string + */ + public function getTableName() { + if(empty($this->trueTableName)) { + $tableName = ''; + foreach ($this->viewFields as $key=>$view){ + // 获取数据表名称 + if(isset($view['_table'])) { // 2011/10/17 添加实际表名定义支持 可以实现同一个表的视图 + $tableName .= $view['_table']; + }else{ + $class = $key.'Model'; + $Model = class_exists($class)?new $class():M($key); + $tableName .= $Model->getTableName(); + } + // 表别名定义 + $tableName .= !empty($view['_as'])?' '.$view['_as']:' '.$key; + // 支持ON 条件定义 + $tableName .= !empty($view['_on'])?' ON '.$view['_on']:''; + // 指定JOIN类型 例如 RIGHT INNER LEFT 下一个表有效 + $type = !empty($view['_type'])?$view['_type']:''; + $tableName .= ' '.strtoupper($type).' JOIN '; + $len = strlen($type.'_JOIN '); + } + $tableName = substr($tableName,0,-$len); + $this->trueTableName = $tableName; + } + return $this->trueTableName; + } + + /** + * 表达式过滤方法 + * @access protected + * @param string $options 表达式 + * @return void + */ + protected function _options_filter(&$options) { + if(isset($options['field'])) + $options['field'] = $this->checkFields($options['field']); + else + $options['field'] = $this->checkFields(); + if(isset($options['group'])) + $options['group'] = $this->checkGroup($options['group']); + if(isset($options['where'])) + $options['where'] = $this->checkCondition($options['where']); + if(isset($options['order'])) + $options['order'] = $this->checkOrder($options['order']); + } + + /** + * 检查是否定义了所有字段 + * @access protected + * @param string $name 模型名称 + * @param array $fields 字段数组 + * @return array + */ + private function _checkFields($name,$fields) { + if(false !== $pos = array_search('*',$fields)) {// 定义所有字段 + $fields = array_merge($fields,M($name)->getDbFields()); + unset($fields[$pos]); + } + return $fields; + } + + /** + * 检查条件中的视图字段 + * @access protected + * @param mixed $data 条件表达式 + * @return array + */ + protected function checkCondition($where) { + if(is_array($where)) { + $view = array(); + // 检查视图字段 + foreach ($this->viewFields as $key=>$val){ + $k = isset($val['_as'])?$val['_as']:$key; + $val = $this->_checkFields($key,$val); + foreach ($where as $name=>$value){ + if(false !== $field = array_search($name,$val,true)) { + // 存在视图字段 + $_key = is_numeric($field)? $k.'.'.$name : $k.'.'.$field; + $view[$_key] = $value; + unset($where[$name]); + } + } + } + $where = array_merge($where,$view); + } + return $where; + } + + /** + * 检查Order表达式中的视图字段 + * @access protected + * @param string $order 字段 + * @return string + */ + protected function checkOrder($order='') { + if(is_string($order) && !empty($order)) { + $orders = explode(',',$order); + $_order = array(); + foreach ($orders as $order){ + $array = explode(' ',$order); + $field = $array[0]; + $sort = isset($array[1])?$array[1]:'ASC'; + // 解析成视图字段 + foreach ($this->viewFields as $name=>$val){ + $k = isset($val['_as'])?$val['_as']:$name; + $val = $this->_checkFields($name,$val); + if(false !== $_field = array_search($field,$val,true)) { + // 存在视图字段 + $field = is_numeric($_field)?$k.'.'.$field:$k.'.'.$_field; + break; + } + } + $_order[] = $field.' '.$sort; + } + $order = implode(',',$_order); + } + return $order; + } + + /** + * 检查Group表达式中的视图字段 + * @access protected + * @param string $group 字段 + * @return string + */ + protected function checkGroup($group='') { + if(!empty($group)) { + $groups = explode(',',$group); + $_group = array(); + foreach ($groups as $field){ + // 解析成视图字段 + foreach ($this->viewFields as $name=>$val){ + $k = isset($val['_as'])?$val['_as']:$name; + $val = $this->_checkFields($name,$val); + if(false !== $_field = array_search($field,$val,true)) { + // 存在视图字段 + $field = is_numeric($_field)?$k.'.'.$field:$k.'.'.$_field; + break; + } + } + $_group[] = $field; + } + $group = implode(',',$_group); + } + return $group; + } + + /** + * 检查fields表达式中的视图字段 + * @access protected + * @param string $fields 字段 + * @return string + */ + protected function checkFields($fields='') { + if(empty($fields) || '*'==$fields ) { + // 获取全部视图字段 + $fields = array(); + foreach ($this->viewFields as $name=>$val){ + $k = isset($val['_as'])?$val['_as']:$name; + $val = $this->_checkFields($name,$val); + foreach ($val as $key=>$field){ + if(is_numeric($key)) { + $fields[] = $k.'.'.$field.' AS '.$field; + }elseif('_' != substr($key,0,1)) { + // 以_开头的为特殊定义 + if( false !== strpos($key,'*') || false !== strpos($key,'(') || false !== strpos($key,'.')) { + //如果包含* 或者 使用了sql方法 则不再添加前面的表名 + $fields[] = $key.' AS '.$field; + }else{ + $fields[] = $k.'.'.$key.' AS '.$field; + } + } + } + } + $fields = implode(',',$fields); + }else{ + if(!is_array($fields)) + $fields = explode(',',$fields); + // 解析成视图字段 + $array = array(); + foreach ($fields as $key=>$field){ + if(strpos($field,'(') || strpos(strtolower($field),' as ')){ + // 使用了函数或者别名 + $array[] = $field; + unset($fields[$key]); + } + } + foreach ($this->viewFields as $name=>$val){ + $k = isset($val['_as'])?$val['_as']:$name; + $val = $this->_checkFields($name,$val); + foreach ($fields as $key=>$field){ + if(false !== $_field = array_search($field,$val,true)) { + // 存在视图字段 + if(is_numeric($_field)) { + $array[] = $k.'.'.$field.' AS '.$field; + }elseif('_' != substr($_field,0,1)){ + if( false !== strpos($_field,'*') || false !== strpos($_field,'(') || false !== strpos($_field,'.')) + //如果包含* 或者 使用了sql方法 则不再添加前面的表名 + $array[] = $_field.' AS '.$field; + else + $array[] = $k.'.'.$_field.' AS '.$field; + } + } + } + } + $fields = implode(',',$array); + } + return $fields; + } +} \ No newline at end of file diff --git a/ThinkPHP/Library/Think/Page.class.php b/ThinkPHP/Library/Think/Page.class.php new file mode 100644 index 000000000..ac2f99235 --- /dev/null +++ b/ThinkPHP/Library/Think/Page.class.php @@ -0,0 +1,144 @@ + +// +---------------------------------------------------------------------- +namespace Think; + +class Page{ + public $firstRow; // 起始行数 + public $listRows; // 列表每页显示行数 + public $parameter; // 分页跳转时要带的参数 + public $totalRows; // 总行数 + public $totalPages; // 分页总页面数 + public $rollPage = 11;// 分页栏每页显示的页数 + public $lastSuffix = true; // 最后一页是否显示总页数 + + private $p = 'p'; //分页参数名 + private $url = ''; //当前链接URL + private $nowPage = 1; + + // 分页显示定制 + private $config = array( + 'header' => '共 %TOTAL_ROW% 条记录', + 'prev' => '<<', + 'next' => '>>', + 'first' => '1...', + 'last' => '...%TOTAL_PAGE%', + 'theme' => '%FIRST% %UP_PAGE% %LINK_PAGE% %DOWN_PAGE% %END%', + ); + + /** + * 架构函数 + * @param array $totalRows 总的记录数 + * @param array $listRows 每页显示记录数 + * @param array $parameter 分页跳转的参数 + */ + public function __construct($totalRows, $listRows, $parameter = array()) { + C('VAR_PAGE') && $this->p = C('VAR_PAGE'); //设置分页参数名称 + /* 基础设置 */ + $this->totalRows = $totalRows; //设置总记录数 + $this->listRows = $listRows; //设置每页显示行数 + $this->parameter = empty($parameter) ? $_GET : $parameter; + $this->nowPage = empty($_GET[$this->p]) ? 1 : intval($_GET[$this->p]); + $this->firstRow = $this->listRows * ($this->nowPage - 1); + } + + /** + * 定制分页链接设置 + * @param string $name 设置名称 + * @param string $value 设置值 + */ + public function setConfig($name,$value) { + if(isset($this->config[$name])) { + $this->config[$name] = $value; + } + } + + /** + * 生成链接URL + * @param integer $page 页码 + * @return string + */ + private function url($page){ + return str_replace(urlencode('[PAGE]'), $page, $this->url); + } + + /** + * 组装分页链接 + * @return string + */ + public function show() { + if(0 == $this->totalRows) return ''; + + /* 生成URL */ + $this->parameter[$this->p] = '[PAGE]'; + $this->url = U(ACTION_NAME, $this->parameter); + /* 计算分页信息 */ + $this->totalPages = ceil($this->totalRows / $this->listRows); //总页数 + if(!empty($this->totalPages) && $this->nowPage > $this->totalPages) { + $this->nowPage = $this->totalPages; + } + + /* 计算分页零时变量 */ + $now_cool_page = $this->rollPage/2; + $now_cool_page_ceil = ceil($now_cool_page); + $this->lastSuffix && $this->config['last'] = $this->totalPages; + + //上一页 + $up_row = $this->nowPage - 1; + $up_page = $up_row > 0 ? '' : ''; + + //下一页 + $down_row = $this->nowPage + 1; + $down_page = ($down_row <= $this->totalPages) ? '' : ''; + + //第一页 + $the_first = ''; + if($this->totalPages > $this->rollPage && ($this->nowPage - $now_cool_page) >= 1){ + $the_first = '' . $this->config['first'] . ''; + } + + //最后一页 + $the_end = ''; + if($this->totalPages > $this->rollPage && ($this->nowPage + $now_cool_page) < $this->totalPages){ + $the_end = '' . $this->config['last'] . ''; + } + + //数字连接 + $link_page = ""; + for($i = 1; $i <= $this->rollPage; $i++){ + if(($this->nowPage - $now_cool_page) <= 0 ){ + $page = $i; + }elseif(($this->nowPage + $now_cool_page - 1) >= $this->totalPages){ + $page = $this->totalPages - $this->rollPage + $i; + }else{ + $page = $this->nowPage - $now_cool_page_ceil + $i; + } + if($page > 0 && $page != $this->nowPage){ + + if($page <= $this->totalPages){ + $link_page .= '' . $page . ''; + }else{ + break; + } + }else{ + if($page > 0 && $this->totalPages != 1){ + $link_page .= '' . $page . ''; + } + } + } + + //替换分页内容 + $page_str = str_replace( + array('%HEADER%', '%NOW_PAGE%', '%UP_PAGE%', '%DOWN_PAGE%', '%FIRST%', '%LINK_PAGE%', '%END%', '%TOTAL_ROW%', '%TOTAL_PAGE%'), + array($this->config['header'], $this->nowPage, $up_page, $down_page, $the_first, $link_page, $the_end, $this->totalRows, $this->totalPages), + $this->config['theme']); + return "
{$page_str}
"; + } +} diff --git a/ThinkPHP/Library/Think/Route.class.php b/ThinkPHP/Library/Think/Route.class.php new file mode 100644 index 000000000..717b48683 --- /dev/null +++ b/ThinkPHP/Library/Think/Route.class.php @@ -0,0 +1,302 @@ + +// +---------------------------------------------------------------------- +namespace Think; +/** + * ThinkPHP路由解析类 + */ +class Route { + + // 路由检测 + public static function check(){ + $depr = C('URL_PATHINFO_DEPR'); + $regx = preg_replace('/\.'.__EXT__.'$/i','',trim($_SERVER['PATH_INFO'],$depr)); + // 分隔符替换 确保路由定义使用统一的分隔符 + if('/' != $depr){ + $regx = str_replace($depr,'/',$regx); + } + // URL映射定义(静态路由) + $maps = C('URL_MAP_RULES'); + if(isset($maps[$regx])) { + $var = self::parseUrl($maps[$regx]); + $_GET = array_merge($var, $_GET); + return true; + } + // 动态路由处理 + $routes = C('URL_ROUTE_RULES'); + if(!empty($routes)) { + foreach ($routes as $rule=>$route){ + if(is_numeric($rule)){ + // 支持 array('rule','adddress',...) 定义路由 + $rule = array_shift($route); + } + if(is_array($route) && isset($route[2])){ + // 路由参数 + $options = $route[2]; + if(isset($options['ext']) && __EXT__ != $options['ext']){ + // URL后缀检测 + continue; + } + if(isset($options['method']) && REQUEST_METHOD != $options['method']){ + // 请求类型检测 + continue; + } + // 自定义检测 + if(!empty($options['callback']) && is_callable($options['callback'])) { + if(false === call_user_func($options['callback'])) { + continue; + } + } + } + if(0===strpos($rule,'/') && preg_match($rule,$regx,$matches)) { // 正则路由 + if($route instanceof \Closure) { + // 执行闭包并中止 + self::invokeRegx($route, $matches); + exit; + } + return self::parseRegex($matches,$route,$regx); + }else{ // 规则路由 + $len1 = substr_count($regx,'/'); + $len2 = substr_count($rule,'/'); + if($len1>=$len2 || strpos($rule,'[')) { + if('$' == substr($rule,-1,1)) {// 完整匹配 + if($len1 != $len2) { + continue; + }else{ + $rule = substr($rule,0,-1); + } + } + $match = self::checkUrlMatch($regx,$rule); + if(false !== $match) { + if($route instanceof \Closure) { + // 执行闭包并中止 + self::invokeRule($route, $match); + exit; + } + return self::parseRule($rule,$route,$regx); + } + } + } + } + } + return false; + } + + // 检测URL和规则路由是否匹配 + private static function checkUrlMatch($regx,$rule) { + $m1 = explode('/',$regx); + $m2 = explode('/',$rule); + $var = array(); + foreach ($m2 as $key=>$val){ + if(0 === strpos($val,'[:')){ + $val = substr($val,1,-1); + } + + if(':' == substr($val,0,1)) {// 动态变量 + if($pos = strpos($val,'|')){ + // 使用函数过滤 + $val = substr($val,1,$pos-1); + } + if(strpos($val,'\\')) { + $type = substr($val,-1); + if('d'==$type) { + if(isset($m1[$key]) && !is_numeric($m1[$key])) + return false; + } + $name = substr($val, 1, -2); + }elseif($pos = strpos($val,'^')){ + $array = explode('|',substr(strstr($val,'^'),1)); + if(in_array($m1[$key],$array)) { + return false; + } + $name = substr($val, 1, $pos - 1); + }else{ + $name = substr($val, 1); + } + $var[$name] = isset($m1[$key])?$m1[$key]:''; + }elseif(0 !== strcasecmp($val,$m1[$key])){ + return false; + } + } + // 成功匹配后返回URL中的动态变量数组 + return $var; + } + + // 解析规范的路由地址 + // 地址格式 [控制器/操作?]参数1=值1&参数2=值2... + private static function parseUrl($url) { + $var = array(); + if(false !== strpos($url,'?')) { // [控制器/操作?]参数1=值1&参数2=值2... + $info = parse_url($url); + $path = explode('/',$info['path']); + parse_str($info['query'],$var); + }elseif(strpos($url,'/')){ // [控制器/操作] + $path = explode('/',$url); + }else{ // 参数1=值1&参数2=值2... + parse_str($url,$var); + } + if(isset($path)) { + $var[C('VAR_ACTION')] = array_pop($path); + if(!empty($path)) { + $var[C('VAR_CONTROLLER')] = array_pop($path); + } + if(!empty($path)) { + $var[C('VAR_MODULE')] = array_pop($path); + } + } + return $var; + } + + // 解析规则路由 + // '路由规则'=>'[控制器/操作]?额外参数1=值1&额外参数2=值2...' + // '路由规则'=>array('[控制器/操作]','额外参数1=值1&额外参数2=值2...') + // '路由规则'=>'外部地址' + // '路由规则'=>array('外部地址','重定向代码') + // 路由规则中 :开头 表示动态变量 + // 外部地址中可以用动态变量 采用 :1 :2 的方式 + // 'news/:month/:day/:id'=>array('News/read?cate=1','status=1'), + // 'new/:id'=>array('/new.php?id=:1',301), 重定向 + private static function parseRule($rule,$route,$regx) { + // 获取路由地址规则 + $url = is_array($route)?$route[0]:$route; + // 获取URL地址中的参数 + $paths = explode('/',$regx); + // 解析路由规则 + $matches = array(); + $rule = explode('/',$rule); + foreach ($rule as $item){ + $fun = ''; + if(0 === strpos($item,'[:')){ + $item = substr($item,1,-1); + } + if(0===strpos($item,':')) { // 动态变量获取 + if($pos = strpos($item,'|')){ + // 支持函数过滤 + $fun = substr($item,$pos+1); + $item = substr($item,0,$pos); + } + if($pos = strpos($item,'^') ) { + $var = substr($item,1,$pos-1); + }elseif(strpos($item,'\\')){ + $var = substr($item,1,-2); + }else{ + $var = substr($item,1); + } + $matches[$var] = !empty($fun)? $fun(array_shift($paths)) : array_shift($paths); + }else{ // 过滤URL中的静态变量 + array_shift($paths); + } + } + + if(0=== strpos($url,'/') || 0===strpos($url,'http')) { // 路由重定向跳转 + if(strpos($url,':')) { // 传递动态参数 + $values = array_values($matches); + $url = preg_replace_callback('/:(\d+)/', function($match) use($values){ return $values[$match[1] - 1]; }, $url); + } + header("Location: $url", true,(is_array($route) && isset($route[1]))?$route[1]:301); + exit; + }else{ + // 解析路由地址 + $var = self::parseUrl($url); + // 解析路由地址里面的动态参数 + $values = array_values($matches); + foreach ($var as $key=>$val){ + if(0===strpos($val,':')) { + $var[$key] = $values[substr($val,1)-1]; + } + } + $var = array_merge($matches,$var); + // 解析剩余的URL参数 + if(!empty($paths)) { + preg_replace_callback('/(\w+)\/([^\/]+)/', function($match) use(&$var){ $var[strtolower($match[1])]=strip_tags($match[2]);}, implode('/',$paths)); + } + // 解析路由自动传入参数 + if(is_array($route) && isset($route[1])) { + parse_str($route[1],$params); + $var = array_merge($var,$params); + } + $_GET = array_merge($var,$_GET); + } + return true; + } + + // 解析正则路由 + // '路由正则'=>'[控制器/操作]?参数1=值1&参数2=值2...' + // '路由正则'=>array('[控制器/操作]?参数1=值1&参数2=值2...','额外参数1=值1&额外参数2=值2...') + // '路由正则'=>'外部地址' + // '路由正则'=>array('外部地址','重定向代码') + // 参数值和外部地址中可以用动态变量 采用 :1 :2 的方式 + // '/new\/(\d+)\/(\d+)/'=>array('News/read?id=:1&page=:2&cate=1','status=1'), + // '/new\/(\d+)/'=>array('/new.php?id=:1&page=:2&status=1','301'), 重定向 + private static function parseRegex($matches,$route,$regx) { + // 获取路由地址规则 + $url = is_array($route)?$route[0]:$route; + $url = preg_replace_callback('/:(\d+)/', function($match) use($matches){return $matches[$match[1]];}, $url); + if(0=== strpos($url,'/') || 0===strpos($url,'http')) { // 路由重定向跳转 + header("Location: $url", true,(is_array($route) && isset($route[1]))?$route[1]:301); + exit; + }else{ + // 解析路由地址 + $var = self::parseUrl($url); + // 解析剩余的URL参数 + $regx = substr_replace($regx,'',0,strlen($matches[0])); + if($regx) { + preg_replace_callback('/(\w+)\/([^\/]+)/', function($match) use(&$var){ + if(strpos($match[2],'|')){ + list($val,$fun) = explode('|',$match[2]); + $val = $fun($val); + }else{ + $val = $match[2]; + } + $var[strtolower($match[1])] = strip_tags($val); + }, $regx); + } + // 解析路由自动传入参数 + if(is_array($route) && isset($route[1])) { + parse_str($route[1],$params); + $var = array_merge($var,$params); + } + $_GET = array_merge($var,$_GET); + } + return true; + } + + // 执行正则匹配下的闭包方法 支持参数调用 + static private function invokeRegx($closure, $var = array()) { + $reflect = new \ReflectionFunction($closure); + $params = $reflect->getParameters(); + $args = array(); + array_shift($var); + foreach ($params as $param){ + if(!empty($var)) { + $args[] = array_shift($var); + }elseif($param->isDefaultValueAvailable()){ + $args[] = $param->getDefaultValue(); + } + } + $reflect->invokeArgs($args); + } + + // 执行规则匹配下的闭包方法 支持参数调用 + static private function invokeRule($closure, $var = array()) { + $reflect = new \ReflectionFunction($closure); + $params = $reflect->getParameters(); + $args = array(); + foreach ($params as $param){ + $name = $param->getName(); + if(isset($var[$name])) { + $args[] = $var[$name]; + }elseif($param->isDefaultValueAvailable()){ + $args[] = $param->getDefaultValue(); + } + } + $reflect->invokeArgs($args); + } +} \ No newline at end of file diff --git a/ThinkPHP/Library/Think/Session/Driver/Db.class.php b/ThinkPHP/Library/Think/Session/Driver/Db.class.php new file mode 100644 index 000000000..4c9bbbec7 --- /dev/null +++ b/ThinkPHP/Library/Think/Session/Driver/Db.class.php @@ -0,0 +1,184 @@ + +// +---------------------------------------------------------------------- +namespace Think\Session\Driver; +/** + * 数据库方式Session驱动 + * CREATE TABLE think_session ( + * session_id varchar(255) NOT NULL, + * session_expire int(11) NOT NULL, + * session_data blob, + * UNIQUE KEY `session_id` (`session_id`) + * ); + */ +class Db { + + /** + * Session有效时间 + */ + protected $lifeTime = ''; + + /** + * session保存的数据库名 + */ + protected $sessionTable = ''; + + /** + * 数据库句柄 + */ + protected $hander = array(); + + /** + * 打开Session + * @access public + * @param string $savePath + * @param mixed $sessName + */ + public function open($savePath, $sessName) { + $this->lifeTime = C('SESSION_EXPIRE')?C('SESSION_EXPIRE'):ini_get('session.gc_maxlifetime'); + $this->sessionTable = C('SESSION_TABLE')?C('SESSION_TABLE'):C("DB_PREFIX")."session"; + //分布式数据库 + $host = explode(',',C('DB_HOST')); + $port = explode(',',C('DB_PORT')); + $name = explode(',',C('DB_NAME')); + $user = explode(',',C('DB_USER')); + $pwd = explode(',',C('DB_PWD')); + if(1 == C('DB_DEPLOY_TYPE')){ + //读写分离 + if(C('DB_RW_SEPARATE')){ + $w = floor(mt_rand(0,C('DB_MASTER_NUM')-1)); + if(is_numeric(C('DB_SLAVE_NO'))){//指定服务器读 + $r = C('DB_SLAVE_NO'); + }else{ + $r = floor(mt_rand(C('DB_MASTER_NUM'),count($host)-1)); + } + //主数据库链接 + $hander = mysql_connect( + $host[$w].(isset($port[$w])?':'.$port[$w]:':'.$port[0]), + isset($user[$w])?$user[$w]:$user[0], + isset($pwd[$w])?$pwd[$w]:$pwd[0] + ); + $dbSel = mysql_select_db( + isset($name[$w])?$name[$w]:$name[0] + ,$hander); + if(!$hander || !$dbSel) + return false; + $this->hander[0] = $hander; + //从数据库链接 + $hander = mysql_connect( + $host[$r].(isset($port[$r])?':'.$port[$r]:':'.$port[0]), + isset($user[$r])?$user[$r]:$user[0], + isset($pwd[$r])?$pwd[$r]:$pwd[0] + ); + $dbSel = mysql_select_db( + isset($name[$r])?$name[$r]:$name[0] + ,$hander); + if(!$hander || !$dbSel) + return false; + $this->hander[1] = $hander; + return true; + } + } + //从数据库链接 + $r = floor(mt_rand(0,count($host)-1)); + $hander = mysql_connect( + $host[$r].(isset($port[$r])?':'.$port[$r]:':'.$port[0]), + isset($user[$r])?$user[$r]:$user[0], + isset($pwd[$r])?$pwd[$r]:$pwd[0] + ); + $dbSel = mysql_select_db( + isset($name[$r])?$name[$r]:$name[0] + ,$hander); + if(!$hander || !$dbSel) + return false; + $this->hander = $hander; + return true; + } + + /** + * 关闭Session + * @access public + */ + public function close() { + if(is_array($this->hander)){ + $this->gc($this->lifeTime); + return (mysql_close($this->hander[0]) && mysql_close($this->hander[1])); + } + $this->gc($this->lifeTime); + return mysql_close($this->hander); + } + + /** + * 读取Session + * @access public + * @param string $sessID + */ + public function read($sessID) { + $hander = is_array($this->hander)?$this->hander[1]:$this->hander; + $res = mysql_query("SELECT session_data AS data FROM ".$this->sessionTable." WHERE session_id = '$sessID' AND session_expire >".time(),$hander); + if($res) { + $row = mysql_fetch_assoc($res); + return $row['data']; + } + return ""; + } + + /** + * 写入Session + * @access public + * @param string $sessID + * @param String $sessData + */ + public function write($sessID,$sessData) { + $hander = is_array($this->hander)?$this->hander[0]:$this->hander; + $expire = time() + $this->lifeTime; + mysql_query("REPLACE INTO ".$this->sessionTable." ( session_id, session_expire, session_data) VALUES( '$sessID', '$expire', '$sessData')",$hander); + if(mysql_affected_rows($hander)) + return true; + return false; + } + + /** + * 删除Session + * @access public + * @param string $sessID + */ + public function destroy($sessID) { + $hander = is_array($this->hander)?$this->hander[0]:$this->hander; + mysql_query("DELETE FROM ".$this->sessionTable." WHERE session_id = '$sessID'",$hander); + if(mysql_affected_rows($hander)) + return true; + return false; + } + + /** + * Session 垃圾回收 + * @access public + * @param string $sessMaxLifeTime + */ + public function gc($sessMaxLifeTime) { + $hander = is_array($this->hander)?$this->hander[0]:$this->hander; + mysql_query("DELETE FROM ".$this->sessionTable." WHERE session_expire < ".time(),$hander); + return mysql_affected_rows($hander); + } + + /** + * 打开Session + * @access public + */ + public function execute() { + session_set_save_handler(array(&$this,"open"), + array(&$this,"close"), + array(&$this,"read"), + array(&$this,"write"), + array(&$this,"destroy"), + array(&$this,"gc")); + } +} \ No newline at end of file diff --git a/ThinkPHP/Library/Think/Storage.class.php b/ThinkPHP/Library/Think/Storage.class.php new file mode 100644 index 000000000..070c65d83 --- /dev/null +++ b/ThinkPHP/Library/Think/Storage.class.php @@ -0,0 +1,45 @@ + +// +---------------------------------------------------------------------- +namespace Think; +// 分布式文件存储类 +class Storage { + + /** + * 操作句柄 + * @var string + * @access protected + */ + static protected $handler ; + + /** + * 连接分布式文件系统 + * @access public + * @param string $type 文件类型 + * @param array $options 配置数组 + * @return void + */ + static public function connect($type,$options=array()) { + $class = 'Think\\Storage\\Driver\\'.ucwords($type); + self::$handler = new $class($options); + } + + static public function __callstatic($method,$args){ + $type=end($args); + $method_type=$method.ucfirst($type); + if(method_exists(self::$handler, $method_type)){ + return call_user_func_array(array(self::$handler,$method_type), $args); + } + //调用缓存类型自己的方法 + if(method_exists(self::$handler, $method)){ + return call_user_func_array(array(self::$handler,$method), $args); + } + } +} diff --git a/ThinkPHP/Library/Think/Storage/Driver/File.class.php b/ThinkPHP/Library/Think/Storage/Driver/File.class.php new file mode 100644 index 000000000..5bfc7fb74 --- /dev/null +++ b/ThinkPHP/Library/Think/Storage/Driver/File.class.php @@ -0,0 +1,121 @@ + +// +---------------------------------------------------------------------- +namespace Think\Storage\Driver; +use Think\Storage; +// 本地文件写入存储类 +class File extends Storage{ + + private $contents=array(); + + /** + * 架构函数 + * @access public + */ + public function __construct() { + } + + /** + * 文件内容读取 + * @access public + * @param string $filename 文件名 + * @return string + */ + public function read($filename,$type=''){ + return $this->get($filename,'content',$type); + } + + /** + * 文件写入 + * @access public + * @param string $filename 文件名 + * @param string $content 文件内容 + * @return boolean + */ + public function put($filename,$content,$type=''){ + $dir = dirname($filename); + if(!is_dir($dir)) + mkdir($dir,0755,true); + if(false === file_put_contents($filename,$content)){ + E(L('_STORAGE_WRITE_ERROR_').':'.$filename); + }else{ + $this->contents[$filename]=$content; + return true; + } + } + + /** + * 文件追加写入 + * @access public + * @param string $filename 文件名 + * @param string $content 追加的文件内容 + * @return boolean + */ + public function append($filename,$content,$type=''){ + if(is_file($filename)){ + $content = $this->read($filename,$type).$content; + } + return $this->put($filename,$content,$type); + } + + /** + * 加载文件 + * @access public + * @param string $filename 文件名 + * @param array $vars 传入变量 + * @return void + */ + public function load($filename,$vars=null,$type=''){ + if(!is_null($vars)) + extract($vars, EXTR_OVERWRITE); + include $filename; + } + + /** + * 文件是否存在 + * @access public + * @param string $filename 文件名 + * @return boolean + */ + public function has($filename,$type=''){ + return file_exists($filename); + } + + /** + * 文件删除 + * @access public + * @param string $filename 文件名 + * @return boolean + */ + public function unlink($filename,$type=''){ + unset($this->contents[$filename]); + return file_exists($filename) ? unlink($filename) : false; + } + + /** + * 读取文件信息 + * @access public + * @param string $filename 文件名 + * @param string $name 信息名 mtime或者content + * @return boolean + */ + public function get($filename,$name,$type=''){ + if(!isset($this->contents[$filename])){ + if(!is_file($filename)) return false; + $this->contents[$filename]=file_get_contents($filename); + } + $content=$this->contents[$filename]; + $info = array( + 'mtime' => filemtime($filename), + 'content' => $content + ); + return $info[$name]; + } +} diff --git a/ThinkPHP/Library/Think/Storage/Driver/Sae.class.php b/ThinkPHP/Library/Think/Storage/Driver/Sae.class.php new file mode 100644 index 000000000..8cfbd2b16 --- /dev/null +++ b/ThinkPHP/Library/Think/Storage/Driver/Sae.class.php @@ -0,0 +1,246 @@ + +// +---------------------------------------------------------------------- +namespace Think\Storage\Driver; +use Think\Storage; +// SAE环境文件写入存储类 +class Sae extends Storage{ + + /** + * 架构函数 + * @access public + */ + private $mc; + private $kvs = array(); + private $htmls = array(); + private $contents = array(); + public function __construct() { + if(!function_exists('memcache_init')){ + header('Content-Type:text/html;charset=utf-8'); + exit('请在SAE平台上运行代码。'); + } + $this->mc = @memcache_init(); + if(!$this->mc){ + header('Content-Type:text/html;charset=utf-8'); + exit('您未开通Memcache服务,请在SAE管理平台初始化Memcache服务'); + } + } + + /** + * 获得SaeKv对象 + */ + + public function getKv(){ + static $kv; + if(!$kv){ + $kv = new \SaeKV(); + if(!$kv->init()) + E('您没有初始化KVDB,请在SAE管理平台初始化KVDB服务'); + } + return $kv; + } + + + /** + * 文件内容读取 + * @access public + * @param string $filename 文件名 + * @return string + */ + public function read($filename,$type=''){ + return $this->get($filename,'content',$type); + } + + public function readHtml($filename,$type=''){ + return $this->getHtml($filename,'content'); + } + + /** + * 读取F缓存 + * + * @param mixed $filename + * @access public + * @return void + */ + public function readF($filename){ + $kv=$this->getKv(); + if(!isset($this->kvs[$filename])){ + $this->kvs[$filename]=$kv->get($filename); + } + return $this->kvs[$filename]; + } + + + /** + * 文件写入 + * @access public + * @param string $filename 文件名 + * @param string $content 文件内容 + * @return boolean + */ + public function put($filename,$content,$type=''){ + $content = time().$content; + if(!$this->mc->set($filename,$content,MEMCACHE_COMPRESSED,0)){ + E(L('_STORAGE_WRITE_ERROR_').':'.$filename); + }else{ + $this->contents[$filename] = $content; + return true; + } + } + + /** + * 写入html静态缓存 + * + * @param mixed $filename + * @param mixed $content + * @access public + * @return void + */ + public function putHtml($filename,$content){ + $kv = $this->getKv(); + $content = time().$content; + $this->htmls[$filename] = $content; + return $kv->set($filename,$content); + } + + /** + * F函数写入缓存 + * + * @param mixed $filename + * @param mixed $content + * @access public + * @return void + */ + public function putF($filename,$content){ + $kv = $this->getKv(); + $this->kvs[$filename] = $content; + return $kv->set($filename,$content); + } + + /** + * 文件追加写入 + * @access public + * @param string $filename 文件名 + * @param string $content 追加的文件内容 + * @return boolean + */ + public function append($filename,$content,$type=''){ + if($old_content = $this->read($filename,$type)){ + $content = $old_content.$content; + } + return $this->put($filename,$content,$type); + } + + /** + * 加载文件 + * @access public + * @param string $filename 文件名 + * @param array $vars 传入变量 + * @return void + */ + public function load($filename,$vars=null){ + if(!is_null($vars)) + extract($vars, EXTR_OVERWRITE); + eval('?>'.$this->read($filename)); + } + + /** + * 文件是否存在 + * @access public + * @param string $filename 文件名 + * @return boolean + */ + public function has($filename,$type=''){ + if($this->read($filename,$type)){ + return true; + }else{ + return false; + } + } + + /** + * F函数,判断是否存在key + * + * @param mixed $filename + * @access public + * @return void + */ + public function hasF($filename){ + if(false!==$this->readF($filename)){ + return true; + } + return false; + } + + /** + * 文件删除 + * @access public + * @param string $filename 文件名 + * @return boolean + */ + public function unlink($filename,$type=''){ + unset($this->contents[$filename]); + return $this->mc->delete($filename); + } + + public function unlinkF($filename){ + $kv=$this->getKv(); + unset($this->kvs[$filename]); + return $kv->delete($filename); + } + + /** + * 读取文件信息 + * @access public + * @param string $filename 文件名 + * @param string $name 信息名 mtime或者content + * @return boolean + */ + public function get($filename,$name,$type=''){ + if(!isset($this->contents[$filename])){ + $this->contents[$filename] = $this->mc->get($filename); + } + $content = $this->contents[$filename]; + if(false===$content){ + return false; + } + $info = array( + 'mtime' => substr($content,0,10), + 'content' => substr($content,10) + ); + return $info[$name]; + } + + + /** + * 读取html静态缓存 + * + * @param string $filename + * @param string $name + * @access public + * @return void + */ + public function getHtml($filename,$name){ + if(!isset($this->htmls[$filename])){ + $kv = $this->getKv(); + $this->htmls[$filename] = $kv->get($filename); + } + $content = $this->htmls[$filename]; + if(false===$content){ + return false; + } + $info = array( + 'mtime' => substr($content,0,10), + 'content' => substr($content,10) + ); + return $info[$name]; + } + +} diff --git a/ThinkPHP/Lib/Template/ThinkTemplate.class.php b/ThinkPHP/Library/Think/Template.class.php similarity index 80% rename from ThinkPHP/Lib/Template/ThinkTemplate.class.php rename to ThinkPHP/Library/Think/Template.class.php index 8fb2be546..8b945b7f5 100644 --- a/ThinkPHP/Lib/Template/ThinkTemplate.class.php +++ b/ThinkPHP/Library/Think/Template.class.php @@ -1,699 +1,700 @@ - -// +---------------------------------------------------------------------- - -/** - * ThinkPHP内置模板引擎类 - * 支持XML标签和普通标签的模板解析 - * 编译型模板引擎 支持动态缓存 - * @category Think - * @package Think - * @subpackage Template - * @author liu21st - */ -class ThinkTemplate { - - // 模板页面中引入的标签库列表 - protected $tagLib = array(); - // 当前模板文件 - protected $templateFile = ''; - // 模板变量 - public $tVar = array(); - public $config = array(); - private $literal = array(); - private $block = array(); - - /** - * 架构函数 - * @access public - */ - public function __construct(){ - $this->config['cache_path'] = C('CACHE_PATH'); - $this->config['template_suffix'] = C('TMPL_TEMPLATE_SUFFIX'); - $this->config['cache_suffix'] = C('TMPL_CACHFILE_SUFFIX'); - $this->config['tmpl_cache'] = C('TMPL_CACHE_ON'); - $this->config['cache_time'] = C('TMPL_CACHE_TIME'); - $this->config['taglib_begin'] = $this->stripPreg(C('TAGLIB_BEGIN')); - $this->config['taglib_end'] = $this->stripPreg(C('TAGLIB_END')); - $this->config['tmpl_begin'] = $this->stripPreg(C('TMPL_L_DELIM')); - $this->config['tmpl_end'] = $this->stripPreg(C('TMPL_R_DELIM')); - $this->config['default_tmpl'] = C('TEMPLATE_NAME'); - $this->config['layout_item'] = C('TMPL_LAYOUT_ITEM'); - } - - private function stripPreg($str) { - return str_replace( - array('{','}','(',')','|','[',']','-','+','*','.','^','?'), - array('\{','\}','\(','\)','\|','\[','\]','\-','\+','\*','\.','\^','\?'), - $str); - } - - // 模板变量获取和设置 - public function get($name) { - if(isset($this->tVar[$name])) - return $this->tVar[$name]; - else - return false; - } - - public function set($name,$value) { - $this->tVar[$name]= $value; - } - - /** - * 加载模板 - * @access public - * @param string $tmplTemplateFile 模板文件 - * @param array $templateVar 模板变量 - * @param string $prefix 模板标识前缀 - * @return void - */ - public function fetch($templateFile,$templateVar,$prefix='') { - $this->tVar = $templateVar; - $templateCacheFile = $this->loadTemplate($templateFile,$prefix); - // 模板阵列变量分解成为独立变量 - extract($templateVar, EXTR_OVERWRITE); - //载入模版缓存文件 - include $templateCacheFile; - } - - /** - * 加载主模板并缓存 - * @access public - * @param string $tmplTemplateFile 模板文件 - * @param string $prefix 模板标识前缀 - * @return string - * @throws ThinkExecption - */ - public function loadTemplate ($tmplTemplateFile,$prefix='') { - if(is_file($tmplTemplateFile)) { - $this->templateFile = $tmplTemplateFile; - // 读取模板文件内容 - $tmplContent = file_get_contents($tmplTemplateFile); - }else{ - $tmplContent = $tmplTemplateFile; - } - // 根据模版文件名定位缓存文件 - $tmplCacheFile = $this->config['cache_path'].$prefix.md5($tmplTemplateFile).$this->config['cache_suffix']; - - // 判断是否启用布局 - if(C('LAYOUT_ON')) { - if(false !== strpos($tmplContent,'{__NOLAYOUT__}')) { // 可以单独定义不使用布局 - $tmplContent = str_replace('{__NOLAYOUT__}','',$tmplContent); - }else{ // 替换布局的主体内容 - $layoutFile = THEME_PATH.C('LAYOUT_NAME').$this->config['template_suffix']; - $tmplContent = str_replace($this->config['layout_item'],$tmplContent,file_get_contents($layoutFile)); - } - } - // 编译模板内容 - $tmplContent = $this->compiler($tmplContent); - // 检测模板目录 - $dir = dirname($tmplCacheFile); - if(!is_dir($dir)) - mkdir($dir,0755,true); - //重写Cache文件 - if( false === file_put_contents($tmplCacheFile,trim($tmplContent))) - throw_exception(L('_CACHE_WRITE_ERROR_').':'.$tmplCacheFile); - return $tmplCacheFile; - } - - /** - * 编译模板文件内容 - * @access protected - * @param mixed $tmplContent 模板内容 - * @return string - */ - protected function compiler($tmplContent) { - //模板解析 - $tmplContent = $this->parse($tmplContent); - // 还原被替换的Literal标签 - $tmplContent = preg_replace('//eis',"\$this->restoreLiteral('\\1')",$tmplContent); - // 添加安全代码 - $tmplContent = ''.$tmplContent; - if(C('TMPL_STRIP_SPACE')) { - /* 去除html空格与换行 */ - $find = array('~>\s+<~','~>(\s+\n|\r)~'); - $replace = array('><','>'); - $tmplContent = preg_replace($find, $replace, $tmplContent); - } - // 优化生成的php代码 - $tmplContent = str_replace('?>config['taglib_begin']; - $end = $this->config['taglib_end']; - // 检查include语法 - $content = $this->parseInclude($content); - // 检查PHP语法 - $content = $this->parsePhp($content); - // 首先替换literal标签内容 - $content = preg_replace('/'.$begin.'literal'.$end.'(.*?)'.$begin.'\/literal'.$end.'/eis',"\$this->parseLiteral('\\1')",$content); - - // 获取需要引入的标签库列表 - // 标签库只需要定义一次,允许引入多个一次 - // 一般放在文件的最前面 - // 格式: - // 当TAGLIB_LOAD配置为true时才会进行检测 - if(C('TAGLIB_LOAD')) { - $this->getIncludeTagLib($content); - if(!empty($this->tagLib)) { - // 对导入的TagLib进行解析 - foreach($this->tagLib as $tagLibName) { - $this->parseTagLib($tagLibName,$content); - } - } - } - // 预先加载的标签库 无需在每个模板中使用taglib标签加载 但必须使用标签库XML前缀 - if(C('TAGLIB_PRE_LOAD')) { - $tagLibs = explode(',',C('TAGLIB_PRE_LOAD')); - foreach ($tagLibs as $tag){ - $this->parseTagLib($tag,$content); - } - } - // 内置标签库 无需使用taglib标签导入就可以使用 并且不需使用标签库XML前缀 - $tagLibs = explode(',',C('TAGLIB_BUILD_IN')); - foreach ($tagLibs as $tag){ - $this->parseTagLib($tag,$content,true); - } - //解析普通模板标签 {tagName} - $content = preg_replace('/('.$this->config['tmpl_begin'].')([^\d\s'.$this->config['tmpl_begin'].$this->config['tmpl_end'].'].+?)('.$this->config['tmpl_end'].')/eis',"\$this->parseTag('\\2')",$content); - return $content; - } - - // 检查PHP语法 - protected function parsePhp($content) { - if(ini_get('short_open_tag')){ - // 开启短标签的情况要将'."\n", $content ); - } - // PHP语法检查 - if(C('TMPL_DENY_PHP') && false !== strpos($content,'config['taglib_begin'].'layout\s(.+?)\s*?\/'.$this->config['taglib_end'].'/is',$content,$matches); - if($find) { - //替换Layout标签 - $content = str_replace($matches[0],'',$content); - //解析Layout标签 - $array = $this->parseXmlAttrs($matches[1]); - if(!C('LAYOUT_ON') || C('LAYOUT_NAME') !=$array['name'] ) { - // 读取布局模板 - $layoutFile = THEME_PATH.$array['name'].$this->config['template_suffix']; - $replace = isset($array['replace'])?$array['replace']:$this->config['layout_item']; - // 替换布局的主体内容 - $content = str_replace($replace,$content,file_get_contents($layoutFile)); - } - }else{ - $content = str_replace('{__NOLAYOUT__}','',$content); - } - return $content; - } - - // 解析模板中的include标签 - protected function parseInclude($content) { - // 解析继承 - $content = $this->parseExtend($content); - // 解析布局 - $content = $this->parseLayout($content); - // 读取模板中的include标签 - $find = preg_match_all('/'.$this->config['taglib_begin'].'include\s(.+?)\s*?\/'.$this->config['taglib_end'].'/is',$content,$matches); - if($find) { - for($i=0;$i<$find;$i++) { - $include = $matches[1][$i]; - $array = $this->parseXmlAttrs($include); - $file = $array['file']; - unset($array['file']); - $content = str_replace($matches[0][$i],$this->parseIncludeItem($file,$array),$content); - } - } - return $content; - } - - // 解析模板中的extend标签 - protected function parseExtend($content) { - $begin = $this->config['taglib_begin']; - $end = $this->config['taglib_end']; - // 读取模板中的继承标签 - $find = preg_match('/'.$begin.'extend\s(.+?)\s*?\/'.$end.'/is',$content,$matches); - if($find) { - //替换extend标签 - $content = str_replace($matches[0],'',$content); - // 记录页面中的block标签 - preg_replace('/'.$begin.'block\sname=(.+?)\s*?'.$end.'(.*?)'.$begin.'\/block'.$end.'/eis',"\$this->parseBlock('\\1','\\2')",$content); - // 读取继承模板 - $array = $this->parseXmlAttrs($matches[1]); - $content = $this->parseTemplateName($array['name']); - // 替换block标签 - $content = preg_replace('/'.$begin.'block\sname=(.+?)\s*?'.$end.'(.*?)'.$begin.'\/block'.$end.'/eis',"\$this->replaceBlock('\\1','\\2')",$content); - }else{ - $content = preg_replace('/'.$begin.'block\sname=(.+?)\s*?'.$end.'(.*?)'.$begin.'\/block'.$end.'/eis',"stripslashes('\\2')",$content); - } - return $content; - } - - /** - * 分析XML属性 - * @access private - * @param string $attrs XML属性字符串 - * @return array - */ - private function parseXmlAttrs($attrs) { - $xml = ''; - $xml = simplexml_load_string($xml); - if(!$xml) - throw_exception(L('_XML_TAG_ERROR_')); - $xml = (array)($xml->tag->attributes()); - $array = array_change_key_case($xml['@attributes']); - return $array; - } - - /** - * 替换页面中的literal标签 - * @access private - * @param string $content 模板内容 - * @return string|false - */ - private function parseLiteral($content) { - if(trim($content)=='') return ''; - $content = stripslashes($content); - $i = count($this->literal); - $parseStr = ""; - $this->literal[$i] = $content; - return $parseStr; - } - - /** - * 还原被替换的literal标签 - * @access private - * @param string $tag literal标签序号 - * @return string|false - */ - private function restoreLiteral($tag) { - // 还原literal标签 - $parseStr = $this->literal[$tag]; - // 销毁literal记录 - unset($this->literal[$tag]); - return $parseStr; - } - - /** - * 记录当前页面中的block标签 - * @access private - * @param string $name block名称 - * @param string $content 模板内容 - * @return string - */ - private function parseBlock($name,$content) { - $this->block[$name] = $content; - return ''; - } - - /** - * 替换继承模板中的block标签 - * @access private - * @param string $name block名称 - * @param string $content 模板内容 - * @return string - */ - private function replaceBlock($name,$content) { - // 替换block标签 没有重新定义则使用原来的 - $replace = isset($this->block[$name])? $this->block[$name] : $content; - return stripslashes($replace); - } - - /** - * 搜索模板页面中包含的TagLib库 - * 并返回列表 - * @access public - * @param string $content 模板内容 - * @return string|false - */ - public function getIncludeTagLib(& $content) { - //搜索是否有TagLib标签 - $find = preg_match('/'.$this->config['taglib_begin'].'taglib\s(.+?)(\s*?)\/'.$this->config['taglib_end'].'\W/is',$content,$matches); - if($find) { - //替换TagLib标签 - $content = str_replace($matches[0],'',$content); - //解析TagLib标签 - $array = $this->parseXmlAttrs($matches[1]); - $this->tagLib = explode(',',$array['name']); - } - return; - } - - /** - * TagLib库解析 - * @access public - * @param string $tagLib 要解析的标签库 - * @param string $content 要解析的模板内容 - * @param boolen $hide 是否隐藏标签库前缀 - * @return string - */ - public function parseTagLib($tagLib,&$content,$hide=false) { - $begin = $this->config['taglib_begin']; - $end = $this->config['taglib_end']; - $className = 'TagLib'.ucwords($tagLib); - $tLib = Think::instance($className); - foreach ($tLib->getTags() as $name=>$val){ - $tags = array($name); - if(isset($val['alias'])) {// 别名设置 - $tags = explode(',',$val['alias']); - $tags[] = $name; - } - $level = isset($val['level'])?$val['level']:1; - $closeTag = isset($val['close'])?$val['close']:true; - foreach ($tags as $tag){ - $parseTag = !$hide? $tagLib.':'.$tag: $tag;// 实际要解析的标签名称 - if(!method_exists($tLib,'_'.$tag)) { - // 别名可以无需定义解析方法 - $tag = $name; - } - $n1 = empty($val['attr'])?'(\s*?)':'\s([^'.$end.']*)'; - if (!$closeTag){ - $patterns = '/'.$begin.$parseTag.$n1.'\/(\s*?)'.$end.'/eis'; - $replacement = "\$this->parseXmlTag('$tagLib','$tag','$1','')"; - $content = preg_replace($patterns, $replacement,$content); - }else{ - $patterns = '/'.$begin.$parseTag.$n1.$end.'(.*?)'.$begin.'\/'.$parseTag.'(\s*?)'.$end.'/eis'; - $replacement = "\$this->parseXmlTag('$tagLib','$tag','$1','$2')"; - for($i=0;$i<$level;$i++) - $content=preg_replace($patterns,$replacement,$content); - } - } - } - } - - /** - * 解析标签库的标签 - * 需要调用对应的标签库文件解析类 - * @access public - * @param string $tagLib 标签库名称 - * @param string $tag 标签名 - * @param string $attr 标签属性 - * @param string $content 标签内容 - * @return string|false - */ - public function parseXmlTag($tagLib,$tag,$attr,$content) { - //if (MAGIC_QUOTES_GPC) { - $attr = stripslashes($attr); - $content= stripslashes($content); - //} - if(ini_get('magic_quotes_sybase')) - $attr = str_replace('\"','\'',$attr); - $tLib = Think::instance('TagLib'.ucwords(strtolower($tagLib))); - $parse = '_'.$tag; - $content = trim($content); - return $tLib->$parse($attr,$content); - } - - /** - * 模板标签解析 - * 格式: {TagName:args [|content] } - * @access public - * @param string $tagStr 标签内容 - * @return string - */ - public function parseTag($tagStr){ - //if (MAGIC_QUOTES_GPC) { - $tagStr = stripslashes($tagStr); - //} - //还原非模板标签 - if(preg_match('/^[\s|\d]/is',$tagStr)) - //过滤空格和数字打头的标签 - return C('TMPL_L_DELIM') . $tagStr .C('TMPL_R_DELIM'); - $flag = substr($tagStr,0,1); - $flag2 = substr($tagStr,1,1); - $name = substr($tagStr,1); - if('$' == $flag && '.' != $flag2 && '(' != $flag2){ //解析模板变量 格式 {$varName} - return $this->parseVar($name); - }elseif('-' == $flag || '+'== $flag){ // 输出计算 - return ''; - }elseif(':' == $flag){ // 输出某个函数的结果 - return ''; - }elseif('~' == $flag){ // 执行某个函数 - return ''; - }elseif(substr($tagStr,0,2)=='//' || (substr($tagStr,0,2)=='/*' && substr($tagStr,-2)=='*/')){ - //注释标签 - return ''; - } - // 未识别的标签直接返回 - return C('TMPL_L_DELIM') . $tagStr .C('TMPL_R_DELIM'); - } - - /** - * 模板变量解析,支持使用函数 - * 格式: {$varname|function1|function2=arg1,arg2} - * @access public - * @param string $varStr 变量数据 - * @return string - */ - public function parseVar($varStr){ - $varStr = trim($varStr); - static $_varParseList = array(); - //如果已经解析过该变量字串,则直接返回变量值 - if(isset($_varParseList[$varStr])) return $_varParseList[$varStr]; - $parseStr = ''; - $varExists = true; - if(!empty($varStr)){ - $varArray = explode('|',$varStr); - //取得变量名称 - $var = array_shift($varArray); - if('Think.' == substr($var,0,6)){ - // 所有以Think.打头的以特殊变量对待 无需模板赋值就可以输出 - $name = $this->parseThinkVar($var); - }elseif( false !== strpos($var,'.')) { - //支持 {$var.property} - $vars = explode('.',$var); - $var = array_shift($vars); - switch(strtolower(C('TMPL_VAR_IDENTIFY'))) { - case 'array': // 识别为数组 - $name = '$'.$var; - foreach ($vars as $key=>$val) - $name .= '["'.$val.'"]'; - break; - case 'obj': // 识别为对象 - $name = '$'.$var; - foreach ($vars as $key=>$val) - $name .= '->'.$val; - break; - default: // 自动判断数组或对象 只支持二维 - $name = 'is_array($'.$var.')?$'.$var.'["'.$vars[0].'"]:$'.$var.'->'.$vars[0]; - } - }elseif(false !== strpos($var,'[')) { - //支持 {$var['key']} 方式输出数组 - $name = "$".$var; - preg_match('/(.+?)\[(.+?)\]/is',$var,$match); - $var = $match[1]; - }elseif(false !==strpos($var,':') && false ===strpos($var,'(') && false ===strpos($var,'::') && false ===strpos($var,'?')){ - //支持 {$var:property} 方式输出对象的属性 - $vars = explode(':',$var); - $var = str_replace(':','->',$var); - $name = "$".$var; - $var = $vars[0]; - }else { - $name = "$$var"; - } - //对变量使用函数 - if(count($varArray)>0) - $name = $this->parseVarFunction($name,$varArray); - $parseStr = ''; - } - $_varParseList[$varStr] = $parseStr; - return $parseStr; - } - - /** - * 对模板变量使用函数 - * 格式 {$varname|function1|function2=arg1,arg2} - * @access public - * @param string $name 变量名 - * @param array $varArray 函数列表 - * @return string - */ - public function parseVarFunction($name,$varArray){ - //对变量使用函数 - $length = count($varArray); - //取得模板禁止使用函数列表 - $template_deny_funs = explode(',',C('TMPL_DENY_FUNC_LIST')); - for($i=0;$i<$length ;$i++ ){ - $args = explode('=',$varArray[$i],2); - //模板函数过滤 - $fun = strtolower(trim($args[0])); - switch($fun) { - case 'default': // 特殊模板函数 - $name = '('.$name.')?('.$name.'):'.$args[1]; - break; - default: // 通用模板函数 - if(!in_array($fun,$template_deny_funs)){ - if(isset($args[1])){ - if(strstr($args[1],'###')){ - $args[1] = str_replace('###',$name,$args[1]); - $name = "$fun($args[1])"; - }else{ - $name = "$fun($name,$args[1])"; - } - }else if(!empty($args[0])){ - $name = "$fun($name)"; - } - } - } - } - return $name; - } - - /** - * 特殊模板变量解析 - * 格式 以 $Think. 打头的变量属于特殊模板变量 - * @access public - * @param string $varStr 变量字符串 - * @return string - */ - public function parseThinkVar($varStr){ - $vars = explode('.',$varStr); - $vars[1] = strtoupper(trim($vars[1])); - $parseStr = ''; - if(count($vars)>=3){ - $vars[2] = trim($vars[2]); - switch($vars[1]){ - case 'SERVER': - $parseStr = '$_SERVER[\''.strtoupper($vars[2]).'\']';break; - case 'GET': - $parseStr = '$_GET[\''.$vars[2].'\']';break; - case 'POST': - $parseStr = '$_POST[\''.$vars[2].'\']';break; - case 'COOKIE': - if(isset($vars[3])) { - $parseStr = '$_COOKIE[\''.$vars[2].'\'][\''.$vars[3].'\']'; - }else{ - $parseStr = 'cookie(\''.$vars[2].'\')'; - } - break; - case 'SESSION': - if(isset($vars[3])) { - $parseStr = '$_SESSION[\''.$vars[2].'\'][\''.$vars[3].'\']'; - }else{ - $parseStr = 'session(\''.$vars[2].'\')'; - } - break; - case 'ENV': - $parseStr = '$_ENV[\''.strtoupper($vars[2]).'\']';break; - case 'REQUEST': - $parseStr = '$_REQUEST[\''.$vars[2].'\']';break; - case 'CONST': - $parseStr = strtoupper($vars[2]);break; - case 'LANG': - $parseStr = 'L("'.$vars[2].'")';break; - case 'CONFIG': - if(isset($vars[3])) { - $vars[2] .= '.'.$vars[3]; - } - $parseStr = 'C("'.$vars[2].'")';break; - default:break; - } - }else if(count($vars)==2){ - switch($vars[1]){ - case 'NOW': - $parseStr = "date('Y-m-d g:i a',time())"; - break; - case 'VERSION': - $parseStr = 'THINK_VERSION'; - break; - case 'TEMPLATE': - $parseStr = "'".$this->templateFile."'";//'C("TEMPLATE_NAME")'; - break; - case 'LDELIM': - $parseStr = 'C("TMPL_L_DELIM")'; - break; - case 'RDELIM': - $parseStr = 'C("TMPL_R_DELIM")'; - break; - default: - if(defined($vars[1])) - $parseStr = $vars[1]; - } - } - return $parseStr; - } - - /** - * 加载公共模板并缓存 和当前模板在同一路径,否则使用相对路径 - * @access private - * @param string $tmplPublicName 公共模板文件名 - * @param array $vars 要传递的变量列表 - * @return string - */ - private function parseIncludeItem($tmplPublicName,$vars=array()){ - // 分析模板文件名并读取内容 - $parseStr = $this->parseTemplateName($tmplPublicName); - // 替换变量 - foreach ($vars as $key=>$val) { - $parseStr = str_replace('['.$key.']',$val,$parseStr); - } - // 再次对包含文件进行模板分析 - return $this->parseInclude($parseStr); - } - - /** - * 分析加载的模板文件并读取内容 支持多个模板文件读取 - * @access private - * @param string $tmplPublicName 模板文件名 - * @return string - */ - private function parseTemplateName($templateName){ - if(substr($templateName,0,1)=='$') - //支持加载变量文件名 - $templateName = $this->get(substr($templateName,1)); - $array = explode(',',$templateName); - $parseStr = ''; - foreach ($array as $templateName){ - if(false === strpos($templateName,$this->config['template_suffix'])) { - // 解析规则为 分组@模板主题:模块:操作 - if(strpos($templateName,'@')){ - list($group,$templateName) = explode('@',$templateName); - if(1==C('APP_GROUP_MODE')){ - $basePath = dirname(BASE_LIB_PATH).'/'.$group.'/'.basename(TMPL_PATH).'/'.(THEME_NAME?THEME_NAME.'/':''); - }else{ - $basePath = TMPL_PATH.'/'.$group.'/'.(THEME_NAME?THEME_NAME.'/':''); - } - }else{ - $basePath = THEME_PATH; - } - $templateName = str_replace(':', '/', $templateName); - $path = explode('/',$templateName); - $action = array_pop($path); - $module = !empty($path)?array_pop($path):MODULE_NAME; - if(!empty($path)) {// 设置模板主题 - $basePath = dirname($basePath).'/'.array_pop($path).'/'; - } - $templateName = $basePath.$module.C('TMPL_FILE_DEPR').$action.$this->config['template_suffix']; - } - // 获取模板文件内容 - $parseStr .= file_get_contents($templateName); - } - return $parseStr; - } -} \ No newline at end of file + +// +---------------------------------------------------------------------- +namespace Think; +/** + * ThinkPHP内置模板引擎类 + * 支持XML标签和普通标签的模板解析 + * 编译型模板引擎 支持动态缓存 + */ +class Template { + + // 模板页面中引入的标签库列表 + protected $tagLib = array(); + // 当前模板文件 + protected $templateFile = ''; + // 模板变量 + public $tVar = array(); + public $config = array(); + private $literal = array(); + private $block = array(); + + /** + * 架构函数 + * @access public + */ + public function __construct(){ + $this->config['cache_path'] = C('CACHE_PATH'); + $this->config['template_suffix'] = C('TMPL_TEMPLATE_SUFFIX'); + $this->config['cache_suffix'] = C('TMPL_CACHFILE_SUFFIX'); + $this->config['tmpl_cache'] = C('TMPL_CACHE_ON'); + $this->config['cache_time'] = C('TMPL_CACHE_TIME'); + $this->config['taglib_begin'] = $this->stripPreg(C('TAGLIB_BEGIN')); + $this->config['taglib_end'] = $this->stripPreg(C('TAGLIB_END')); + $this->config['tmpl_begin'] = $this->stripPreg(C('TMPL_L_DELIM')); + $this->config['tmpl_end'] = $this->stripPreg(C('TMPL_R_DELIM')); + $this->config['default_tmpl'] = C('TEMPLATE_NAME'); + $this->config['layout_item'] = C('TMPL_LAYOUT_ITEM'); + } + + private function stripPreg($str) { + return str_replace( + array('{','}','(',')','|','[',']','-','+','*','.','^','?'), + array('\{','\}','\(','\)','\|','\[','\]','\-','\+','\*','\.','\^','\?'), + $str); + } + + // 模板变量获取和设置 + public function get($name) { + if(isset($this->tVar[$name])) + return $this->tVar[$name]; + else + return false; + } + + public function set($name,$value) { + $this->tVar[$name]= $value; + } + + /** + * 加载模板 + * @access public + * @param string $tmplTemplateFile 模板文件 + * @param array $templateVar 模板变量 + * @param string $prefix 模板标识前缀 + * @return void + */ + public function fetch($templateFile,$templateVar,$prefix='') { + $this->tVar = $templateVar; + $templateCacheFile = $this->loadTemplate($templateFile,$prefix); + Storage::load($templateCacheFile,$this->tVar,null,'tpl'); + } + + /** + * 加载主模板并缓存 + * @access public + * @param string $tmplTemplateFile 模板文件 + * @param string $prefix 模板标识前缀 + * @return string + * @throws ThinkExecption + */ + public function loadTemplate ($tmplTemplateFile,$prefix='') { + if(is_file($tmplTemplateFile)) { + $this->templateFile = $tmplTemplateFile; + // 读取模板文件内容 + $tmplContent = file_get_contents($tmplTemplateFile); + }else{ + $tmplContent = $tmplTemplateFile; + } + // 根据模版文件名定位缓存文件 + $tmplCacheFile = $this->config['cache_path'].$prefix.md5($tmplTemplateFile).$this->config['cache_suffix']; + + // 判断是否启用布局 + if(C('LAYOUT_ON')) { + if(false !== strpos($tmplContent,'{__NOLAYOUT__}')) { // 可以单独定义不使用布局 + $tmplContent = str_replace('{__NOLAYOUT__}','',$tmplContent); + }else{ // 替换布局的主体内容 + $layoutFile = THEME_PATH.C('LAYOUT_NAME').$this->config['template_suffix']; + $tmplContent = str_replace($this->config['layout_item'],$tmplContent,file_get_contents($layoutFile)); + } + } + // 编译模板内容 + $tmplContent = $this->compiler($tmplContent); + Storage::put($tmplCacheFile,trim($tmplContent),'tpl'); + return $tmplCacheFile; + } + + /** + * 编译模板文件内容 + * @access protected + * @param mixed $tmplContent 模板内容 + * @return string + */ + protected function compiler($tmplContent) { + //模板解析 + $tmplContent = $this->parse($tmplContent); + // 还原被替换的Literal标签 + $tmplContent = preg_replace_callback('//is', array($this, 'restoreLiteral'), $tmplContent); + // 添加安全代码 + $tmplContent = ''.$tmplContent; + // 优化生成的php代码 + $tmplContent = str_replace('?>config['taglib_begin']; + $end = $this->config['taglib_end']; + // 检查include语法 + $content = $this->parseInclude($content); + // 检查PHP语法 + $content = $this->parsePhp($content); + // 首先替换literal标签内容 + $content = preg_replace_callback('/'.$begin.'literal'.$end.'(.*?)'.$begin.'\/literal'.$end.'/is', array($this, 'parseLiteral'),$content); + + // 获取需要引入的标签库列表 + // 标签库只需要定义一次,允许引入多个一次 + // 一般放在文件的最前面 + // 格式: + // 当TAGLIB_LOAD配置为true时才会进行检测 + if(C('TAGLIB_LOAD')) { + $this->getIncludeTagLib($content); + if(!empty($this->tagLib)) { + // 对导入的TagLib进行解析 + foreach($this->tagLib as $tagLibName) { + $this->parseTagLib($tagLibName,$content); + } + } + } + // 预先加载的标签库 无需在每个模板中使用taglib标签加载 但必须使用标签库XML前缀 + if(C('TAGLIB_PRE_LOAD')) { + $tagLibs = explode(',',C('TAGLIB_PRE_LOAD')); + foreach ($tagLibs as $tag){ + $this->parseTagLib($tag,$content); + } + } + // 内置标签库 无需使用taglib标签导入就可以使用 并且不需使用标签库XML前缀 + $tagLibs = explode(',',C('TAGLIB_BUILD_IN')); + foreach ($tagLibs as $tag){ + $this->parseTagLib($tag,$content,true); + } + //解析普通模板标签 {tagName} + $content = preg_replace_callback('/('.$this->config['tmpl_begin'].')([^\d\s'.$this->config['tmpl_begin'].$this->config['tmpl_end'].'].+?)('.$this->config['tmpl_end'].')/is', array($this, 'parseTag'),$content); + return $content; + } + + // 检查PHP语法 + protected function parsePhp($content) { + if(ini_get('short_open_tag')){ + // 开启短标签的情况要将'."\n", $content ); + } + // PHP语法检查 + if(C('TMPL_DENY_PHP') && false !== strpos($content,'config['taglib_begin'].'layout\s(.+?)\s*?\/'.$this->config['taglib_end'].'/is',$content,$matches); + if($find) { + //替换Layout标签 + $content = str_replace($matches[0],'',$content); + //解析Layout标签 + $array = $this->parseXmlAttrs($matches[1]); + if(!C('LAYOUT_ON') || C('LAYOUT_NAME') !=$array['name'] ) { + // 读取布局模板 + $layoutFile = THEME_PATH.$array['name'].$this->config['template_suffix']; + $replace = isset($array['replace'])?$array['replace']:$this->config['layout_item']; + // 替换布局的主体内容 + $content = str_replace($replace,$content,file_get_contents($layoutFile)); + } + }else{ + $content = str_replace('{__NOLAYOUT__}','',$content); + } + return $content; + } + + // 解析模板中的include标签 + protected function parseInclude($content, $extend = true) { + // 解析继承 + if($extend) + $content = $this->parseExtend($content); + // 解析布局 + $content = $this->parseLayout($content); + // 读取模板中的include标签 + $find = preg_match_all('/'.$this->config['taglib_begin'].'include\s(.+?)\s*?\/'.$this->config['taglib_end'].'/is',$content,$matches); + if($find) { + for($i=0;$i<$find;$i++) { + $include = $matches[1][$i]; + $array = $this->parseXmlAttrs($include); + $file = $array['file']; + unset($array['file']); + $content = str_replace($matches[0][$i],$this->parseIncludeItem($file,$array,$extend),$content); + } + } + return $content; + } + + // 解析模板中的extend标签 + protected function parseExtend($content) { + $begin = $this->config['taglib_begin']; + $end = $this->config['taglib_end']; + // 读取模板中的继承标签 + $find = preg_match('/'.$begin.'extend\s(.+?)\s*?\/'.$end.'/is',$content,$matches); + if($find) { + //替换extend标签 + $content = str_replace($matches[0],'',$content); + // 记录页面中的block标签 + preg_replace_callback('/'.$begin.'block\sname=(.+?)\s*?'.$end.'(.*?)'.$begin.'\/block'.$end.'/is', array($this, 'parseBlock'),$content); + // 读取继承模板 + $array = $this->parseXmlAttrs($matches[1]); + $content = $this->parseTemplateName($array['name']); + $content = $this->parseInclude($content, false); //对继承模板中的include进行分析 + // 替换block标签 + $content = $this->replaceBlock($content); + }else{ + $content = preg_replace_callback('/'.$begin.'block\sname=(.+?)\s*?'.$end.'(.*?)'.$begin.'\/block'.$end.'/is', function($match){return stripslashes($match[2]);}, $content); + } + return $content; + } + + /** + * 分析XML属性 + * @access private + * @param string $attrs XML属性字符串 + * @return array + */ + private function parseXmlAttrs($attrs) { + $xml = ''; + $xml = simplexml_load_string($xml); + if(!$xml) + E(L('_XML_TAG_ERROR_')); + $xml = (array)($xml->tag->attributes()); + $array = array_change_key_case($xml['@attributes']); + return $array; + } + + /** + * 替换页面中的literal标签 + * @access private + * @param string $content 模板内容 + * @return string|false + */ + private function parseLiteral($content) { + if(is_array($content)) $content = $content[1]; + if(trim($content)=='') return ''; + //$content = stripslashes($content); + $i = count($this->literal); + $parseStr = ""; + $this->literal[$i] = $content; + return $parseStr; + } + + /** + * 还原被替换的literal标签 + * @access private + * @param string $tag literal标签序号 + * @return string|false + */ + private function restoreLiteral($tag) { + if(is_array($tag)) $tag = $tag[1]; + // 还原literal标签 + $parseStr = $this->literal[$tag]; + // 销毁literal记录 + unset($this->literal[$tag]); + return $parseStr; + } + + /** + * 记录当前页面中的block标签 + * @access private + * @param string $name block名称 + * @param string $content 模板内容 + * @return string + */ + private function parseBlock($name,$content = '') { + if(is_array($name)){ + $content = $name[2]; + $name = $name[1]; + } + $this->block[$name] = $content; + return ''; + } + + /** + * 替换继承模板中的block标签 + * @access private + * @param string $content 模板内容 + * @return string + */ + private function replaceBlock($content){ + static $parse = 0; + $begin = $this->config['taglib_begin']; + $end = $this->config['taglib_end']; + $reg = '/('.$begin.'block\sname=(.+?)\s*?'.$end.')(.*?)'.$begin.'\/block'.$end.'/is'; + if(is_string($content)){ + do{ + $content = preg_replace_callback($reg, array($this, 'replaceBlock'), $content); + } while ($parse && $parse--); + return $content; + } elseif(is_array($content)){ + if(preg_match('/'.$begin.'block\sname=(.+?)\s*?'.$end.'/is', $content[3])){ //存在嵌套,进一步解析 + $parse = 1; + $content[3] = preg_replace_callback($reg, array($this, 'replaceBlock'), "{$content[3]}{$begin}/block{$end}"); + return $content[1] . $content[3]; + } else { + $name = $content[2]; + $content = $content[3]; + $content = isset($this->block[$name]) ? $this->block[$name] : $content; + return $content; + } + } + } + + /** + * 搜索模板页面中包含的TagLib库 + * 并返回列表 + * @access public + * @param string $content 模板内容 + * @return string|false + */ + public function getIncludeTagLib(& $content) { + //搜索是否有TagLib标签 + $find = preg_match('/'.$this->config['taglib_begin'].'taglib\s(.+?)(\s*?)\/'.$this->config['taglib_end'].'\W/is',$content,$matches); + if($find) { + //替换TagLib标签 + $content = str_replace($matches[0],'',$content); + //解析TagLib标签 + $array = $this->parseXmlAttrs($matches[1]); + $this->tagLib = explode(',',$array['name']); + } + return; + } + + /** + * TagLib库解析 + * @access public + * @param string $tagLib 要解析的标签库 + * @param string $content 要解析的模板内容 + * @param boolen $hide 是否隐藏标签库前缀 + * @return string + */ + public function parseTagLib($tagLib,&$content,$hide=false) { + $begin = $this->config['taglib_begin']; + $end = $this->config['taglib_end']; + if(strpos($tagLib,'\\')){ + // 支持指定标签库的命名空间 + $className = $tagLib; + $tagLib = substr($tagLib,strrpos($tagLib,'\\')+1); + }else{ + $className = 'Think\\Template\TagLib\\'.ucwords($tagLib); + } + $tLib = \Think\Think::instance($className); + $that = $this; + foreach ($tLib->getTags() as $name=>$val){ + $tags = array($name); + if(isset($val['alias'])) {// 别名设置 + $tags = explode(',',$val['alias']); + $tags[] = $name; + } + $level = isset($val['level'])?$val['level']:1; + $closeTag = isset($val['close'])?$val['close']:true; + foreach ($tags as $tag){ + $parseTag = !$hide? $tagLib.':'.$tag: $tag;// 实际要解析的标签名称 + if(!method_exists($tLib,'_'.$tag)) { + // 别名可以无需定义解析方法 + $tag = $name; + } + $n1 = empty($val['attr'])?'(\s*?)':'\s([^'.$end.']*)'; + $this->tempVar = array($tagLib, $tag); + + if (!$closeTag){ + $patterns = '/'.$begin.$parseTag.$n1.'\/(\s*?)'.$end.'/is'; + $content = preg_replace_callback($patterns, function($matches) use($tLib,$tag,$that){ + return $that->parseXmlTag($tLib,$tag,$matches[1],$matches[2]); + },$content); + }else{ + $patterns = '/'.$begin.$parseTag.$n1.$end.'(.*?)'.$begin.'\/'.$parseTag.'(\s*?)'.$end.'/is'; + for($i=0;$i<$level;$i++) { + $content=preg_replace_callback($patterns,function($matches) use($tLib,$tag,$that){ + return $that->parseXmlTag($tLib,$tag,$matches[1],$matches[2]); + },$content); + } + } + } + } + } + + /** + * 解析标签库的标签 + * 需要调用对应的标签库文件解析类 + * @access public + * @param object $tagLib 标签库对象实例 + * @param string $tag 标签名 + * @param string $attr 标签属性 + * @param string $content 标签内容 + * @return string|false + */ + public function parseXmlTag($tagLib,$tag,$attr,$content) { + if(ini_get('magic_quotes_sybase')) + $attr = str_replace('\"','\'',$attr); + $parse = '_'.$tag; + $content = trim($content); + $tags = $tagLib->parseXmlAttr($attr,$tag); + return $tagLib->$parse($tags,$content); + } + + /** + * 模板标签解析 + * 格式: {TagName:args [|content] } + * @access public + * @param string $tagStr 标签内容 + * @return string + */ + public function parseTag($tagStr){ + if(is_array($tagStr)) $tagStr = $tagStr[2]; + //if (MAGIC_QUOTES_GPC) { + $tagStr = stripslashes($tagStr); + //} + //还原非模板标签 + if(preg_match('/^[\s|\d]/is',$tagStr)) + //过滤空格和数字打头的标签 + return C('TMPL_L_DELIM') . $tagStr .C('TMPL_R_DELIM'); + $flag = substr($tagStr,0,1); + $flag2 = substr($tagStr,1,1); + $name = substr($tagStr,1); + if('$' == $flag && '.' != $flag2 && '(' != $flag2){ //解析模板变量 格式 {$varName} + return $this->parseVar($name); + }elseif('-' == $flag || '+'== $flag){ // 输出计算 + return ''; + }elseif(':' == $flag){ // 输出某个函数的结果 + return ''; + }elseif('~' == $flag){ // 执行某个函数 + return ''; + }elseif(substr($tagStr,0,2)=='//' || (substr($tagStr,0,2)=='/*' && substr(rtrim($tagStr),-2)=='*/')){ + //注释标签 + return ''; + } + // 未识别的标签直接返回 + return C('TMPL_L_DELIM') . $tagStr .C('TMPL_R_DELIM'); + } + + /** + * 模板变量解析,支持使用函数 + * 格式: {$varname|function1|function2=arg1,arg2} + * @access public + * @param string $varStr 变量数据 + * @return string + */ + public function parseVar($varStr){ + $varStr = trim($varStr); + static $_varParseList = array(); + //如果已经解析过该变量字串,则直接返回变量值 + if(isset($_varParseList[$varStr])) return $_varParseList[$varStr]; + $parseStr = ''; + $varExists = true; + if(!empty($varStr)){ + $varArray = explode('|',$varStr); + //取得变量名称 + $var = array_shift($varArray); + if('Think.' == substr($var,0,6)){ + // 所有以Think.打头的以特殊变量对待 无需模板赋值就可以输出 + $name = $this->parseThinkVar($var); + }elseif( false !== strpos($var,'.')) { + //支持 {$var.property} + $vars = explode('.',$var); + $var = array_shift($vars); + switch(strtolower(C('TMPL_VAR_IDENTIFY'))) { + case 'array': // 识别为数组 + $name = '$'.$var; + foreach ($vars as $key=>$val) + $name .= '["'.$val.'"]'; + break; + case 'obj': // 识别为对象 + $name = '$'.$var; + foreach ($vars as $key=>$val) + $name .= '->'.$val; + break; + default: // 自动判断数组或对象 只支持二维 + $name = 'is_array($'.$var.')?$'.$var.'["'.$vars[0].'"]:$'.$var.'->'.$vars[0]; + } + }elseif(false !== strpos($var,'[')) { + //支持 {$var['key']} 方式输出数组 + $name = "$".$var; + preg_match('/(.+?)\[(.+?)\]/is',$var,$match); + $var = $match[1]; + }elseif(false !==strpos($var,':') && false ===strpos($var,'(') && false ===strpos($var,'::') && false ===strpos($var,'?')){ + //支持 {$var:property} 方式输出对象的属性 + $vars = explode(':',$var); + $var = str_replace(':','->',$var); + $name = "$".$var; + $var = $vars[0]; + }else { + $name = "$$var"; + } + //对变量使用函数 + if(count($varArray)>0) + $name = $this->parseVarFunction($name,$varArray); + $parseStr = ''; + } + $_varParseList[$varStr] = $parseStr; + return $parseStr; + } + + /** + * 对模板变量使用函数 + * 格式 {$varname|function1|function2=arg1,arg2} + * @access public + * @param string $name 变量名 + * @param array $varArray 函数列表 + * @return string + */ + public function parseVarFunction($name,$varArray){ + //对变量使用函数 + $length = count($varArray); + //取得模板禁止使用函数列表 + $template_deny_funs = explode(',',C('TMPL_DENY_FUNC_LIST')); + for($i=0;$i<$length ;$i++ ){ + $args = explode('=',$varArray[$i],2); + //模板函数过滤 + $fun = strtolower(trim($args[0])); + switch($fun) { + case 'default': // 特殊模板函数 + $name = '(isset('.$name.') && ('.$name.' !== ""))?('.$name.'):'.$args[1]; + break; + default: // 通用模板函数 + if(!in_array($fun,$template_deny_funs)){ + if(isset($args[1])){ + if(strstr($args[1],'###')){ + $args[1] = str_replace('###',$name,$args[1]); + $name = "$fun($args[1])"; + }else{ + $name = "$fun($name,$args[1])"; + } + }else if(!empty($args[0])){ + $name = "$fun($name)"; + } + } + } + } + return $name; + } + + /** + * 特殊模板变量解析 + * 格式 以 $Think. 打头的变量属于特殊模板变量 + * @access public + * @param string $varStr 变量字符串 + * @return string + */ + public function parseThinkVar($varStr){ + $vars = explode('.',$varStr); + $vars[1] = strtoupper(trim($vars[1])); + $parseStr = ''; + if(count($vars)>=3){ + $vars[2] = trim($vars[2]); + switch($vars[1]){ + case 'SERVER': + $parseStr = '$_SERVER[\''.strtoupper($vars[2]).'\']';break; + case 'GET': + $parseStr = '$_GET[\''.$vars[2].'\']';break; + case 'POST': + $parseStr = '$_POST[\''.$vars[2].'\']';break; + case 'COOKIE': + if(isset($vars[3])) { + $parseStr = '$_COOKIE[\''.$vars[2].'\'][\''.$vars[3].'\']'; + }else{ + $parseStr = 'cookie(\''.$vars[2].'\')'; + } + break; + case 'SESSION': + if(isset($vars[3])) { + $parseStr = '$_SESSION[\''.$vars[2].'\'][\''.$vars[3].'\']'; + }else{ + $parseStr = 'session(\''.$vars[2].'\')'; + } + break; + case 'ENV': + $parseStr = '$_ENV[\''.strtoupper($vars[2]).'\']';break; + case 'REQUEST': + $parseStr = '$_REQUEST[\''.$vars[2].'\']';break; + case 'CONST': + $parseStr = strtoupper($vars[2]);break; + case 'LANG': + $parseStr = 'L("'.$vars[2].'")';break; + case 'CONFIG': + if(isset($vars[3])) { + $vars[2] .= '.'.$vars[3]; + } + $parseStr = 'C("'.$vars[2].'")';break; + default:break; + } + }else if(count($vars)==2){ + switch($vars[1]){ + case 'NOW': + $parseStr = "date('Y-m-d g:i a',time())"; + break; + case 'VERSION': + $parseStr = 'THINK_VERSION'; + break; + case 'TEMPLATE': + $parseStr = "'".$this->templateFile."'";//'C("TEMPLATE_NAME")'; + break; + case 'LDELIM': + $parseStr = 'C("TMPL_L_DELIM")'; + break; + case 'RDELIM': + $parseStr = 'C("TMPL_R_DELIM")'; + break; + default: + if(defined($vars[1])) + $parseStr = $vars[1]; + } + } + return $parseStr; + } + + /** + * 加载公共模板并缓存 和当前模板在同一路径,否则使用相对路径 + * @access private + * @param string $tmplPublicName 公共模板文件名 + * @param array $vars 要传递的变量列表 + * @return string + */ + private function parseIncludeItem($tmplPublicName,$vars=array(),$extend){ + // 分析模板文件名并读取内容 + $parseStr = $this->parseTemplateName($tmplPublicName); + // 替换变量 + foreach ($vars as $key=>$val) { + $parseStr = str_replace('['.$key.']',$val,$parseStr); + } + // 再次对包含文件进行模板分析 + return $this->parseInclude($parseStr,$extend); + } + + /** + * 分析加载的模板文件并读取内容 支持多个模板文件读取 + * @access private + * @param string $tmplPublicName 模板文件名 + * @return string + */ + private function parseTemplateName($templateName){ + if(substr($templateName,0,1)=='$') + //支持加载变量文件名 + $templateName = $this->get(substr($templateName,1)); + $array = explode(',',$templateName); + $parseStr = ''; + foreach ($array as $templateName){ + if(empty($templateName)) continue; + if(false === strpos($templateName,$this->config['template_suffix'])) { + // 解析规则为 模块@主题/控制器/操作 + $templateName = T($templateName); + } + // 获取模板文件内容 + $parseStr .= file_get_contents($templateName); + } + return $parseStr; + } +} diff --git a/ThinkPHP/Library/Think/Template/Driver/Ease.class.php b/ThinkPHP/Library/Think/Template/Driver/Ease.class.php new file mode 100644 index 000000000..a80a62bd9 --- /dev/null +++ b/ThinkPHP/Library/Think/Template/Driver/Ease.class.php @@ -0,0 +1,42 @@ + +// +---------------------------------------------------------------------- +namespace Think\Template\Driver; +defined('THINK_PATH') or exit(); +/** + * EaseTemplate模板引擎驱动 + */ +class Ease { + /** + * 渲染模板输出 + * @access public + * @param string $templateFile 模板文件名 + * @param array $var 模板变量 + * @return void + */ + public function fetch($templateFile,$var) { + $templateFile = substr($templateFile,strlen(THEME_PATH),-5); + $CacheDir = substr(CACHE_PATH,0,-1); + $TemplateDir = substr(THEME_PATH,0,-1); + vendor('EaseTemplate.template#ease'); + $config = array( + 'CacheDir' => $CacheDir, + 'TemplateDir' => $TemplateDir, + 'TplType' => 'html' + ); + if(C('TMPL_ENGINE_CONFIG')) { + $config = array_merge($config,C('TMPL_ENGINE_CONFIG')); + } + $tpl = new EaseTemplate($config); + $tpl->set_var($var); + $tpl->set_file($templateFile); + $tpl->p(); + } +} \ No newline at end of file diff --git a/ThinkPHP/Library/Think/Template/Driver/Lite.class.php b/ThinkPHP/Library/Think/Template/Driver/Lite.class.php new file mode 100644 index 000000000..86638abc8 --- /dev/null +++ b/ThinkPHP/Library/Think/Template/Driver/Lite.class.php @@ -0,0 +1,40 @@ + +// +---------------------------------------------------------------------- +namespace Think\Template\Driver; +defined('THINK_PATH') or exit(); +/** + * TemplateLite模板引擎驱动 + */ +class Lite { + /** + * 渲染模板输出 + * @access public + * @param string $templateFile 模板文件名 + * @param array $var 模板变量 + * @return void + */ + public function fetch($templateFile,$var) { + vendor("TemplateLite.class#template"); + $templateFile = substr($templateFile,strlen(THEME_PATH)); + $tpl = new Template_Lite(); + $tpl->template_dir = THEME_PATH; + $tpl->compile_dir = CACHE_PATH ; + $tpl->cache_dir = TEMP_PATH ; + if(C('TMPL_ENGINE_CONFIG')) { + $config = C('TMPL_ENGINE_CONFIG'); + foreach ($config as $key=>$val){ + $tpl->{$key} = $val; + } + } + $tpl->assign($var); + $tpl->display($templateFile); + } +} \ No newline at end of file diff --git a/ThinkPHP/Library/Think/Template/Driver/Mobile.class.php b/ThinkPHP/Library/Think/Template/Driver/Mobile.class.php new file mode 100644 index 000000000..662606485 --- /dev/null +++ b/ThinkPHP/Library/Think/Template/Driver/Mobile.class.php @@ -0,0 +1,29 @@ + +// +---------------------------------------------------------------------- +namespace Think\Template\Driver; +defined('THINK_PATH') or exit(); +/** + * MobileTemplate模板引擎驱动 + */ +class Mobile { + /** + * 渲染模板输出 + * @access public + * @param string $templateFile 模板文件名 + * @param array $var 模板变量 + * @return void + */ + public function fetch($templateFile,$var) { + $templateFile=substr($templateFile,strlen(THEME_PATH)); + $var['_think_template_path']=$templateFile; + exit(json_encode($var)); + } +} diff --git a/ThinkPHP/Library/Think/Template/Driver/Smart.class.php b/ThinkPHP/Library/Think/Template/Driver/Smart.class.php new file mode 100644 index 000000000..50e7d4775 --- /dev/null +++ b/ThinkPHP/Library/Think/Template/Driver/Smart.class.php @@ -0,0 +1,41 @@ + +// +---------------------------------------------------------------------- +namespace Think\Template\Driver; +defined('THINK_PATH') or exit(); +/** + * Smart模板引擎驱动 + */ +class Smart { + /** + * 渲染模板输出 + * @access public + * @param string $templateFile 模板文件名 + * @param array $var 模板变量 + * @return void + */ + public function fetch($templateFile,$var) { + $templateFile = substr($templateFile,strlen(THEME_PATH)); + vendor('SmartTemplate.class#smarttemplate'); + $tpl = new \SmartTemplate($templateFile); + $tpl->caching = C('TMPL_CACHE_ON'); + $tpl->template_dir = THEME_PATH; + $tpl->compile_dir = CACHE_PATH ; + $tpl->cache_dir = TEMP_PATH ; + if(C('TMPL_ENGINE_CONFIG')) { + $config = C('TMPL_ENGINE_CONFIG'); + foreach ($config as $key=>$val){ + $tpl->{$key} = $val; + } + } + $tpl->assign($var); + $tpl->output(); + } +} \ No newline at end of file diff --git a/ThinkPHP/Library/Think/Template/Driver/Smarty.class.php b/ThinkPHP/Library/Think/Template/Driver/Smarty.class.php new file mode 100644 index 000000000..6d93260b0 --- /dev/null +++ b/ThinkPHP/Library/Think/Template/Driver/Smarty.class.php @@ -0,0 +1,42 @@ + +// +---------------------------------------------------------------------- +namespace Think\Template\Driver; +defined('THINK_PATH') or exit(); +/** + * Smarty模板引擎驱动 + */ +class Smarty { + + /** + * 渲染模板输出 + * @access public + * @param string $templateFile 模板文件名 + * @param array $var 模板变量 + * @return void + */ + public function fetch($templateFile,$var) { + $templateFile = substr($templateFile,strlen(THEME_PATH)); + vendor('Smarty.Smarty#class'); + $tpl = new \Smarty(); + $tpl->caching = C('TMPL_CACHE_ON'); + $tpl->template_dir = THEME_PATH; + $tpl->compile_dir = CACHE_PATH ; + $tpl->cache_dir = TEMP_PATH ; + if(C('TMPL_ENGINE_CONFIG')) { + $config = C('TMPL_ENGINE_CONFIG'); + foreach ($config as $key=>$val){ + $tpl->{$key} = $val; + } + } + $tpl->assign($var); + $tpl->display($templateFile); + } +} \ No newline at end of file diff --git a/ThinkPHP/Lib/Template/TagLib.class.php b/ThinkPHP/Library/Think/Template/TagLib.class.php similarity index 81% rename from ThinkPHP/Lib/Template/TagLib.class.php rename to ThinkPHP/Library/Think/Template/TagLib.class.php index ea3993c4d..05cd18333 100644 --- a/ThinkPHP/Lib/Template/TagLib.class.php +++ b/ThinkPHP/Library/Think/Template/TagLib.class.php @@ -2,19 +2,15 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK IT ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006-2013 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- - +namespace Think\Template; /** * ThinkPHP标签库TagLib解析基类 - * @category Think - * @package Think - * @subpackage Template - * @author liu21st */ class TagLib { @@ -68,7 +64,7 @@ class TagLib { */ public function __construct() { $this->tagLib = strtolower(substr(get_class($this),6)); - $this->tpl = Think::instance('ThinkTemplate'); + $this->tpl = \Think\Think::instance('Think\\Template'); } /** @@ -83,25 +79,41 @@ public function parseXmlAttr($attr,$tag) { $xml = ''; $xml = simplexml_load_string($xml); if(!$xml) { - throw_exception(L('_XML_TAG_ERROR_').' : '.$attr); + E(L('_XML_TAG_ERROR_').' : '.$attr); } $xml = (array)($xml->tag->attributes()); - $array = array_change_key_case($xml['@attributes']); - if($array) { - $attrs = explode(',',$this->tags[strtolower($tag)]['attr']); - if(isset($this->tags[strtolower($tag)]['must'])){ - $must = explode(',',$this->tags[strtolower($tag)]['must']); - }else{ - $must = array(); - } - foreach($attrs as $name) { - if( isset($array[$name])) { - $array[$name] = str_replace('___','&',$array[$name]); - }elseif(false !== array_search($name,$must)){ - throw_exception(L('_PARAM_ERROR_').':'.$name); + if(isset($xml['@attributes'])){ + $array = array_change_key_case($xml['@attributes']); + if($array) { + $tag = strtolower($tag); + if(!isset($this->tags[$tag])){ + // 检测是否存在别名定义 + foreach($this->tags as $key=>$val){ + if(isset($val['alias']) && in_array($tag,explode(',',$val['alias']))){ + $item = $val; + break; + } + } + }else{ + $item = $this->tags[$tag]; + } + $attrs = explode(',',$item['attr']); + if(isset($item['must'])){ + $must = explode(',',$item['must']); + }else{ + $must = array(); } + foreach($attrs as $name) { + if( isset($array[$name])) { + $array[$name] = str_replace('___','&',$array[$name]); + }elseif(false !== array_search($name,$must)){ + E(L('_PARAM_ERROR_').':'.$name); + } + } + return $array; } - return $array; + }else{ + return array(); } } @@ -125,7 +137,7 @@ public function parseCondition($condition) { $condition = preg_replace('/\$(\w+)\.(\w+)\s/is','(is_array($\\1)?$\\1["\\2"]:$\\1->\\2) ',$condition); } if(false !== strpos($condition, '$Think')) - $condition = preg_replace('/(\$Think.*?)\s/ies',"\$this->parseThinkVar('\\1');" , $condition); + $condition = preg_replace_callback('/(\$Think.*?)\s/is', array($this, 'parseThinkVar'), $condition); return $condition; } @@ -178,6 +190,9 @@ public function autoBuildVar($name) { * @return string */ public function parseThinkVar($varStr){ + if(is_array($varStr)){//用于正则替换回调函数 + $varStr = $varStr[1]; + } $vars = explode('.',$varStr); $vars[1] = strtoupper(trim($vars[1])); $parseStr = ''; diff --git a/ThinkPHP/Lib/Driver/TagLib/TagLibCx.class.php b/ThinkPHP/Library/Think/Template/TagLib/Cx.class.php similarity index 78% rename from ThinkPHP/Lib/Driver/TagLib/TagLibCx.class.php rename to ThinkPHP/Library/Think/Template/TagLib/Cx.class.php index 7f8c2a0b1..8e0e425f9 100644 --- a/ThinkPHP/Lib/Driver/TagLib/TagLibCx.class.php +++ b/ThinkPHP/Library/Think/Template/TagLib/Cx.class.php @@ -2,22 +2,19 @@ // +---------------------------------------------------------------------- // | ThinkPHP [ WE CAN DO IT JUST THINK IT ] // +---------------------------------------------------------------------- -// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved. +// | Copyright (c) 2006-2013 http://thinkphp.cn All rights reserved. // +---------------------------------------------------------------------- // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 ) // +---------------------------------------------------------------------- // | Author: liu21st // +---------------------------------------------------------------------- - +namespace Think\Template\TagLib; +use Think\Template\TagLib; defined('THINK_PATH') or exit(); /** * CX标签库解析类 - * @category Think - * @package Think - * @subpackage Driver.Taglib - * @author liu21st */ -class TagLibCx extends TagLib { +class Cx extends TagLib { // 标签定义 protected $tags = array( @@ -48,11 +45,11 @@ class TagLibCx extends TagLib { /** * php标签解析 * @access public - * @param string $attr 标签属性 + * @param array $tag 标签属性 * @param string $content 标签内容 * @return string */ - public function _php($attr,$content) { + public function _php($tag,$content) { $parseStr = ''; return $parseStr; } @@ -65,17 +62,11 @@ public function _php($attr,$content) { * {user.email} * * @access public - * @param string $attr 标签属性 + * @param array $tag 标签属性 * @param string $content 标签内容 * @return string|void */ - public function _volist($attr,$content) { - static $_iterateParseCache = array(); - //如果已经解析过,则直接返回变量值 - $cacheIterateId = md5($attr.$content); - if(isset($_iterateParseCache[$cacheIterateId])) - return $_iterateParseCache[$cacheIterateId]; - $tag = $this->parseXmlAttr($attr,'volist'); + public function _volist($tag,$content) { $name = $tag['name']; $id = $tag['id']; $empty = isset($tag['empty'])?$tag['empty']:''; @@ -104,7 +95,6 @@ public function _volist($attr,$content) { $parseStr .= '++$'.$key.';?>'; $parseStr .= $this->tpl->parse($content); $parseStr .= ''; - $_iterateParseCache[$cacheIterateId] = $parseStr; if(!empty($parseStr)) { return $parseStr; @@ -115,17 +105,11 @@ public function _volist($attr,$content) { /** * foreach标签解析 循环输出数据集 * @access public - * @param string $attr 标签属性 + * @param array $tag 标签属性 * @param string $content 标签内容 * @return string|void */ - public function _foreach($attr,$content) { - static $_iterateParseCache = array(); - //如果已经解析过,则直接返回变量值 - $cacheIterateId = md5($attr.$content); - if(isset($_iterateParseCache[$cacheIterateId])) - return $_iterateParseCache[$cacheIterateId]; - $tag = $this->parseXmlAttr($attr,'foreach'); + public function _foreach($tag,$content) { $name = $tag['name']; $item = $tag['item']; $key = !empty($tag['key'])?$tag['key']:'key'; @@ -133,7 +117,7 @@ public function _foreach($attr,$content) { $parseStr = '$'.$item.'): ?>'; $parseStr .= $this->tpl->parse($content); $parseStr .= ''; - $_iterateParseCache[$cacheIterateId] = $parseStr; + if(!empty($parseStr)) { return $parseStr; } @@ -149,12 +133,11 @@ public function _foreach($attr,$content) { * * 表达式支持 eq neq gt egt lt elt == > >= < <= or and || && * @access public - * @param string $attr 标签属性 + * @param array $tag 标签属性 * @param string $content 标签内容 * @return string */ - public function _if($attr,$content) { - $tag = $this->parseXmlAttr($attr,'if'); + public function _if($tag,$content) { $condition = $this->parseCondition($tag['condition']); $parseStr = ''.$content.''; return $parseStr; @@ -164,12 +147,11 @@ public function _if($attr,$content) { * else标签解析 * 格式:见if标签 * @access public - * @param string $attr 标签属性 + * @param array $tag 标签属性 * @param string $content 标签内容 * @return string */ - public function _elseif($attr,$content) { - $tag = $this->parseXmlAttr($attr,'elseif'); + public function _elseif($tag,$content) { $condition = $this->parseCondition($tag['condition']); $parseStr = ''; return $parseStr; @@ -178,10 +160,10 @@ public function _elseif($attr,$content) { /** * else标签解析 * @access public - * @param string $attr 标签属性 + * @param array $tag 标签属性 * @return string */ - public function _else($attr) { + public function _else($tag) { $parseStr = ''; return $parseStr; } @@ -195,12 +177,11 @@ public function _else($attr) { * other * * @access public - * @param string $attr 标签属性 + * @param array $tag 标签属性 * @param string $content 标签内容 * @return string */ - public function _switch($attr,$content) { - $tag = $this->parseXmlAttr($attr,'switch'); + public function _switch($tag,$content) { $name = $tag['name']; $varArray = explode('|',$name); $name = array_shift($varArray); @@ -214,12 +195,11 @@ public function _switch($attr,$content) { /** * case标签解析 需要配合switch才有效 * @access public - * @param string $attr 标签属性 + * @param array $tag 标签属性 * @param string $content 标签内容 * @return string */ - public function _case($attr,$content) { - $tag = $this->parseXmlAttr($attr,'case'); + public function _case($tag,$content) { $value = $tag['value']; if('$' == substr($value,0,1)) { $varArray = explode('|',$value); @@ -249,11 +229,11 @@ public function _case($attr,$content) { * default标签解析 需要配合switch才有效 * 使用: ddfdf * @access public - * @param string $attr 标签属性 + * @param array $tag 标签属性 * @param string $content 标签内容 * @return string */ - public function _default($attr) { + public function _default($tag) { $parseStr = ''; return $parseStr; } @@ -263,12 +243,11 @@ public function _default($attr) { * 用于值的比较 支持 eq neq gt lt egt elt heq nheq 默认是eq * 格式: content * @access public - * @param string $attr 标签属性 + * @param array $tag 标签属性 * @param string $content 标签内容 * @return string */ - public function _compare($attr,$content,$type='eq') { - $tag = $this->parseXmlAttr($attr,'compare'); + public function _compare($tag,$content,$type='eq') { $name = $tag['name']; $value = $tag['value']; $type = isset($tag['type'])?$tag['type']:$type; @@ -287,44 +266,44 @@ public function _compare($attr,$content,$type='eq') { return $parseStr; } - public function _eq($attr,$content) { - return $this->_compare($attr,$content,'eq'); + public function _eq($tag,$content) { + return $this->_compare($tag,$content,'eq'); } - public function _equal($attr,$content) { - return $this->_compare($attr,$content,'eq'); + public function _equal($tag,$content) { + return $this->_compare($tag,$content,'eq'); } - public function _neq($attr,$content) { - return $this->_compare($attr,$content,'neq'); + public function _neq($tag,$content) { + return $this->_compare($tag,$content,'neq'); } - public function _notequal($attr,$content) { - return $this->_compare($attr,$content,'neq'); + public function _notequal($tag,$content) { + return $this->_compare($tag,$content,'neq'); } - public function _gt($attr,$content) { - return $this->_compare($attr,$content,'gt'); + public function _gt($tag,$content) { + return $this->_compare($tag,$content,'gt'); } - public function _lt($attr,$content) { - return $this->_compare($attr,$content,'lt'); + public function _lt($tag,$content) { + return $this->_compare($tag,$content,'lt'); } - public function _egt($attr,$content) { - return $this->_compare($attr,$content,'egt'); + public function _egt($tag,$content) { + return $this->_compare($tag,$content,'egt'); } - public function _elt($attr,$content) { - return $this->_compare($attr,$content,'elt'); + public function _elt($tag,$content) { + return $this->_compare($tag,$content,'elt'); } - public function _heq($attr,$content) { - return $this->_compare($attr,$content,'heq'); + public function _heq($tag,$content) { + return $this->_compare($tag,$content,'heq'); } - public function _nheq($attr,$content) { - return $this->_compare($attr,$content,'nheq'); + public function _nheq($tag,$content) { + return $this->_compare($tag,$content,'nheq'); } /** @@ -333,13 +312,12 @@ public function _nheq($attr,$content) { * 格式: content * example: content * @access public - * @param string $attr 标签属性 + * @param array $tag 标签属性 * @param string $content 标签内容 * @param string $type 比较类型 * @return string */ - public function _range($attr,$content,$type='in') { - $tag = $this->parseXmlAttr($attr,'range'); + public function _range($tag,$content,$type='in') { $name = $tag['name']; $value = $tag['value']; $varArray = explode('|',$name); @@ -369,21 +347,21 @@ public function _range($attr,$content,$type='in') { } // range标签的别名 用于in判断 - public function _in($attr,$content) { - return $this->_range($attr,$content,'in'); + public function _in($tag,$content) { + return $this->_range($tag,$content,'in'); } // range标签的别名 用于notin判断 - public function _notin($attr,$content) { - return $this->_range($attr,$content,'notin'); + public function _notin($tag,$content) { + return $this->_range($tag,$content,'notin'); } - public function _between($attr,$content){ - return $this->_range($attr,$content,'between'); + public function _between($tag,$content){ + return $this->_range($tag,$content,'between'); } - public function _notbetween($attr,$content){ - return $this->_range($attr,$content,'notbetween'); + public function _notbetween($tag,$content){ + return $this->_range($tag,$content,'notbetween'); } /** @@ -391,12 +369,11 @@ public function _notbetween($attr,$content){ * 如果某个变量已经设置 则输出内容 * 格式: content * @access public - * @param string $attr 标签属性 + * @param array $tag 标签属性 * @param string $content 标签内容 * @return string */ - public function _present($attr,$content) { - $tag = $this->parseXmlAttr($attr,'present'); + public function _present($tag,$content) { $name = $tag['name']; $name = $this->autoBuildVar($name); $parseStr = ''.$content.''; @@ -408,12 +385,11 @@ public function _present($attr,$content) { * 如果某个变量没有设置,则输出内容 * 格式: content * @access public - * @param string $attr 标签属性 + * @param array $tag 标签属性 * @param string $content 标签内容 * @return string */ - public function _notpresent($attr,$content) { - $tag = $this->parseXmlAttr($attr,'notpresent'); + public function _notpresent($tag,$content) { $name = $tag['name']; $name = $this->autoBuildVar($name); $parseStr = ''.$content.''; @@ -425,20 +401,18 @@ public function _notpresent($attr,$content) { * 如果某个变量为empty 则输出内容 * 格式: content * @access public - * @param string $attr 标签属性 + * @param array $tag 标签属性 * @param string $content 标签内容 * @return string */ - public function _empty($attr,$content) { - $tag = $this->parseXmlAttr($attr,'empty'); + public function _empty($tag,$content) { $name = $tag['name']; $name = $this->autoBuildVar($name); $parseStr = ''.$content.''; return $parseStr; } - public function _notempty($attr,$content) { - $tag = $this->parseXmlAttr($attr,'notempty'); + public function _notempty($tag,$content) { $name = $tag['name']; $name = $this->autoBuildVar($name); $parseStr = ''.$content.''; @@ -452,15 +426,13 @@ public function _notempty($attr,$content) { * @param $content * @return string */ - public function _defined($attr,$content) { - $tag = $this->parseXmlAttr($attr,'defined'); + public function _defined($tag,$content) { $name = $tag['name']; $parseStr = ''.$content.''; return $parseStr; } - public function _notdefined($attr,$content) { - $tag = $this->parseXmlAttr($attr,'_notdefined'); + public function _notdefined($tag,$content) { $name = $tag['name']; $parseStr = ''.$content.''; return $parseStr; @@ -470,14 +442,13 @@ public function _notdefined($attr,$content) { * import 标签解析 * * @access public - * @param string $attr 标签属性 + * @param array $tag 标签属性 * @param string $content 标签内容 * @param boolean $isFile 是否文件方式 * @param string $type 类型 * @return string */ - public function _import($attr,$content,$isFile=false,$type='') { - $tag = $this->parseXmlAttr($attr,'import'); + public function _import($tag,$content,$isFile=false,$type='') { $file = isset($tag['file'])?$tag['file']:$tag['href']; $parseStr = ''; $endStr = ''; @@ -539,18 +510,18 @@ public function _import($attr,$content,$isFile=false,$type='') { } // import别名 采用文件方式加载(要使用命名空间必须用import) 例如 - public function _load($attr,$content) { - return $this->_import($attr,$content,true); + public function _load($tag,$content) { + return $this->_import($tag,$content,true); } // import别名使用 导入css文件 - public function _css($attr,$content) { - return $this->_import($attr,$content,true,'css'); + public function _css($tag,$content) { + return $this->_import($tag,$content,true,'css'); } // import别名使用 导入js文件 - public function _js($attr,$content) { - return $this->_import($attr,$content,true,'js'); + public function _js($tag,$content) { + return $this->_import($tag,$content,true,'js'); } /** @@ -558,12 +529,11 @@ public function _js($attr,$content) { * 在模板中给某个变量赋值 支持变量赋值 * 格式: * @access public - * @param string $attr 标签属性 + * @param array $tag 标签属性 * @param string $content 标签内容 * @return string */ - public function _assign($attr,$content) { - $tag = $this->parseXmlAttr($attr,'assign'); + public function _assign($tag,$content) { $name = $this->autoBuildVar($tag['name']); if('$'==substr($tag['value'],0,1)) { $value = $this->autoBuildVar(substr($tag['value'],1)); @@ -579,12 +549,11 @@ public function _assign($attr,$content) { * 在模板中定义常量 支持变量赋值 * 格式: * @access public - * @param string $attr 标签属性 + * @param array $tag 标签属性 * @param string $content 标签内容 * @return string */ - public function _define($attr,$content) { - $tag = $this->parseXmlAttr($attr,'define'); + public function _define($tag,$content) { $name = '\''.$tag['name']. '\''; if('$'==substr($tag['value'],0,1)) { $value = $this->autoBuildVar(substr($tag['value'],1)); @@ -599,11 +568,11 @@ public function _define($attr,$content) { * for标签解析 * 格式: * @access public - * @param string $attr 标签属性 + * @param array $tag 标签属性 * @param string $content 标签内容 * @return string */ - public function _for($attr, $content){ + public function _for($tag, $content){ //设置默认值 $start = 0; $end = 0; @@ -612,7 +581,7 @@ public function _for($attr, $content){ $name = 'i'; $rand = rand(); //添加随机数,防止嵌套变量冲突 //获取属性 - foreach ($this->parseXmlAttr($attr, 'for') as $key => $value){ + foreach ($tag as $key => $value){ $value = trim($value); if(':'==substr($value,0,1)) $value = substr($value,1); diff --git a/ThinkPHP/Library/Think/Template/TagLib/Html.class.php b/ThinkPHP/Library/Think/Template/TagLib/Html.class.php new file mode 100644 index 000000000..f860cf5f4 --- /dev/null +++ b/ThinkPHP/Library/Think/Template/TagLib/Html.class.php @@ -0,0 +1,524 @@ + +// +---------------------------------------------------------------------- +namespace Think\Template\TagLib; +use Think\Template\TagLib; +defined('THINK_PATH') or exit(); +/** + * Html标签库驱动 + */ +class Html extends TagLib{ + // 标签定义 + protected $tags = array( + // 标签定义: attr 属性列表 close 是否闭合(0 或者1 默认1) alias 标签别名 level 嵌套层次 + 'editor' => array('attr'=>'id,name,style,width,height,type','close'=>1), + 'select' => array('attr'=>'name,options,values,output,multiple,id,size,first,change,selected,dblclick','close'=>0), + 'grid' => array('attr'=>'id,pk,style,action,actionlist,show,datasource','close'=>0), + 'list' => array('attr'=>'id,pk,style,action,actionlist,show,datasource,checkbox','close'=>0), + 'imagebtn' => array('attr'=>'id,name,value,type,style,click','close'=>0), + 'checkbox' => array('attr'=>'name,checkboxes,checked,separator','close'=>0), + 'radio' => array('attr'=>'name,radios,checked,separator','close'=>0) + ); + + /** + * editor标签解析 插入可视化编辑器 + * 格式: {$vo.remark} + * @access public + * @param array $tag 标签属性 + * @return string|void + */ + public function _editor($tag,$content) { + $id = !empty($tag['id'])?$tag['id']: '_editor'; + $name = $tag['name']; + $style = !empty($tag['style'])?$tag['style']:''; + $width = !empty($tag['width'])?$tag['width']: '100%'; + $height = !empty($tag['height'])?$tag['height'] :'320px'; + // $content = $tag['content']; + $type = $tag['type'] ; + switch(strtoupper($type)) { + case 'FCKEDITOR': + $parseStr = ' '; + break; + case 'FCKMINI': + $parseStr = ' '; + break; + case 'EWEBEDITOR': + $parseStr = ""; + break; + case 'NETEASE': + $parseStr = ''; + break; + case 'UBB': + $parseStr = '
'; + break; + case 'KINDEDITOR': + $parseStr = ''; + break; + default : + $parseStr = ''; + } + + return $parseStr; + } + + /** + * imageBtn标签解析 + * 格式: + * @access public + * @param array $tag 标签属性 + * @return string|void + */ + public function _imageBtn($tag) { + $name = $tag['name']; //名称 + $value = $tag['value']; //文字 + $id = isset($tag['id'])?$tag['id']:''; //ID + $style = isset($tag['style'])?$tag['style']:''; //样式名 + $click = isset($tag['click'])?$tag['click']:''; //点击 + $type = empty($tag['type'])?'button':$tag['type']; //按钮类型 + + if(!empty($name)) { + $parseStr = '
'; + }else { + $parseStr = '
'; + } + + return $parseStr; + } + + /** + * imageLink标签解析 + * 格式: + * @access public + * @param array $tag 标签属性 + * @return string|void + */ + public function _imgLink($tag) { + $name = $tag['name']; //名称 + $alt = $tag['alt']; //文字 + $id = $tag['id']; //ID + $style = $tag['style']; //样式名 + $click = $tag['click']; //点击 + $type = $tag['type']; //点击 + if(empty($type)) { + $type = 'button'; + } + $parseStr = ''; + + return $parseStr; + } + + /** + * select标签解析 + * 格式: + * @access public + * @param array $tag 标签属性 + * @return string|void + */ + public function _select($tag) { + $name = $tag['name']; + $options = $tag['options']; + $values = $tag['values']; + $output = $tag['output']; + $multiple = $tag['multiple']; + $id = $tag['id']; + $size = $tag['size']; + $first = $tag['first']; + $selected = $tag['selected']; + $style = $tag['style']; + $ondblclick = $tag['dblclick']; + $onchange = $tag['change']; + + if(!empty($multiple)) { + $parseStr = ''; + } + if(!empty($first)) { + $parseStr .= ''; + } + if(!empty($options)) { + $parseStr .= '$val) { ?>'; + if(!empty($selected)) { + $parseStr .= ''; + $parseStr .= ''; + $parseStr .= ''; + $parseStr .= ''; + }else { + $parseStr .= ''; + } + $parseStr .= ''; + }else if(!empty($values)) { + $parseStr .= ''; + if(!empty($selected)) { + $parseStr .= ''; + $parseStr .= ''; + $parseStr .= ''; + $parseStr .= ''; + }else { + $parseStr .= ''; + } + $parseStr .= ''; + } + $parseStr .= ''; + return $parseStr; + } + + /** + * checkbox标签解析 + * 格式: + * @access public + * @param array $tag 标签属性 + * @return string|void + */ + public function _checkbox($tag) { + $name = $tag['name']; + $checkboxes = $tag['checkboxes']; + $checked = $tag['checked']; + $separator = $tag['separator']; + $checkboxes = $this->tpl->get($checkboxes); + $checked = $this->tpl->get($checked)?$this->tpl->get($checked):$checked; + $parseStr = ''; + foreach($checkboxes as $key=>$val) { + if($checked == $key || in_array($key,$checked) ) { + $parseStr .= ''.$val.$separator; + }else { + $parseStr .= ''.$val.$separator; + } + } + return $parseStr; + } + + /** + * radio标签解析 + * 格式: + * @access public + * @param array $tag 标签属性 + * @return string|void + */ + public function _radio($tag) { + $name = $tag['name']; + $radios = $tag['radios']; + $checked = $tag['checked']; + $separator = $tag['separator']; + $radios = $this->tpl->get($radios); + $checked = $this->tpl->get($checked)?$this->tpl->get($checked):$checked; + $parseStr = ''; + foreach($radios as $key=>$val) { + if($checked == $key ) { + $parseStr .= ''.$val.$separator; + }else { + $parseStr .= ''.$val.$separator; + } + + } + return $parseStr; + } + + /** + * list标签解析 + * 格式: + * @access public + * @param array $tag 标签属性 + * @return string + */ + public function _grid($tag) { + $id = $tag['id']; //表格ID + $datasource = $tag['datasource']; //列表显示的数据源VoList名称 + $pk = empty($tag['pk'])?'id':$tag['pk'];//主键名,默认为id + $style = $tag['style']; //样式名 + $name = !empty($tag['name'])?$tag['name']:'vo'; //Vo对象名 + $action = !empty($tag['action'])?$tag['action']:false; //是否显示功能操作 + $key = !empty($tag['key'])?true:false; + if(isset($tag['actionlist'])) { + $actionlist = explode(',',trim($tag['actionlist'])); //指定功能列表 + } + + if(substr($tag['show'],0,1)=='$') { + $show = $this->tpl->get(substr($tag['show'],1)); + }else { + $show = $tag['show']; + } + $show = explode(',',$show); //列表显示字段列表 + + //计算表格的列数 + $colNum = count($show); + if(!empty($action)) $colNum++; + if(!empty($key)) $colNum++; + + //显示开始 + $parseStr = "\n"; + $parseStr .= ''; + $parseStr .= ''; + $parseStr .= ''; + //列表需要显示的字段 + $fields = array(); + foreach($show as $val) { + $fields[] = explode(':',$val); + } + + if(!empty($key)) { + $parseStr .= ''; + } + foreach($fields as $field) {//显示指定的字段 + $property = explode('|',$field[0]); + $showname = explode('|',$field[1]); + if(isset($showname[1])) { + $parseStr .= ''; + } + if(!empty($action)) {//如果指定显示操作功能列 + $parseStr .= ''; + } + $parseStr .= ''; + $parseStr .= ''; //支持鼠标移动单元行颜色变化 具体方法在js中定义 + + if(!empty($key)) { + $parseStr .= ''; + } + foreach($fields as $field) { + //显示定义的列表字段 + $parseStr .= ''; + + } + if(!empty($action)) {//显示功能操作 + if(!empty($actionlist[0])) {//显示指定的功能项 + $parseStr .= ''; + } + } + $parseStr .= '
No'; + }else { + $parseStr .= ''; + } + $parseStr .= $showname[0].'操作
{$i}'; + if(!empty($field[2])) { + // 支持列表字段链接功能 具体方法由JS函数实现 + $href = explode('|',$field[2]); + if(count($href)>1) { + //指定链接传的字段值 + // 支持多个字段传递 + $array = explode('^',$href[1]); + if(count($array)>1) { + foreach ($array as $a){ + $temp[] = '\'{$'.$name.'.'.$a.'|addslashes}\''; + } + $parseStr .= ''; + }else{ + $parseStr .= ''; + } + }else { + //如果没有指定默认传编号值 + $parseStr .= ''; + } + } + if(strpos($field[0],'^')) { + $property = explode('^',$field[0]); + foreach ($property as $p){ + $unit = explode('|',$p); + if(count($unit)>1) { + $parseStr .= '{$'.$name.'.'.$unit[0].'|'.$unit[1].'} '; + }else { + $parseStr .= '{$'.$name.'.'.$p.'} '; + } + } + }else{ + $property = explode('|',$field[0]); + if(count($property)>1) { + $parseStr .= '{$'.$name.'.'.$property[0].'|'.$property[1].'}'; + }else { + $parseStr .= '{$'.$name.'.'.$field[0].'}'; + } + } + if(!empty($field[2])) { + $parseStr .= ''; + } + $parseStr .= ''; + foreach($actionlist as $val) { + if(strpos($val,':')) { + $a = explode(':',$val); + if(count($a)>2) { + $parseStr .= ''.$a[1].' '; + }else { + $parseStr .= ''.$a[1].' '; + } + }else{ + $array = explode('|',$val); + if(count($array)>2) { + $parseStr .= ' '.$array[2].' '; + }else{ + $parseStr .= ' {$'.$name.'.'.$val.'} '; + } + } + } + $parseStr .= '
'; + $parseStr .= "\n\n"; + return $parseStr; + } + + /** + * list标签解析 + * 格式: + * @access public + * @param array $tag 标签属性 + * @return string + */ + public function _list($tag) { + $id = $tag['id']; //表格ID + $datasource = $tag['datasource']; //列表显示的数据源VoList名称 + $pk = empty($tag['pk'])?'id':$tag['pk'];//主键名,默认为id + $style = $tag['style']; //样式名 + $name = !empty($tag['name'])?$tag['name']:'vo'; //Vo对象名 + $action = $tag['action']=='true'?true:false; //是否显示功能操作 + $key = !empty($tag['key'])?true:false; + $sort = $tag['sort']=='false'?false:true; + $checkbox = $tag['checkbox']; //是否显示Checkbox + if(isset($tag['actionlist'])) { + if(substr($tag['actionlist'],0,1)=='$') { + $actionlist = $this->tpl->get(substr($tag['actionlist'],1)); + }else { + $actionlist = $tag['actionlist']; + } + $actionlist = explode(',',trim($actionlist)); //指定功能列表 + } + + if(substr($tag['show'],0,1)=='$') { + $show = $this->tpl->get(substr($tag['show'],1)); + }else { + $show = $tag['show']; + } + $show = explode(',',$show); //列表显示字段列表 + + //计算表格的列数 + $colNum = count($show); + if(!empty($checkbox)) $colNum++; + if(!empty($action)) $colNum++; + if(!empty($key)) $colNum++; + + //显示开始 + $parseStr = "\n"; + $parseStr .= ''; + $parseStr .= ''; + $parseStr .= ''; + //列表需要显示的字段 + $fields = array(); + foreach($show as $val) { + $fields[] = explode(':',$val); + } + if(!empty($checkbox) && 'true'==strtolower($checkbox)) {//如果指定需要显示checkbox列 + $parseStr .=''; + } + if(!empty($key)) { + $parseStr .= ''; + } + foreach($fields as $field) {//显示指定的字段 + $property = explode('|',$field[0]); + $showname = explode('|',$field[1]); + if(isset($showname[1])) { + $parseStr .= ''; + }else{ + $parseStr .= $showname[0].''; + } + + } + if(!empty($action)) {//如果指定显示操作功能列 + $parseStr .= ''; + } + + $parseStr .= ''; + $parseStr .= ''; + } + if(!empty($key)) { + $parseStr .= ''; + } + foreach($fields as $field) { + //显示定义的列表字段 + $parseStr .= ''; + + } + if(!empty($action)) {//显示功能操作 + if(!empty($actionlist[0])) {//显示指定的功能项 + $parseStr .= ''; + } + } + $parseStr .= '
No'; + }else { + $parseStr .= ''; + } + $showname[2] = isset($showname[2])?$showname[2]:$showname[0]; + if($sort) { + $parseStr .= ''.$showname[0].'操作
{$i}'; + if(!empty($field[2])) { + // 支持列表字段链接功能 具体方法由JS函数实现 + $href = explode('|',$field[2]); + if(count($href)>1) { + //指定链接传的字段值 + // 支持多个字段传递 + $array = explode('^',$href[1]); + if(count($array)>1) { + foreach ($array as $a){ + $temp[] = '\'{$'.$name.'.'.$a.'|addslashes}\''; + } + $parseStr .= ''; + }else{ + $parseStr .= ''; + } + }else { + //如果没有指定默认传编号值 + $parseStr .= ''; + } + } + if(strpos($field[0],'^')) { + $property = explode('^',$field[0]); + foreach ($property as $p){ + $unit = explode('|',$p); + if(count($unit)>1) { + $parseStr .= '{$'.$name.'.'.$unit[0].'|'.$unit[1].'} '; + }else { + $parseStr .= '{$'.$name.'.'.$p.'} '; + } + } + }else{ + $property = explode('|',$field[0]); + if(count($property)>1) { + $parseStr .= '{$'.$name.'.'.$property[0].'|'.$property[1].'}'; + }else { + $parseStr .= '{$'.$name.'.'.$field[0].'}'; + } + } + if(!empty($field[2])) { + $parseStr .= ''; + } + $parseStr .= ''; + foreach($actionlist as $val) { + if(strpos($val,':')) { + $a = explode(':',$val); + if(count($a)>2) { + $parseStr .= ''.$a[1].' '; + }else { + $parseStr .= ''.$a[1].' '; + } + }else{ + $array = explode('|',$val); + if(count($array)>2) { + $parseStr .= ' '.$array[2].' '; + }else{ + $parseStr .= ' {$'.$name.'.'.$val.'} '; + } + } + } + $parseStr .= '
'; + $parseStr .= "\n\n"; + return $parseStr; + } +} \ No newline at end of file diff --git a/ThinkPHP/Library/Think/Think.class.php b/ThinkPHP/Library/Think/Think.class.php new file mode 100644 index 000000000..99d8ea359 --- /dev/null +++ b/ThinkPHP/Library/Think/Think.class.php @@ -0,0 +1,322 @@ + +// +---------------------------------------------------------------------- + +namespace Think; +/** + * ThinkPHP 引导类 + */ +class Think { + + // 类映射 + private static $_map = array(); + + // 实例化对象 + private static $_instance = array(); + + /** + * 应用程序初始化 + * @access public + * @return void + */ + static public function start() { + // 注册AUTOLOAD方法 + spl_autoload_register('Think\Think::autoload'); + // 设定错误和异常处理 + register_shutdown_function('Think\Think::fatalError'); + set_error_handler('Think\Think::appError'); + set_exception_handler('Think\Think::appException'); + + // 初始化文件存储方式 + Storage::connect(STORAGE_TYPE); + + $runtimefile = RUNTIME_PATH.APP_MODE.'~runtime.php'; + if(!APP_DEBUG && Storage::has($runtimefile,'runtime')){ + Storage::load($runtimefile,null,'runtime'); + }else{ + if(Storage::has($runtimefile,'runtime')) + Storage::unlink($runtimefile,'runtime'); + $content = ''; + // 读取应用模式 + $mode = include is_file(COMMON_PATH.'Conf/core.php')?COMMON_PATH.'Conf/core.php':THINK_PATH.'Conf/Mode/'.APP_MODE.'.php'; + // 加载核心文件 + foreach ($mode['core'] as $file){ + if(is_file($file)) { + include $file; + if(!APP_DEBUG) $content .= compile($file); + } + } + + // 加载应用模式配置文件 + foreach ($mode['config'] as $key=>$file){ + is_numeric($key)?C(include $file):C($key,include $file); + } + + // 加载模式别名定义 + if(isset($mode['alias'])){ + self::addMap(is_array($mode['alias'])?$mode['alias']:include $mode['alias']); + } + + // 加载应用别名定义文件 + if(is_file(COMMON_PATH.'Conf/alias.php')) + self::addMap(include COMMON_PATH.'Conf/alias.php'); + + // 加载模式行为定义 + if(isset($mode['tags'])) { + Hook::import(is_array($mode['tags'])?$mode['tags']:include $mode['tags']); + } + + // 加载应用行为定义 + if(is_file(COMMON_PATH.'Conf/tags.php')) + // 允许应用增加开发模式配置定义 + Hook::import(include COMMON_PATH.'Conf/tags.php'); + + // 加载框架底层语言包 + L(include THINK_PATH.'Lang/'.strtolower(C('DEFAULT_LANG')).'.php'); + + if(!APP_DEBUG){ + $content .= "\nnamespace { Think\Think::addMap(".var_export(self::$_map,true).");"; + $content .= "\nL(".var_export(L(),true).");\nC(".var_export(C(),true).');Think\Hook::import('.var_export(Hook::get(),true).');}'; + Storage::put($runtimefile,strip_whitespace('getMessage(); + $trace = $e->getTrace(); + if('E'==$trace[0]['function']) { + $error['file'] = $trace[0]['file']; + $error['line'] = $trace[0]['line']; + }else{ + $error['file'] = $e->getFile(); + $error['line'] = $e->getLine(); + } + $error['trace'] = $e->getTraceAsString(); + Log::record($error['message'],Log::ERR); + // 发送404信息 + header('HTTP/1.1 404 Not Found'); + header('Status:404 Not Found'); + self::halt($error); + } + + /** + * 自定义错误处理 + * @access public + * @param int $errno 错误类型 + * @param string $errstr 错误信息 + * @param string $errfile 错误文件 + * @param int $errline 错误行数 + * @return void + */ + static public function appError($errno, $errstr, $errfile, $errline) { + switch ($errno) { + case E_ERROR: + case E_PARSE: + case E_CORE_ERROR: + case E_COMPILE_ERROR: + case E_USER_ERROR: + ob_end_clean(); + $errorStr = "$errstr ".$errfile." 第 $errline 行."; + if(C('LOG_RECORD')) Log::write("[$errno] ".$errorStr,Log::ERR); + self::halt($errorStr); + break; + case E_STRICT: + case E_USER_WARNING: + case E_USER_NOTICE: + default: + $errorStr = "[$errno] $errstr ".$errfile." 第 $errline 行."; + self::trace($errorStr,'','NOTIC'); + break; + } + } + + // 致命错误捕获 + static public function fatalError() { + Log::save(); + if ($e = error_get_last()) { + + switch($e['type']){ + case E_ERROR: + case E_PARSE: + case E_CORE_ERROR: + case E_COMPILE_ERROR: + case E_USER_ERROR: + ob_end_clean(); + self::halt($e); + break; + } + } + } + + /** + * 错误输出 + * @param mixed $error 错误 + * @return void + */ + static public function halt($error) { + $e = array(); + if (APP_DEBUG || IS_CLI) { + //调试模式下输出错误信息 + if (!is_array($error)) { + $trace = debug_backtrace(); + $e['message'] = $error; + $e['file'] = $trace[0]['file']; + $e['line'] = $trace[0]['line']; + ob_start(); + debug_print_backtrace(); + $e['trace'] = ob_get_clean(); + } else { + $e = $error; + } + if(IS_CLI){ + exit($e['message'].PHP_EOL.'FILE: '.$e['file'].'('.$e['line'].')'.PHP_EOL.$e['trace']); + } + } else { + //否则定向到错误页面 + $error_page = C('ERROR_PAGE'); + if (!empty($error_page)) { + redirect($error_page); + } else { + if (!C('SHOW_ERROR_MSG')) + $e['message'] = is_array($error) ? $error['message'] : $error; + else + $e['message'] = C('ERROR_MESSAGE'); + } + } + // 包含异常页面模板 + $TMPL_EXCEPTION_FILE=C('TMPL_EXCEPTION_FILE'); + if(!$TMPL_EXCEPTION_FILE){ + //显示在加载配置文件之前的程序错误 + exit('Error:'.$e['message'].' in '.$e['file'].' on line '.$e['line'].''); + } + include $TMPL_EXCEPTION_FILE; + exit; + } + + /** + * 添加和获取页面Trace记录 + * @param string $value 变量 + * @param string $label 标签 + * @param string $level 日志级别(或者页面Trace的选项卡) + * @param boolean $record 是否记录日志 + * @return void + */ + static public function trace($value='[think]',$label='',$level='DEBUG',$record=false) { + static $_trace = array(); + if('[think]' === $value){ // 获取trace信息 + return $_trace; + }else{ + $info = ($label?$label.':':'').print_r($value,true); + if('ERR' == $level && C('TRACE_EXCEPTION')) {// 抛出异常 + E($info); + } + $level = strtoupper($level); + if(!isset($_trace[$level]) || count($_trace[$level])>C('TRACE_MAX_RECORD')) { + $_trace[$level] = array(); + } + $_trace[$level][] = $info; + if((defined('IS_AJAX') && IS_AJAX) || !C('SHOW_PAGE_TRACE') || $record) { + Log::record($info,$level,$record); + } + } + } +} diff --git a/ThinkPHP/Library/Think/Upload.class.php b/ThinkPHP/Library/Think/Upload.class.php new file mode 100644 index 000000000..57dfca925 --- /dev/null +++ b/ThinkPHP/Library/Think/Upload.class.php @@ -0,0 +1,374 @@ + +// +---------------------------------------------------------------------- +namespace Think; +class Upload{ + /** + * 默认上传配置 + * @var array + */ + private $config = array( + 'mimes' => array(), //允许上传的文件MiMe类型 + 'maxSize' => 0, //上传的文件大小限制 (0-不做限制) + 'exts' => array(), //允许上传的文件后缀 + 'autoSub' => true, //自动子目录保存文件 + 'subName' => array('date', 'Y-m-d'), //子目录创建方式,[0]-函数名,[1]-参数,多个参数使用数组 + 'rootPath' => './Uploads/', //保存根路径 + 'savePath' => '', //保存路径 + 'saveName' => array('uniqid', ''), //上传文件命名规则,[0]-函数名,[1]-参数,多个参数使用数组 + 'saveExt' => '', //文件保存后缀,空则使用原后缀 + 'replace' => false, //存在同名是否覆盖 + 'hash' => true, //是否生成hash编码 + 'callback' => false, //检测文件是否存在回调,如果存在返回文件信息数组 + ); + + /** + * 上传错误信息 + * @var string + */ + private $error = ''; //上传错误信息 + + /** + * 上传驱动实例 + * @var Object + */ + private $uploader; + + /** + * 构造方法,用于构造上传实例 + * @param array $config 配置 + * @param string $driver 要使用的上传驱动 LOCAL-本地上传驱动,FTP-FTP上传驱动 + */ + public function __construct($config = array(), $driver = '', $driverConfig = null){ + /* 获取配置 */ + $this->config = array_merge($this->config, $config); + $driver = $driver? $driver : C('FILE_UPLOAD_TYPE'); + + /* 设置上传驱动 */ + if(!strpos($driver,'\\')){ + $class = 'Think\\Upload\\Driver\\'.ucfirst(strtolower($driver)); + }else{ + $class = $driver; + } + $this->setDriver($class, $driverConfig); + + /* 调整配置,把字符串配置参数转换为数组 */ + if(!empty($this->config['mimes'])){ + if(is_string($this->mimes)) { + $this->config['mimes'] = explode(',', $this->mimes); + } + $this->config['mimes'] = array_map('strtolower', $this->mimes); + } + if(!empty($this->config['exts'])){ + if (is_string($this->exts)){ + $this->config['exts'] = explode(',', $this->exts); + } + $this->config['exts'] = array_map('strtolower', $this->exts); + } + } + + /** + * 使用 $this->name 获取配置 + * @param string $name 配置名称 + * @return multitype 配置值 + */ + public function __get($name) { + return $this->config[$name]; + } + + /** + * 获取最后一次上传错误信息 + * @return string 错误信息 + */ + public function getError(){ + return $this->error; + } + + /** + * 上传单个文件 + * @param array $file 文件数组 + * @return array 上传成功后的文件信息 + */ + public function uploadOne($file){ + $info = $this->upload(array($file)); + return $info ? $info[0] : $info; + } + + /** + * 上传文件 + * @param 文件信息数组 $files ,通常是 $_FILES数组 + */ + public function upload($files) { + if(empty($files)){ + $this->error = '没有上传的文件!'; + return false; + } + + /* 检测上传根目录 */ + if(!$this->uploader->checkRootPath()){ + $this->error = $this->uploader->getError(); + return false; + } + + /* 检查上传目录 */ + if(!$this->uploader->checkSavePath($this->savePath)){ + $this->error = $this->uploader->getError(); + return false; + } + + /* 逐个检测并上传文件 */ + $info = array(); + foreach ($files as $key => $file) { + /* 通过扩展获取文件类型,可解决FLASH上传$FILES数组返回文件类型错误的问题 */ + if(function_exists('mime_content_type')){ + $file['type'] = mime_content_type($file['tmp_name']); + } + + /* 获取上传文件后缀,允许上传无后缀文件 */ + $file['ext'] = pathinfo($file['name'], PATHINFO_EXTENSION); + + /* 文件上传检测 */ + if (!$this->check($file)){ + continue; + } + + /* 获取文件hash */ + if($this->hash){ + $file['md5'] = md5_file($file['tmp_name']); + $file['sha1'] = sha1_file($file['tmp_name']); + } + + /* 调用回调函数检测文件是否存在 */ + $data = call_user_func($this->callback, $file); + if( $this->callback && $data ){ + if ( file_exists('.'.$data['path']) ) { + $info[$key] = $data; + continue; + }elseif($this->removeTrash){ + call_user_func($this->removeTrash,$data);//删除垃圾据 + } + } + + /* 生成保存文件名 */ + $savename = $this->getSaveName($file); + if(false == $savename){ + continue; + } else { + $file['savename'] = $savename; + } + + /* 检测并创建子目录 */ + $subpath = $this->getSubPath($file['name']); + if(false === $subpath){ + continue; + } else { + $file['savepath'] = $this->savePath . $subpath; + } + + /* 对图像文件进行严格检测 */ + $ext = strtolower($file['ext']); + if(in_array($ext, array('gif','jpg','jpeg','bmp','png','swf'))) { + $imginfo = getimagesize($file['tmp_name']); + if(empty($imginfo) || ($ext == 'gif' && empty($imginfo['bits']))){ + $this->error = '非法图像文件!'; + continue; + } + } + + /* 保存文件 并记录保存成功的文件 */ + if ($this->uploader->save($file)) { + unset($file['error'], $file['tmp_name']); + $info[$key] = $file; + } else { + $this->error = $this->uploader->getError(); + } + } + + return empty($info) ? false : $info; + } + + /** + * 设置上传驱动 + * @param string $class 驱动类名称 + */ + private function setDriver($class, $config){ + $this->uploader = new $class($this->rootPath, $config); + if(!$this->uploader){ + E("不存在上传驱动:{$name}"); + } + } + + /** + * 检查上传的文件 + * @param array $file 文件信息 + */ + private function check($file) { + /* 文件上传失败,捕获错误代码 */ + if ($file['error']) { + $this->error($file['error']); + return false; + } + + /* 无效上传 */ + if (empty($file['name'])){ + $this->error = '未知上传错误!'; + } + + /* 检查是否合法上传 */ + if (!is_uploaded_file($file['tmp_name'])) { + $this->error = '非法上传文件!'; + return false; + } + + /* 检查文件大小 */ + if (!$this->checkSize($file['size'])) { + $this->error = '上传文件大小不符!'; + return false; + } + + /* 检查文件Mime类型 */ + //TODO:FLASH上传的文件获取到的mime类型都为application/octet-stream + if (!$this->checkMime($file['type'])) { + $this->error = '上传文件MIME类型不允许!'; + return false; + } + + /* 检查文件后缀 */ + if (!$this->checkExt($file['ext'])) { + $this->error = '上传文件后缀不允许'; + return false; + } + + /* 通过检测 */ + return true; + } + + + /** + * 获取错误代码信息 + * @param string $errorNo 错误号 + */ + private function error($errorNo) { + switch ($errorNo) { + case 1: + $this->error = '上传的文件超过了 php.ini 中 upload_max_filesize 选项限制的值!'; + break; + case 2: + $this->error = '上传文件的大小超过了 HTML 表单中 MAX_FILE_SIZE 选项指定的值!'; + break; + case 3: + $this->error = '文件只有部分被上传!'; + break; + case 4: + $this->error = '没有文件被上传!'; + break; + case 6: + $this->error = '找不到临时文件夹!'; + break; + case 7: + $this->error = '文件写入失败!'; + break; + default: + $this->error = '未知上传错误!'; + } + } + + /** + * 检查文件大小是否合法 + * @param integer $size 数据 + */ + private function checkSize($size) { + return !($size > $this->maxSize) || (0 == $this->maxSize); + } + + /** + * 检查上传的文件MIME类型是否合法 + * @param string $mime 数据 + */ + private function checkMime($mime) { + return empty($this->config['mimes']) ? true : in_array(strtolower($mime), $this->mimes); + } + + /** + * 检查上传的文件后缀是否合法 + * @param string $ext 后缀 + */ + private function checkExt($ext) { + return empty($this->config['exts']) ? true : in_array(strtolower($ext), $this->exts); + } + + /** + * 根据上传文件命名规则取得保存文件名 + * @param string $file 文件信息 + */ + private function getSaveName($file) { + $rule = $this->saveName; + if (empty($rule)) { //保持文件名不变 + /* 解决pathinfo中文文件名BUG */ + $filename = substr(pathinfo("_{$file['name']}", PATHINFO_FILENAME), 1); + $savename = $filename; + } else { + $savename = $this->getName($rule, $file['name']); + if(empty($savename)){ + $this->error = '文件命名规则错误!'; + return false; + } + } + + /* 文件保存后缀,支持强制更改文件后缀 */ + $ext = empty($this->config['saveExt']) ? $file['ext'] : $this->saveExt; + + return $savename . '.' . $ext; + } + + /** + * 获取子目录的名称 + * @param array $file 上传的文件信息 + */ + private function getSubPath($filename) { + $subpath = ''; + $rule = $this->subName; + if ($this->autoSub && !empty($rule)) { + $subpath = $this->getName($rule, $filename) . '/'; + + if(!empty($subpath) && !$this->uploader->mkdir($this->savePath . $subpath)){ + $this->error = $this->uploader->getError(); + return false; + } + } + return $subpath; + } + + /** + * 根据指定的规则获取文件或目录名称 + * @param array $rule 规则 + * @param string $filename 原文件名 + * @return string 文件或目录名称 + */ + private function getName($rule, $filename){ + $name = ''; + if(is_array($rule)){ //数组规则 + $func = $rule[0]; + $param = (array)$rule[1]; + foreach ($param as &$value) { + $value = str_replace('__FILE__', $filename, $value); + } + $name = call_user_func_array($func, $param); + } elseif (is_string($rule)){ //字符串规则 + if(function_exists($rule)){ + $name = call_user_func($rule); + } else { + $name = $rule; + } + } + return $name; + } + +} diff --git a/ThinkPHP/Library/Think/Upload/Driver/Bcs.class.php b/ThinkPHP/Library/Think/Upload/Driver/Bcs.class.php new file mode 100644 index 000000000..7870c4060 --- /dev/null +++ b/ThinkPHP/Library/Think/Upload/Driver/Bcs.class.php @@ -0,0 +1,237 @@ + +// +---------------------------------------------------------------------- +namespace Think\Upload\Driver; +use Think\Upload\Driver\Bcs\BaiduBcs; +class Bcs{ + /** + * 上传文件根目录 + * @var string + */ + private $rootPath; + const DEFAULT_URL = 'bcs.duapp.com'; + + /** + * 上传错误信息 + * @var string + */ + private $error = ''; + + public $config = array( + 'AccessKey'=> '', + 'SecretKey'=> '', //百度云服务器 + 'bucket' => '', //空间名称 + 'rename' => false, + 'timeout' => 3600, //超时时间 + ); + + public $bcs = null; + + /** + * 构造函数,用于设置上传根路径 + * @param string $root 根目录 + * @param array $config FTP配置 + */ + public function __construct($root, $config){ + /* 默认FTP配置 */ + $this->config = array_merge($this->config, $config); + /* 设置根目录 */ + $this->rootPath = str_replace('./', '/', $root); + $bcsClass = dirname(__FILE__). "/Bcs/bcs.class.php"; + if(is_file($bcsClass)) + require_once($bcsClass); + $this->bcs = new BaiduBCS ( $this->config['AccessKey'], $this->config['SecretKey'], self:: DEFAULT_URL ); + } + + /** + * 检测上传根目录(百度云上传时支持自动创建目录,直接返回) + * @return boolean true-检测通过,false-检测失败 + */ + public function checkRootPath(){ + return true; + } + + /** + * 检测上传目录(百度云上传时支持自动创建目录,直接返回) + * @param string $savepath 上传目录 + * @return boolean 检测结果,true-通过,false-失败 + */ + public function checkSavePath($savepath){ + return true; + } + + /** + * 创建文件夹 (百度云上传时支持自动创建目录,直接返回) + * @param string $savepath 目录名称 + * @return boolean true-创建成功,false-创建失败 + */ + public function mkdir($savepath){ + return true; + } + + /** + * 保存指定文件 + * @param array $file 保存的文件信息 + * @param boolean $replace 同名文件是否覆盖 + * @return boolean 保存状态,true-成功,false-失败 + */ + public function save(&$file) { + $opt = array (); + $opt ['acl'] = BaiduBCS::BCS_SDK_ACL_TYPE_PUBLIC_WRITE; + $opt ['curlopts'] = array ( + CURLOPT_CONNECTTIMEOUT => 10, + CURLOPT_TIMEOUT => 1800 + ); + $object = "/{$file['savepath']}{$file['savename']}"; + $response = $this->bcs->create_object ( $this->config['bucket'], $object, $file['tmp_name'], $opt ); + $url = $this->download($object); + $file['url'] = $url; + return $response->isOK() ? true : false; + } + + public function download($file){ + $file = str_replace('./', '/', $file); + $opt = array(); + $opt['time'] = mktime('2049-12-31'); //这是最长有效时间!-- + $response = $this->bcs->generate_get_object_url ( $this->config['bucket'], $file, $opt ); + return $response; + } + + /** + * 获取最后一次上传错误信息 + * @return string 错误信息 + */ + public function getError(){ + return $this->error; + } + + /** + * 请求百度云服务器 + * @param string $path 请求的PATH + * @param string $method 请求方法 + * @param array $headers 请求header + * @param resource $body 上传文件资源 + * @return boolean + */ + private function request($path, $method, $headers = null, $body = null){ + $ch = curl_init($path); + + $_headers = array('Expect:'); + if (!is_null($headers) && is_array($headers)){ + foreach($headers as $k => $v) { + array_push($_headers, "{$k}: {$v}"); + } + } + + $length = 0; + $date = gmdate('D, d M Y H:i:s \G\M\T'); + + if (!is_null($body)) { + if(is_resource($body)){ + fseek($body, 0, SEEK_END); + $length = ftell($body); + fseek($body, 0); + + array_push($_headers, "Content-Length: {$length}"); + curl_setopt($ch, CURLOPT_INFILE, $body); + curl_setopt($ch, CURLOPT_INFILESIZE, $length); + } else { + $length = @strlen($body); + array_push($_headers, "Content-Length: {$length}"); + curl_setopt($ch, CURLOPT_POSTFIELDS, $body); + } + } else { + array_push($_headers, "Content-Length: {$length}"); + } + + // array_push($_headers, 'Authorization: ' . $this->sign($method, $uri, $date, $length)); + array_push($_headers, "Date: {$date}"); + + curl_setopt($ch, CURLOPT_HTTPHEADER, $_headers); + curl_setopt($ch, CURLOPT_TIMEOUT, $this->config['timeout']); + curl_setopt($ch, CURLOPT_HEADER, 1); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0); + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method); + + if ($method == 'PUT' || $method == 'POST') { + curl_setopt($ch, CURLOPT_POST, 1); + } else { + curl_setopt($ch, CURLOPT_POST, 0); + } + + if ($method == 'HEAD') { + curl_setopt($ch, CURLOPT_NOBODY, true); + } + + $response = curl_exec($ch); + $status = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + list($header, $body) = explode("\r\n\r\n", $response, 2); + + if ($status == 200) { + if ($method == 'GET') { + return $body; + } else { + $data = $this->response($header); + return count($data) > 0 ? $data : true; + } + } else { + $this->error($header); + return false; + } + } + + /** + * 获取响应数据 + * @param string $text 响应头字符串 + * @return array 响应数据列表 + */ + private function response($text){ + $items = json_decode($text, true); + return $items; + } + + /** + * 生成请求签名 + * @return string 请求签名 + */ + private function sign($method, $Bucket, $object='/', $size=''){ + if(!$size) + $size = $this->config['size']; + $param = array( + 'ak'=>$this->config['AccessKey'], + 'sk'=>$this->config['SecretKey'], + 'size'=>$size, + 'bucket'=>$Bucket, + 'host'=>self :: DEFAULT_URL, + 'date'=>time()+$this->config['timeout'], + 'ip'=>'', + 'object'=>$object + ); + $response = $this->request($this->apiurl.'?'.http_build_query($param), 'POST'); + if($response) + $response = json_decode($response, true); + return $response['content'][$method]; + } + + + /** + * 获取请求错误信息 + * @param string $header 请求返回头信息 + */ + private function error($header) { + list($status, $stash) = explode("\r\n", $header, 2); + list($v, $code, $message) = explode(" ", $status, 3); + $message = is_null($message) ? 'File Not Found' : "[{$status}]:{$message}"; + $this->error = $message; + } + +} diff --git a/ThinkPHP/Library/Think/Upload/Driver/Bcs/bcs.class.php b/ThinkPHP/Library/Think/Upload/Driver/Bcs/bcs.class.php new file mode 100644 index 000000000..a990aecbf --- /dev/null +++ b/ThinkPHP/Library/Think/Upload/Driver/Bcs/bcs.class.php @@ -0,0 +1,1318 @@ +ak = $ak; + $this->sk = $sk; + } elseif (defined ( 'BCS_AK' ) && defined ( 'BCS_SK' ) && strlen ( BCS_AK ) > 0 && strlen ( BCS_SK ) > 0) { + $this->ak = BCS_AK; + $this->sk = BCS_SK; + } elseif (false !== getenv ( 'HTTP_BAE_ENV_AK' ) && false !== getenv ( 'HTTP_BAE_ENV_SK' )) { + $this->ak = getenv ( 'HTTP_BAE_ENV_AK' ); + $this->sk = getenv ( 'HTTP_BAE_ENV_SK' ); + } else { + throw new BCS_Exception ( 'Construct can not get ak &sk pair, please check!' ); + } + //valid $hostname + if (NULL !== $hostname) { + $this->hostname = $hostname; + } elseif (false !== getenv ( 'HTTP_BAE_ENV_ADDR_BCS' )) { + $this->hostname = getenv ( 'HTTP_BAE_ENV_ADDR_BCS' ); + } else { + $this->hostname = self::DEFAULT_URL; + } + } + + /** + * 将消息发往Baidu BCS. + * @param array $opt + * @return BCS_ResponseCore + */ + private function authenticate($opt) { + //set common param into opt + $opt [self::AK] = $this->ak; + $opt [self::SK] = $this->sk; + + // Validate the S3 bucket name, only list_bucket didnot need validate_bucket + if (! ('/' == $opt [self::OBJECT] && '' == $opt [self::BUCKET] && 'GET' == $opt [self::METHOD] && ! isset ( $opt [self::QUERY_STRING] [self::ACL] )) && ! self::validate_bucket ( $opt [self::BUCKET] )) { + throw new BCS_Exception ( $opt [self::BUCKET] . 'is not valid, please check!' ); + } + //Validate object + if (isset ( $opt [self::OBJECT] ) && ! self::validate_object ( $opt [self::OBJECT] )) { + throw new BCS_Exception ( "Invalid object param[" . $opt [self::OBJECT] . "], please check.", - 1 ); + } + //construct url + $url = $this->format_url ( $opt ); + if ($url === false) { + throw new BCS_Exception ( 'Can not format url, please check your param!', - 1 ); + } + $opt ['url'] = $url; + $this->log ( "[method:" . $opt [self::METHOD] . "][url:$url]", $opt ); + //build request + $request = new BCS_RequestCore ( $opt ['url'] ); + $headers = array ( + 'Content-Type' => 'application/x-www-form-urlencoded' ); + + $request->set_method ( $opt [self::METHOD] ); + //Write get_object content to fileWriteTo + if (isset ( $opt ['fileWriteTo'] )) { + $request->set_write_file ( $opt ['fileWriteTo'] ); + } + // Merge the HTTP headers + if (isset ( $opt [self::HEADERS] )) { + $headers = array_merge ( $headers, $opt [self::HEADERS] ); + } + // Set content to Http-Body + if (isset ( $opt ['content'] )) { + $request->set_body ( $opt ['content'] ); + } + // Upload file + if (isset ( $opt ['fileUpload'] )) { + if (! file_exists ( $opt ['fileUpload'] )) { + throw new BCS_Exception ( 'File[' . $opt ['fileUpload'] . '] not found!', - 1 ); + } + $request->set_read_file ( $opt ['fileUpload'] ); + // Determine the length to read from the file + $length = $request->read_stream_size; // The file size by default + $file_size = $length; + if (isset ( $opt ["length"] )) { + if ($opt ["length"] > $file_size) { + throw new BCS_Exception ( "Input opt[length] invalid! It can not bigger than file-size", - 1 ); + } + $length = $opt ['length']; + } + if (isset ( $opt ['seekTo'] ) && ! isset ( $opt ["length"] )) { + // Read from seekTo until EOF by default, when set seekTo but not set $opt["length"] + $length -= ( integer ) $opt ['seekTo']; + } + $request->set_read_stream_size ( $length ); + // Attempt to guess the correct mime-type + if ($headers ['Content-Type'] === 'application/x-www-form-urlencoded') { + $extension = explode ( '.', $opt ['fileUpload'] ); + $extension = array_pop ( $extension ); + $mime_type = BCS_MimeTypes::get_mimetype ( $extension ); + $headers ['Content-Type'] = $mime_type; + } + $headers ['Content-MD5'] = ''; + } + // Handle streaming file offsets + if (isset ( $opt ['seekTo'] )) { + // Pass the seek position to BCS_RequestCore + $request->set_seek_position ( ( integer ) $opt ['seekTo'] ); + } + // Add headers to request and compute the string to sign + foreach ( $headers as $header_key => $header_value ) { + // Strip linebreaks from header values as they're illegal and can allow for security issues + $header_value = str_replace ( array ( + "\r", + "\n" ), '', $header_value ); + // Add the header if it has a value + if ($header_value !== '') { + $request->add_header ( $header_key, $header_value ); + } + } + // Set the curl options. + if (isset ( $opt ['curlopts'] ) && count ( $opt ['curlopts'] )) { + $request->set_curlopts ( $opt ['curlopts'] ); + } + $request->send_request (); + require_once(dirname(__FILE__). "/requestcore.class.php"); + return new BCS_ResponseCore ( $request->get_response_header (), $request->get_response_body (), $request->get_response_code () ); + } + + /** + * 获取当前密钥对拥有者的bucket列表 + * @param array $opt (Optional) + * BaiduBCS::IMPORT_BCS_LOG_METHOD - String - Optional: 支持用户传入日志处理函数,函数定义如 function f($log) + * @throws BCS_Exception + * @return BCS_ResponseCore + */ + public function list_bucket($opt = array()) { + $this->assertParameterArray ( $opt ); + $opt [self::BUCKET] = ''; + $opt [self::METHOD] = 'GET'; + $opt [self::OBJECT] = '/'; + $response = $this->authenticate ( $opt ); + $this->log ( $response->isOK () ? "List bucket success!" : "List bucket failed! Response: [" . $response->body . "]", $opt ); + return $response; + } + + /** + * 创建 bucket + * @param string $bucket (Required) bucket名称 + * @param string $acl (Optional) bucket权限设置,若为null,使用server分配的默认权限 + * @param array $opt (Optional) + * @throws BCS_Exception + * @return BCS_ResponseCore + */ + public function create_bucket($bucket, $acl = NULL, $opt = array()) { + $this->assertParameterArray ( $opt ); + $opt [self::BUCKET] = $bucket; + $opt [self::METHOD] = 'PUT'; + $opt [self::OBJECT] = '/'; + if (NULL !== $acl) { + if (! in_array ( $acl, self::$ACL_TYPES )) { + throw new BCS_Exception ( "Invalid acl_type[" . $acl . "], please check!", - 1 ); + } + self::set_header_into_opt ( "x-bs-acl", $acl, $opt ); + } + $response = $this->authenticate ( $opt ); + $this->log ( $response->isOK () ? "Create bucket success!" : "Create bucket failed! Response: [" . $response->body . "]", $opt ); + return $response; + } + + /** + * 删除bucket + * @param string $bucket (Required) + * @param array $opt (Optional) + * @return boolean|BCS_ResponseCore + */ + public function delete_bucket($bucket, $opt = array()) { + $this->assertParameterArray ( $opt ); + $opt [self::BUCKET] = $bucket; + $opt [self::METHOD] = 'DELETE'; + $opt [self::OBJECT] = '/'; + $response = $this->authenticate ( $opt ); + $this->log ( $response->isOK () ? "Delete bucket success!" : "Delete bucket failed! Response: [" . $response->body . "]", $opt ); + return $response; + } + + /** + * 设置bucket的acl,有三种模式, + * (1).设置详细json格式的acl; + * a. $acl 为json的array + * b. $acl 为json的string + * (2).通过acl_type字段进行设置 + * a. $acl 为BaiduBCS::$ACL_TYPES中的字段 + * @param string $bucket (Required) + * @param string $acl (Required) + * @param array $opt (Optional) + * @return boolean|BCS_ResponseCore + */ + public function set_bucket_acl($bucket, $acl, $opt = array()) { + $this->assertParameterArray ( $opt ); + $result = $this->analyze_user_acl ( $acl ); + $opt = array_merge ( $opt, $result ); + $opt [self::BUCKET] = $bucket; + $opt [self::METHOD] = 'PUT'; + $opt [self::OBJECT] = '/'; + $opt [self::QUERY_STRING] = array ( + self::ACL => 1 ); + $response = $this->authenticate ( $opt ); + $this->log ( $response->isOK () ? "Set bucket acl success!" : "Set bucket acl failed! Response: [" . $response->body . "]", $opt ); + return $response; + } + + /** + * 获取bucket的acl + * @param string $bucket (Required) + * @param array $opt (Optional) + * @return BCS_ResponseCore + */ + public function get_bucket_acl($bucket, $opt = array()) { + $this->assertParameterArray ( $opt ); + $opt [self::BUCKET] = $bucket; + $opt [self::METHOD] = 'GET'; + $opt [self::OBJECT] = '/'; + $opt [self::QUERY_STRING] = array ( + self::ACL => 1 ); + $response = $this->authenticate ( $opt ); + $this->log ( $response->isOK () ? "Get bucket acl success!" : "Get bucket acl failed! Response: [" . $response->body . "]", $opt ); + return $response; + } + + /** + * 获取bucket中object列表 + * @param string $bucket (Required) + * @param array $opt (Optional) + * start : 主要用于翻页功能,用法同mysql中start的用法 + * limit : 主要用于翻页功能,用法同mysql中limit的用法 + * prefix: 只返回以prefix为前缀的object,此处prefix必须以'/'开头 + * @throws BCS_Exception + * @return BCS_ResponseCore + */ + public function list_object($bucket, $opt = array()) { + $this->assertParameterArray ( $opt ); + $opt [self::BUCKET] = $bucket; + if (empty ( $opt [self::BUCKET] )) { + throw new BCS_Exception ( "Bucket should not be empty, please check", - 1 ); + } + $opt [self::METHOD] = 'GET'; + $opt [self::OBJECT] = '/'; + $opt [self::QUERY_STRING] = array (); + if (isset ( $opt ['start'] ) && is_int ( $opt ['start'] )) { + $opt [self::QUERY_STRING] ['start'] = $opt ['start']; + } + if (isset ( $opt ['limit'] ) && is_int ( $opt ['limit'] )) { + $opt [self::QUERY_STRING] ['limit'] = $opt ['limit']; + } + if (isset ( $opt ['prefix'] )) { + $opt [self::QUERY_STRING] ['prefix'] = rawurlencode ( $opt ['prefix'] ); + } + $response = $this->authenticate ( $opt ); + $this->log ( $response->isOK () ? "List object success!" : "Lit object failed! Response: [" . $response->body . "]", $opt ); + return $response; + } + + /** + * 以目录形式获取bucket中object列表 + * @param string $bucket (Required) + * @param $dir (Required) + * 目录名,格式为必须以'/'开头和结尾,默认为'/' + * @param string $list_model (Required) + * 目录展现形式,值可以为0,1,2,默认为2,以下对各个值的功能进行介绍: + * 0->只返回object列表,不返回子目录列表 + * 1->只返回子目录列表,不返回object列表 + * 2->同时返回子目录列表和object列表 + * @param array $opt (Optional) + * start : 主要用于翻页功能,用法同mysql中start的用法 + * limit : 主要用于翻页功能,用法同mysql中limit的用法 + * @throws BCS_Exception + * @return BCS_ResponseCore + */ + public function list_object_by_dir($bucket, $dir = '/', $list_model = 2, $opt = array()) { + $this->assertParameterArray ( $opt ); + $opt [self::BUCKET] = $bucket; + if (empty ( $opt [self::BUCKET] )) { + throw new BCS_Exception ( "Bucket should not be empty, please check", - 1 ); + } + $opt [self::METHOD] = 'GET'; + $opt [self::OBJECT] = '/'; + $opt [self::QUERY_STRING] = array (); + if (isset ( $opt ['start'] ) && is_int ( $opt ['start'] )) { + $opt [self::QUERY_STRING] ['start'] = $opt ['start']; + } + if (isset ( $opt ['limit'] ) && is_int ( $opt ['limit'] )) { + $opt [self::QUERY_STRING] ['limit'] = $opt ['limit']; + } + + $opt [self::QUERY_STRING] ['prefix'] = rawurlencode ( $dir ); + $opt [self::QUERY_STRING] ['dir'] = $list_model; + + $response = $this->authenticate ( $opt ); + $this->log ( $response->isOK () ? "List object success!" : "Lit object failed! Response: [" . $response->body . "]", $opt ); + return $response; + } + + /** + * 上传文件 + * @param string $bucket (Required) + * @param string $object (Required) + * @param string $file (Required); 需要上传的文件的文件路径 + * @param array $opt (Optional) + * filename - Optional; 指定文件名 + * acl - Optional ; 上传文件的acl,只能使用acl_type + * seekTo - Optional; 上传文件的偏移位置 + * length - Optional; 待上传长度 + * @return BCS_ResponseCore + */ + public function create_object($bucket, $object, $file, $opt = array()) { + $this->assertParameterArray ( $opt ); + $opt [self::BUCKET] = $bucket; + $opt [self::OBJECT] = $object; + $opt ['fileUpload'] = $file; + $opt [self::METHOD] = 'PUT'; + if (isset ( $opt ['acl'] )) { + if (in_array ( $opt ['acl'], self::$ACL_TYPES )) { + self::set_header_into_opt ( "x-bs-acl", $opt ['acl'], $opt ); + } else { + throw new BCS_Exception ( "Invalid acl string, it should be acl_type", - 1 ); + } + unset ( $opt ['acl'] ); + } + if (isset ( $opt ['filename'] )) { + self::set_header_into_opt ( "Content-Disposition", 'attachment; filename=' . $opt ['filename'], $opt ); + } + $response = $this->authenticate ( $opt ); + $this->log ( $response->isOK () ? "Create object[$object] file[$file] success!" : "Create object[$object] file[$file] failed! Response: [" . $response->body . "] Logid[" . $response->header ["x-bs-request-id"] . "]", $opt ); + return $response; + } + + /** + * 上传文件 + * @param string $bucket (Required) + * @param string $object (Required) + * @param string $file (Required); 需要上传的文件的文件路径 + * @param array $opt (Optional) + * filename - Optional; 指定文件名 + * acl - Optional ; 上传文件的acl,只能使用acl_type + * @return BCS_ResponseCore + */ + public function create_object_by_content($bucket, $object, $content, $opt = array()) { + $this->assertParameterArray ( $opt ); + $opt [self::BUCKET] = $bucket; + $opt [self::OBJECT] = $object; + $opt [self::METHOD] = 'PUT'; + if ($content !== NULL && is_string ( $content )) { + $opt ['content'] = $content; + } else { + throw new BCS_Exception ( "Invalid object content, please check.", - 1 ); + } + if (isset ( $opt ['acl'] )) { + if (in_array ( $opt ['acl'], self::$ACL_TYPES )) { + self::set_header_into_opt ( "x-bs-acl", $opt ['acl'], $opt ); + } else { + throw new BCS_Exception ( "Invalid acl string, it should be acl_type", - 1 ); + } + unset ( $opt ['acl'] ); + } + if (isset ( $opt ['filename'] )) { + self::set_header_into_opt ( "Content-Disposition", 'attachment; filename=' . $opt ['filename'], $opt ); + } + $response = $this->authenticate ( $opt ); + $this->log ( $response->isOK () ? "Create object[$object] success!" : "Create object[$object] failed! Response: [" . $response->body . "] Logid[" . $response->header ["x-bs-request-id"] . "]", $opt ); + return $response; + } + + /** + * 通过superfile的方式上传文件 + * @param string $bucket (Required) + * @param string $object (Required) + * @param string $file (Required); 需要上传的文件的文件路径 + * @param array $opt (Optional) + * filename - Optional; 指定文件名 + * sub_object_size - Optional; 指定子文件的划分大小,单位B,建议以256KB为单位进行子object划分,默认为1MB进行划分 + * @return BCS_ResponseCore + */ + public function create_object_superfile($bucket, $object, $file, $opt = array()) { + if (isset ( $opt ['length'] ) || isset ( $opt ['seekTo'] )) { + throw new BCS_Exception ( "Temporary unsupport opt of length and seekTo of superfile.", - 1 ); + } + //$opt array + $this->assertParameterArray ( $opt ); + $opt [self::BUCKET] = $bucket; + $opt ['fileUpload'] = $file; + $opt [self::METHOD] = 'PUT'; + if (isset ( $opt ['acl'] )) { + if (in_array ( $opt ['acl'], self::$ACL_TYPES )) { + self::set_header_into_opt ( "x-bs-acl", $opt ['acl'], $opt ); + } else { + throw new BCS_Exception ( "Invalid acl string, it should be acl_type", - 1 ); + } + unset ( $opt ['acl'] ); + } + //切片上传 + if (! file_exists ( $opt ['fileUpload'] )) { + throw new BCS_Exception ( 'File not found!', - 1 ); + } + $fileSize = filesize ( $opt ['fileUpload'] ); + $sub_object_size = 1024 * 1024; //default 1MB + if (defined ( "BCS_SUPERFILE_SLICE_SIZE" )) { + $sub_object_size = BCS_SUPERFILE_SLICE_SIZE; + } + if (isset ( $opt ["sub_object_size"] )) { + if (is_int ( $opt ["sub_object_size"] ) && $opt ["sub_object_size"] > 0) { + $sub_object_size = $opt ["sub_object_size"]; + } else { + throw new BCS_Exception ( "Param [sub_object_size] invalid ,please check!", - 1 ); + } + } + $sliceNum = intval ( ceil ( $fileSize / $sub_object_size ) ); + $this->log ( "File[" . $opt ['fileUpload'] . "], size=[$fileSize], sub_object_size=[$sub_object_size], sub_object_num=[$sliceNum]", $opt ); + $object_list = array ( + 'object_list' => array () ); + for($i = 0; $i < $sliceNum; $i ++) { + //send slice + $opt ['seekTo'] = $i * $sub_object_size; + + if (($i + 1) === $sliceNum) { + //last sub object + $opt ['length'] = (0 === $fileSize % $sub_object_size) ? $sub_object_size : $fileSize % $sub_object_size; + } else { + $opt ['length'] = $sub_object_size; + } + $opt [self::OBJECT] = $object . BCS_SUPERFILE_POSTFIX . $i; + $object_list ['object_list'] ['part_' . $i] = array (); + $object_list ['object_list'] ['part_' . $i] ['url'] = 'bs://' . $bucket . $opt [self::OBJECT]; + $this->log ( "Begin to upload Sub-object[" . $opt [self::OBJECT] . "][$i/$sliceNum][seekto:" . $opt ['seekTo'] . "][Length:" . $opt ['length'] . "]", $opt ); + $response = $this->create_object ( $bucket, $opt [self::OBJECT], $file, $opt ); + if ($response->isOK ()) { + $this->log ( "Sub-object upload[" . $opt [self::OBJECT] . "][$i/$sliceNum][seekto:" . $opt ['seekTo'] . "][Length:" . $opt ['length'] . "]success! ", $opt ); + $object_list ['object_list'] ['part_' . $i] ['etag'] = $response->header ['Content-MD5']; + continue; + } else { + $this->log ( "Sub-object upload[" . $opt [self::OBJECT] . "][$i/$sliceNum] failed! ", $opt ); + return $response; + } + } + //将子文件分片的列表构造成 superfile + unset ( $opt ['fileUpload'] ); + unset ( $opt ['length'] ); + unset ( $opt ['seekTo'] ); + $opt ['content'] = self::array_to_json ( $object_list ); + $opt [self::QUERY_STRING] = array ( + "superfile" => 1 ); + $opt [self::OBJECT] = $object; + if (isset ( $opt ['filename'] )) { + self::set_header_into_opt ( "Content-Disposition", 'attachment; filename=' . $opt ['filename'], $opt ); + } + $response = $this->authenticate ( $opt ); + $this->log ( $response->isOK () ? "Create object-superfile success!" : "Create object-superfile failed! Response: [" . $response->body . "]", $opt ); + return $response; + } + + /** + * 将目录中的所有文件进行上传,每个文件为单独object,object命名方式下详: + * 如有 /home/worker/a/b/c.txt 需上传目录为$dir=/home/worker/a + * object命令方式为 + * 1. object默认命名方式为 “子目录名 +文件名”,如上述文件c.txt,默认为 '/b/c.txt' + * 2. 增强命名模式,在$opt中有可选参数进行配置 + * 举例说明 :prefix . has_sub_directory?"/b":"" . '/c.txt' + * @param string $bucket (Required) + * @param string $dir (Required) + * @param array $opt(Optional) + * string prefix 文件object前缀 + * boolean has_sub_directory(default=true) object命名中是否携带文件的子目录结构,若置为false,请确认待上传的目录和所有子目录中没有重名文件,否则会产生object覆盖问题 + * BaiduBCS::IMPORT_BCS_PRE_FILTER 用户可自定义上传文件前的操作函数 + * 1. 函数参数列表顺序需为 ($bucket,$object,$file,&$opt),注意$opt为upload_directory函数传入的$opt的拷贝,只对当前object生效 + * 2. 函数返回值必须为boolean,当true该文件进行上传,若false跳过上传 + * 3. 如果函数返回false,将不会进行post_filter的调用 + * BaiduBCS::IMPORT_BCS_POST_FILTER 用户可自定义上传文件后的操作函数 + * 1. 函数参数列表顺序需为 ($bucket,$object,$file,&$opt,$response),注意$opt为upload_directory函数传入的$opt的拷贝,只对当前object生效 + * 2. 函数返回值无要求 + * string seek_object 用户断点续传,需要为object名称,如果该object在目录中不存在,抛出异常,若存在则将该object和此后的object进行上传 + * string seek_object_id 作用同seek_object,只需要传入上传过程中日志中展示的[a/b]中object序号即可,注意object序号是以1开始计算的 + * @return array 数组形式的上传结果 + * 'success' => int 上传成功的文件数目 + * 'skipped' => int 被跳过的文件 + * 'failed' => array() 上传失败的文件 + * + */ + public function upload_directory($bucket, $dir, $opt = array()) { + $this->assertParameterArray ( $opt ); + if (! is_dir ( $dir )) { + throw new BCS_Exception ( "$dir is not a dir!", - 1 ); + } + $result = array ( + "success" => 0, + "failed" => array (), + "skipped" => 0 ); + $prefix = ""; + if (isset ( $opt ['prefix'] )) { + $prefix = $opt ['prefix']; + } + $has_sub_directory = true; + if (isset ( $opt ['has_sub_directory'] ) && is_bool ( $opt ['has_sub_directory'] )) { + $has_sub_directory = $opt ['has_sub_directory']; + } + //获取文件树和构造object名 + $file_tree = self::get_filetree ( $dir ); + $objects = array (); + foreach ( $file_tree as $file ) { + $object = $has_sub_directory == true ? substr ( $file, strlen ( $dir ) ) : "/" . basename ( $file ); + $objects [$prefix . $object] = $file; + } + $objectCount = count ( $objects ); + $before_upload_log = "Upload directory: bucket[$bucket] upload_dir[$dir] file_sum[$objectCount]"; + if (isset ( $opt ["seek_object_id"] )) { + $before_upload_log .= " seek_object_id[" . $opt ["seek_object_id"] . "/$objectCount]"; + } + if (isset ( $opt ["seek_object"] )) { + $before_upload_log .= " seek_object[" . $opt ["seek_object"] . "]"; + } + $this->log ( $before_upload_log, $opt ); + //查看是否需要查询断点,进行断点续传 + if (isset ( $opt ["seek_object_id"] ) && isset ( $opt ["seek_object"] )) { + throw new BCS_Exception ( "Can not set see_object_id and seek_object at the same time!", - 1 ); + } + + $num = 1; + if (isset ( $opt ["seek_object"] )) { + if (isset ( $objects [$opt ["seek_object"]] )) { + foreach ( $objects as $object => $file ) { + if ($object != $opt ["seek_object"]) { + //当非断点文件,该object已完成上传 + $this->log ( "Seeking[" . $opt ["seek_object"] . "]. Skip id[$num/$objectCount]object[$object]file[$file].", $opt ); + //$result ['skipped'] [] = "[$num/$objectCount] " . $file; + $result ['skipped'] ++; + unset ( $objects [$object] ); + } else { + //当找到断点文件,停止循环,从断点文件重新上传 + //当非断点文件,该object已完成上传 + $this->log ( "Found seek id[$num/$objectCount]object[$object]file[$file], begin from here.", $opt ); + break; + } + $num ++; + } + } else { + throw new BCS_Exception ( "Can not find you seek object, please check!", - 1 ); + } + } + if (isset ( $opt ["seek_object_id"] )) { + if (is_int ( $opt ["seek_object_id"] ) && $opt ["seek_object_id"] <= $objectCount) { + foreach ( $objects as $object => $file ) { + if ($num < $opt ["seek_object_id"]) { + $this->log ( "Seeking object of [" . $opt ["seek_object_id"] . "/$objectCount]. Skip id[$num/$objectCount]object[$object]file[$file].", $opt ); + //$result ['skipped'] [] = "[$num/$objectCount] " . $file; + $result ['skipped'] ++; + unset ( $objects [$object] ); + } else { + break; + } + $num ++; + } + } else { + throw new BCS_Exception ( "Param seek_object_id not valid, please check!", - 1 ); + } + } + //上传objects + $objectCount = count ( $objects ); + foreach ( $objects as $object => $file ) { + $tmp_opt = array_merge ( $opt ); + if (isset ( $opt [self::IMPORT_BCS_PRE_FILTER] ) && function_exists ( $opt [self::IMPORT_BCS_PRE_FILTER] )) { + $bolRes = $opt [self::IMPORT_BCS_PRE_FILTER] ( $bucket, $object, $file, $tmp_opt ); + if ($bolRes !== true) { + $this->log ( "User pre_filter_function return un-true. Skip id[$num/$objectCount]object[$object]file[$file].", $opt ); + //$result ['skipped'] [] = "id[$num/$objectCount]object[$object]file[$file]"; + $result ['skipped'] ++; + $num ++; + continue; + } + } + try { + $response = $this->create_object ( $bucket, $object, $file, $tmp_opt ); + } catch ( Exception $e ) { + $this->log ( $e->getMessage (), $opt ); + $this->log ( "Upload Failed id[$num/$objectCount]object[$object]file[$file].", $opt ); + $num ++; + continue; + } + if ($response->isOK ()) { + $result ["success"] ++; + $this->log ( "Upload Success id[$num/$objectCount]object[$object]file[$file].", $opt ); + } else { + $result ["failed"] [] = "id[$num/$objectCount]object[$object]file[$file]"; + $this->log ( "Upload Failed id[$num/$objectCount]object[$object]file[$file].", $opt ); + } + if (isset ( $opt [self::IMPORT_BCS_POST_FILTER] ) && function_exists ( $opt [self::IMPORT_BCS_POST_FILTER] )) { + $opt [self::IMPORT_BCS_POST_FILTER] ( $bucket, $object, $file, $tmp_opt, $response ); + } + $num ++; + } + //打印日志并返回结果数组 + $result_str = "\r\n\r\nUpload $dir to $bucket finished!\r\n"; + $result_str .= "**********************************************************\r\n"; + $result_str .= "**********************Result Summary**********************\r\n"; + $result_str .= "**********************************************************\r\n"; + $result_str .= "Upload directory : [$dir]\r\n"; + $result_str .= "File num : [$objectCount]\r\n"; + $result_str .= "Success: \r\n\tNum: " . $result ["success"] . "\r\n"; + $result_str .= "Skipped:\r\n\tNum:" . $result ["skipped"] . "\r\n"; + // foreach ( $result ["skipped"] as $skip ) { + // $result_str .= "\t$skip\r\n"; + // } + $result_str .= "Failed:\r\n\tNum:" . count ( $result ["failed"] ) . "\r\n"; + foreach ( $result ["failed"] as $fail ) { + $result_str .= "\t$fail\r\n"; + } + if (isset ( $opt [self::IMPORT_BCS_LOG_METHOD] )) { + $this->log ( $result_str, $opt ); + } else { + echo $result_str; + } + return $result; + } + + /** + * 通过此方法以拷贝的方式创建object,object来源为$source + * @param array $source (Required) object 来源 + * bucket(Required) + * object(Required) + * @param array $dest (Required) 待拷贝的目标object + * bucket(Required) + * object(Required) + * @param array $opt (Optional) + * source_tag 指定拷贝对象的版本号 + * @throws BCS_Exception + * @return BCS_ResponseCore + */ + public function copy_object($source, $dest, $opt = array()) { + $this->assertParameterArray ( $opt ); + //valid source and dest + if (empty ( $source ) || ! is_array ( $source ) || ! isset ( $source [self::BUCKET] ) || ! isset ( $source [self::OBJECT] )) { + throw new BCS_Exception ( '$source invalid, please check!', - 1 ); + } + if (empty ( $dest ) || ! is_array ( $dest ) || ! isset ( $dest [self::BUCKET] ) || ! isset ( $dest [self::OBJECT] ) || ! self::validate_bucket ( $dest [self::BUCKET] ) || ! self::validate_object ( $dest [self::OBJECT] )) { + throw new BCS_Exception ( '$dest invalid, please check!', - 1 ); + } + $opt [self::BUCKET] = $dest [self::BUCKET]; + $opt [self::OBJECT] = $dest [self::OBJECT]; + $opt [self::METHOD] = 'PUT'; + self::set_header_into_opt ( 'x-bs-copy-source', 'bs://' . $source [self::BUCKET] . $source [self::OBJECT], $opt ); + if (isset ( $opt ['source_tag'] )) { + self::set_header_into_opt ( 'x-bs-copy-source-tag', $opt ['source_tag'], $opt ); + } + $response = $this->authenticate ( $opt ); + $this->log ( $response->isOK () ? "Copy object success!" : "Copy object failed! Response: [" . $response->body . "]", $opt ); + return $response; + } + + /** + * 设置object的meta信息 + * @param string $bucket (Required) + * @param string $object (Required) + * @param array $opt (Optional) + * 目前支持的meta信息如下: + * Content-Type + * Cache-Control + * Content-Disposition + * Content-Encoding + * Content-MD5 + * Expires + * @return BCS_ResponseCore + */ + public function set_object_meta($bucket, $object, $meta, $opt = array()) { + $this->assertParameterArray ( $opt ); + $this->assertParameterArray ( $meta ); + $opt [self::BUCKET] = $bucket; + $opt [self::OBJECT] = $object; + $opt [self::METHOD] = 'PUT'; + //利用copy_object接口来设置meta信息 + $source = "bs://$bucket$object"; + if (empty ( $meta )) { + throw new BCS_Exception ( '$meta can not be empty! And $meta must be array.', - 1 ); + } + foreach ( $meta as $header => $value ) { + self::set_header_into_opt ( $header, $value, $opt ); + } + $source = array ( + self::BUCKET => $bucket, + self::OBJECT => $object ); + $response = $this->copy_object ( $source, $source, $opt ); + $this->log ( $response->isOK () ? "Set object meta success!" : "Set object meta failed! Response: [" . $response->body . "]", $opt ); + return $response; + } + + /** + * 获取object的acl + * @param string $bucket (Required) + * @param string $object (Required) + * @param array $opt (Optional) + * @throws BCS_Exception + * @return BCS_ResponseCore + */ + public function get_object_acl($bucket, $object, $opt = array()) { + $this->assertParameterArray ( $opt ); + $opt [self::BUCKET] = $bucket; + $opt [self::METHOD] = 'GET'; + $opt [self::OBJECT] = $object; + $opt [self::QUERY_STRING] = array ( + self::ACL => 1 ); + $response = $this->authenticate ( $opt ); + $this->log ( $response->isOK () ? "Get object acl success!" : "Get object acl failed! Response: [" . $response->body . "]", $opt ); + return $response; + } + + /** + * 设置object的acl,有三种模式, + * (1).设置详细json格式的acl; + * a. $acl 为json的array + * b. $acl 为json的string + * (2).通过acl_type字段进行设置 + * a. $acl 为BaiduBCS::$ACL_ACTIONS中的字段 + * @param string $bucket (Required) + * @param string $object (Required) + * @param string|array $acl (Required) + * @param array $opt (Optional) + * @return BCS_ResponseCore + */ + public function set_object_acl($bucket, $object, $acl, $opt = array()) { + $this->assertParameterArray ( $opt ); + //analyze acl + $result = $this->analyze_user_acl ( $acl ); + $opt = array_merge ( $opt, $result ); + $opt [self::BUCKET] = $bucket; + $opt [self::METHOD] = 'PUT'; + $opt [self::OBJECT] = $object; + $opt [self::QUERY_STRING] = array ( + self::ACL => 1 ); + $response = $this->authenticate ( $opt ); + $this->log ( $response->isOK () ? "Set object acl success!" : "Set object acl failed! Response: [" . $response->body . "]", $opt ); + return $response; + } + + /** + * 删除object + * @param string $bucket (Required) + * @param string $object (Required) + * @param array $opt (Optional) + * @throws BCS_Exception + * @return BCS_ResponseCore + */ + public function delete_object($bucket, $object, $opt = array()) { + $this->assertParameterArray ( $opt ); + $opt [self::BUCKET] = $bucket; + $opt [self::METHOD] = 'DELETE'; + $opt [self::OBJECT] = $object; + $response = $this->authenticate ( $opt ); + $this->log ( $response->isOK () ? "Delete object success!" : "Delete object failed! Response: [" . $response->body . "]", $opt ); + return $response; + } + + /** + * 判断object是否存在 + * @param string $bucket (Required) + * @param string $object (Required) + * @param array $opt (Optional) + * @throws BCS_Exception + * @return boolean true|boolean false|BCS_ResponseCore + * true:object存在 + * false:不存在 + * BCS_ResponseCore其他错误 + */ + public function is_object_exist($bucket, $object, $opt = array()) { + $this->assertParameterArray ( $opt ); + $opt [self::BUCKET] = $bucket; + $opt [self::METHOD] = 'HEAD'; + $opt [self::OBJECT] = $object; + $response = $this->get_object_info ( $bucket, $object, $opt ); + if ($response->isOK ()) { + return true; + } elseif ($response->status === 404) { + return false; + } + return $response; + } + + /** + * 获取文件信息,发送的为HTTP HEAD请求,文件信息都在http response的header中,不会提取文件的内容 + * @param string $bucket (Required) + * @param string $object (Required) + * @param array $opt (Optional) + * @throws BCS_Exception + * @return array BCS_ResponseCore + */ + public function get_object_info($bucket, $object, $opt = array()) { + $this->assertParameterArray ( $opt ); + $opt [self::BUCKET] = $bucket; + $opt [self::METHOD] = 'HEAD'; + $opt [self::OBJECT] = $object; + $response = $this->authenticate ( $opt ); + $this->log ( $response->isOK () ? "Get object info success!" : "Get object info failed! Response: [" . $response->body . "]", $opt ); + return $response; + } + + /** + * 下载object + * @param string $bucket (Required) + * @param string $object (Required) + * @param array $opt (Optional) + * fileWriteTo (Optional)直接将请求结果写入该文件,如果fileWriteTo文件存在,sdk进行重命名再存储 + * @throws BCS_Exception + * @return BCS_ResponseCore + */ + public function get_object($bucket, $object, $opt = array()) { + $this->assertParameterArray ( $opt ); + //若fileWriteTo待写入的文件已经存在,需要进行重命名 + if (isset ( $opt ["fileWriteTo"] ) && file_exists ( $opt ["fileWriteTo"] )) { + $original_file_write_to = $opt ["fileWriteTo"]; + $arr = explode ( DIRECTORY_SEPARATOR, $opt ["fileWriteTo"] ); + $file_name = $arr [count ( $arr ) - 1]; + $num = 1; + while ( file_exists ( $opt ["fileWriteTo"] ) ) { + $new_name_arr = explode ( ".", $file_name ); + if (count ( $new_name_arr ) > 1) { + $new_name_arr [count ( $new_name_arr ) - 2] .= " ($num)"; + } else { + $new_name_arr [0] .= " ($num)"; + } + $arr [count ( $arr ) - 1] = implode ( ".", $new_name_arr ); + $opt ["fileWriteTo"] = implode ( DIRECTORY_SEPARATOR, $arr ); + $num ++; + } + $this->log ( "[$original_file_write_to] already exist, rename it to [" . $opt ["fileWriteTo"] . "]", $opt ); + } + $opt [self::BUCKET] = $bucket; + $opt [self::METHOD] = 'GET'; + $opt [self::OBJECT] = $object; + $response = $this->authenticate ( $opt ); + $this->log ( $response->isOK () ? "Get object success!" : "Get object failed! Response: [" . $response->body . "]", $opt ); + if (! $response->isOK () && isset ( $opt ["fileWriteTo"] )) { + unlink ( $opt ["fileWriteTo"] ); + } + return $response; + } + + /** + * 生成签名链接 + */ + private function generate_user_url($method, $bucket, $object, $opt = array()) { + $opt [self::AK] = $this->ak; + $opt [self::SK] = $this->sk; + $opt [self::BUCKET] = $bucket; + $opt [self::METHOD] = $method; + $opt [self::OBJECT] = $object; + $opt [self::QUERY_STRING] = array (); + if (isset ( $opt ["time"] )) { + $opt [self::QUERY_STRING] ["time"] = $opt ["time"]; + } + if (isset ( $opt ["size"] )) { + $opt [self::QUERY_STRING] ["size"] = $opt ["size"]; + } + return $this->format_url ( $opt ); + } + + /** + * 生成get_object的url + * @param string $bucket (Required) + * @param string $object (Required) + * return false| string url + */ + public function generate_get_object_url($bucket, $object, $opt = array()) { + $this->assertParameterArray ( $opt ); + return $this->generate_user_url ( "GET", $bucket, $object, $opt ); + } + + /** + * 生成put_object的url + * @param string $bucket (Required) + * @param string $object (Required) + * return false| string url + */ + public function generate_put_object_url($bucket, $object, $opt = array()) { + $this->assertParameterArray ( $opt ); + return $this->generate_user_url ( "PUT", $bucket, $object, $opt ); + } + + /** + * 生成post_object的url + * @param string $bucket (Required) + * @param string $object (Required) + * return false| string url + */ + public function generate_post_object_url($bucket, $object, $opt = array()) { + $this->assertParameterArray ( $opt ); + return $this->generate_user_url ( "POST", $bucket, $object, $opt ); + } + + /** + * 生成delete_object的url + * @param string $bucket (Required) + * @param string $object (Required) + * return false| string url + */ + public function generate_delete_object_url($bucket, $object, $opt = array()) { + $this->assertParameterArray ( $opt ); + return $this->generate_user_url ( "DELETE", $bucket, $object, $opt ); + } + + /** + * 生成head_object的url + * @param string $bucket (Required) + * @param string $object (Required) + * return false| string url + */ + public function generate_head_object_url($bucket, $object, $opt = array()) { + $this->assertParameterArray ( $opt ); + return $this->generate_user_url ( "HEAD", $bucket, $object, $opt ); + } + + /** + * @return the $use_ssl + */ + public function getUse_ssl() { + return $this->use_ssl; + } + + /** + * @param boolean $use_ssl + */ + public function setUse_ssl($use_ssl) { + $this->use_ssl = $use_ssl; + } + + /** + * 校验bucket是否合法,bucket规范 + * 1. 由小写字母,数字和横线'-'组成,长度为6~63位 + * 2. 不能以数字作为Bucket开头 + * 3. 不能以'-'作为Bucket的开头或者结尾 + * @param string $bucket + * @return boolean + */ + public static function validate_bucket($bucket) { + //bucket 正则 + $pattern1 = '/^[a-z][-a-z0-9]{4,61}[a-z0-9]$/'; + if (! preg_match ( $pattern1, $bucket )) { + return false; + } + return true; + } + + /** + * 校验object是否合法,object命名规范 + * 1. object必须以'/'开头 + * @param string $object + * @return boolean + */ + public static function validate_object($object) { + $pattern = '/^\//'; + if (empty ( $object ) || ! preg_match ( $pattern, $object )) { + return false; + } + return true; + } + + /** + * 将常用set http-header的动作抽离出来 + * @param string $header + * @param string $value + * @param array $opt + * @throws BCS_Exception + * @return void + */ + private static function set_header_into_opt($header, $value, &$opt) { + if (isset ( $opt [self::HEADERS] )) { + if (! is_array ( $opt [self::HEADERS] )) { + trigger_error ( 'Invalid $opt[\'headers\'], please check.' ); + throw new BCS_Exception ( 'Invalid $opt[\'headers\'], please check.', - 1 ); + } + } else { + $opt [self::HEADERS] = array (); + } + $opt [self::HEADERS] [$header] = $value; + } + + /** + * 使用特定function对数组中所有元素做处理 + * @param string &$array 要处理的字符串 + * @param string $function 要执行的函数 + * @param boolean $apply_to_keys_also 是否也应用到key上 + */ + private static function array_recursive(&$array, $function, $apply_to_keys_also = false) { + foreach ( $array as $key => $value ) { + if (is_array ( $value )) { + self::array_recursive ( $array [$key], $function, $apply_to_keys_also ); + } else { + $array [$key] = $function ( $value ); + } + + if ($apply_to_keys_also && is_string ( $key )) { + $new_key = $function ( $key ); + if ($new_key != $key) { + $array [$new_key] = $array [$key]; + unset ( $array [$key] ); + } + } + } + } + + /** + * 由数组构造json字符串,增加了一些特殊处理以支持特殊字符和不同编码的中文 + * @param array $array + */ + private static function array_to_json($array) { + if (! is_array ( $array )) { + throw new BCS_Exception ( "Param must be array in function array_to_json()", - 1 ); + } + self::array_recursive ( $array, 'addslashes', false ); + self::array_recursive ( $array, 'rawurlencode', false ); + return rawurldecode ( json_encode ( $array ) ); + } + + /** + * 根据用户传入的acl,进行相应的处理 + * (1).设置详细json格式的acl; + * a. $acl 为json的array + * b. $acl 为json的string + * (2).通过acl_type字段进行设置 + * @param string|array $acl + * @throws BCS_Exception + * @return array + */ + private function analyze_user_acl($acl) { + $result = array (); + if (is_array ( $acl )) { + //(1).a + $result ['content'] = $this->check_user_acl ( $acl ); + } else if (is_string ( $acl )) { + if (in_array ( $acl, self::$ACL_TYPES )) { + //(2).a + $result ["headers"] = array ( + "x-bs-acl" => $acl ); + } else { + //(1).b + $result ['content'] = $acl; + } + } else { + throw new BCS_Exception ( "Invalid acl.", - 1 ); + } + return $result; + } + + /** + * 生成签名 + * @param array $opt + * @return boolean|string + */ + private function format_signature($opt) { + $flags = ""; + $content = ''; + if (! isset ( $opt [self::AK] ) || ! isset ( $opt [self::SK] )) { + trigger_error ( 'ak or sk is not in the array when create factor!' ); + return false; + } + if (isset ( $opt [self::BUCKET] ) && isset ( $opt [self::METHOD] ) && isset ( $opt [self::OBJECT] )) { + $flags .= 'MBO'; + $content .= "Method=" . $opt [self::METHOD] . "\n"; //method + $content .= "Bucket=" . $opt [self::BUCKET] . "\n"; //bucket + $content .= "Object=" . self::trimUrl ( $opt [self::OBJECT] ) . "\n"; //object + } else { + trigger_error ( 'bucket、method and object cann`t be NULL!' ); + return false; + } + if (isset ( $opt ['ip'] )) { + $flags .= 'I'; + $content .= "Ip=" . $opt ['ip'] . "\n"; + } + if (isset ( $opt ['time'] )) { + $flags .= 'T'; + $content .= "Time=" . $opt ['time'] . "\n"; + } + if (isset ( $opt ['size'] )) { + $flags .= 'S'; + $content .= "Size=" . $opt ['size'] . "\n"; + } + $content = $flags . "\n" . $content; + $sign = base64_encode ( hash_hmac ( 'sha1', $content, $opt [self::SK], true ) ); + return 'sign=' . $flags . ':' . $opt [self::AK] . ':' . urlencode ( $sign ); + } + + /** + * 检查用户输入的acl array是否合法,并转为json + * @param array $acl + * @throws BCS_Exception + * @return string acl-json + */ + private function check_user_acl($acl) { + if (! is_array ( $acl )) { + throw new BCS_Exception ( "Invalid acl array" ); + } + foreach ( $acl ['statements'] as $key => $statement ) { + // user resource action effect must in statement + if (! isset ( $statement ['user'] ) || ! isset ( $statement ['resource'] ) || ! isset ( $statement ['action'] ) || ! isset ( $statement ['effect'] )) { + throw new BCS_Exception ( 'Param miss: format acl error, please check your param!' ); + } + if (! is_array ( $statement ['user'] ) || ! is_array ( $statement ['resource'] )) { + throw new BCS_Exception ( 'Param error: user or resource must be array, please check your param!' ); + } + if (! is_array ( $statement ['action'] ) || ! count ( array_diff ( $statement ['action'], self::$ACL_ACTIONS ) ) == 0) { + throw new BCS_Exception ( 'Param error: action, please check your param!' ); + } + if (! in_array ( $statement ['effect'], self::$ACL_EFFECTS )) { + throw new BCS_Exception ( 'Param error: effect, please check your param!' ); + } + if (isset ( $statement ['time'] )) { + if (! is_array ( $statement ['time'] )) { + throw new BCS_Exception ( 'Param error: time, please check your param!' ); + } + } + } + + return self::array_to_json ( $acl ); + } + + /** + * 构造url + * @param array $opt + * @return boolean|string + */ + private function format_url($opt) { + $sign = $this->format_signature ( $opt ); + if ($sign === false) { + trigger_error ( "Format signature failed, please check!" ); + return false; + } + $opt ['sign'] = $sign; + $url = ""; + $url .= $this->use_ssl ? 'https://' : 'http://'; + $url .= $this->hostname; + $url .= '/' . $opt [self::BUCKET]; + if (isset ( $opt [self::OBJECT] ) && '/' !== $opt [self::OBJECT]) { + $url .= "/" . rawurlencode ( $opt [self::OBJECT] ); + } + $url .= '?' . $sign; + if (isset ( $opt [self::QUERY_STRING] )) { + foreach ( $opt [self::QUERY_STRING] as $key => $value ) { + $url .= '&' . $key . '=' . $value; + } + } + return $url; + } + + /** + * 将url中 '//' 替换为 '/' + * @param $url + * @return string + */ + public static function trimUrl($url) { + $result = str_replace ( "//", "/", $url ); + while ( $result !== $url ) { + $url = $result; + $result = str_replace ( "//", "/", $url ); + } + return $result; + } + + /** + * 获取传入目录的文件列表 + * @param string $dir 文件目录 + * @return array 文件树 + */ + public static function get_filetree($dir, $file_prefix = "/*") { + $tree = array (); + foreach ( glob ( $dir . $file_prefix ) as $single ) { + if (is_dir ( $single )) { + $tree = array_merge ( $tree, self::get_filetree ( $single ) ); + } else { + $tree [] = $single; + } + } + return $tree; + } + + /** + * 内置的日志函数,可以根据用户传入的log函数,进行日志输出 + * @param string $log + * @param array $opt + */ + public function log($log, $opt) { + if (isset ( $opt [self::IMPORT_BCS_LOG_METHOD] ) && function_exists ( $opt [self::IMPORT_BCS_LOG_METHOD] )) { + $opt [self::IMPORT_BCS_LOG_METHOD] ( $log ); + } else { + trigger_error ( $log ); + } + } + + /** + * make sure $opt is an array + * @param $opt + */ + private function assertParameterArray($opt) { + if (! is_array ( $opt )) { + throw new BCS_Exception ( 'Parameter must be array, please check!', - 1 ); + } + } +} \ No newline at end of file diff --git a/ThinkPHP/Library/Think/Upload/Driver/Bcs/mimetypes.class.php b/ThinkPHP/Library/Think/Upload/Driver/Bcs/mimetypes.class.php new file mode 100644 index 000000000..61c06c0b4 --- /dev/null +++ b/ThinkPHP/Library/Think/Upload/Driver/Bcs/mimetypes.class.php @@ -0,0 +1,137 @@ + 'video/3gpp', 'ai' => 'application/postscript', + 'aif' => 'audio/x-aiff', 'aifc' => 'audio/x-aiff', + 'aiff' => 'audio/x-aiff', 'asc' => 'text/plain', + 'atom' => 'application/atom+xml', 'au' => 'audio/basic', + 'avi' => 'video/x-msvideo', 'bcpio' => 'application/x-bcpio', + 'bin' => 'application/octet-stream', 'bmp' => 'image/bmp', + 'cdf' => 'application/x-netcdf', 'cgm' => 'image/cgm', + 'class' => 'application/octet-stream', + 'cpio' => 'application/x-cpio', + 'cpt' => 'application/mac-compactpro', + 'csh' => 'application/x-csh', 'css' => 'text/css', + 'dcr' => 'application/x-director', 'dif' => 'video/x-dv', + 'dir' => 'application/x-director', 'djv' => 'image/vnd.djvu', + 'djvu' => 'image/vnd.djvu', + 'dll' => 'application/octet-stream', + 'dmg' => 'application/octet-stream', + 'dms' => 'application/octet-stream', + 'doc' => 'application/msword', 'dtd' => 'application/xml-dtd', + 'dv' => 'video/x-dv', 'dvi' => 'application/x-dvi', + 'dxr' => 'application/x-director', + 'eps' => 'application/postscript', 'etx' => 'text/x-setext', + 'exe' => 'application/octet-stream', + 'ez' => 'application/andrew-inset', 'flv' => 'video/x-flv', + 'gif' => 'image/gif', 'gram' => 'application/srgs', + 'grxml' => 'application/srgs+xml', + 'gtar' => 'application/x-gtar', 'gz' => 'application/x-gzip', + 'hdf' => 'application/x-hdf', + 'hqx' => 'application/mac-binhex40', 'htm' => 'text/html', + 'html' => 'text/html', 'ice' => 'x-conference/x-cooltalk', + 'ico' => 'image/x-icon', 'ics' => 'text/calendar', + 'ief' => 'image/ief', 'ifb' => 'text/calendar', + 'iges' => 'model/iges', 'igs' => 'model/iges', + 'jnlp' => 'application/x-java-jnlp-file', 'jp2' => 'image/jp2', + 'jpe' => 'image/jpeg', 'jpeg' => 'image/jpeg', + 'jpg' => 'image/jpeg', 'js' => 'application/x-javascript', + 'kar' => 'audio/midi', 'latex' => 'application/x-latex', + 'lha' => 'application/octet-stream', + 'lzh' => 'application/octet-stream', + 'm3u' => 'audio/x-mpegurl', 'm4a' => 'audio/mp4a-latm', + 'm4p' => 'audio/mp4a-latm', 'm4u' => 'video/vnd.mpegurl', + 'm4v' => 'video/x-m4v', 'mac' => 'image/x-macpaint', + 'man' => 'application/x-troff-man', + 'mathml' => 'application/mathml+xml', + 'me' => 'application/x-troff-me', 'mesh' => 'model/mesh', + 'mid' => 'audio/midi', 'midi' => 'audio/midi', + 'mif' => 'application/vnd.mif', 'mov' => 'video/quicktime', + 'movie' => 'video/x-sgi-movie', 'mp2' => 'audio/mpeg', + 'mp3' => 'audio/mpeg', 'mp4' => 'video/mp4', + 'mpe' => 'video/mpeg', 'mpeg' => 'video/mpeg', + 'mpg' => 'video/mpeg', 'mpga' => 'audio/mpeg', + 'ms' => 'application/x-troff-ms', 'msh' => 'model/mesh', + 'mxu' => 'video/vnd.mpegurl', 'nc' => 'application/x-netcdf', + 'oda' => 'application/oda', 'ogg' => 'application/ogg', + 'ogv' => 'video/ogv', 'pbm' => 'image/x-portable-bitmap', + 'pct' => 'image/pict', 'pdb' => 'chemical/x-pdb', + 'pdf' => 'application/pdf', + 'pgm' => 'image/x-portable-graymap', + 'pgn' => 'application/x-chess-pgn', 'pic' => 'image/pict', + 'pict' => 'image/pict', 'png' => 'image/png', + 'pnm' => 'image/x-portable-anymap', + 'pnt' => 'image/x-macpaint', 'pntg' => 'image/x-macpaint', + 'ppm' => 'image/x-portable-pixmap', + 'ppt' => 'application/vnd.ms-powerpoint', + 'ps' => 'application/postscript', 'qt' => 'video/quicktime', + 'qti' => 'image/x-quicktime', 'qtif' => 'image/x-quicktime', + 'ra' => 'audio/x-pn-realaudio', + 'ram' => 'audio/x-pn-realaudio', 'ras' => 'image/x-cmu-raster', + 'rdf' => 'application/rdf+xml', 'rgb' => 'image/x-rgb', + 'rm' => 'application/vnd.rn-realmedia', + 'roff' => 'application/x-troff', 'rtf' => 'text/rtf', + 'rtx' => 'text/richtext', 'sgm' => 'text/sgml', + 'sgml' => 'text/sgml', 'sh' => 'application/x-sh', + 'shar' => 'application/x-shar', 'silo' => 'model/mesh', + 'sit' => 'application/x-stuffit', + 'skd' => 'application/x-koan', 'skm' => 'application/x-koan', + 'skp' => 'application/x-koan', 'skt' => 'application/x-koan', + 'smi' => 'application/smil', 'smil' => 'application/smil', + 'snd' => 'audio/basic', 'so' => 'application/octet-stream', + 'spl' => 'application/x-futuresplash', + 'src' => 'application/x-wais-source', + 'sv4cpio' => 'application/x-sv4cpio', + 'sv4crc' => 'application/x-sv4crc', 'svg' => 'image/svg+xml', + 'swf' => 'application/x-shockwave-flash', + 't' => 'application/x-troff', 'tar' => 'application/x-tar', + 'tcl' => 'application/x-tcl', 'tex' => 'application/x-tex', + 'texi' => 'application/x-texinfo', + 'texinfo' => 'application/x-texinfo', 'tif' => 'image/tiff', + 'tiff' => 'image/tiff', 'tr' => 'application/x-troff', + 'tsv' => 'text/tab-separated-values', 'txt' => 'text/plain', + 'ustar' => 'application/x-ustar', + 'vcd' => 'application/x-cdlink', 'vrml' => 'model/vrml', + 'vxml' => 'application/voicexml+xml', 'wav' => 'audio/x-wav', + 'wbmp' => 'image/vnd.wap.wbmp', + 'wbxml' => 'application/vnd.wap.wbxml', 'webm' => 'video/webm', + 'wml' => 'text/vnd.wap.wml', + 'wmlc' => 'application/vnd.wap.wmlc', + 'wmls' => 'text/vnd.wap.wmlscript', + 'wmlsc' => 'application/vnd.wap.wmlscriptc', + 'wmv' => 'video/x-ms-wmv', 'wrl' => 'model/vrml', + 'xbm' => 'image/x-xbitmap', 'xht' => 'application/xhtml+xml', + 'xhtml' => 'application/xhtml+xml', + 'xls' => 'application/vnd.ms-excel', + 'xml' => 'application/xml', 'xpm' => 'image/x-xpixmap', + 'xsl' => 'application/xml', 'xslt' => 'application/xslt+xml', + 'xul' => 'application/vnd.mozilla.xul+xml', + 'xwd' => 'image/x-xwindowdump', 'xyz' => 'chemical/x-xyz', + 'zip' => 'application/zip', + //add by zhengkan 20110905 + "apk" => "application/vnd.android.package-archive", + "bin" => "application/octet-stream", + "cab" => "application/vnd.ms-cab-compressed", + "gb" => "application/chinese-gb", + "gba" => "application/octet-stream", + "gbc" => "application/octet-stream", + "jad" => "text/vnd.sun.j2me.app-descriptor", + "jar" => "application/java-archive", + "nes" => "application/octet-stream", + "rar" => "application/x-rar-compressed", + "sis" => "application/vnd.symbian.install", + "sisx" => "x-epoc/x-sisx-app", + "smc" => "application/octet-stream", + "smd" => "application/octet-stream", + "swf" => "application/x-shockwave-flash", + "zip" => "application/x-zip-compressed", + "wap" => "text/vnd.wap.wml wml", "mrp" => "application/mrp", + //add by zhengkan 20110914 + "wma" => "audio/x-ms-wma", + "lrc" => "application/lrc" ); + public static function get_mimetype($ext) { + $ext = strtolower ( $ext ); + return (isset ( self::$mime_types [$ext] ) ? self::$mime_types [$ext] : 'application/octet-stream'); + } +} diff --git a/ThinkPHP/Library/Think/Upload/Driver/Bcs/requestcore.class.php b/ThinkPHP/Library/Think/Upload/Driver/Bcs/requestcore.class.php new file mode 100644 index 000000000..c401bcd1f --- /dev/null +++ b/ThinkPHP/Library/Think/Upload/Driver/Bcs/requestcore.class.php @@ -0,0 +1,840 @@ +). + */ + public $request_class = 'BCS_RequestCore'; + /** + * The default class to use for HTTP Responses (defaults to ). + */ + public $response_class = 'BCS_ResponseCore'; + /** + * Default useragent string to use. + */ + public $useragent = 'BCS_RequestCore/1.4.2'; + /** + * File to read from while streaming up. + */ + public $read_file = null; + /** + * The resource to read from while streaming up. + */ + public $read_stream = null; + /** + * The size of the stream to read from. + */ + public $read_stream_size = null; + /** + * The length already read from the stream. + */ + public $read_stream_read = 0; + /** + * File to write to while streaming down. + */ + public $write_file = null; + /** + * The resource to write to while streaming down. + */ + public $write_stream = null; + /** + * Stores the intended starting seek position. + */ + public $seek_position = null; + /** + * The user-defined callback function to call when a stream is read from. + */ + public $registered_streaming_read_callback = null; + /** + * The user-defined callback function to call when a stream is written to. + */ + public $registered_streaming_write_callback = null; + /*%******************************************************************************************%*/ + // CONSTANTS + /** + * GET HTTP Method + */ + const HTTP_GET = 'GET'; + /** + * POST HTTP Method + */ + const HTTP_POST = 'POST'; + /** + * PUT HTTP Method + */ + const HTTP_PUT = 'PUT'; + /** + * DELETE HTTP Method + */ + const HTTP_DELETE = 'DELETE'; + /** + * HEAD HTTP Method + */ + const HTTP_HEAD = 'HEAD'; + + /*%******************************************************************************************%*/ + // CONSTRUCTOR/DESTRUCTOR + /** + * Constructs a new instance of this class. + * + * @param string $url (Optional) The URL to request or service endpoint to query. + * @param string $proxy (Optional) The faux-url to use for proxy settings. Takes the following format: `proxy://user:pass@hostname:port` + * @param array $helpers (Optional) An associative array of classnames to use for request, and response functionality. Gets passed in automatically by the calling class. + * @return $this A reference to the current instance. + */ + public function __construct($url = null, $proxy = null, $helpers = null) { + // Set some default values. + $this->request_url = $url; + $this->method = self::HTTP_GET; + $this->request_headers = array (); + $this->request_body = ''; + // Set a new Request class if one was set. + if (isset ( $helpers ['request'] ) && ! empty ( $helpers ['request'] )) { + $this->request_class = $helpers ['request']; + } + // Set a new Request class if one was set. + if (isset ( $helpers ['response'] ) && ! empty ( $helpers ['response'] )) { + $this->response_class = $helpers ['response']; + } + if ($proxy) { + $this->set_proxy ( $proxy ); + } + return $this; + } + + /** + * Destructs the instance. Closes opened file handles. + * + * @return $this A reference to the current instance. + */ + public function __destruct() { + if (isset ( $this->read_file ) && isset ( $this->read_stream )) { + fclose ( $this->read_stream ); + } + if (isset ( $this->write_file ) && isset ( $this->write_stream )) { + fclose ( $this->write_stream ); + } + return $this; + } + + /*%******************************************************************************************%*/ + // REQUEST METHODS + /** + * Sets the credentials to use for authentication. + * + * @param string $user (Required) The username to authenticate with. + * @param string $pass (Required) The password to authenticate with. + * @return $this A reference to the current instance. + */ + public function set_credentials($user, $pass) { + $this->username = $user; + $this->password = $pass; + return $this; + } + + /** + * Adds a custom HTTP header to the cURL request. + * + * @param string $key (Required) The custom HTTP header to set. + * @param mixed $value (Required) The value to assign to the custom HTTP header. + * @return $this A reference to the current instance. + */ + public function add_header($key, $value) { + $this->request_headers [$key] = $value; + return $this; + } + + /** + * Removes an HTTP header from the cURL request. + * + * @param string $key (Required) The custom HTTP header to set. + * @return $this A reference to the current instance. + */ + public function remove_header($key) { + if (isset ( $this->request_headers [$key] )) { + unset ( $this->request_headers [$key] ); + } + return $this; + } + + /** + * Set the method type for the request. + * + * @param string $method (Required) One of the following constants: , , , , . + * @return $this A reference to the current instance. + */ + public function set_method($method) { + $this->method = strtoupper ( $method ); + return $this; + } + + /** + * Sets a custom useragent string for the class. + * + * @param string $ua (Required) The useragent string to use. + * @return $this A reference to the current instance. + */ + public function set_useragent($ua) { + $this->useragent = $ua; + return $this; + } + + /** + * Set the body to send in the request. + * + * @param string $body (Required) The textual content to send along in the body of the request. + * @return $this A reference to the current instance. + */ + public function set_body($body) { + $this->request_body = $body; + return $this; + } + + /** + * Set the URL to make the request to. + * + * @param string $url (Required) The URL to make the request to. + * @return $this A reference to the current instance. + */ + public function set_request_url($url) { + $this->request_url = $url; + return $this; + } + + /** + * Set additional CURLOPT settings. These will merge with the default settings, and override if + * there is a duplicate. + * + * @param array $curlopts (Optional) A set of key-value pairs that set `CURLOPT` options. These will merge with the existing CURLOPTs, and ones passed here will override the defaults. Keys should be the `CURLOPT_*` constants, not strings. + * @return $this A reference to the current instance. + */ + public function set_curlopts($curlopts) { + $this->curlopts = $curlopts; + return $this; + } + + /** + * Sets the length in bytes to read from the stream while streaming up. + * + * @param integer $size (Required) The length in bytes to read from the stream. + * @return $this A reference to the current instance. + */ + public function set_read_stream_size($size) { + $this->read_stream_size = $size; + return $this; + } + + /** + * Sets the resource to read from while streaming up. Reads the stream from its current position until + * EOF or `$size` bytes have been read. If `$size` is not given it will be determined by and + * . + * + * @param resource $resource (Required) The readable resource to read from. + * @param integer $size (Optional) The size of the stream to read. + * @return $this A reference to the current instance. + */ + public function set_read_stream($resource, $size = null) { + if (! isset ( $size ) || $size < 0) { + $stats = fstat ( $resource ); + if ($stats && $stats ['size'] >= 0) { + $position = ftell ( $resource ); + if ($position !== false && $position >= 0) { + $size = $stats ['size'] - $position; + } + } + } + $this->read_stream = $resource; + return $this->set_read_stream_size ( $size ); + } + + /** + * Sets the file to read from while streaming up. + * + * @param string $location (Required) The readable location to read from. + * @return $this A reference to the current instance. + */ + public function set_read_file($location) { + $this->read_file = $location; + $read_file_handle = fopen ( $location, 'r' ); + return $this->set_read_stream ( $read_file_handle ); + } + + /** + * Sets the resource to write to while streaming down. + * + * @param resource $resource (Required) The writeable resource to write to. + * @return $this A reference to the current instance. + */ + public function set_write_stream($resource) { + $this->write_stream = $resource; + return $this; + } + + /** + * Sets the file to write to while streaming down. + * + * @param string $location (Required) The writeable location to write to. + * @return $this A reference to the current instance. + */ + public function set_write_file($location) { + $this->write_file = $location; + $write_file_handle = fopen ( $location, 'w' ); + return $this->set_write_stream ( $write_file_handle ); + } + + /** + * Set the proxy to use for making requests. + * + * @param string $proxy (Required) The faux-url to use for proxy settings. Takes the following format: `proxy://user:pass@hostname:port` + * @return $this A reference to the current instance. + */ + public function set_proxy($proxy) { + $proxy = parse_url ( $proxy ); + $proxy ['user'] = isset ( $proxy ['user'] ) ? $proxy ['user'] : null; + $proxy ['pass'] = isset ( $proxy ['pass'] ) ? $proxy ['pass'] : null; + $proxy ['port'] = isset ( $proxy ['port'] ) ? $proxy ['port'] : null; + $this->proxy = $proxy; + return $this; + } + + /** + * Set the intended starting seek position. + * + * @param integer $position (Required) The byte-position of the stream to begin reading from. + * @return $this A reference to the current instance. + */ + public function set_seek_position($position) { + $this->seek_position = isset ( $position ) ? ( integer ) $position : null; + return $this; + } + + /** + * Register a callback function to execute whenever a data stream is read from using + * . + * + * The user-defined callback function should accept three arguments: + * + *
    + *
  • $curl_handle - resource - Required - The cURL handle resource that represents the in-progress transfer.
  • + *
  • $file_handle - resource - Required - The file handle resource that represents the file on the local file system.
  • + *
  • $length - integer - Required - The length in kilobytes of the data chunk that was transferred.
  • + *
+ * + * @param string|array|function $callback (Required) The callback function is called by , so you can pass the following values:
    + *
  • The name of a global function to execute, passed as a string.
  • + *
  • A method to execute, passed as array('ClassName', 'MethodName').
  • + *
  • An anonymous function (PHP 5.3+).
+ * @return $this A reference to the current instance. + */ + public function register_streaming_read_callback($callback) { + $this->registered_streaming_read_callback = $callback; + return $this; + } + + /** + * Register a callback function to execute whenever a data stream is written to using + * . + * + * The user-defined callback function should accept two arguments: + * + *
    + *
  • $curl_handle - resource - Required - The cURL handle resource that represents the in-progress transfer.
  • + *
  • $length - integer - Required - The length in kilobytes of the data chunk that was transferred.
  • + *
+ * + * @param string|array|function $callback (Required) The callback function is called by , so you can pass the following values:
    + *
  • The name of a global function to execute, passed as a string.
  • + *
  • A method to execute, passed as array('ClassName', 'MethodName').
  • + *
  • An anonymous function (PHP 5.3+).
+ * @return $this A reference to the current instance. + */ + public function register_streaming_write_callback($callback) { + $this->registered_streaming_write_callback = $callback; + return $this; + } + + /*%******************************************************************************************%*/ + // PREPARE, SEND, AND PROCESS REQUEST + /** + * A callback function that is invoked by cURL for streaming up. + * + * @param resource $curl_handle (Required) The cURL handle for the request. + * @param resource $file_handle (Required) The open file handle resource. + * @param integer $length (Required) The maximum number of bytes to read. + * @return binary Binary data from a stream. + */ + public function streaming_read_callback($curl_handle, $file_handle, $length) { + // Once we've sent as much as we're supposed to send... + if ($this->read_stream_read >= $this->read_stream_size) { + // Send EOF + return ''; + } + // If we're at the beginning of an upload and need to seek... + if ($this->read_stream_read == 0 && isset ( $this->seek_position ) && $this->seek_position !== ftell ( $this->read_stream )) { + if (fseek ( $this->read_stream, $this->seek_position ) !== 0) { + throw new BCS_RequestCore_Exception ( 'The stream does not support seeking and is either not at the requested position or the position is unknown.' ); + } + } + $read = fread ( $this->read_stream, min ( $this->read_stream_size - $this->read_stream_read, $length ) ); // Remaining upload data or cURL's requested chunk size + $this->read_stream_read += strlen ( $read ); + $out = $read === false ? '' : $read; + // Execute callback function + if ($this->registered_streaming_read_callback) { + call_user_func ( $this->registered_streaming_read_callback, $curl_handle, $file_handle, $out ); + } + return $out; + } + + /** + * A callback function that is invoked by cURL for streaming down. + * + * @param resource $curl_handle (Required) The cURL handle for the request. + * @param binary $data (Required) The data to write. + * @return integer The number of bytes written. + */ + public function streaming_write_callback($curl_handle, $data) { + $length = strlen ( $data ); + $written_total = 0; + $written_last = 0; + while ( $written_total < $length ) { + $written_last = fwrite ( $this->write_stream, substr ( $data, $written_total ) ); + if ($written_last === false) { + return $written_total; + } + $written_total += $written_last; + } + // Execute callback function + if ($this->registered_streaming_write_callback) { + call_user_func ( $this->registered_streaming_write_callback, $curl_handle, $written_total ); + } + return $written_total; + } + + /** + * Prepares and adds the details of the cURL request. This can be passed along to a + * function. + * + * @return resource The handle for the cURL object. + */ + public function prep_request() { + $curl_handle = curl_init (); + // Set default options. + curl_setopt ( $curl_handle, CURLOPT_URL, $this->request_url ); + curl_setopt ( $curl_handle, CURLOPT_FILETIME, true ); + curl_setopt ( $curl_handle, CURLOPT_FRESH_CONNECT, false ); + curl_setopt ( $curl_handle, CURLOPT_SSL_VERIFYPEER, false ); + curl_setopt ( $curl_handle, CURLOPT_SSL_VERIFYHOST, true ); + curl_setopt ( $curl_handle, CURLOPT_CLOSEPOLICY, CURLCLOSEPOLICY_LEAST_RECENTLY_USED ); + curl_setopt ( $curl_handle, CURLOPT_MAXREDIRS, 5 ); + curl_setopt ( $curl_handle, CURLOPT_HEADER, true ); + curl_setopt ( $curl_handle, CURLOPT_RETURNTRANSFER, true ); + curl_setopt ( $curl_handle, CURLOPT_TIMEOUT, 5184000 ); + curl_setopt ( $curl_handle, CURLOPT_CONNECTTIMEOUT, 120 ); + curl_setopt ( $curl_handle, CURLOPT_NOSIGNAL, true ); + curl_setopt ( $curl_handle, CURLOPT_REFERER, $this->request_url ); + curl_setopt ( $curl_handle, CURLOPT_USERAGENT, $this->useragent ); + curl_setopt ( $curl_handle, CURLOPT_READFUNCTION, array ( + $this, + 'streaming_read_callback' ) ); + if ($this->debug_mode) { + curl_setopt ( $curl_handle, CURLOPT_VERBOSE, true ); + } + //if (! ini_get ( 'safe_mode' )) { + //modify by zhengkan + //curl_setopt($curl_handle, CURLOPT_FOLLOWLOCATION, true); + //} + // Enable a proxy connection if requested. + if ($this->proxy) { + curl_setopt ( $curl_handle, CURLOPT_HTTPPROXYTUNNEL, true ); + $host = $this->proxy ['host']; + $host .= ($this->proxy ['port']) ? ':' . $this->proxy ['port'] : ''; + curl_setopt ( $curl_handle, CURLOPT_PROXY, $host ); + if (isset ( $this->proxy ['user'] ) && isset ( $this->proxy ['pass'] )) { + curl_setopt ( $curl_handle, CURLOPT_PROXYUSERPWD, $this->proxy ['user'] . ':' . $this->proxy ['pass'] ); + } + } + // Set credentials for HTTP Basic/Digest Authentication. + if ($this->username && $this->password) { + curl_setopt ( $curl_handle, CURLOPT_HTTPAUTH, CURLAUTH_ANY ); + curl_setopt ( $curl_handle, CURLOPT_USERPWD, $this->username . ':' . $this->password ); + } + // Handle the encoding if we can. + if (extension_loaded ( 'zlib' )) { + curl_setopt ( $curl_handle, CURLOPT_ENCODING, '' ); + } + // Process custom headers + if (isset ( $this->request_headers ) && count ( $this->request_headers )) { + $temp_headers = array (); + foreach ( $this->request_headers as $k => $v ) { + $temp_headers [] = $k . ': ' . $v; + } + curl_setopt ( $curl_handle, CURLOPT_HTTPHEADER, $temp_headers ); + } + switch ($this->method) { + case self::HTTP_PUT : + curl_setopt ( $curl_handle, CURLOPT_CUSTOMREQUEST, 'PUT' ); + if (isset ( $this->read_stream )) { + if (! isset ( $this->read_stream_size ) || $this->read_stream_size < 0) { + throw new BCS_RequestCore_Exception ( 'The stream size for the streaming upload cannot be determined.' ); + } + curl_setopt ( $curl_handle, CURLOPT_INFILESIZE, $this->read_stream_size ); + curl_setopt ( $curl_handle, CURLOPT_UPLOAD, true ); + } else { + curl_setopt ( $curl_handle, CURLOPT_POSTFIELDS, $this->request_body ); + } + break; + case self::HTTP_POST : + curl_setopt ( $curl_handle, CURLOPT_POST, true ); + curl_setopt ( $curl_handle, CURLOPT_POSTFIELDS, $this->request_body ); + break; + case self::HTTP_HEAD : + curl_setopt ( $curl_handle, CURLOPT_CUSTOMREQUEST, self::HTTP_HEAD ); + curl_setopt ( $curl_handle, CURLOPT_NOBODY, 1 ); + break; + default : // Assumed GET + curl_setopt ( $curl_handle, CURLOPT_CUSTOMREQUEST, $this->method ); + if (isset ( $this->write_stream )) { + curl_setopt ( $curl_handle, CURLOPT_WRITEFUNCTION, array ( + $this, + 'streaming_write_callback' ) ); + curl_setopt ( $curl_handle, CURLOPT_HEADER, false ); + } else { + curl_setopt ( $curl_handle, CURLOPT_POSTFIELDS, $this->request_body ); + } + break; + } + // Merge in the CURLOPTs + if (isset ( $this->curlopts ) && sizeof ( $this->curlopts ) > 0) { + foreach ( $this->curlopts as $k => $v ) { + curl_setopt ( $curl_handle, $k, $v ); + } + } + return $curl_handle; + } + + /** + * is the environment BAE? + * @return boolean the result of the answer + */ + private function isBaeEnv() { + if (isset ( $_SERVER ['HTTP_HOST'] )) { + $host = $_SERVER ['HTTP_HOST']; + $pos = strpos ( $host, '.' ); + if ($pos !== false) { + $substr = substr ( $host, $pos + 1 ); + if ($substr == 'duapp.com') { + return true; + } + } + } + if (isset ( $_SERVER ["HTTP_BAE_LOGID"] )) { + return true; + } + + return false; + } + + /** + * Take the post-processed cURL data and break it down into useful header/body/info chunks. Uses the + * data stored in the `curl_handle` and `response` properties unless replacement data is passed in via + * parameters. + * + * @param resource $curl_handle (Optional) The reference to the already executed cURL request. + * @param string $response (Optional) The actual response content itself that needs to be parsed. + * @return BCS_ResponseCore A object containing a parsed HTTP response. + */ + public function process_response($curl_handle = null, $response = null) { + // Accept a custom one if it's passed. + if ($curl_handle && $response) { + $this->curl_handle = $curl_handle; + $this->response = $response; + } + // As long as this came back as a valid resource... + if (is_resource ( $this->curl_handle )) { + // Determine what's what. + $header_size = curl_getinfo ( $this->curl_handle, CURLINFO_HEADER_SIZE ); + $this->response_headers = substr ( $this->response, 0, $header_size ); + $this->response_body = substr ( $this->response, $header_size ); + $this->response_code = curl_getinfo ( $this->curl_handle, CURLINFO_HTTP_CODE ); + $this->response_info = curl_getinfo ( $this->curl_handle ); + // Parse out the headers + $this->response_headers = explode ( "\r\n\r\n", trim ( $this->response_headers ) ); + $this->response_headers = array_pop ( $this->response_headers ); + $this->response_headers = explode ( "\r\n", $this->response_headers ); + array_shift ( $this->response_headers ); + // Loop through and split up the headers. + $header_assoc = array (); + foreach ( $this->response_headers as $header ) { + $kv = explode ( ': ', $header ); + //$header_assoc [strtolower ( $kv [0] )] = $kv [1]; + $header_assoc [$kv [0]] = $kv [1]; + } + // Reset the headers to the appropriate property. + $this->response_headers = $header_assoc; + $this->response_headers ['_info'] = $this->response_info; + $this->response_headers ['_info'] ['method'] = $this->method; + if ($curl_handle && $response) { + $class='\Think\Upload\Driver\Bcs\\'. $this->response_class; + return new $class ( $this->response_headers, $this->response_body, $this->response_code, $this->curl_handle ); + } + } + // Return false + return false; + } + + /** + * Sends the request, calling necessary utility functions to update built-in properties. + * + * @param boolean $parse (Optional) Whether to parse the response with BCS_ResponseCore or not. + * @return string The resulting unparsed data from the request. + */ + public function send_request($parse = false) { + if (false === $this->isBaeEnv ()) { + set_time_limit ( 0 ); + } + $curl_handle = $this->prep_request (); + $this->response = curl_exec ( $curl_handle ); + if ($this->response === false || + ($this->method === self::HTTP_GET && + curl_errno($curl_handle) === CURLE_PARTIAL_FILE)) { + throw new BCS_RequestCore_Exception ( 'cURL resource: ' . ( string ) $curl_handle . '; cURL error: ' . curl_error ( $curl_handle ) . ' (' . curl_errno ( $curl_handle ) . ')' ); + } + $parsed_response = $this->process_response ( $curl_handle, $this->response ); + curl_close ( $curl_handle ); + if ($parse) { + return $parsed_response; + } + return $this->response; + } + + /** + * Sends the request using , enabling parallel requests. Uses the "rolling" method. + * + * @param array $handles (Required) An indexed array of cURL handles to process simultaneously. + * @param array $opt (Optional) An associative array of parameters that can have the following keys:
    + *
  • callback - string|array - Optional - The string name of a function to pass the response data to. If this is a method, pass an array where the [0] index is the class and the [1] index is the method name.
  • + *
  • limit - integer - Optional - The number of simultaneous requests to make. This can be useful for scaling around slow server responses. Defaults to trusting cURLs judgement as to how many to use.
+ * @return array Post-processed cURL responses. + */ + public function send_multi_request($handles, $opt = null) { + if (false === $this->isBaeEnv ()) { + set_time_limit ( 0 ); + } + // Skip everything if there are no handles to process. + if (count ( $handles ) === 0) + return array (); + if (! $opt) + $opt = array (); + + // Initialize any missing options + $limit = isset ( $opt ['limit'] ) ? $opt ['limit'] : - 1; + // Initialize + $handle_list = $handles; + $http = new $this->request_class (); + $multi_handle = curl_multi_init (); + $handles_post = array (); + $added = count ( $handles ); + $last_handle = null; + $count = 0; + $i = 0; + // Loop through the cURL handles and add as many as it set by the limit parameter. + while ( $i < $added ) { + if ($limit > 0 && $i >= $limit) + break; + curl_multi_add_handle ( $multi_handle, array_shift ( $handles ) ); + $i ++; + } + do { + $active = false; + // Start executing and wait for a response. + while ( ($status = curl_multi_exec ( $multi_handle, $active )) === CURLM_CALL_MULTI_PERFORM ) { + // Start looking for possible responses immediately when we have to add more handles + if (count ( $handles ) > 0) + break; + } + // Figure out which requests finished. + $to_process = array (); + while ( $done = curl_multi_info_read ( $multi_handle ) ) { + // Since curl_errno() isn't reliable for handles that were in multirequests, we check the 'result' of the info read, which contains the curl error number, (listed here http://curl.haxx.se/libcurl/c/libcurl-errors.html ) + if ($done ['result'] > 0) { + throw new BCS_RequestCore_Exception ( 'cURL resource: ' . ( string ) $done ['handle'] . '; cURL error: ' . curl_error ( $done ['handle'] ) . ' (' . $done ['result'] . ')' ); + } // Because curl_multi_info_read() might return more than one message about a request, we check to see if this request is already in our array of completed requests +elseif (! isset ( $to_process [( int ) $done ['handle']] )) { + $to_process [( int ) $done ['handle']] = $done; + } + } + // Actually deal with the request + foreach ( $to_process as $pkey => $done ) { + $response = $http->process_response ( $done ['handle'], curl_multi_getcontent ( $done ['handle'] ) ); + $key = array_search ( $done ['handle'], $handle_list, true ); + $handles_post [$key] = $response; + if (count ( $handles ) > 0) { + curl_multi_add_handle ( $multi_handle, array_shift ( $handles ) ); + } + curl_multi_remove_handle ( $multi_handle, $done ['handle'] ); + curl_close ( $done ['handle'] ); + } + } while ( $active || count ( $handles_post ) < $added ); + curl_multi_close ( $multi_handle ); + ksort ( $handles_post, SORT_NUMERIC ); + return $handles_post; + } + + /*%******************************************************************************************%*/ + // RESPONSE METHODS + /** + * Get the HTTP response headers from the request. + * + * @param string $header (Optional) A specific header value to return. Defaults to all headers. + * @return string|array All or selected header values. + */ + public function get_response_header($header = null) { + if ($header) { + // return $this->response_headers [strtolower ( $header )]; + return $this->response_headers [$header]; + } + return $this->response_headers; + } + + /** + * Get the HTTP response body from the request. + * + * @return string The response body. + */ + public function get_response_body() { + return $this->response_body; + } + + /** + * Get the HTTP response code from the request. + * + * @return string The HTTP response code. + */ + public function get_response_code() { + return $this->response_code; + } +} +/** + * Container for all response-related methods. + */ +class BCS_ResponseCore { + /** + * Stores the HTTP header information. + */ + public $header; + /** + * Stores the SimpleXML response. + */ + public $body; + /** + * Stores the HTTP response code. + */ + public $status; + + /** + * Constructs a new instance of this class. + * + * @param array $header (Required) Associative array of HTTP headers (typically returned by ). + * @param string $body (Required) XML-formatted response from AWS. + * @param integer $status (Optional) HTTP response status code from the request. + * @return object Contains an `header` property (HTTP headers as an associative array), a or `body` property, and an `status` code. + */ + public function __construct($header, $body, $status = null) { + $this->header = $header; + $this->body = $body; + $this->status = $status; + return $this; + } + + /** + * Did we receive the status code we expected? + * + * @param integer|array $codes (Optional) The status code(s) to expect. Pass an for a single acceptable value, or an of integers for multiple acceptable values. + * @return boolean Whether we received the expected status code or not. + */ + public function isOK($codes = array(200, 201, 204, 206)) { + if (is_array ( $codes )) { + return in_array ( $this->status, $codes ); + } + return $this->status === $codes; + } +} +/** + * Default BCS_RequestCore Exception. + */ +class BCS_RequestCore_Exception extends \Exception { +} diff --git a/ThinkPHP/Library/Think/Upload/Driver/Ftp.class.php b/ThinkPHP/Library/Think/Upload/Driver/Ftp.class.php new file mode 100644 index 000000000..d96298fc7 --- /dev/null +++ b/ThinkPHP/Library/Think/Upload/Driver/Ftp.class.php @@ -0,0 +1,164 @@ + +// +---------------------------------------------------------------------- + +namespace Think\Upload\Driver; +class Ftp{ + /** + * 上传文件根目录 + * @var string + */ + private $rootPath; + + /** + * 本地上传错误信息 + * @var string + */ + private $error = ''; //上传错误信息 + + /** + * FTP连接 + * @var resource + */ + private $link; + + private $config = array( + 'host' => '', //服务器 + 'port' => 21, //端口 + 'timeout' => 90, //超时时间 + 'username' => '', //用户名 + 'password' => '', //密码 + ); + + /** + * 构造函数,用于设置上传根路径 + * @param string $root 根目录 + * @param array $config FTP配置 + */ + public function __construct($root, $config){ + /* 默认FTP配置 */ + $this->config = array_merge($this->config, $config); + + /* 登录FTP服务器 */ + if(!$this->login()){ + throw new \Exception($this->error); + } + + /* 设置根目录 */ + $this->rootPath = ftp_pwd($this->link) . '/' . ltrim($root, '/'); + } + + /** + * 检测上传根目录 + * @return boolean true-检测通过,false-检测失败 + */ + public function checkRootPath(){ + if(!@ftp_chdir($this->link, $this->rootPath)){ + $this->error = '上传根目录不存在!'; + return false; + } + return true; + } + + /** + * 检测上传目录 + * @param string $savepath 上传目录 + * @return boolean 检测结果,true-通过,false-失败 + */ + public function checkSavePath($savepath){ + /* 检测并创建目录 */ + if (!$this->mkdir($savepath)) { + return false; + } else { + //TODO:检测目录是否可写 + return true; + } + } + + /** + * 保存指定文件 + * @param array $file 保存的文件信息 + * @param boolean $replace 同名文件是否覆盖 + * @return boolean 保存状态,true-成功,false-失败 + */ + public function save($file, $replace) { + $filename = $this->rootPath . $file['savepath'] . $file['savename']; + + /* 不覆盖同名文件 */ + // if (!$replace && is_file($filename)) { + // $this->error = '存在同名文件' . $file['savename']; + // return false; + // } + + /* 移动文件 */ + if (!ftp_put($this->link, $filename, $file['tmp_name'], FTP_BINARY)) { + $this->error = '文件上传保存错误!'; + return false; + } + + return true; + } + + /** + * 创建目录 + * @param string $savepath 要创建的穆里 + * @return boolean 创建状态,true-成功,false-失败 + */ + public function mkdir($savepath){ + $dir = $this->rootPath . $savepath; + if(ftp_chdir($this->link, $dir)){ + return true; + } + + if(ftp_mkdir($this->link, $dir)){ + return true; + } elseif($this->mkdir(dirname($savepath)) && ftp_mkdir($this->link, $dir)) { + return true; + } else { + $this->error = "目录 {$savepath} 创建失败!"; + return false; + } + } + + /** + * 获取最后一次上传错误信息 + * @return string 错误信息 + */ + public function getError(){ + return $this->error; + } + + /** + * 登录到FTP服务器 + * @return boolean true-登录成功,false-登录失败 + */ + private function login(){ + extract($this->config); + $this->link = ftp_connect($host, $port, $timeout); + if($this->link) { + if (ftp_login($this->link, $username, $password)) { + return true; + } else { + $this->error = "无法登录到FTP服务器:username - {$username}"; + } + } else { + $this->error = "无法连接到FTP服务器:{$host}"; + } + return false; + } + + /** + * 析构方法,用于断开当前FTP连接 + */ + public function __destruct() { + ftp_close($this->link); + } + +} diff --git a/ThinkPHP/Library/Think/Upload/Driver/Local.class.php b/ThinkPHP/Library/Think/Upload/Driver/Local.class.php new file mode 100644 index 000000000..90488350b --- /dev/null +++ b/ThinkPHP/Library/Think/Upload/Driver/Local.class.php @@ -0,0 +1,117 @@ + +// +---------------------------------------------------------------------- + +namespace Think\Upload\Driver; +class Local{ + /** + * 上传文件根目录 + * @var string + */ + private $rootPath; + + /** + * 本地上传错误信息 + * @var string + */ + private $error = ''; //上传错误信息 + + /** + * 构造函数,用于设置上传根路径 + * @param string $root 根目录 + */ + public function __construct($root, $config = null){ + $this->rootPath = $root; + } + + /** + * 检测上传根目录 + * @return boolean true-检测通过,false-检测失败 + */ + public function checkRootPath(){ + if(!(is_dir($this->rootPath) && is_writable($this->rootPath))){ + $this->error = '上传根目录不存在!请尝试手动创建:'.$this->rootPath; + return false; + } + return true; + } + + /** + * 检测上传目录 + * @param string $savepath 上传目录 + * @return boolean 检测结果,true-通过,false-失败 + */ + public function checkSavePath($savepath){ + /* 检测并创建目录 */ + if (!$this->mkdir($savepath)) { + return false; + } else { + /* 检测目录是否可写 */ + if (!is_writable($this->rootPath . $savepath)) { + $this->error = '上传目录 ' . $savepath . ' 不可写!'; + return false; + } else { + return true; + } + } + } + + /** + * 保存指定文件 + * @param array $file 保存的文件信息 + * @param boolean $replace 同名文件是否覆盖 + * @return boolean 保存状态,true-成功,false-失败 + */ + public function save($file, $replace) { + $filename = $this->rootPath . $file['savepath'] . $file['savename']; + + /* 不覆盖同名文件 */ + if (!$replace && is_file($filename)) { + $this->error = '存在同名文件' . $file['savename']; + return false; + } + + /* 移动文件 */ + if (!move_uploaded_file($file['tmp_name'], $filename)) { + $this->error = '文件上传保存错误!'; + return false; + } + + return true; + } + + /** + * 创建目录 + * @param string $savepath 要创建的穆里 + * @return boolean 创建状态,true-成功,false-失败 + */ + public function mkdir($savepath){ + $dir = $this->rootPath . $savepath; + if(is_dir($dir)){ + return true; + } + + if(mkdir($dir, 0777, true)){ + return true; + } else { + $this->error = "目录 {$savepath} 创建失败!"; + return false; + } + } + + /** + * 获取最后一次上传错误信息 + * @return string 错误信息 + */ + public function getError(){ + return $this->error; + } + +} diff --git a/ThinkPHP/Library/Think/Upload/Driver/Qiniu.class.php b/ThinkPHP/Library/Think/Upload/Driver/Qiniu.class.php new file mode 100644 index 000000000..6ce48211f --- /dev/null +++ b/ThinkPHP/Library/Think/Upload/Driver/Qiniu.class.php @@ -0,0 +1,102 @@ + +// +---------------------------------------------------------------------- + +namespace Think\Upload\Driver; +use Think\Upload\Driver\Qiniu\QiniuStorage; + +class Qiniu{ + /** + * 上传文件根目录 + * @var string + */ + private $rootPath; + + /** + * 上传错误信息 + * @var string + */ + private $error = ''; + + private $config = array( + 'secrectKey' => '', //七牛服务器 + 'accessKey' => '', //七牛用户 + 'domain' => '', //七牛密码 + 'bucket' => '', //空间名称 + 'timeout' => 300, //超时时间 + ); + + /** + * 构造函数,用于设置上传根路径 + * @param string $root 根目录 + * @param array $config FTP配置 + */ + public function __construct($root, $config){ + $this->config = array_merge($this->config, $config); + /* 设置根目录 */ + $this->qiniu = new QiniuStorage($config); + $this->rootPath = trim($root, './') . '/'; + } + + /** + * 检测上传根目录(七牛上传时支持自动创建目录,直接返回) + * @return boolean true-检测通过,false-检测失败 + */ + public function checkRootPath(){ + return true; + } + + /** + * 检测上传目录(七牛上传时支持自动创建目录,直接返回) + * @param string $savepath 上传目录 + * @return boolean 检测结果,true-通过,false-失败 + */ + public function checkSavePath($savepath){ + return true; + } + + /** + * 创建文件夹 (七牛上传时支持自动创建目录,直接返回) + * @param string $savepath 目录名称 + * @return boolean true-创建成功,false-创建失败 + */ + public function mkdir($savepath){ + return true; + } + + /** + * 保存指定文件 + * @param array $file 保存的文件信息 + * @param boolean $replace 同名文件是否覆盖 + * @return boolean 保存状态,true-成功,false-失败 + */ + public function save(&$file) { + $file['name'] = $file['savepath'] . $file['savename']; + $key = str_replace('/', '_', $file['name']); + $upfile = array( + 'name'=>'file', + 'fileName'=>$key, + 'fileBody'=>file_get_contents($file['tmp_name']) + ); + $config = array(); + $result = $this->qiniu->upload($config, $upfile); + $url = $this->qiniu->downlink($key); + $file['url'] = $url; + return false ===$result ? false : true; + } + + /** + * 获取最后一次上传错误信息 + * @return string 错误信息 + */ + public function getError(){ + return $this->qiniu->errorStr; + } +} diff --git a/ThinkPHP/Library/Think/Upload/Driver/Qiniu/QiniuStorage.class.php b/ThinkPHP/Library/Think/Upload/Driver/Qiniu/QiniuStorage.class.php new file mode 100644 index 000000000..95763cdc9 --- /dev/null +++ b/ThinkPHP/Library/Think/Upload/Driver/Qiniu/QiniuStorage.class.php @@ -0,0 +1,333 @@ +sk = $config['secrectKey']; + $this->ak = $config['accessKey']; + $this->domain = $config['domain']; + $this->bucket = $config['bucket']; + $this->timeout = isset($config['timeout'])? $config['timeout'] : 3600; + } + + static function sign($sk, $ak, $data){ + $sign = hash_hmac('sha1', $data, $sk, true); + return $ak . ':' . self::Qiniu_Encode($sign); + } + + static function signWithData($sk, $ak, $data){ + $data = self::Qiniu_Encode($data); + return self::sign($sk, $ak, $data) . ':' . $data; + } + + public function accessToken($url, $body=''){ + $parsed_url = parse_url($url); + $path = $parsed_url['path']; + $access = $path; + if (isset($parsed_url['query'])) { + $access .= "?" . $parsed_url['query']; + } + $access .= "\n"; + + if($body){ + $access .= $body; + } + return self::sign($this->sk, $this->ak, $access); + } + + public function UploadToken($sk ,$ak ,$param){ + $param['deadline'] = $param['Expires'] == 0? 3600: $param['Expires']; + $param['deadline'] += time(); + $data = array('scope'=> $this->bucket, 'deadline'=>$param['deadline']); + if (!empty($param['CallbackUrl'])) { + $data['callbackUrl'] = $param['CallbackUrl']; + } + if (!empty($param['CallbackBody'])) { + $data['callbackBody'] = $param['CallbackBody']; + } + if (!empty($param['ReturnUrl'])) { + $data['returnUrl'] = $param['ReturnUrl']; + } + if (!empty($param['ReturnBody'])) { + $data['returnBody'] = $param['ReturnBody']; + } + if (!empty($param['AsyncOps'])) { + $data['asyncOps'] = $param['AsyncOps']; + } + if (!empty($param['EndUser'])) { + $data['endUser'] = $param['EndUser']; + } + $data = json_encode($data); + return self::SignWithData($sk, $ak, $data); + } + + public function upload($config, $file){ + $uploadToken = $this->UploadToken($this->sk, $this->ak, $config); + + $url = "{$this->QINIU_UP_HOST}"; + $mimeBoundary = md5(microtime()); + $header = array('Content-Type'=>'multipart/form-data;boundary='.$mimeBoundary); + $data = array(); + + $fields = array( + 'token'=>$uploadToken, + 'key'=>$config['saveName']? $config['save_name'] : $file['fileName'], + ); + + if(is_array($config['custom_fields']) && $config['custom_fields'] !== array()){ + $fields = array_merge($fields, $config['custom_fields']); + } + + foreach ($fields as $name => $val) { + array_push($data, '--' . $mimeBoundary); + array_push($data, "Content-Disposition: form-data; name=\"$name\""); + array_push($data, ''); + array_push($data, $val); + } + + //文件 + array_push($data, '--' . $mimeBoundary); + $name = $file['name']; + $fileName = $file['fileName']; + $fileBody = $file['fileBody']; + $fileName = self::Qiniu_escapeQuotes($fileName); + array_push($data, "Content-Disposition: form-data; name=\"$name\"; filename=\"$fileName\""); + array_push($data, 'Content-Type: application/octet-stream'); + array_push($data, ''); + array_push($data, $fileBody); + + array_push($data, '--' . $mimeBoundary . '--'); + array_push($data, ''); + + $body = implode("\r\n", $data); + $response = $this->request($url, 'POST', $header, $body); + return $response; + } + + public function dealWithType($key, $type){ + $param = $this->buildUrlParam(); + $url = ''; + + switch($type){ + case 'img': + $url = $this->downLink($key); + if($param['imageInfo']){ + $url .= '?imageInfo'; + }else if($param['exif']){ + $url .= '?exif'; + }else if($param['imageView']){ + $url .= '?imageView/'.$param['mode']; + if($param['w']) + $url .= "/w/{$param['w']}"; + if($param['h']) + $url .= "/h/{$param['h']}"; + if($param['q']) + $url .= "/q/{$param['q']}"; + if($param['format']) + $url .= "/format/{$param['format']}"; + } + break; + case 'video': //TODO 视频处理 + case 'doc': + $url = $this->downLink($key); + $url .= '?md2html'; + if(isset($param['mode'])) + $url .= '/'.(int)$param['mode']; + if($param['cssurl']) + $url .= '/'. self::Qiniu_Encode($param['cssurl']); + break; + + } + return $url; + } + + public function buildUrlParam(){ + return $_REQUEST; + } + + //获取某个路径下的文件列表 + public function getList($query = array(), $path = ''){ + $query = array_merge(array('bucket'=>$this->bucket), $query); + $url = "{$this->QINIU_RSF_HOST}/list?".http_build_query($query); + $accessToken = $this->accessToken($url); + $response = $this->request($url, 'POST', array('Authorization'=>"QBox $accessToken")); + return $response; + } + + //获取某个文件的信息 + public function info($key){ + $key = trim($key); + $url = "{$this->QINIU_RS_HOST}/stat/" . self::Qiniu_Encode("{$this->bucket}:{$key}"); + $accessToken = $this->accessToken($url); + $response = $this->request($url, 'POST', array( + 'Authorization'=>"QBox $accessToken", + )); + return $response; + } + + //获取文件下载资源链接 + public function downLink($key){ + $key = urlencode($key); + $key = self::Qiniu_escapeQuotes($key); + $url = "http://{$this->domain}/{$key}"; + return $url; + } + + //重命名单个文件 + public function rename($file, $new_file){ + $key = trim($file); + $url = "{$this->QINIU_RS_HOST}/move/" . self::Qiniu_Encode("{$this->bucket}:{$key}") .'/'. self::Qiniu_Encode("{$this->bucket}:{$new_file}"); + trace($url); + $accessToken = $this->accessToken($url); + $response = $this->request($url, 'POST', array('Authorization'=>"QBox $accessToken")); + return $response; + } + + //删除单个文件 + public function del($file){ + $key = trim($file); + $url = "{$this->QINIU_RS_HOST}/delete/" . self::Qiniu_Encode("{$this->bucket}:{$key}"); + $accessToken = $this->accessToken($url); + $response = $this->request($url, 'POST', array('Authorization'=>"QBox $accessToken")); + return $response; + } + + //批量删除文件 + public function delBatch($files){ + $url = $this->QINIU_RS_HOST . '/batch'; + $ops = array(); + foreach ($files as $file) { + $ops[] = "/delete/". self::Qiniu_Encode("{$this->bucket}:{$file}"); + } + $params = 'op=' . implode('&op=', $ops); + $url .= '?'.$params; + trace($url); + $accessToken = $this->accessToken($url); + $response = $this->request($url, 'POST', array('Authorization'=>"QBox $accessToken")); + return $response; + } + + static function Qiniu_Encode($str) {// URLSafeBase64Encode + $find = array('+', '/'); + $replace = array('-', '_'); + return str_replace($find, $replace, base64_encode($str)); + } + + static function Qiniu_escapeQuotes($str){ + $find = array("\\", "\""); + $replace = array("\\\\", "\\\""); + return str_replace($find, $replace, $str); + } + + /** + * 请求百度云服务器 + * @param string $path 请求的PATH + * @param string $method 请求方法 + * @param array $headers 请求header + * @param resource $body 上传文件资源 + * @return boolean + */ + private function request($path, $method, $headers = null, $body = null){ + $ch = curl_init($path); + + $_headers = array('Expect:'); + if (!is_null($headers) && is_array($headers)){ + foreach($headers as $k => $v) { + array_push($_headers, "{$k}: {$v}"); + } + } + + $length = 0; + $date = gmdate('D, d M Y H:i:s \G\M\T'); + + if (!is_null($body)) { + if(is_resource($body)){ + fseek($body, 0, SEEK_END); + $length = ftell($body); + fseek($body, 0); + + array_push($_headers, "Content-Length: {$length}"); + curl_setopt($ch, CURLOPT_INFILE, $body); + curl_setopt($ch, CURLOPT_INFILESIZE, $length); + } else { + $length = @strlen($body); + array_push($_headers, "Content-Length: {$length}"); + curl_setopt($ch, CURLOPT_POSTFIELDS, $body); + } + } else { + array_push($_headers, "Content-Length: {$length}"); + } + + // array_push($_headers, 'Authorization: ' . $this->sign($method, $uri, $date, $length)); + array_push($_headers, "Date: {$date}"); + + curl_setopt($ch, CURLOPT_HTTPHEADER, $_headers); + curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeout); + curl_setopt($ch, CURLOPT_HEADER, 1); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0); + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method); + + if ($method == 'PUT' || $method == 'POST') { + curl_setopt($ch, CURLOPT_POST, 1); + } else { + curl_setopt($ch, CURLOPT_POST, 0); + } + + if ($method == 'HEAD') { + curl_setopt($ch, CURLOPT_NOBODY, true); + } + + $response = curl_exec($ch); + $status = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + list($header, $body) = explode("\r\n\r\n", $response, 2); + if ($status == 200) { + if ($method == 'GET') { + return $body; + } else { + return $this->response($response); + } + } else { + $this->error($header , $body); + return false; + } + } + + /** + * 获取响应数据 + * @param string $text 响应头字符串 + * @return array 响应数据列表 + */ + private function response($text){ + $headers = explode(PHP_EOL, $text); + $items = array(); + foreach($headers as $header) { + $header = trim($header); + if(strpos($header, '{') !== False){ + $items = json_decode($header, 1); + break; + } + } + return $items; + } + + /** + * 获取请求错误信息 + * @param string $header 请求返回头信息 + */ + private function error($header, $body) { + list($status, $stash) = explode("\r\n", $header, 2); + list($v, $code, $message) = explode(" ", $status, 3); + $message = is_null($message) ? 'File Not Found' : "[{$status}]:{$message}]"; + $this->error = $message; + $this->errorStr = json_decode($body ,1); + $this->errorStr = $this->errorStr['error']; + } + } diff --git a/ThinkPHP/Library/Think/Upload/Driver/Sae.class.php b/ThinkPHP/Library/Think/Upload/Driver/Sae.class.php new file mode 100644 index 000000000..0fa770196 --- /dev/null +++ b/ThinkPHP/Library/Think/Upload/Driver/Sae.class.php @@ -0,0 +1,102 @@ + +// +---------------------------------------------------------------------- + +namespace Think\Upload\Driver; +class Sae{ + /** + * Storage的Domain + * @var string + */ + private $domain=''; + + private $rootPath=''; + + /** + * 本地上传错误信息 + * @var string + */ + private $error = ''; //上传错误信息 + + /** + * 构造函数,设置storage的domain, 如果有传配置,则domain为配置项,如果没有传domain为第一个路径的目录名称。 + * @param string $root 根目录 + */ + public function __construct($root, $config = null){ + $arr=explode('/',trim($root,'./')); + $domain=strtolower(array_shift($arr)); + if(is_array($config) && isset($config['domain'])){ + $this->domain=strtolower($config['domain']); + }else{ + $this->domain=$domain; + } + $this->rootPath=implode('/',$arr); + } + + /** + * 检测上传根目录 + * @return boolean true-检测通过,false-检测失败 + */ + public function checkRootPath(){ + $st=new \SaeStorage(); + if(false===$st->getDomainCapacity($this->domain)){ + $this->error='您好像没有建立Storage的domain['.$this->domain.']'; + return false; + } + + return true; + } + + /** + * 检测上传目录 + * @param string $savepath 上传目录 + * @return boolean 检测结果,true-通过,false-失败 + */ + public function checkSavePath($savepath){ + return true; + } + + /** + * 保存指定文件 + * @param array $file 保存的文件信息 + * @param boolean $replace 同名文件是否覆盖 + * @return boolean 保存状态,true-成功,false-失败 + */ + public function save($file, $replace=true) { + $filename = ltrim($this->rootPath .'/'. $file['savepath'] . $file['savename'],'/'); + $st=new \SaeStorage(); + /* 不覆盖同名文件 */ + if (!$replace && $st->fileExists($this->domain,$filename)) { + $this->error = '存在同名文件' . $file['savename']; + return false; + } + + /* 移动文件 */ + if (!$st->upload($this->domain,$filename,$file['tmp_name'])) { + $this->error = '文件上传保存错误!['.$st->errno().']:'.$st->errmsg(); + return false; + } + + return true; + } + + public function mkdir(){ + return true; + } + + /** + * 获取最后一次上传错误信息 + * @return string 错误信息 + */ + public function getError(){ + return $this->error; + } + +} diff --git a/ThinkPHP/Library/Think/Upload/Driver/Upyun.class.php b/ThinkPHP/Library/Think/Upload/Driver/Upyun.class.php new file mode 100644 index 000000000..d53c0ff20 --- /dev/null +++ b/ThinkPHP/Library/Think/Upload/Driver/Upyun.class.php @@ -0,0 +1,219 @@ + +// +---------------------------------------------------------------------- + +namespace Think\Upload\Driver; +class Upyun{ + /** + * 上传文件根目录 + * @var string + */ + private $rootPath; + + /** + * 上传错误信息 + * @var string + */ + private $error = ''; + + private $config = array( + 'host' => '', //又拍云服务器 + 'username' => '', //又拍云用户 + 'password' => '', //又拍云密码 + 'bucket' => '', //空间名称 + 'timeout' => 90, //超时时间 + ); + + /** + * 构造函数,用于设置上传根路径 + * @param string $root 根目录 + * @param array $config FTP配置 + */ + public function __construct($root, $config){ + /* 默认FTP配置 */ + $this->config = array_merge($this->config, $config); + $this->config['password'] = md5($this->config['password']); + + /* 设置根目录 */ + $this->rootPath = trim($root, './') . '/'; + } + + /** + * 检测上传根目录(又拍云上传时支持自动创建目录,直接返回) + * @return boolean true-检测通过,false-检测失败 + */ + public function checkRootPath(){ + return true; + } + + /** + * 检测上传目录(又拍云上传时支持自动创建目录,直接返回) + * @param string $savepath 上传目录 + * @return boolean 检测结果,true-通过,false-失败 + */ + public function checkSavePath($savepath){ + return true; + } + + /** + * 创建文件夹 (又拍云上传时支持自动创建目录,直接返回) + * @param string $savepath 目录名称 + * @return boolean true-创建成功,false-创建失败 + */ + public function mkdir($savepath){ + return true; + } + + /** + * 保存指定文件 + * @param array $file 保存的文件信息 + * @param boolean $replace 同名文件是否覆盖 + * @return boolean 保存状态,true-成功,false-失败 + */ + public function save($file, $replace = true) { + $header['Content-Type'] = $file['type']; + $header['Content-MD5'] = md5_file($file['md5']); + $header['Mkdir'] = 'true'; + $resource = fopen($file['tmp_name'], 'r'); + + $save = $this->rootPath . $file['savepath'] . $file['savename']; + $data = $this->request($save, 'PUT', $header, $resource); + return false === $data ? false : true; + } + + /** + * 获取最后一次上传错误信息 + * @return string 错误信息 + */ + public function getError(){ + return $this->error; + } + + /** + * 请求又拍云服务器 + * @param string $path 请求的PATH + * @param string $method 请求方法 + * @param array $headers 请求header + * @param resource $body 上传文件资源 + * @return boolean + */ + private function request($path, $method, $headers = null, $body = null){ + $uri = "/{$this->config['bucket']}/{$path}"; + $ch = curl_init($this->config['host'] . $uri); + + $_headers = array('Expect:'); + if (!is_null($headers) && is_array($headers)){ + foreach($headers as $k => $v) { + array_push($_headers, "{$k}: {$v}"); + } + } + + $length = 0; + $date = gmdate('D, d M Y H:i:s \G\M\T'); + + if (!is_null($body)) { + if(is_resource($body)){ + fseek($body, 0, SEEK_END); + $length = ftell($body); + fseek($body, 0); + + array_push($_headers, "Content-Length: {$length}"); + curl_setopt($ch, CURLOPT_INFILE, $body); + curl_setopt($ch, CURLOPT_INFILESIZE, $length); + } else { + $length = @strlen($body); + array_push($_headers, "Content-Length: {$length}"); + curl_setopt($ch, CURLOPT_POSTFIELDS, $body); + } + } else { + array_push($_headers, "Content-Length: {$length}"); + } + + array_push($_headers, 'Authorization: ' . $this->sign($method, $uri, $date, $length)); + array_push($_headers, "Date: {$date}"); + + curl_setopt($ch, CURLOPT_HTTPHEADER, $_headers); + curl_setopt($ch, CURLOPT_TIMEOUT, $this->config['timeout']); + curl_setopt($ch, CURLOPT_HEADER, 1); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0); + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method); + + if ($method == 'PUT' || $method == 'POST') { + curl_setopt($ch, CURLOPT_POST, 1); + } else { + curl_setopt($ch, CURLOPT_POST, 0); + } + + if ($method == 'HEAD') { + curl_setopt($ch, CURLOPT_NOBODY, true); + } + + $response = curl_exec($ch); + $status = curl_getinfo($ch, CURLINFO_HTTP_CODE); + curl_close($ch); + list($header, $body) = explode("\r\n\r\n", $response, 2); + + if ($status == 200) { + if ($method == 'GET') { + return $body; + } else { + $data = $this->response($header); + return count($data) > 0 ? $data : true; + } + } else { + $this->error($header); + return false; + } + } + + /** + * 获取响应数据 + * @param string $text 响应头字符串 + * @return array 响应数据列表 + */ + private function response($text){ + $headers = explode("\r\n", $text); + $items = array(); + foreach($headers as $header) { + $header = trim($header); + if(strpos($header, 'x-upyun') !== False){ + list($k, $v) = explode(':', $header); + $items[trim($k)] = in_array(substr($k,8,5), array('width','heigh','frame')) ? intval($v) : trim($v); + } + } + return $items; + } + + /** + * 生成请求签名 + * @param string $method 请求方法 + * @param string $uri 请求URI + * @param string $date 请求时间 + * @param integer $length 请求内容大小 + * @return string 请求签名 + */ + private function sign($method, $uri, $date, $length){ + $sign = "{$method}&{$uri}&{$date}&{$length}&{$this->config['password']}"; + return 'UpYun ' . $this->config['username'] . ':' . md5($sign); + } + + /** + * 获取请求错误信息 + * @param string $header 请求返回头信息 + */ + private function error($header) { + list($status, $stash) = explode("\r\n", $header, 2); + list($v, $code, $message) = explode(" ", $status, 3); + $message = is_null($message) ? 'File Not Found' : "[{$status}]:{$message}"; + $this->error = $message; + } + +} diff --git a/ThinkPHP/Library/Think/Verify.class.php b/ThinkPHP/Library/Think/Verify.class.php new file mode 100644 index 000000000..aa5ba66d5 --- /dev/null +++ b/ThinkPHP/Library/Think/Verify.class.php @@ -0,0 +1,255 @@ + +// +---------------------------------------------------------------------- + +namespace Think; + +class Verify { + public $seKey = 'ThinkPHP.CN'; //验证码加密密钥 + public $expire = 1800; // 验证码过期时间(s) + public $useZh = false; // 使用中文验证码 + public $useImgBg = false; // 使用背景图片 + public $fontSize = 25; // 验证码字体大小(px) + public $useCurve = true; // 是否画混淆曲线 + public $useNoise = true; // 是否添加杂点 + public $imageH = 0; // 验证码图片宽 + public $imageL = 0; // 验证码图片长 + public $length = 5; // 验证码位数 + public $fontttf = ''; // 验证码字体,不设置随机获取 + public $bg = array(243, 251, 254); // 背景 + + + /** + * 验证码中使用的字符,01IO容易混淆,建议不用 + * + * @var string + */ + private $_codeSet = '2345678abcdefhijkmnpqrstuvwxyzABCDEFGHJKLMNPQRTUVWXY'; + private $_image = NULL; // 验证码图片实例 + private $_color = NULL; // 验证码字体颜色 + + /** + * 验证验证码是否正确 + * + * @param string $code 用户验证码 + * @return bool 用户验证码是否正确 + */ + public function check($code, $id = '') { + $key = $this->authcode($this->seKey); + // 验证码不能为空 + $session = session($key); + if(empty($code) || empty($session)) { + return false; + } + + $secode = $id ? $session[$id] : $session; + // session 过期 + if(NOW_TIME - $secode['time'] > $this->expire) { + session($key, null); + return false; + } + + if($this->authcode(strtoupper($code)) == $secode['code']) { + session($key, null); + return true; + } + + return false; + } + + /** + * 输出验证码并把验证码的值保存的session中 + * 验证码保存到session的格式为: array('code' => '验证码值', 'time' => '验证码创建时间'); + */ + public function entry($id = '') { + // 图片宽(px) + $this->imageL || $this->imageL = $this->length*$this->fontSize*1.5 + $this->length*$this->fontSize/2; + // 图片高(px) + $this->imageH || $this->imageH = $this->fontSize * 2.5; + // 建立一幅 $this->imageL x $this->imageH 的图像 + $this->_image = imagecreate($this->imageL, $this->imageH); + // 设置背景 + imagecolorallocate($this->_image, $this->bg[0], $this->bg[1], $this->bg[2]); + + // 验证码字体随机颜色 + $this->_color = imagecolorallocate($this->_image, mt_rand(1,150), mt_rand(1,150), mt_rand(1,150)); + // 验证码使用随机字体 + $ttfPath = dirname(__FILE__) . '/Verify/' . ($this->useZh ? 'zhttfs' : 'ttfs') . '/'; + + if(empty($this->fontttf)){ + $dir = dir($ttfPath); + $ttfs = array(); + while (false !== ($file = $dir->read())) { + if($file[0] != '.' && substr($file, -4) == '.ttf') { + $ttfs[] = $file; + } + } + $dir->close(); + $this->fontttf = $ttfs[array_rand($ttfs)]; + } + $this->fontttf = $ttfPath . $this->fontttf; + + if($this->useImgBg) { + $this->_background(); + } + + if ($this->useNoise) { + // 绘杂点 + $this->_writeNoise(); + } + if ($this->useCurve) { + // 绘干扰线 + $this->_writeCurve(); + } + + // 绘验证码 + $code = array(); // 验证码 + $codeNX = 0; // 验证码第N个字符的左边距 + for ($i = 0; $i<$this->length; $i++) { + if($this->useZh) { + $code[$i] = chr(mt_rand(0xB0,0xF7)).chr(mt_rand(0xA1,0xFE)); + } else { + $code[$i] = $this->_codeSet[mt_rand(0, 51)]; + $codeNX += mt_rand($this->fontSize*1.2, $this->fontSize*1.6); + // 写一个验证码字符 + $this->useZh || imagettftext($this->_image, $this->fontSize, mt_rand(-40, 40), $codeNX, $this->fontSize*1.6, $this->_color, $this->fontttf, $code[$i]); + } + } + + $this->useZh && imagettftext($this->_image, $this->fontSize, 0, ($this->imageL - $this->fontSize*$this->length*1.2)/3, $this->fontSize * 1.5, $this->_color, $this->fontttf, iconv("GB2312","UTF-8", join('', $code))); + + // 保存验证码 + $key = $this->authcode($this->seKey); + $code = $this->authcode(strtoupper(implode('', $code))); + $session = array(); + if($id) { + $session[$id]['code'] = $code; // 把校验码保存到session + $session[$id]['time'] = NOW_TIME; // 验证码创建时间 + } else { + $session['code'] = $code; // 把校验码保存到session + $session['time'] = NOW_TIME; // 验证码创建时间 + } + session($key, $session); + + + header('Cache-Control: private, max-age=0, no-store, no-cache, must-revalidate'); + header('Cache-Control: post-check=0, pre-check=0', false); + header('Pragma: no-cache'); + header("content-type: image/png"); + + // 输出图像 + imagepng($this->_image); + imagedestroy($this->_image); + } + + /** + * 画一条由两条连在一起构成的随机正弦函数曲线作干扰线(你可以改成更帅的曲线函数) + * + * 高中的数学公式咋都忘了涅,写出来 + * 正弦型函数解析式:y=Asin(ωx+φ)+b + * 各常数值对函数图像的影响: + * A:决定峰值(即纵向拉伸压缩的倍数) + * b:表示波形在Y轴的位置关系或纵向移动距离(上加下减) + * φ:决定波形与X轴位置关系或横向移动距离(左加右减) + * ω:决定周期(最小正周期T=2π/∣ω∣) + * + */ + private function _writeCurve() { + $px = $py = 0; + + // 曲线前部分 + $A = mt_rand(1, $this->imageH/2); // 振幅 + $b = mt_rand(-$this->imageH/4, $this->imageH/4); // Y轴方向偏移量 + $f = mt_rand(-$this->imageH/4, $this->imageH/4); // X轴方向偏移量 + $T = mt_rand($this->imageH, $this->imageL*2); // 周期 + $w = (2* M_PI)/$T; + + $px1 = 0; // 曲线横坐标起始位置 + $px2 = mt_rand($this->imageL/2, $this->imageL * 0.8); // 曲线横坐标结束位置 + + for ($px=$px1; $px<=$px2; $px = $px + 1) { + if ($w!=0) { + $py = $A * sin($w*$px + $f)+ $b + $this->imageH/2; // y = Asin(ωx+φ) + b + $i = (int) ($this->fontSize/5); + while ($i > 0) { + imagesetpixel($this->_image, $px + $i , $py + $i, $this->_color); // 这里(while)循环画像素点比imagettftext和imagestring用字体大小一次画出(不用这while循环)性能要好很多 + $i--; + } + } + } + + // 曲线后部分 + $A = mt_rand(1, $this->imageH/2); // 振幅 + $f = mt_rand(-$this->imageH/4, $this->imageH/4); // X轴方向偏移量 + $T = mt_rand($this->imageH, $this->imageL*2); // 周期 + $w = (2* M_PI)/$T; + $b = $py - $A * sin($w*$px + $f) - $this->imageH/2; + $px1 = $px2; + $px2 = $this->imageL; + + for ($px=$px1; $px<=$px2; $px=$px+ 1) { + if ($w!=0) { + $py = $A * sin($w*$px + $f)+ $b + $this->imageH/2; // y = Asin(ωx+φ) + b + $i = (int) ($this->fontSize/5); + while ($i > 0) { + imagesetpixel($this->_image, $px + $i, $py + $i, $this->_color); + $i--; + } + } + } + } + + /** + * 画杂点 + * 往图片上写不同颜色的字母或数字 + */ + private function _writeNoise() { + for($i = 0; $i < 10; $i++){ + //杂点颜色 + $noiseColor = imagecolorallocate($this->_image, mt_rand(150,225), mt_rand(150,225), mt_rand(150,225)); + for($j = 0; $j < 5; $j++) { + // 绘杂点 + imagestring($this->_image, 5, mt_rand(-10, $this->imageL), mt_rand(-10, $this->imageH), $this->_codeSet[mt_rand(0, 27)], $noiseColor); + } + } + } + + /** + * 绘制背景图片 + * 注:如果验证码输出图片比较大,将占用比较多的系统资源 + */ + private function _background() { + $path = dirname(__FILE__).'/bgs/'; + $dir = dir($path); + + $bgs = array(); + while (false !== ($file = $dir->read())) { + if($file[0] != '.' && substr($file, -4) == '.jpg') { + $bgs[] = $path . $file; + } + } + $dir->close(); + + $gb = $bgs[array_rand($bgs)]; + + list($width, $height) = @getimagesize($gb); + // Resample + $bgImage = @imagecreatefromjpeg($gb); + @imagecopyresampled($this->_image, $bgImage, 0, 0, 0, 0, $this->imageL, $this->imageH, $width, $height); + @imagedestroy($bgImage); + } + + /* 加密验证码 */ + private function authcode($str){ + $key = substr(md5($this->seKey), 5, 8); + $str = substr(md5($str), 8, 10); + return md5($key . $str); + } +} diff --git a/ThinkPHP/Library/Think/Verify/bgs/1.jpg b/ThinkPHP/Library/Think/Verify/bgs/1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d417136bb4613984dd88ac25590d2794344c990f GIT binary patch literal 30428 zcmeHwcU)7=((p+mw9rASgx*U60YdK*igcu^ln9}O7K+#a0R#OQ9wlj zu~1ct(k!5YfTE}%-$}6G^E~&ym+yP;Umwfw%$c2?nVp@TbJ!)>VfpFu2*74;N-zZ= zPzYozWGetHk1{HnM3Z&^fRz;>3jhE;fP`=WFc5=)KLCUuK+tdi@PY{Z!u=uAKX{-Z z4+a1sAP8Pz5G)Pn0`b%XBmn+Hwh+8`0yy6h0FYw)c{lJ0_9CKf{DLXL;eNp(Xd`

>%aJv{?GGXn!NI};-lJ2xvcGb=YQCnq;2CoelQt^ByHRQ?Jf zC?+Np3yO_}g^i1ag@ua>Sh!Y1*#8p+%gq2gJ)jSqgF!?AC_4nk4q1K%4x4eg1)>L9 ziGa`wXfUlV7!8(m2z>$K+N4MQua3 z;}~)7O2X})i181mQdxzG)yGqFM7A3N`7{ppGF3j2jOG<^v=XJ1*+fj|e56^TubeJg{v)s`+QNhZB<|B^^ZkoGy z;=&MsnA*j3qC0{`xbJ(FsZqYZbb&tW$!{4*8$H&HGg>)sRbNz3kq(`Aor5CH3^@pV<((}xO z7P;M`YdrFL9KMFX;u0x7+Qeltc8HpUuPAvNO;b-sAbFoL#jE{H^g$Px;$}_iAUkc*=h!;4)|9 zwQc(>pM8w@6jyq7+OXJwVM1$`B8-a??@MNs(#6qgw-e>8`Qdu9B#WTgj&gf*eoYuRcdT>s=mO zPWri76YJ&9r{#k}(*pT>O73vHx=wfFw$st@>c{(35dwz<$GwfC&)|f58N%bjUq0uk zt;>J;nPG3|umuS+)Umm7m|?LOL)o&eaL>C;!Dh{%?{@p$nT(9dGqYCw(?|A+8j3jC z_Fo<_*4-H_cK_T4S3y)lJtrzu+w8j??!M$!)};5+iz8*4bC#NsUjj5sy%b1+)o(>w z(l4^;5*`{2UQFvL*uV2M?t2-`A|ZB9;Z8Q2sa?;F%wnYscVgx&4mh}ZUPbLfg;_w- z#I8lYNXoexSXH-yzT3L1&*sG97;AJF#|8SKC&Ee7z6qAli?#e7#D<|))tUA8Tjy=D zeD;w^sG?@AsGw*88-b6XkkHL(QxK`K6w;tec=GexHRW`sO=qV+2kB4ii62QlvLz#6 zD57^SBea=rSV(*y0&BGSCdZWcgkE*ZhY5#(%Xg;42AYS-*Y~ECc=*L~A3FS|yx-G1 z_tjb75Df{PBf(EmVUvOT`GtD)2D}b-_|`5Rcyi==v)G3$p`GE|P>|Y_Vkf?rei5;g zd=&pyh~N5CvmVFhYYDpvAI}&Gi9b5u%)q}#IA)_6a;yjWdd%j8yUs;r>(?mN@AuLU zF+uW=;}UCCGaI6jvGh~ZD90C>EaH6e)^T=G-J%w;v$Hm*H;>=n-33jQo?Zr)yL!L6 zswelEOb1S$A2$+_GbsH=e>`e|E9aJrcv3a*abA9fM;oMWa#w_Yir=1$X%WE<3aTxR zG)tdU2xo4v{ZhC$YUIGAs^c5iIo@#qa`F3zB5lW=1#Uau!tQqZ2#H*4Jt}+Sm^Q0T zXkqH?w{{Pg;s*^kZco&c`rTR|?8@!DTXT5(l3XtGdFrjZWfwYYPjBD@amXY7iVmoekX{o@;t(XkVAg zhZEZ=bf^6&ty^+FGX70MbEF5N?Ijw*h2GT?LzM?t8TzF^bY z4A^*F9vmU=eQrb5;NwBQEoy_v5|#jC@`p2q{&PYeo)<4_5)`HO&w5>a&1ME)-S zfbyOFnWzupu{P)Ky)PWDiblN4A?T%xJuH1Ry)dVpVb8Yb749qo{hr*k&!<`S1b=j^ zbWQIQEko0;yyVx``Nv9G4mjAdkD^)OMyalQ%AdU+UIsJ`Mz1&XNAH>NC^cy2otgPy z6K)oHedD5}lnc_K<>b&_zfxG-(9R+D)1}!PReRbQo1?U6hu_mz>`rslf;~!+uwL$8 zo?>PGy<$^QR0cE*3080k+H!%723G-U8*FN&jk?+d*H6%&cbc3et&Qckh+ZtPq7g-- zQP+>rG)}%>^^G*GA82(38Uz7kMT(JD2UlrS9&n{eEsV5P8x@1nB))g z1R=OS1PkN`CGTX;FAA1McLm{39vqFL@S8%@xw1wK0oQ>4SYQ(%|9_#4+BeljU;)>w zv>J6K4gkzF_yf@B%CrjI%JPmzp^kw%F6x>VNu$uyC{(Y3G^qZ{^eOEK3?%O zKeY-2myAC=L#+aU4S2PI7s6N84|(DQpa5XN8nuVNmen+>1Xc2nvYO#%!w=J_RdPgN zAb6t=m(D9Vg6tD+?d9(c)_%y@c~hue)4byVZY~0Y$-ZEnRxF7-D68v+l;EHrb($G= zzJ5R3six6|2a>#r;ZA{;;b0B&M?VN!8%X8=FC?u(FkYn_=^GXt5%LF#E;x+jOCl4= z5ka5~vxz-byETml)={1jl;BN7GBM1PLi7O%fWyuZ;tyuV6=o`h+Cm8OMT58h_V{5D zVSx@N&JJK#Kb%W-{+|@9a9`pd6gtm9ii4-`A2b$kA}B|UrVzr-9IPz8f`bF83h956 z|6peD3l57h2qgLb^c3sL;LU!LK}nH5BOeP6o1Fa7^vUrJj?iGa%>0B{5^2z7zP3K#%BKrrA15CJr} z!SDld3V4Onun>@g^MBw#14e*7u(AoH^{}!FM6P@e0s%ig(X8^LP(n17l*r+Vp487X z6upCkl%hRDlrW0QN`SUrbcm;S0Fi?BB7$pv9ntpR$kB;aToRzXwh!N3`WEK-f zw2#^B;2jg-jrS4N(`D3-){G7c2_jNF(a}MH?U_^Bp(P*@Gn9mMPJ7d!yl3-0o^oNO2QBjIfDvH5jzDgK89dWJ;uav?=Vsbg%nIiQ}ud+J1vTis3^6gUuDHaAMaoNgn;`6S}#7{ zO2j~75Rps?2i<{D`lTF{)%Nk$+z}iWH^sXzMAR-$&i$`INp zsS5r=|DOy5=j4}#|2SEHSO;=z8if%(Dc}|X+@|Q#KFRs#&#JVk)BOkYZ}({bY9bng z`#D|e$65*)tO8ce;pfL%a>^Q-%F3&htZ@EChgGl-X~)k0M8_)5zv=)Z$H$Z6`5$Rn z&HG=N3M;FBKN&$mO8*pP;S@XK?|}ZtX$+@s>6Gk<;lUAM-b9f7cT7{G2AmKpD^25I z?+9vK5{z{tB1k@(riRKGyoNCrkHxDR8)7g9CKw|F6%9ii7N?9?RmIV!=TEsmoeQ=R z$l(-EvN!RUPNV-!=PJ3s=`<#Wks^screVQBwD=D33=1bx2dE?ZbA+qImO4P1i!@1p zF-AjO*~q{|O#=@O=bs1oH@V-&{8sDp7r*_dYFEkqR{P7TzX$p2;r`!x>M5ih{~}(f zEwq>PY6oglshZ#)W5C$(q`vlaG1^LhqpcbOt<9M_7l9EpeifWDwJ2ez@Q3W`_P@%y z{139L+y5&2Thx(EqUd6OboUqXU!^vK1B)aYlYEKcpbSn;9*a{4FAea*%VX8B@>q3M z@B(QXs`5A$W$?m)I7rt}k;mfIYU%CHqnTnc*nyS32GG0xY2El1k$6!|=mPT2DDj*$)S>aKYr%I{QAULJq zbb%BQf)rH^oH7l9(+T3>WP%W!esvWvIH(Zh2O*vcH9$@fQu|T?Lxl>dy{Ld8M1`O% z2x+ol0I6bB!B#2+tp(ugHawo%Bc7%cPqhTAj8T&Z!&V*)b$K;;b$JbWygcX{ z3`QPhfUBV?kc;DZ6iyB0>-*vJH{YGkTx zprVS!tKd{sjMY@|YFI-9&}Jk2kIDRF#{Rd1Jmlw>Y5qCVe>ML-+a#TAWw2&UIz0Q38RiF7=@!$Yj>O{qCx0PxHEXzI84 zsrc{m>G4W-m>vZ)8#MYi{XfFky+gvlEG`gg`W+P?@YE@YCxCch6eWa8r)EXr@(Q5h zP-;pat}xI*5a*@hzALyqjb{bdr{X?AWH5malxlN`Pmm84ZvpXxkrC9yIxtHRPl_ZF zqd>eD#Ki+6f=D1v&E>=uMDzrc{lKXiSHvkqZ$A)M265&v2RkDW*9P;gF#E2;y;k8A zFvAVV3m655?4;#$hQx&NE?TkXeOU^fs4BmswjG~gJJ1Dpj4fl}ZSPzBTh*MXbB zU7!QZ8r%mA0wcgn;4Lr%d;-3K8O)Fn6oeDP2N8xyK;$4;hz3L#Vgj***g;$%+abOX zG9&`B8?qmA2$BKGf#g9-A(tUnAvYoIkS<6+WE3(9nS*?V!l2AhE~pSx5~>8%fEqw8 zpbk(Es4p}W8Usy$rb16Z^Pv}^wa}Z;4rm{A1o{>_4<;05g7LsaUM z9{4DH2L2s^LI@({5Sj=A!WrRG!_ zC)3B%XVaI_H_~_0zo!4jz{ViKpvhp(;KQ(!;V45P!!?FS3@;hJF|spCG3qcnF#0pb zF`i(&#CV5si17mx6O$+tp2?Pp#1zYPf~k_JjcJtW3o{3^EVB`_J97kcDsu^QGjl)l z2NVh=iPA^8q9~|TR4M8<>N#qGg_A{*g}~y&vXA8yOD#(`%QPzks|2e7>sHnn)@;@* ztdCgVu`#eovKg^?vh8I%#dekL3EMn7Cp(7Snmvg9Fnbw$JNpC&l0%Zigu{m;fun%q zHpe(8j8lx$h|`;MKW8E59nP0rbX-zg1TKHBLtN!t54mQzIk;81ow%d9PjTPi9^rxU zNb(SP0(p+|RPj9K`MN=9gTV&khU5*GHgs?J%qzgF&r9S@;jQ59k)+T%uLtv!s;d7RdvW zb&?ZOyix?I7^w?VL((W|J?T*CeCb{pIvEX_0GZP=ow86_oUEVhDcMJIP&qX@lH6&z zE_noau8}OCFaJb=S;0UdQsIKas3MP|rDD8do#M2TxRR?BpscV(P%pmL$|Acg~D zj)})y!^~l2vEJBI*j^QsimA#zm3oy~RXJ6n>KWCiI8K}u?f~uwv;weyHI;vM^wjC zCr@WY7p=Qp_nhvCo`{~OUcTO#zL>s`ezE>*0~rH}U-3_40XMmXMbVs&zNDs}q2#du4`mJw$q=RM9HF8nSemwH#E ztCMT7>%5zZ+cCG7?l|`(_s1Sm9?>4{Tlu#JZoRRMb(`n5E87vI00pPpZ~-#d~KDTg%cZ{~m2 z|8szKKuN%I;FiFOAo`%~L08EfPj?wG&%bIPT8HwJ733`#uV*>@ABStYq!YmxZR_B z4EE&hh3xg(duyNAzJz@*V>iW~k7JArh@}m32&T`}O`b!Fz@+x>L4pjn`5tVN) zZ@>Jw%A)Gl6^$#GswJv(YdC9CY9X~dYiH{G>PG5a>btI*U%hor>sn2NVnfMwk?W^! zaNjuE$k>?BxZD)eG~XQ3{O+dj&GB2?ZVldczTMkm+w$;^#htdhrgv|*8niaG>9k#M z*KEIfPvc%)hgwJNecb(;2e=0{57i#lK2m>F--++M)}`Im*sa%nv&XpSZZDy?qi=Ix z*JH=WPoKCy8F}jSbfQ17e|8{p;M-vA5Mn6h8QZh$=Yr4khh>H(0rs8`vqgo!VzrR1@ zJo9okY<79>@CUvRB_CBk-kP_WfBq@x)3?tl3w#Ubzi51E{krAr>u*tu$i)*&GE3LK zTYMi{4gwRO{?2%>53U7PGTy^s)B-~A_aS&85pXyHNl!WS^r-$-rE3eFbJ3;{&&WEJ}~1wxU2>L-2t_L2(7>oFen`a_>u7* z3Wcq1{WG&56au4Wyr)CLKmZMgKw<1~00E}FH?XDS^aNAhb79l-klZU7=SNj|yk^A1 z;%6m{RP8hJtGvT+;f$p+3$CbbaPXnr?jEC;+|R(s%a@R4Vp>@3)Z-}4KR5n?n)RL- zk$7w+^Zma_e6L~V>=%9T#QFNRrxOb@c!CRQXY$F?tL^=hUt~4SUHxNHa>}mV8+h|| zB||<8fdI4i!|7qLAX>J1YLb2fge_<>U1(f7Ht+Hb*Uhd`F+*-UudrDaaaE&uo(y}5 zeDA7T$nb95nDPD%4w>Np1K{P8R5Rh1@}W4Y&lOy`EiKbC{vjc&u=-DvO;=^>U!AP~ z51apu$$uu*KXd&d5o>OlasSSM6WP+@bO+~E+}kr(*n0|Ii)RF$8;B&OU4{n_`)}+m zY5MZ1Au+K=q35y;zgwUMUG#E zLv7)xJI^Ubj>?xet($lCG<6gcZ01_3j!oW*Jw0i)7^a`c=$(~kIPWpR@Urr0=&*c0 zqG6Zsvx7?ml|viHV}e|_v~r5anbqjAE6l>aIh4)_1gDwj_L-{aDKZAw$@G4@#6HxL zH~l_n%Ij;J#HW#DkL2${*w8o$0%41N!;9{0ZJ|caO0IV@H;^4z4H%Qbz3Xm$h+M5L zF+7TL*>Jo4=9guxZu4^>2%m&>=JaKGv59#AqtH>SZ=SLjZXcGusV@%I4BC1+;C-48 zn0mc)f~D}P?@(fXPsQ`dM=q?nMbqify)3WCN?aphb?)^%;`q_SZaB49NYO?ioo`+& z6Sh4;ms$?Be4o9^Zu;yK*V`J_M}nCQv6j$w{4t^&b8R2CRH{f;rf%OE`xeB`E2EN& zIY}6a7G;j;2FDXNlrN*{=gdXryA|JbcjeW8JeD00xe%u%)K*bvS*CLA(3=4-=_kfz zatC!BERy`r*%0Ke`co!Pa?sWK!?#W}e6w&nWqoO|WyZ{kUGPax1T&G?S7|{xkyno&mcHYq`eJL1?%;b%_D2y$ zk(;zm#_G%l!CXbyj;ZL_=Sj6toa)prH zN|HCE$XPbWMt7$0^N)#<^sUv;+n-dp73XbZz*Ua2QvX)fDZ>@p>^moEzpIC)IqvU$~=caJ190Ypjm&McLK-x=e3U(XJ{ z-#mD1W~gc0m;cTTwzuZ{)w8l`&sqeyU2r$F?}Tz$hz@x$atuYwaKG<$cp{t1;4GCE zgcrLJVKCrs#M!EI>uY{&2-ow%?h?gZ!c$yJY+$k8*1BtwhN)G7=N}HjE>FH6lsU}2 z=RuO8#b{2qx}=v!MuO=%p|`dkcQm~*qH4yL2G302yb&^Q&oJZ|i$ z`PNoKR>JtJgzlhh!u=|nRz@%lNNOylBiu61pn|QcaVjV^t?tl<{Ap*|_|1LfVN-g( z(7r(#$ZbmIpxc9}H=FnhQ)(Rjk6gHcVhumZk#@w*-FtU-HMaj8wiI&2p|dkyr+KD5 z6dLJeK+kks0al?Id(kZ>V)D2N0udnGDv%`GwyE}6YhdL$CjakVRrv?T%%K4@M=n_1 z(cZ1x92lRH+HG5ML_h7#I|ytlB!txArA0LLK9qPRwy$AJmuGd4Zl$XW-;$cmp>}g8n|SNLLU8wPHPBc?l1`d`{+i-;nWZJ{}3#RXH3+ z7{)4`zZQ0+<%a&@ph{qgSKny4d!kCLe@NBRyh9-HncRqJOtrt)u%I43i|Hd#euu6J1P_}oj#mm zZnkIyS5*}(bq{SurR^Zp@J&A$H9P5~XYJPu)7Sc_+wbFf>#luu<5=X8=ZqPHVS7&M zm&|>tNb+D0WH7J_;C}S}5a7p~^`=i?>cd99Kp!Ixw$6v0kNKRcP-Rg7zfF)wWx8K= zl<2IST<8v*wtBfHyU~bTTGE&rR<7y0 z((NNhY9L?tR05F7QxeLR^;fFL9&t;^!_2KVL8HzU_d7Y?b93_%7oDHp*}Xi7?kZKXv#%iaubM#b8qO$l(U50eRE;^GgL*GY>-r z`wwQeEBAa%4}ZHi5_lcw<{!}A#72xo4WNY7pv=?LCyr<%hyxd9<06K;hUCw-fVe-d6qGP7@x@)jF%g(jY-lt(YOac%XJOYep?~>{K9p7H0zV& z)#W+cHaqI@oJ#L~a>*=_k}7dAJ*PYF_(0==Sd~MwXwg2uZw~v;y65Btqd5ySG4qDA zPg8JOg1J`cB=wykvnreT(9(<_2gfD?40pZq@#=QEiM1>;?21+8E|olOFnh~Hf`j?O z28j!1vc0$n|H$!?fI*Q5c3-xViWFbSCz|O;!YYBtVTFSb1bmOg_m7wN&c9KcR_{n! zJW(TfCM&(I@O=4BhtrLt$w$h9AL6+SeHAN0D);lcVgoe9dd5T9HazT2dz>d@UnvkBd9Of4=8H-ea5TptRJpc7 z_^{J~J#RaE-w&(A)(IAP^^BV##vgvjpigt{+51A6e+TBC<$1>MSJE&k4PQi>to5E` zwQ}-m9DF9!C<*j(KF(@q-k77^8TQ^g}b^I;YOERieD?QI2`lW$5t~JekGbQ=trpv?Kyb=L{v@IX-3nb zCy`5Kfm)Frhq#@N=+NcZ-!m;?>}B6p=wsl3u@i-Cx@%=n5&UV+JpXX)neCUQM!672 zNMC2Vw=MUcH5(~)5WhSW*9lt;f2?2fkl;Mtb6~72^YH=iZ9=UE8LtvFvTRc}S}i_s zoiYzvx~j}O;206A(8KnqowG!rVdL0IiWiK7;D%_6C!^~adt#-gf|}gZk0d}3WxtI- zdoVw8Vz1c84AK)hcHfqaA=m3e8JLIqgLWx$LuB2(e7lL3vYpaJP2hiWfybrx=5YzU zyc6%~J%1>6g8hC9E64RxqbDVe;CA34I*WKFUa90XF|1fkd$9ObgH3A9M!e;R8DLOw zw~66f)1E?k+vj{+MwtuK8*d*AsO!c)eVG=3;i=N0lUB%{TN*Iqw&*g^Wv@|_ikV*q zRN`IZt(kY$GJ9RT;2)V?{1|0;6WSa}v^TK&#`syNinmBnj8D;wvGVw2ol}!rGMPR$ z3~0zGbBvNK4BEE4t%LJcKxDm8kHRL8y4s!DJQfE}+IJa7y)v=#V<<`LKXla6Y{M1G z71sT1^Rel0h*2)`>XL z+a8Ke)4E)~*Js2iU4uvA2B7-oY;d+()@Q>y=U2Nf+_6bJTD=Ug!9Svd?QKu&Y%de+ z*ei0QyjOl;Qp5rBz8EE@9WdF_^-=tZcduuwuD~=y7P;Z+=~t&igQW_)V1fs7S@~E{ zq)M?0_eV(vQoPLvT>CwiHjj;&U|PvY^e|KK*4UA(@$FGn?5cLJBr-Fh`skD+b#Dh- z6`6Su&VyrluIc7BDI06vCbBN~okD)R>2>?4otl*A$N5JdqQe?~*V^9QANpLD(krcV zUhTF+%Q0khm&;WJy>`_iKlNd8e4ccUspIxj5`@DtKxR+vw;lS-TwY0Y(Qn}jGw;N? zgmtSc=5P7(evo08%3yE20-Kd62-&3ZqMSjC|LE>YTb{cIefT}@9L~miJfAZ)GUA_V zj~z-`641Tn#lz#t%_uP)j>WUc3#yD)x zR%sCz5K)F84%X&rM+SLyC7Ou036I6#cmu6;J`byH<+7~L-K*j*6TpcPXEPIEuiFP} zbbst-*2(HH536V+hZH7OHForEY-0U1mYC%zJ>9FtKh+ebwiI2K|6qb}jRpQrHfG^W z(*+1mX=0Xt&q<+J037wFWF2HvTaR>lu_rEdWblCgA@T6^hZ~AyZV-yF$@+v`AH)6r z_pi*>+Y5$P@Vc^Zh80EEws?gCGpNLx1SmV@FPetsbEoRX5aXDOP-*c~N47alE9~!oez6n! zcs5fond9#D_#Cc0sq@3YF*DoOuQJrs5-p@96SuoLx@9L|QYk)R0+j2+gn3qq-)N{5~DMhi`8U4Twk1GC~hY!de4979y3&VmylWO zmbFpng!hGKs`aT~G8~=9>+AHMwQhxf+iiGSg-2V9qG(xv!m4-wTV{G$+k?(YFZIRk zgD#vpI2S^1Swnb{`tYuqdn@l)%h7oQ?jpHb&oQ7a{)J^ao8f^IqVk?68D2`~iTTgw z2`u4vocO>T&SD~cxk~-Gf6da<3-?T7SXs|nwzuo@*4)xINq_Dl&}O{N*rDgjooA;MI z9?hat`njX$n4F#`bT>pG11mibe%QorQCG_RIw#W=K=>gd-}WeY^-3E^MU+fMA7*^5 zce$fvK&)kcG9^*c7n@ivZ57jVb<$nNy)q^#^_g_^yz0!`TDW31)(-+mpX0T0yL`rt z)W~vV=9=1@!52Od=5m#Q8k-Rr*WKv-SDyy=ko&hViOZ>IW~j~6mq$%&@5V-$=|4j| zEtsj=T||z5oolu^ZkeZ1!{iVsV`n9|u*+vGvG%w<-$5sIJ(KyA!Q&fpNw!RWSA&(@ zKC_04>Ypo%yLVs$DLZmh^VxCsm%+W>_6@|o_n zK1)o?+THDjpDIX4-S^BRSD(+*K_T5Ab}4q0?!iYtj(s<1-xS#IeZ&~aVRt1UXg*Hpd`;uwNBqjp zy&Md%7&cOOy~KfC$;E9ixJ`^~dVTtQ>?S8K>d)x=n~=sW&uDu=4!>?G60l;$aFw%d z-;j~Bv1ZD$GS>8+!6kEZ#y0DUhX$XLhk7QZST|b|j6}9@!@=LSEyUboRpR0$qCko3 z>D1xP&_ukG#zb>ZImu&@?zQ-a459w3Jo@_3k`n)KqfT!enP6Ll{mvYlv@YOwd7~0o zaOpwq@asl4tsbjHAJ@xcP1T!%8w9E|{c%bXrp>`ls^^hcheZ?329p&Y`7_peOnx49 zdJ%a}$MG6}%Gm-Ao2yI?I?`pPOBd211e33aS}1}CT8+#dBHDW73<=U(AS8V}tRwCG zSFIiir=)2^u8pOTwx^xFv0A-HW@1Z&o-PBM;QZWApOh0sPilNH-`KY;i)ip7_q(L5n**13*^CS-@WLw?1M2| zZewB4(OC_rau+k)8+`DBrxvEVIBe_G)1ygPeb_ms$}hx`z&kLd_uT3WWkws9>N>oN z%zaI=%26h|9$2GHj!HsHU=#cF;CDVn0jn|wXZy3(5Q7CD^V5%|75(&WkTw8(i8nqc z=x}Ie4a;EEVn~AY1rA-6dkqehl8!*xVr!9ECAI)p{&Z_p!&rHyt-h?b=AMPJr*CaE z>&zE=iV?5+7fw3_Iu$j}jwZTFFkn6l``K3x4esuC4kIn7gJBec5ri-OCA<^KNzFf8P^ literal 0 HcmV?d00001 diff --git a/ThinkPHP/Library/Think/Verify/bgs/2.jpg b/ThinkPHP/Library/Think/Verify/bgs/2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..56640bde4ed9a02c4e46b951f2108e5e4814b14a GIT binary patch literal 29677 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 literal 0 HcmV?d00001 diff --git a/ThinkPHP/Library/Think/Verify/bgs/3.jpg b/ThinkPHP/Library/Think/Verify/bgs/3.jpg new file mode 100644 index 0000000000000000000000000000000000000000..83e5bd9026f9d46c96738a4209f1abb91f7e1e6f GIT binary patch literal 32109 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 WW2Q1p-X6|ip1UGwC*Qp@{Qm&B(nP5M literal 0 HcmV?d00001 diff --git a/ThinkPHP/Library/Think/Verify/bgs/4.jpg b/ThinkPHP/Library/Think/Verify/bgs/4.jpg new file mode 100644 index 0000000000000000000000000000000000000000..97a3721bc777a569c6665e38dec04a82df9176da GIT binary patch literal 29081 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�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
5eqK))^(a`g}#Vel}`0jqQ{$m(#9bM;B`pV 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%0Dja6n-|cc61%dSLS`lUd7W-JGp5n>o88 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૦ilU=I8^3w$Rh1aryLRN1@vEe`O?@pzT+nv6 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 R;s=GvM3(ZxPL-v5{|~;{ne6}o literal 0 HcmV?d00001 diff --git a/ThinkPHP/Library/Think/Verify/bgs/8.jpg b/ThinkPHP/Library/Think/Verify/bgs/8.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e10cf28115e47d1f5413e76efeccc39cd655b6cc GIT binary patch literal 30188 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 literal 0 HcmV?d00001 diff --git a/ThinkPHP/Library/Think/Verify/ttfs/1.ttf b/ThinkPHP/Library/Think/Verify/ttfs/1.ttf new file mode 100644 index 0000000000000000000000000000000000000000..d4ee155870e0011906a24cf200a8f6a11d2daa0a GIT binary patch literal 57520 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 literal 0 HcmV?d00001 diff --git a/ThinkPHP/Library/Think/Verify/ttfs/2.ttf b/ThinkPHP/Library/Think/Verify/ttfs/2.ttf new file mode 100644 index 0000000000000000000000000000000000000000..3a452b68f3baa612539ad43cd427725e96f44100 GIT binary patch literal 28328 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
h?Dh;`UO$BEWkO}@9qw>ZI2^xAN(lX_pcD;%+W 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 c%R7_2IG>vddcb)xU-zgoC({L12w|r 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 literal 0 HcmV?d00001 diff --git a/ThinkPHP/Library/Think/Verify/ttfs/6.ttf b/ThinkPHP/Library/Think/Verify/ttfs/6.ttf new file mode 100644 index 0000000000000000000000000000000000000000..7f183e20820646f07ae833b64230629ce815fd36 GIT binary patch literal 28036 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

NiFR; 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%0AxGNr4ql@>e2TVjC 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 z

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 z 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≻d;ycWSqKxMrFva1_ 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 ttadbN)KkB`o93VPe`p>kARxCs`}iJdNs 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¶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

^SXbDKBsQ1XA*)qi2H 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

^CQo4_4}AmejKBGFmFAO&Abo0!5(&&~ltX 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 z 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�}ATq8*lvF&xo8oF6E9$Y=E)i$n%`e^<@k*Wk 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