diff --git a/Application/README.md b/Application/README.md new file mode 100644 index 0000000000000000000000000000000000000000..5bc1d44fee7452e15604bea8dd5477a35062c199 --- /dev/null +++ b/Application/README.md @@ -0,0 +1 @@ +项目目录 \ No newline at end of file diff --git a/Common/runtime.php b/Common/runtime.php deleted file mode 100644 index 3d3dc6a8f34e077250c2e90da703cf3f7348bbf4..0000000000000000000000000000000000000000 --- a/Common/runtime.php +++ /dev/null @@ -1,243 +0,0 @@ - -// +---------------------------------------------------------------------- -// $Id$ - -/** - +------------------------------------------------------------------------------ - * ThinkPHP 运行时文件 编译后不再加载 - +------------------------------------------------------------------------------ - */ -defined('THINK_PATH') or exit(); -if(version_compare(PHP_VERSION,'5.2.0','<')) die('require PHP > 5.2.0 !'); - -// 版本信息 -define('THINK_VERSION', '3.1RC'); - -// 系统信息 -if(version_compare(PHP_VERSION,'5.3.0','<')) { - set_magic_quotes_runtime(0); - define('MAGIC_QUOTES_GPC',get_magic_quotes_gpc()?True:False); -}else{ - define('MAGIC_QUOTES_GPC',True); -} -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,0777,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,0777,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='') { - // 目录安全写入 - 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/Conf/convention.php b/Conf/convention.php deleted file mode 100644 index 0c851287656150a09dbc5d7ada19ccc67e73fea3..0000000000000000000000000000000000000000 --- a/Conf/convention.php +++ /dev/null @@ -1,139 +0,0 @@ - -// +---------------------------------------------------------------------- -// $Id: convention.php 3088 2012-07-29 09:12:19Z luofei614@gmail.com $ - -/** - +------------------------------------------------------------------------------ - * 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' - 'ACTION_SUFFIX' => '', // 操作方法后缀 - - /* Cookie设置 */ - 'COOKIE_EXPIRE' => 3600, // Coodie有效期 - 'COOKIE_DOMAIN' => '', // Cookie有效域名 - 'COOKIE_PATH' => '/', // Cookie路径 - 'COOKIE_PREFIX' => '', // Cookie前缀 避免冲突 - - /* 默认设定 */ - 'DEFAULT_M_LAYER' => 'Model', // 默认的模型层名称 - 'DEFAULT_C_LAYER' => 'Action', // 默认的控制器层名称 - '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_FILTER' => 'htmlspecialchars', // 默认参数过滤方法 用于 $this->_get('变量名');$this->_post('变量名')... - - /* 数据库设置 */ - '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执行日志记录 - - /* 数据缓存设置 */ - 'DATA_CACHE_TIME' => 0, // 数据缓存有效期 0表示永久缓存 - 'DATA_CACHE_COMPRESS' => false, // 数据缓存是否压缩缓存 - 'DATA_CACHE_CHECK' => false, // 数据缓存是否校验缓存 - '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, // 显示错误信息 - - /* 日志设置 */ - '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, // 是否记录异常信息日志 - - /* SESSION设置 */ - 'SESSION_AUTO_START' => true, // 是否自动开启Session - 'SESSION_OPTIONS' => array(), // session 配置数组 支持type name id path expire domian 等参数 - '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之间的分割符,只对项目分组部署有效 - - /* 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' => '', // URL伪静态后缀设置 - 'URL_PARAMS_BIND' => true, // URL变量绑定到Action方法参数 - - /* 系统变量名称设置 */ - 'VAR_GROUP' => 'g', // 默认分组获取变量 - 'VAR_MODULE' => 'm', // 默认模块获取变量 - 'VAR_ACTION' => 'a', // 默认操作获取变量 - 'VAR_AJAX_SUBMIT' => 'ajax', // 默认的AJAX提交变量 - 'VAR_PATHINFO' => 's', // PATHINFO 兼容模式获取变量例如 ?s=/module/action/id/1 后面的参数取决于URL_PATHINFO_DEPR - 'VAR_URL_PARAMS' => '_URL_', // PATHINFO URL参数变量 - 'VAR_TEMPLATE' => 't', // 默认模板切换变量 - 'VAR_FILTERS' => '', // 全局系统变量的默认过滤方法 多个用逗号分割 - - 'OUTPUT_ENCODE' => true, // 页面压缩输出 - -); \ No newline at end of file diff --git a/Lang/zh-cn.php b/Lang/zh-cn.php deleted file mode 100644 index 03a8f7f503db4e00a9ea9e3b1bfe6324095e25fe..0000000000000000000000000000000000000000 --- a/Lang/zh-cn.php +++ /dev/null @@ -1,58 +0,0 @@ - -// +---------------------------------------------------------------------- -// $Id: zh-cn.php 3034 2012-06-20 16:07:41Z liu21st@gmail.com $ - -/** - +------------------------------------------------------------------------------ - * ThinkPHP 简体中文语言包 - +------------------------------------------------------------------------------ - * @category Think - * @package Lang - * @author liu21st - * @version $Id: zh-cn.php 3034 2012-06-20 16:07:41Z liu21st@gmail.com $ - +------------------------------------------------------------------------------ - */ -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 diff --git a/Lib/Behavior/LocationTemplateBehavior.class.php b/Lib/Behavior/LocationTemplateBehavior.class.php deleted file mode 100644 index 17092f35f9cd09fdf362a3a195abb0c3b66e5a05..0000000000000000000000000000000000000000 --- a/Lib/Behavior/LocationTemplateBehavior.class.php +++ /dev/null @@ -1,61 +0,0 @@ - -// +---------------------------------------------------------------------- -// $Id: LocationTemplateBehavior.class.php 3001 2012-06-15 03:39:19Z liu21st@gmail.com $ - -defined('THINK_PATH') or exit(); -/** - +------------------------------------------------------------------------------ - * 系统行为扩展 自动定位模板文件 - +------------------------------------------------------------------------------ - */ -class LocationTemplateBehavior extends Behavior { - // 行为扩展的执行入口必须是run - public function run(&$templateFile){ - // 自动定位模板文件 - if(!file_exists_case($templateFile)) - $templateFile = $this->parseTemplateFile($templateFile); - } - - /** - +---------------------------------------------------------- - * 自动定位模板文件 - +---------------------------------------------------------- - * @access private - +---------------------------------------------------------- - * @param string $templateFile 文件名 - +---------------------------------------------------------- - * @return string - +---------------------------------------------------------- - * @throws ThinkExecption - +---------------------------------------------------------- - */ - private function parseTemplateFile($templateFile) { - if(''==$templateFile) { - // 如果模板文件名为空 按照默认规则定位 - $templateFile = C('TEMPLATE_NAME'); - }elseif(false === strpos($templateFile,C('TMPL_TEMPLATE_SUFFIX'))){ - // 解析规则为 模板主题:模块:操作 不支持 跨项目和跨分组调用 - $path = explode(':',$templateFile); - $action = array_pop($path); - $module = !empty($path)?array_pop($path):MODULE_NAME; - if(!empty($path)) {// 设置模板主题 - $path = dirname(THEME_PATH).'/'.array_pop($path).'/'; - }else{ - $path = THEME_PATH; - } - $depr = defined('GROUP_NAME')?C('TMPL_FILE_DEPR'):'/'; - $templateFile = $path.$module.$depr.$action.C('TMPL_TEMPLATE_SUFFIX'); - } - if(!file_exists_case($templateFile)) - throw_exception(L('_TEMPLATE_NOT_EXIST_').'['.$templateFile.']'); - return $templateFile; - } -} \ No newline at end of file diff --git a/Lib/Core/Dispatcher.class.php b/Lib/Core/Dispatcher.class.php deleted file mode 100644 index 356ab4337d0c0f0258ab394518969317df0be24c..0000000000000000000000000000000000000000 --- a/Lib/Core/Dispatcher.class.php +++ /dev/null @@ -1,226 +0,0 @@ - -// +---------------------------------------------------------------------- -// $Id: Dispatcher.class.php 3067 2012-07-13 10:02:49Z liu21st@gmail.com $ - -/** - +------------------------------------------------------------------------------ - * ThinkPHP内置的Dispatcher类 - * 完成URL解析、路由和调度 - +------------------------------------------------------------------------------ - * @category Think - * @package Think - * @subpackage Util - * @author liu21st - * @version $Id: Dispatcher.class.php 3067 2012-07-13 10:02:49Z liu21st@gmail.com $ - +------------------------------------------------------------------------------ - */ -class Dispatcher { - - /** - +---------------------------------------------------------- - * URL映射到控制器 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @return void - +---------------------------------------------------------- - */ - static public function dispatch() { - $urlMode = C('URL_MODEL'); - if(!empty($_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'); - $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(empty($_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(C('URL_HTML_SUFFIX')) { - $_SERVER['PATH_INFO'] = preg_replace('/\.('.trim(C('URL_HTML_SUFFIX'),'.').')$/i', '', $_SERVER['PATH_INFO']); - }elseif(__EXT__) { - $_SERVER['PATH_INFO'] = preg_replace('/.'.__EXT__.'$/i','',$_SERVER['PATH_INFO']); - } - if(!self::routerCheck()){ // 检测路由规则 如果没有则按默认规则调度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']); - } - - // 获取分组 模块和操作名称 - if (C('APP_GROUP_LIST')) { - define('GROUP_NAME', self::getGroup(C('VAR_GROUP'))); - } - define('MODULE_NAME',self::getModule(C('VAR_MODULE'))); - define('ACTION_NAME',self::getAction(C('VAR_ACTION'))); - // URL常量 - define('__SELF__',strip_tags($_SERVER['REQUEST_URI'])); - // 当前项目地址 - define('__APP__',strip_tags(PHP_FILE)); - // 当前模块和分组地址 - if(defined('GROUP_NAME')) { - define('__GROUP__',(!empty($domainGroup) || strtolower(GROUP_NAME) == strtolower(C('DEFAULT_GROUP')) )?__APP__ : __APP__.'/'.GROUP_NAME); - define('__URL__',!empty($domainModule)?__GROUP__.$depr : __GROUP__.$depr.MODULE_NAME); - }else{ - define('__URL__',!empty($domainModule)?__APP__.'/' : __APP__.'/'.MODULE_NAME); - } - // 当前操作地址 - define('__ACTION__',__URL__.$depr.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(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]); - 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); - } - -} \ No newline at end of file diff --git a/Lib/Core/Think.class.php b/Lib/Core/Think.class.php deleted file mode 100644 index 95bcc7dd8b8f2dbc718f29a36d85bac85600f78d..0000000000000000000000000000000000000000 --- a/Lib/Core/Think.class.php +++ /dev/null @@ -1,319 +0,0 @@ - -// +---------------------------------------------------------------------- -// $Id: Think.class.php 3066 2012-07-11 13:16:29Z liu21st@gmail.com $ - -/** - +------------------------------------------------------------------------------ - * ThinkPHP Portal类 - +------------------------------------------------------------------------------ - * @category Think - * @package Think - * @subpackage Core - * @author liu21st - * @version $Id: Think.class.php 3066 2012-07-11 13:16:29Z liu21st@gmail.com $ - +------------------------------------------------------------------------------ - */ -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() { - // 加载底层惯例配置文件 - C(include THINK_PATH.'Conf/convention.php'); - - // 读取运行模式 - if(defined('MODE_NAME')) { // 模式的设置并入核心模式 - $mode = include MODE_PATH.strtolower(MODE_NAME).'.php'; - }else{ - $mode = array(); - } - - // 加载模式配置文件 - 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 ; - - if(substr($class,-8)=='Behavior') { // 加载行为 - if(require_cache(CORE_PATH.'Behavior/'.$class.'.class.php') - || require_cache(EXTEND_PATH.'Behavior/'.$class.'.class.php') - || require_cache(LIB_PATH.'Behavior/'.$class.'.class.php') - || (defined('MODE_NAME') && require_cache(MODE_PATH.ucwords(MODE_NAME).'/Behavior/'.$class.'.class.php'))) { - return ; - } - }elseif(substr($class,-5)=='Model'){ // 加载模型 - if((defined('GROUP_NAME') && require_cache(LIB_PATH.'Model/'.GROUP_NAME.'/'.$class.'.class.php')) - || require_cache(LIB_PATH.'Model/'.$class.'.class.php') - || require_cache(EXTEND_PATH.'Model/'.$class.'.class.php') ) { - return ; - } - }elseif(substr($class,-6)=='Action'){ // 加载控制器 - if((defined('GROUP_NAME') && require_cache(LIB_PATH.'Action/'.GROUP_NAME.'/'.$class.'.class.php')) - || require_cache(LIB_PATH.'Action/'.$class.'.class.php') - || require_cache(EXTEND_PATH.'Action/'.$class.'.class.php') ) { - 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) { - halt($e->__toString()); - } - - /** - +---------------------------------------------------------- - * 自定义错误处理 - +---------------------------------------------------------- - * @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); - 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,'','ERR'); - break; - } - } - - // 致命错误捕获 - static public function fatalError() { - if ($e = error_get_last()) { - Think::appError($e['type'],$e['message'],$e['file'],$e['line']); - } - } - - /** - +---------------------------------------------------------- - * 自动变量设置 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @param $name 属性名称 - * @param $value 属性值 - +---------------------------------------------------------- - */ - public function __set($name ,$value) { - if(property_exists($this,$name)) - $this->$name = $value; - } - - /** - +---------------------------------------------------------- - * 自动变量获取 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @param $name 属性名称 - +---------------------------------------------------------- - * @return mixed - +---------------------------------------------------------- - */ - public function __get($name) { - return isset($this->$name)?$this->$name:null; - } -} \ No newline at end of file diff --git a/Lib/Core/ThinkException.class.php b/Lib/Core/ThinkException.class.php deleted file mode 100644 index 76b94bf3bcac7862be92d1c71008544adf165ab0..0000000000000000000000000000000000000000 --- a/Lib/Core/ThinkException.class.php +++ /dev/null @@ -1,104 +0,0 @@ - -// +---------------------------------------------------------------------- -// $Id: ThinkException.class.php 2977 2012-06-11 12:32:59Z luofei614@gmail.com $ - -/** - +------------------------------------------------------------------------------ - * ThinkPHP系统异常基类 - +------------------------------------------------------------------------------ - * @category Think - * @package Think - * @subpackage Exception - * @author liu21st - * @version $Id: ThinkException.class.php 2977 2012-06-11 12:32:59Z luofei614@gmail.com $ - +------------------------------------------------------------------------------ - */ -class ThinkException extends Exception { - - /** - +---------------------------------------------------------- - * 异常类型 - +---------------------------------------------------------- - * @var string - * @access private - +---------------------------------------------------------- - */ - private $type; - - // 是否存在多余调试信息 - private $extra; - - /** - +---------------------------------------------------------- - * 架构函数 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @param string $message 异常信息 - +---------------------------------------------------------- - */ - public function __construct($message,$code=0,$extra=false) { - parent::__construct($message,$code); - $this->type = get_class($this); - $this->extra = $extra; - } - - /** - +---------------------------------------------------------- - * 异常输出 所有异常处理类均通过__toString方法输出错误 - * 每次异常都会写入系统日志 - * 该方法可以被子类重载 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @return array - +---------------------------------------------------------- - */ - public function __toString() { - $trace = $this->getTrace(); - if($this->extra) - // 通过throw_exception抛出的异常要去掉多余的调试信息 - array_shift($trace); - $this->class = isset($trace[0]['class'])?$trace[0]['class']:''; - $this->function = isset($trace[0]['function'])?$trace[0]['function']:''; - $this->file = $trace[0]['file']; - $this->line = $trace[0]['line']; - $file = file($this->file); - $traceInfo=''; - $time = date('y-m-d H:i:m'); - foreach($trace as $t) { - $traceInfo .= '['.$time.'] '.$t['file'].' ('.$t['line'].') '; - $traceInfo .= $t['class'].$t['type'].$t['function'].'('; - $traceInfo .= implode(', ', $t['args']); - $traceInfo .=")\n"; - } - $error['message'] = $this->message; - $error['type'] = $this->type; - $error['detail'] = L('_MODULE_').'['.MODULE_NAME.'] '.L('_ACTION_').'['.ACTION_NAME.']'."\n"; - $error['detail'] .= ($this->line-2).': '.$file[$this->line-3]; - $error['detail'] .= ($this->line-1).': '.$file[$this->line-2]; - $error['detail'] .= ''.($this->line).': '.$file[$this->line-1].''; - $error['detail'] .= ($this->line+1).': '.$file[$this->line]; - $error['detail'] .= ($this->line+2).': '.$file[$this->line+1]; - $error['class'] = $this->class; - $error['function'] = $this->function; - $error['file'] = $this->file; - $error['line'] = $this->line; - $error['trace'] = $traceInfo; - - // 记录 Exception 日志 - if(C('LOG_EXCEPTION_RECORD')) { - Log::Write('('.$this->type.') '.$this->message); - } - return $error ; - } - -} \ No newline at end of file diff --git a/Lib/Core/Widget.class.php b/Lib/Core/Widget.class.php deleted file mode 100644 index 7331aa246f5dba84dad5f7bdbc22e2a77175ea2c..0000000000000000000000000000000000000000 --- a/Lib/Core/Widget.class.php +++ /dev/null @@ -1,127 +0,0 @@ - -// +---------------------------------------------------------------------- -// $Id: Widget.class.php 2783 2012-02-25 06:49:45Z liu21st $ - -/** - +------------------------------------------------------------------------------ - * ThinkPHP Widget类 抽象类 - +------------------------------------------------------------------------------ - * @category Think - * @package Think - * @subpackage Util - * @author liu21st - * @version $Id: Widget.class.php 2783 2012-02-25 06:49:45Z 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 = 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/Public/README.md b/Public/README.md new file mode 100644 index 0000000000000000000000000000000000000000..40f011ace8d90828a2697d995c147a3b8e7791bd --- /dev/null +++ b/Public/README.md @@ -0,0 +1 @@ +资源文件目录 \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000000000000000000000000000000000000..35d3f16d77918b7737f19375027ea4a7d5adf63a --- /dev/null +++ b/README.md @@ -0,0 +1,38 @@ +## 简介 + +ThinkPHP 是一个免费开源的,快速、简单的面向对象的 轻量级PHP开发框架 ,创立于2006年初,遵循Apache2开源协议发布,是为了敏捷WEB应用开发和简化企业应用开发而诞生的。ThinkPHP从诞生以来一直秉承简洁实用的设计原则,在保持出色的性能和至简的代码的同时,也注重易用性。并且拥有众多的原创功能和特性,在社区团队的积极参与下,在易用性、扩展性和性能方面不断优化和改进,已经成长为国内最领先和最具影响力的WEB应用开发框架,众多的典型案例确保可以稳定用于商业以及门户级的开发。 + +## 全面的WEB开发特性支持 + +最新的ThinkPHP为WEB应用开发提供了强有力的支持,这些支持包括: + +* MVC支持-基于多层模型(M)、视图(V)、控制器(C)的设计模式 +* ORM支持-提供了全功能和高性能的ORM支持,支持大部分数据库 +* 模板引擎支持-内置了高性能的基于标签库和XML标签的编译型模板引擎 +* RESTFul支持-REST模式提供了RESTFul支持,为你打造全新的URL设计和访问体验 +* 云引擎支持-提供了对新浪SAE平台和百度BAE平台的强力支持,具备“横跨性”和“平滑性”,支持本地化开发和调试以及部署切换,让你轻松过渡,打造全新的开发体验。 +* CLI支持-支持基于命令行的应用开发 +* AMF支持-支持Flex开发和Flash通讯,打造互联网富应用 +* PHPRPC支持-提供基于PHPRpc的WEBService解决方案 +* MongoDb支持-提供NoSQL的支持 +* 缓存支持-提供了包括文件、数据库、Memcache、Xcache、Redis等多种类型的缓存支持 + +## 大道至简的开发理念 + +ThinkPHP从诞生以来一直秉承大道至简的开发理念,无论从底层实现还是应用开发,我们都倡导用最少的代码完成相同的功能,正是由于对简单的执着和代码的修炼,让我们长期保持出色的性能和极速的开发体验。在主流PHP开发框架的评测数据中表现卓越,简单和快速开发是我们不变的宗旨。 + +## 安全性 + +框架在系统层面提供了众多的安全特性,确保你的网站和产品安全无忧。这些特性包括: + +* XSS安全防护 +* 表单自动验证 +* 强制数据类型转换 +* 输入数据过滤 +* 表单令牌验证 +* 防SQL注入 +* 图像上传检测 + +## 商业友好的开源协议 + +ThinkPHP遵循Apache2开源协议发布。Apache Licence是著名的非盈利开源组织Apache采用的协议。该协议和BSD类似,鼓励代码共享和尊重原作者的著作权,同样允许代码修改,再作为开源或商业软件发布。 \ No newline at end of file diff --git a/ThinkPHP/Common/build.php b/ThinkPHP/Common/build.php new file mode 100644 index 0000000000000000000000000000000000000000..ed99f4b72aaf98955fe87141159aa2e3f0eb66c3 --- /dev/null +++ b/ThinkPHP/Common/build.php @@ -0,0 +1,105 @@ + +// +---------------------------------------------------------------------- + +/** + * ThinkPHP 目录创建和初始化 + * @category Think + * @package Common + * @author liu21st + */ +defined('THINK_PATH') or exit(); + +// 检查项目目录结构 如果不存在则自动创建 +if(!is_dir(COMMON_PATH)) { + // 创建项目目录结构 + build_app_dir(); +}elseif(!is_dir(CACHE_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/', + COMMON_PATH.'Lang/', + 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('项目目录不可写,目录无法自动生成!
请使用项目生成器或者手动生成项目目录~'); + } +} + +// 创建测试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()) { + // 目录安全写入 + 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); + } + } +} \ No newline at end of file diff --git a/Common/common.php b/ThinkPHP/Common/common.php similarity index 39% rename from Common/common.php rename to ThinkPHP/Common/common.php index d09a53ea26e3338b8b2f13e72202cd98d8f6a45f..c7ba90e2e869ed4ba3fb080bb8001f0b6a1165f8 100644 --- a/Common/common.php +++ b/ThinkPHP/Common/common.php @@ -1,536 +1,691 @@ - -// +---------------------------------------------------------------------- -// $Id: common.php 3084 2012-07-27 04:17:58Z liu21st@gmail.com $ - -/** - +------------------------------------------------------------------------------ - * Think 基础函数库 - +------------------------------------------------------------------------------ - * @category Think - * @package Common - * @author liu21st - * @version $Id: common.php 3084 2012-07-27 04:17:58Z liu21st@gmail.com $ - +------------------------------------------------------------------------------ - */ - -// 记录和统计时间(微秒) -function G($start,$end='',$dec=4) { - static $_info = array(); - if(is_float($end)) { // 记录时间 - $_info[$start] = $end; - }elseif(!empty($end)){ // 统计时间 - if(!isset($_info[$end])) $_info[$end] = microtime(TRUE); - return number_format(($_info[$end]-$_info[$start]),$dec); - }else{ // 记录时间 - $_info[$start] = microtime(TRUE); - } -} - -// 设置和获取统计数据 -function N($key, $step=0) { - static $_num = array(); - if (!isset($_num[$key])) { - $_num[$key] = 0; - } - if (empty($step)) - return $_num[$key]; - else - $_num[$key] = $_num[$key] + (int) $step; -} - -/** - +---------------------------------------------------------- - * 字符串命名风格转换 - * type - * =0 将Java风格转换为C的风格 - * =1 将C风格转换为Java的风格 - +---------------------------------------------------------- - * @access protected - +---------------------------------------------------------- - * @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 -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]; -} - -// 区分大小写的文件存在判断 -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 boolen - +---------------------------------------------------------- - */ -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)) { - if ('@' == $class_strut[0] || APP_NAME == $class_strut[0]) { - //加载当前项目应用类库 - $baseUrl = dirname(LIB_PATH); - $class = substr_replace($class, basename(LIB_PATH).'/', 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(LIB_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 = COMMON_PATH; - $name = substr($name, 2); - } else { - //加载ThinkPHP 系统函数库 - $baseUrl = EXTEND_PATH . 'Function/'; - } - } - if (substr($baseUrl, -1) != '/') - $baseUrl .= '/'; - require_cache($baseUrl . $name . $ext); -} - -// 快速导入第三方框架类库 -// 所有第三方框架的类库文件统一放到 系统的Vendor目录下面 -// 并且默认都是以.php后缀导入 -function vendor($class, $baseUrl = '', $ext='.php') { - if (empty($baseUrl)) - $baseUrl = VENDOR_PATH; - return import($class, $baseUrl, $ext); -} - -// 快速定义和导入别名 -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,'://')) {// 指定项目 - $name = str_replace('://','/'.$layer.'/',$name); - }else{ - $name = C('DEFAULT_APP').'/'.$layer.'/'.$name; - } - if(isset($_model[$name])) return $_model[$name]; - import($name.$layer); - $class = basename($name.$layer); - if(class_exists($class)) { - $model = new $class(); - }else { - $model = new Model(basename($name)); - } - $_model[$name] = $model; - return $model; -} - -/** - +---------------------------------------------------------- - * M函数用于实例化一个没有模型文件的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 控制层名称 - +---------------------------------------------------------- - * @return Action - +---------------------------------------------------------- - */ -function A($name,$layer='') { - static $_action = array(); - $layer = $layer?$layer:C('DEFAULT_C_LAYER'); - if(strpos($name,'://')) {// 指定项目 - $name = str_replace('://','/'.$layer.'/',$name); - }else{ - $name = '@/'.$layer.'/'.$name; - } - if(isset($_action[$name])) return $_action[$name]; - import($name.$layer); - $class = basename($name.$layer); - if(class_exists($class,false)) { - $action = new $class(); - $_action[$name] = $action; - return $action; - }else { - return false; - } -} - -// 远程调用模块的操作方法 -// URL 参数格式 [项目://][分组/]模块/操作 -function R($url,$vars=array(),$layer='') { - $info = pathinfo($url); - $action = $info['basename']; - $module = $info['dirname']; - $class = A($module,$layer); - if($class) - return call_user_func_array(array(&$class,$action),$vars); - else - return false; -} - -// 获取和设置语言定义(不区分大小写) -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; -} - -// 获取配置值 -function C($name=null, $value=null) { - static $_config = array(); - // 无参数时获取所有 - if (empty($name)) { - if(!empty($value) && $array = cache('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)) {// 保存配置值 - cache('c_'.$value,$_config); - } - return; - } - return null; // 避免非法参数 -} - -// 处理标签扩展 -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; - } -} - -// 动态添加行为扩展到某个标签 -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); -} - -// 过滤器方法 -function filter($name, &$content) { - $class = $name . 'Filter'; - require_cache(LIB_PATH . 'Filter/' . $class . '.class.php'); - $filter = new $class(); - $content = $filter->run($content); -} - -// 执行行为 -function B($name, &$params=NULL) { - $class = $name.'Behavior'; - G('behaviorStart'); - $behavior = new $class(); - $behavior->run($params); - if(APP_DEBUG) { // 记录行为的执行日志 - trace('Run '.$name.' Behavior [ RunTime:'.G('behaviorStart','behaviorEnd',6).'s ]','','INFO'); - } -} - -// 渲染输出Widget -function W($name, $data=array(), $return=false) { - $class = $name . 'Widget'; - require_cache(LIB_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; -} - -// 去除代码中的空白和注释 -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记录 -function trace($value='[think]',$label='',$level='DEBUG') { - static $_trace = array(); - if('[think]' === $value){ // 获取trace信息 - return $_trace; - }else{ - $info = ($label?$label.':':'').print_r($value,true); - if((defined('IS_AJAX') && IS_AJAX) || !C('SHOW_PAGE_TRACE')) { - Log::record($info,$level); - }else{ - if(!isset($_trace[$level])) { - $_trace[$level] = array(); - } - $_trace[$level][] = $info; - } - } + +// +---------------------------------------------------------------------- + +/** + * Think 基础函数库 + * @category Think + * @package Common + * @author liu21st + */ + +/** + * 抛出异常处理 + * @param string $msg 异常消息 + * @param integer $code 异常代码 默认为0 + * @return void + */ +function E($msg, $code=0) { + throw new Think\Exception($msg, $code); +} + +/** + * 获取模版文件 格式 资源://模块@主题/控制器/操作 + * @param string $name 模版资源地址 + * @param string $layer 视图层(目录)名称 + * @return string + */ +function T($template='',$layer=''){ + if(is_file($template)) { + return $template; + } + // 解析模版资源地址 + 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.'/'; + }else{ // 分组模式 + $baseUrl = APP_PATH.$module.$layer.'/'; + } + // 获取主题 + $array = explode('/',$file); + if(count($array)>2){ + $theme = array_shift($array); + }else{ + $theme = C('DEFAULT_THEME'); + } + // 分析模板文件规则 + if('' == $file) { + // 如果模板文件名为空 按照默认规则定位 + $file = CONTROLLER_NAME . C('TMPL_FILE_DEPR') . ACTION_NAME; + }elseif(false === strpos($file, '/')){ + $file = CONTROLLER_NAME . C('TMPL_FILE_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; + } + 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_callback('/_([a-zA-Z])/', function($match){return strtoupper($match[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 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); + }if (in_array(strtolower($class_strut[0]), array('think','org', 'com'))) { + // org 第三方公共类库 com 企业公共类库 + $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 = COMMON_PATH.'Common/'; + $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); +} + +/** + * D函数用于实例化Model 格式 目录://模块/模型 + * @param string $name Model资源地址 + * @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)); + }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 = $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函数用于实例化Action 格式:[资源://][模块/]控制器 + * @param string $name 资源地址 + * @param string $layer 控制层名称 + * @param integer $level 控制器层次 + * @return Action|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|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 $name) { + 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 .= "<< -// +---------------------------------------------------------------------- -// $Id$ - -/** - +------------------------------------------------------------------------------ - * Think 标准模式公共函数库 - +------------------------------------------------------------------------------ - * @category Think - * @package Common - * @author liu21st - * @version $Id$ - +------------------------------------------------------------------------------ - */ - -// 错误输出 -function halt($error) { - $e = array(); - if (APP_DEBUG) { - //调试模式下输出错误信息 - if (!is_array($error)) { - $trace = debug_backtrace(); - $e['message'] = $error; - $e['file'] = $trace[0]['file']; - $e['class'] = isset($trace[0]['class'])?$trace[0]['class']:''; - $e['function'] = isset($trace[0]['function'])?$trace[0]['function']:''; - $e['line'] = $trace[0]['line']; - $traceInfo = ''; - $time = date('y-m-d H:i:m'); - foreach ($trace as $t) { - $traceInfo .= '[' . $time . '] ' . $t['file'] . ' (' . $t['line'] . ') '; - $traceInfo .= $t['class'] . $t['type'] . $t['function'] . '('; - $traceInfo .= implode(', ', $t['args']); - $traceInfo .=')
'; - } - $e['trace'] = $traceInfo; - } else { - $e = $error; - } - } 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'); - } - } - // 包含异常页面模板 - include C('TMPL_EXCEPTION_FILE'); - exit; -} - -// 自定义异常处理 -function throw_exception($msg, $type='ThinkException', $code=0) { - if (class_exists($type, false)) - throw new $type($msg, $code, true); - else - halt($msg); // 异常类型不存在则输出错误信息字串 -} - -// 浏览器友好的变量输出 -function dump($var, $echo=true, $label=null, $strict=true) { - $label = ($label === null) ? '' : rtrim($label) . ' '; - if (!$strict) { - if (ini_get('html_errors')) { - $output = print_r($var, true); - $output = '
' . $label . htmlspecialchars($output, ENT_QUOTES) . '
'; - } else { - $output = $label . print_r($var, true); - } - } else { - ob_start(); - var_dump($var); - $output = ob_get_clean(); - if (!extension_loaded('xdebug')) { - $output = preg_replace("/\]\=\>\n(\s+)/m", '] => ', $output); - $output = '
' . $label . htmlspecialchars($output, ENT_QUOTES) . '
'; - } - } - if ($echo) { - echo($output); - return null; - }else - return $output; -} - -// 404 处理 -function _404($msg='',$url='') { - APP_DEBUG && throw_exception($msg); - if($msg && C('LOG_EXCEPTION_RECORD')) Log::write($msg); - if(empty($url) && C('URL_404_REDIRECT')) { - $url = C('URL_404_REDIRECT'); - } - if($url) { - redirect($url); - }else{ - send_http_status(404); - exit; - } -} - - // 区间调试开始 -function debug_start($label='') { - $GLOBALS[$label]['_beginTime'] = microtime(TRUE); - if (MEMORY_LIMIT_ON) - $GLOBALS[$label]['_beginMem'] = memory_get_usage(); -} - -// 区间调试结束,显示指定标记到当前位置的调试 -function debug_end($label='') { - $GLOBALS[$label]['_endTime'] = microtime(TRUE); - echo '
Process ' . $label . ': Times ' . number_format($GLOBALS[$label]['_endTime'] - $GLOBALS[$label]['_beginTime'], 6) . 's '; - if (MEMORY_LIMIT_ON) { - $GLOBALS[$label]['_endMem'] = memory_get_usage(); - echo ' Memories ' . number_format(($GLOBALS[$label]['_endMem'] - $GLOBALS[$label]['_beginMem']) / 1024) . ' k'; - } - echo '
'; -} - -// 设置当前页面的布局 -function layout($layout) { - if(false !== $layout) { - // 开启布局 - C('LAYOUT_ON',true); - if(is_string($layout)) { // 设置新的布局模板 - C('LAYOUT_NAME',$layout); - } - }else{// 临时关闭布局 - C('LAYOUT_ON',false); - } -} - -// URL组装 支持不同模式 -// 格式:U('[分组/模块/操作@域名]?参数','参数','伪静态后缀','是否跳转','显示域名') -function U($url='',$vars='',$suffix=true,$redirect=false,$domain=false) { - // 解析URL - $info = parse_url($url); - $url = !empty($info['path'])?$info['path']:ACTION_NAME; - if(false !== strpos($url,'@')) { // 解析域名 - list($url,$host) = explode('@',$info['path'], 2); - } - // 解析子域名 - if(isset($host)) { - $domain = $host.(strpos($host,'.')?'':strstr($_SERVER['HTTP_HOST'],'.')); - }elseif($domain===true){ - $domain = $_SERVER['HTTP_HOST']; - if(C('APP_SUB_DOMAIN_DEPLOY') ) { // 开启子域名部署 - $domain = $domain=='localhost'?'localhost':'www'.strstr($_SERVER['HTTP_HOST'],'.'); - // '子域名'=>array('项目[/分组]'); - foreach (C('APP_SUB_DOMAIN_RULES') as $key => $rule) { - if(false === strpos($key,'*') && 0=== strpos($url,$rule[0])) { - $domain = $key.strstr($domain,'.'); // 生成对应子域名 - $url = substr_replace($url,'',0,strlen($rule[0])); - break; - } - } - } - } - - // 解析参数 - if(is_string($vars)) { // aaa=1&bbb=2 转换成数组 - parse_str($vars,$vars); - }elseif(!is_array($vars)){ - $vars = array(); - } - if(isset($info['query'])) { // 解析地址里面参数 合并到vars - parse_str($info['query'],$params); - $vars = array_merge($params,$vars); - } - - // URL组装 - $depr = C('URL_PATHINFO_DEPR'); - if($url) { - if(0=== strpos($url,'/')) {// 定义路由 - $route = true; - $url = substr($url,1); - if('/' != $depr) { - $url = str_replace('/',$depr,$url); - } - }else{ - 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; - if(C('URL_CASE_INSENSITIVE')) { - $var[C('VAR_MODULE')] = parse_name($var[C('VAR_MODULE')]); - } - if(!C('APP_SUB_DOMAIN_DEPLOY') && C('APP_GROUP_LIST')) { - if(!empty($path)) { - $group = array_pop($path); - $var[C('VAR_GROUP')] = $group; - }else{ - if(GROUP_NAME != C('DEFAULT_GROUP')) { - $var[C('VAR_GROUP')] = GROUP_NAME; - } - } - if(C('URL_CASE_INSENSITIVE') && isset($var[C('VAR_GROUP')])) { - $var[C('VAR_GROUP')] = strtolower($var[C('VAR_GROUP')]); - } - } - } - } - - if(C('URL_MODEL') == 0) { // 普通模式URL转换 - $url = __APP__.'?'.http_build_query(array_reverse($var)); - if(!empty($vars)) { - $vars = urldecode(http_build_query($vars)); - $url .= '&'.$vars; - } - }else{ // PATHINFO模式或者兼容URL模式 - if(isset($route)) { - $url = __APP__.'/'.rtrim($url,$depr); - }else{ - $url = __APP__.'/'.implode($depr,array_reverse($var)); - } - if(!empty($vars)) { // 添加参数 - foreach ($vars as $var => $val) - $url .= $depr.$var . $depr . $val; - } - if($suffix) { - $suffix = $suffix===true?C('URL_HTML_SUFFIX'):$suffix; - if($pos = strpos($suffix, '|')){ - $suffix = substr($suffix, 0, $pos); - } - if($suffix && $url[1]){ - $url .= '.'.ltrim($suffix,'.'); - } - } - } - if($domain) { - $url = (is_ssl()?'https://':'http://').$domain.$url; - } - if($redirect) // 直接跳转URL - redirect($url); - else - return $url; -} - -// 判断是否SSL协议 -function is_ssl() { - if(isset($_SERVER['HTTPS']) && ('1' == $_SERVER['HTTPS'] || 'on' == strtolower($_SERVER['HTTPS']))){ - return true; - }elseif(isset($_SERVER['SERVER_PORT']) && ('443' == $_SERVER['SERVER_PORT'] )) { - return true; - } - return false; -} - -// URL重定向 -function redirect($url, $time=0, $msg='') { - //多行URL地址支持 - $url = str_replace(array("\n", "\r"), '', $url); - if (empty($msg)) - $msg = "系统将在{$time}秒之后自动跳转到{$url}!"; - if (!headers_sent()) { - // redirect - if (0 === $time) { - header('Location: ' . $url); - } else { - header("refresh:{$time};url={$url}"); - echo($msg); - } - exit(); - } else { - $str = ""; - if ($time != 0) - $str .= $msg; - exit($str); - } -} - -// 缓存管理函数 -function cache($name,$value='',$expire=0) { - static $cache = ''; - if(is_array($name)) { // 缓存初始化 - $type = isset($name['type'])?$name['type']:C('DATA_CACHE_TYPE'); - unset($name['type']); - $cache = Cache::getInstance($type,$name); - return $cache; - } - if(empty($cache)) { // 自动初始化 - $cache = Cache::getInstance(); - } - if(''=== $value){ // 获取缓存值 - // 获取缓存数据 - return $cache->get($name); - }elseif(is_null($value)) { // 删除缓存 - return $cache->rm($name); - }else { // 缓存数据 - return $cache->set($name, $value, $expire); - } -} - -// 全局缓存设置和读取 -function S($name, $value='', $expire=null, $type='',$options=null) { - static $_cache = array(); - //取得缓存对象实例 - $cache = Cache::getInstance($type,$options); - if ('' !== $value) { - if (is_null($value)) { - // 删除缓存 - $result = $cache->rm($name); - if ($result) - unset($_cache[$type . '_' . $name]); - return $result; - }else { - // 缓存数据 - $cache->set($name, $value, $expire); - $_cache[$type . '_' . $name] = $value; - } - return; - } - if (isset($_cache[$type . '_' . $name])) - return $_cache[$type . '_' . $name]; - // 获取缓存数据 - $value = $cache->get($name); - $_cache[$type . '_' . $name] = $value; - return $value; -} - -// 快速文件数据读取和保存 针对简单类型数据 字符串、数组 -function F($name, $value='', $path=DATA_PATH) { - static $_cache = array(); - $filename = $path . $name . '.php'; - if ('' !== $value) { - if (is_null($value)) { - // 删除缓存 - return unlink($filename); - } else { - // 缓存数据 - $dir = dirname($filename); - // 目录不存在则创建 - if (!is_dir($dir)) - mkdir($dir); - $_cache[$name] = $value; - return file_put_contents($filename, json_encode($value)); - } - } - if (isset($_cache[$name])) - return $_cache[$name]; - // 获取缓存数据 - if (is_file($filename)) { - $value = json_decode(file_get_contents($filename),true); - $_cache[$name] = $value; - } else { - $value = false; - } - return $value; -} - -// 取得对象实例 支持调用类的静态方法 -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各种类型变量生成唯一标识号 -function to_guid_string($mix) { - if (is_object($mix) && function_exists('spl_object_hash')) { - return spl_object_hash($mix); - } elseif (is_resource($mix)) { - $mix = get_resource_type($mix) . strval($mix); - } else { - $mix = serialize($mix); - } - return md5($mix); -} - -// xml编码 -function xml_encode($data, $encoding='utf-8', $root='think') { - $xml = ''; - $xml.= '<' . $root . '>'; - $xml.= data_to_xml($data); - $xml.= ''; - return $xml; -} - -function data_to_xml($data) { - $xml = ''; - foreach ($data as $key => $val) { - is_numeric($key) && $key = "item id=\"$key\""; - $xml.="<$key>"; - $xml.= ( is_array($val) || is_object($val)) ? data_to_xml($val) : $val; - list($key, ) = explode(' ', $key); - $xml.=""; - } - return $xml; -} - -// session管理函数 -function session($name,$value='') { - $prefix = C('SESSION_PREFIX'); - if(is_array($name)) { // session初始化 在session_start 之前调用 - if(isset($name['prefix'])) C('SESSION_PREFIX',$name['prefix']); - if(C('VAR_SESSION_ID') && isset($_REQUEST[C('VAR_SESSION_ID')])){ - session_id($_REQUEST[C('VAR_SESSION_ID')]); - }elseif(isset($name['id'])) { - session_id($name['id']); - } - ini_set('session.auto_start', 0); - if(isset($name['name'])) session_name($name['name']); - if(isset($name['path'])) session_save_path($name['path']); - if(isset($name['domain'])) ini_set('session.cookie_domain', $name['domain']); - if(isset($name['expire'])) ini_set('session.gc_maxlifetime', $name['expire']); - if(isset($name['use_trans_sid'])) ini_set('session.use_trans_sid', $name['use_trans_sid']?1:0); - if(isset($name['use_cookies'])) ini_set('session.use_cookies', $name['use_cookies']?1:0); - if(isset($name['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); - } - } - // 启动session - if(C('SESSION_AUTO_START')) session_start(); - }elseif('' === $value){ - if(0===strpos($name,'[')) { // session 操作 - if('[pause]'==$name){ // 暂停session - session_write_close(); - }elseif('[start]'==$name){ // 启动session - session_start(); - }elseif('[destroy]'==$name){ // 销毁session - $_SESSION = array(); - session_unset(); - session_destroy(); - }elseif('[regenerate]'==$name){ // 重新生成id - session_regenerate_id(); - } - }elseif(0===strpos($name,'?')){ // 检查session - $name = substr($name,1); - if($prefix) { - return isset($_SESSION[$prefix][$name]); - }else{ - return isset($_SESSION[$name]); - } - }elseif(is_null($name)){ // 清空session - if($prefix) { - unset($_SESSION[$prefix]); - }else{ - $_SESSION = array(); - } - }elseif($prefix){ // 获取session - return isset($_SESSION[$prefix][$name])?$_SESSION[$prefix][$name]:null; - }else{ - return isset($_SESSION[$name])?$_SESSION[$name]:null; - } - }elseif(is_null($value)){ // 删除session - if($prefix){ - unset($_SESSION[$prefix][$name]); - }else{ - unset($_SESSION[$name]); - } - }else{ // 设置session - if($prefix){ - if (!is_array($_SESSION[$prefix])) { - $_SESSION[$prefix] = array(); - } - $_SESSION[$prefix][$name] = $value; - }else{ - $_SESSION[$name] = $value; - } - } -} - -// Cookie 设置、获取、删除 -function cookie($name, $value='', $option=null) { - // 默认设置 - $config = array( - 'prefix' => C('COOKIE_PREFIX'), // cookie 名称前缀 - 'expire' => C('COOKIE_EXPIRE'), // cookie 保存时间 - 'path' => C('COOKIE_PATH'), // cookie 保存路径 - 'domain' => C('COOKIE_DOMAIN'), // cookie 有效域名 - ); - // 参数设置(会覆盖黙认设置) - if (!empty($option)) { - if (is_numeric($option)) - $option = array('expire' => $option); - elseif (is_string($option)) - parse_str($option, $option); - $config = array_merge($config, array_change_key_case($option)); - } - // 清除指定前缀的所有cookie - if (is_null($name)) { - if (empty($_COOKIE)) - return; - // 要删除的cookie前缀,不指定则删除config设置的指定前缀 - $prefix = empty($value) ? $config['prefix'] : $value; - if (!empty($prefix)) {// 如果前缀为空字符串将不作处理直接返回 - foreach ($_COOKIE as $key => $val) { - if (0 === stripos($key, $prefix)) { - setcookie($key, '', time() - 3600, $config['path'], $config['domain']); - unset($_COOKIE[$key]); - } - } - } - return; - } - $name = $config['prefix'] . $name; - if ('' === $value) { - return isset($_COOKIE[$name]) ? json_decode($_COOKIE[$name]) : null; // 获取指定Cookie - } else { - if (is_null($value)) { - setcookie($name, '', time() - 3600, $config['path'], $config['domain']); - unset($_COOKIE[$name]); // 删除指定cookie - } else { - // 设置cookie - $value = json_encode($value); - $expire = !empty($config['expire']) ? time() + intval($config['expire']) : 0; - setcookie($name, $value, $expire, $config['path'], $config['domain']); - $_COOKIE[$name] = $value; - } - } -} - -// 加载扩展配置文件 -function load_ext_file() { - // 加载自定义外部文件 - if(C('LOAD_EXT_FILE')) { - $files = explode(',',C('LOAD_EXT_FILE')); - foreach ($files as $file){ - $file = COMMON_PATH.$file.'.php'; - if(is_file($file)) include $file; - } - } - // 加载自定义的动态配置文件 - if(C('LOAD_EXT_CONFIG')) { - $configs = C('LOAD_EXT_CONFIG'); - if(is_string($configs)) $configs = explode(',',$configs); - foreach ($configs as $key=>$config){ - $file = CONF_PATH.$config.'.php'; - if(is_file($file)) { - is_numeric($key)?C(include $file):C($key,include $file); - } - } - } -} - -// 获取客户端IP地址 -function get_client_ip($type = 0) { - $type = $type ? 1 : 0; - static $ip = NULL; - if ($ip !== NULL) return $ip[$type]; - if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) { - $arr = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']); - $pos = array_search('unknown',$arr); - if(false !== $pos) unset($arr[$pos]); - $ip = trim($arr[0]); - }elseif (isset($_SERVER['HTTP_CLIENT_IP'])) { - $ip = $_SERVER['HTTP_CLIENT_IP']; - }elseif (isset($_SERVER['REMOTE_ADDR'])) { - $ip = $_SERVER['REMOTE_ADDR']; - } - // IP地址合法验证 - $long = ip2long($ip); - $ip = $long ? array($ip, $long) : array('0.0.0.0', 0); - return $ip[$type]; -} - -function send_http_status($code) { - static $_status = array( - // Success 2xx - 200 => 'OK', - // Redirection 3xx - 301 => 'Moved Permanently', - 302 => 'Moved Temporarily ', // 1.1 - // Client Error 4xx - 400 => 'Bad Request', - 403 => 'Forbidden', - 404 => 'Not Found', - // Server Error 5xx - 500 => 'Internal Server Error', - 503 => 'Service Unavailable', - ); - if(isset($_status[$code])) { - header('HTTP/1.1 '.$code.' '.$_status[$code]); - // 确保FastCGI模式下正常 - header('Status:'.$code.' '.$_status[$code]); - } -} \ No newline at end of file + +// +---------------------------------------------------------------------- + +/** + * Think 标准模式公共函数库 + * @category Think + * @package Common + * @author liu21st + */ + +/** + * 自定义异常处理 + * @param string $msg 异常消息 + * @param string $type 异常类型 默认为Think\Exception + * @param integer $code 异常代码 默认为0 + * @return void + */ +function throw_exception($msg, $type='Think\\Exception', $code=0) { + Think\Log::record('建议使用E方法替代throw_exception',Think\Log::NOTICE); + if (class_exists($type, false)) + throw new $type($msg, $code); + else + Think\Think::halt($msg); // 异常类型不存在则输出错误信息字串 +} + +/** + * 浏览器友好的变量输出 + * @param mixed $var 变量 + * @param boolean $echo 是否输出 默认为True 如果为false 则返回输出字符串 + * @param string $label 标签 默认为空 + * @param boolean $strict 是否严谨 默认为true + * @return void|string + */ +function dump($var, $echo=true, $label=null, $strict=true) { + $label = ($label === null) ? '' : rtrim($label) . ' '; + if (!$strict) { + if (ini_get('html_errors')) { + $output = print_r($var, true); + $output = '
' . $label . htmlspecialchars($output, ENT_QUOTES) . '
'; + } else { + $output = $label . print_r($var, true); + } + } else { + ob_start(); + var_dump($var); + $output = ob_get_clean(); + if (!extension_loaded('xdebug')) { + $output = preg_replace('/\]\=\>\n(\s+)/m', '] => ', $output); + $output = '
' . $label . htmlspecialchars($output, ENT_QUOTES) . '
'; + } + } + if ($echo) { + echo($output); + return null; + }else + return $output; +} + +/** + * 设置当前页面的布局 + * @param string|false $layout 布局名称 为false的时候表示关闭布局 + * @return void + */ +function layout($layout) { + if(false !== $layout) { + // 开启布局 + C('LAYOUT_ON',true); + if(is_string($layout)) { // 设置新的布局模板 + C('LAYOUT_NAME',$layout); + } + }else{// 临时关闭布局 + C('LAYOUT_ON',false); + } +} + +/** + * URL组装 支持不同URL模式 + * @param string $url URL表达式,格式:'[模块/控制器/操作#锚点@域名]?参数1=值1&参数2=值2...' + * @param string|array $vars 传入的参数,支持数组和字符串 + * @param string $suffix 伪静态后缀,默认为true表示获取配置值 + * @param boolean $redirect 是否跳转,如果设置为true则表示跳转到该URL地址 + * @param boolean $domain 是否显示域名 + * @return string + */ +function U($url='',$vars='',$suffix=true,$redirect=false,$domain=false) { + // 解析URL + $info = parse_url($url); + $url = !empty($info['path'])?$info['path']:ACTION_NAME; + if(isset($info['fragment'])) { // 解析锚点 + $anchor = $info['fragment']; + if(false !== strpos($anchor,'?')) { // 解析参数 + list($anchor,$info['query']) = explode('?',$anchor,2); + } + if(false !== strpos($anchor,'@')) { // 解析域名 + list($anchor,$host) = explode('@',$anchor, 2); + } + }elseif(false !== strpos($url,'@')) { // 解析域名 + list($url,$host) = explode('@',$info['path'], 2); + } + // 解析子域名 + if(isset($host)) { + $domain = $host.(strpos($host,'.')?'':strstr($_SERVER['HTTP_HOST'],'.')); + }elseif($domain===true){ + $domain = $_SERVER['HTTP_HOST']; + if(C('APP_SUB_DOMAIN_DEPLOY') ) { // 开启子域名部署 + $domain = $domain=='localhost'?'localhost':'www'.strstr($_SERVER['HTTP_HOST'],'.'); + // '子域名'=>array('项目[/分组]'); + foreach (C('APP_SUB_DOMAIN_RULES') as $key => $rule) { + if(false === strpos($key,'*') && 0=== strpos($url,$rule[0])) { + $domain = $key.strstr($domain,'.'); // 生成对应子域名 + $url = substr_replace($url,'',0,strlen($rule[0])); + break; + } + } + } + } + + // 解析参数 + if(is_string($vars)) { // aaa=1&bbb=2 转换成数组 + parse_str($vars,$vars); + }elseif(!is_array($vars)){ + $vars = array(); + } + if(isset($info['query'])) { // 解析地址里面参数 合并到vars + parse_str($info['query'],$params); + $vars = array_merge($params,$vars); + } + + // URL组装 + $depr = C('URL_PATHINFO_DEPR'); + if($url) { + if(0=== strpos($url,'/')) {// 定义路由 + $route = true; + $url = substr($url,1); + if('/' != $depr) { + $url = str_replace('/',$depr,$url); + } + }else{ + 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; + if(C('URL_CASE_INSENSITIVE')) { + $var[C('VAR_ACTION')] = strtolower($var[C('VAR_ACTION')]); + } + $var[C('VAR_CONTROLLER')] = !empty($path)?array_pop($path):CONTROLLER_NAME; + if($maps = C('URL_ACTION_MAP')) { + 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_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_CONTROLLER')] = parse_name($var[C('VAR_CONTROLLER')]); + } + $module = ''; + if(!defined('BIND_MODULE')) { + if(!empty($path)) { + $var[C('VAR_MODULE')] = array_pop($path); + }else{ + if(C('MULTI_MODULE')) { + $var[C('VAR_MODULE')]= MODULE_NAME; + } + } + if($maps = C('URL_MODULE_MAP')) { + if($_module = array_search(strtolower($var[C('VAR_MODULE')]),$maps)){ + $var[C('VAR_MODULE')] = $_module; + } + } + if(C('URL_CASE_INSENSITIVE') && isset($var[C('VAR_MODULE')])) { + $var[C('VAR_MODULE')] = strtolower($var[C('VAR_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__.'/'.$module.'?'.http_build_query(array_reverse($var)); + if(!empty($vars)) { + $vars = urldecode(http_build_query($vars)); + $url .= '&'.$vars; + } + }else{ // PATHINFO模式或者兼容URL模式 + if(isset($route)) { + $url = __APP__.'/'.($module?$module.MODULE_PATHINFO_DEPR:'').rtrim($url,$depr); + }else{ + $url = __APP__.'/'.($module?$module.MODULE_PATHINFO_DEPR:'').implode($depr,array_reverse($var)); + } + if(!empty($vars)) { // 添加参数 + foreach ($vars as $var => $val){ + if('' !== trim($val)) $url .= $depr . $var . $depr . urlencode($val); + } + } + if($suffix) { + $suffix = $suffix===true?C('URL_HTML_SUFFIX'):$suffix; + if($pos = strpos($suffix, '|')){ + $suffix = substr($suffix, 0, $pos); + } + if($suffix && '/' != substr($url,-1)){ + $url .= '.'.ltrim($suffix,'.'); + } + } + } + if(isset($anchor)){ + $url .= '#'.$anchor; + } + if($domain) { + $url = (is_ssl()?'https://':'http://').$domain.$url; + } + if($redirect) // 直接跳转URL + redirect($url); + else + return $url; +} + +/** + * 渲染输出Widget + * @param string $name Widget名称 + * @param array $data 传入的参数 + * @return void + */ +function W($name, $data=array()) { + return R($name,$data,'Widget'); +} + +/** + * 判断是否SSL协议 + * @return boolean + */ +function is_ssl() { + if(isset($_SERVER['HTTPS']) && ('1' == $_SERVER['HTTPS'] || 'on' == strtolower($_SERVER['HTTPS']))){ + return true; + }elseif(isset($_SERVER['SERVER_PORT']) && ('443' == $_SERVER['SERVER_PORT'] )) { + return true; + } + return false; +} + +/** + * URL重定向 + * @param string $url 重定向的URL地址 + * @param integer $time 重定向的等待时间(秒) + * @param string $msg 重定向前的提示信息 + * @return void + */ +function redirect($url, $time=0, $msg='') { + //多行URL地址支持 + $url = str_replace(array("\n", "\r"), '', $url); + if (empty($msg)) + $msg = "系统将在{$time}秒之后自动跳转到{$url}!"; + if (!headers_sent()) { + // redirect + if (0 === $time) { + header('Location: ' . $url); + } else { + header("refresh:{$time};url={$url}"); + echo($msg); + } + exit(); + } else { + $str = ""; + if ($time != 0) + $str .= $msg; + exit($str); + } +} + +/** + * 缓存管理 + * @param mixed $name 缓存名称,如果为数组表示进行缓存设置 + * @param mixed $value 缓存值 + * @param mixed $options 缓存参数 + * @return mixed + */ +function S($name,$value='',$options=null) { + static $cache = ''; + if(is_array($options) && empty($cache)){ + // 缓存操作的同时初始化 + $type = isset($options['type'])?$options['type']:''; + $cache = Think\Cache::getInstance($type,$options); + }elseif(is_array($name)) { // 缓存初始化 + $type = isset($name['type'])?$name['type']:''; + $cache = Think\Cache::getInstance($type,$name); + return $cache; + }elseif(empty($cache)) { // 自动初始化 + $cache = Think\Cache::getInstance(); + } + if(''=== $value){ // 获取缓存 + return $cache->get($name); + }elseif(is_null($value)) { // 删除缓存 + return $cache->rm($name); + }else { // 缓存数据 + if(is_array($options)) { + $expire = isset($options['expire'])?$options['expire']:NULL; + }else{ + $expire = is_numeric($options)?$options:NULL; + } + return $cache->set($name, $value, $expire); + } +} + +/** + * 快速文件数据读取和保存 针对简单类型数据 字符串、数组 + * @param string $name 缓存名称 + * @param mixed $value 缓存值 + * @param string $path 缓存路径 + * @return mixed + */ +function F($name, $value='', $path=DATA_PATH) { + static $_cache = array(); + $filename = $path . $name . '.php'; + if ('' !== $value) { + if (is_null($value)) { + // 删除缓存 + if(false !== strpos($name,'*')){ + return false; // TODO + }else{ + return Think\Storage::unlink($filename,'F'); + } + } else { + Think\Storage::put($filename,serialize($value),'F'); + // 缓存数据 + $_cache[$name] = $value; + return ; + } + } + // 获取缓存数据 + if (isset($_cache[$name])) + return $_cache[$name]; + if (Think\Storage::has($filename,'F')){ + $value = unserialize(Think\Storage::read($filename,'F')); + $_cache[$name] = $value; + } else { + $value = false; + } + return $value; +} + +/** + * 根据PHP各种类型变量生成唯一标识号 + * @param mixed $mix 变量 + * @return string + */ +function to_guid_string($mix) { + if (is_object($mix)) { + return spl_object_hash($mix); + } elseif (is_resource($mix)) { + $mix = get_resource_type($mix) . strval($mix); + } else { + $mix = serialize($mix); + } + return md5($mix); +} + +/** + * XML编码 + * @param mixed $data 数据 + * @param string $root 根节点名 + * @param string $item 数字索引的子节点名 + * @param string $attr 根节点属性 + * @param string $id 数字索引子节点key转换的属性名 + * @param string $encoding 数据编码 + * @return string + */ +function xml_encode($data, $root='think', $item='item', $attr='', $id='id', $encoding='utf-8') { + if(is_array($attr)){ + $_attr = array(); + foreach ($attr as $key => $value) { + $_attr[] = "{$key}=\"{$value}\""; + } + $attr = implode(' ', $_attr); + } + $attr = trim($attr); + $attr = empty($attr) ? '' : " {$attr}"; + $xml = ""; + $xml .= "<{$root}{$attr}>"; + $xml .= data_to_xml($data, $item, $id); + $xml .= ""; + return $xml; +} + +/** + * 数据XML编码 + * @param mixed $data 数据 + * @param string $item 数字索引时的节点名称 + * @param string $id 数字索引key转换为的属性名 + * @return string + */ +function data_to_xml($data, $item='item', $id='id') { + $xml = $attr = ''; + foreach ($data as $key => $val) { + if(is_numeric($key)){ + $id && $attr = " {$id}=\"{$key}\""; + $key = $item; + } + $xml .= "<{$key}{$attr}>"; + $xml .= (is_array($val) || is_object($val)) ? data_to_xml($val, $item, $id) : $val; + $xml .= ""; + } + return $xml; +} + +/** + * session管理函数 + * @param string|array $name session名称 如果为数组则表示进行session设置 + * @param mixed $value session值 + * @return mixed + */ +function session($name,$value='') { + $prefix = C('SESSION_PREFIX'); + if(is_array($name)) { // session初始化 在session_start 之前调用 + if(isset($name['prefix'])) C('SESSION_PREFIX',$name['prefix']); + if(C('VAR_SESSION_ID') && isset($_REQUEST[C('VAR_SESSION_ID')])){ + session_id($_REQUEST[C('VAR_SESSION_ID')]); + }elseif(isset($name['id'])) { + session_id($name['id']); + } + ini_set('session.auto_start', 0); + if(isset($name['name'])) session_name($name['name']); + if(isset($name['path'])) session_save_path($name['path']); + if(isset($name['domain'])) ini_set('session.cookie_domain', $name['domain']); + if(isset($name['expire'])) ini_set('session.gc_maxlifetime', $name['expire']); + if(isset($name['use_trans_sid'])) ini_set('session.use_trans_sid', $name['use_trans_sid']?1:0); + if(isset($name['use_cookies'])) ini_set('session.use_cookies', $name['use_cookies']?1:0); + if(isset($name['cache_limiter'])) session_cache_limiter($name['cache_limiter']); + if(isset($name['cache_expire'])) session_cache_expire($name['cache_expire']); + if(isset($name['type'])) C('SESSION_TYPE',$name['type']); + if(C('SESSION_TYPE')) { // 读取session驱动 + $class = 'Think\\Session\\Driver\\'. ucwords(strtolower(C('SESSION_TYPE'))); + $hander = new $class(); + $hander->execute(); + } + // 启动session + if(C('SESSION_AUTO_START')) session_start(); + }elseif('' === $value){ + if(0===strpos($name,'[')) { // session 操作 + if('[pause]'==$name){ // 暂停session + session_write_close(); + }elseif('[start]'==$name){ // 启动session + session_start(); + }elseif('[destroy]'==$name){ // 销毁session + $_SESSION = array(); + session_unset(); + session_destroy(); + }elseif('[regenerate]'==$name){ // 重新生成id + session_regenerate_id(); + } + }elseif(0===strpos($name,'?')){ // 检查session + $name = substr($name,1); + if(strpos($name,'.')){ // 支持数组 + list($name1,$name2) = explode('.',$name); + return $prefix?isset($_SESSION[$prefix][$name1][$name2]):isset($_SESSION[$name1][$name2]); + }else{ + return $prefix?isset($_SESSION[$prefix][$name]):isset($_SESSION[$name]); + } + }elseif(is_null($name)){ // 清空session + if($prefix) { + unset($_SESSION[$prefix]); + }else{ + $_SESSION = array(); + } + }elseif($prefix){ // 获取session + if(strpos($name,'.')){ + list($name1,$name2) = explode('.',$name); + return isset($_SESSION[$prefix][$name1][$name2])?$_SESSION[$prefix][$name1][$name2]:null; + }else{ + return isset($_SESSION[$prefix][$name])?$_SESSION[$prefix][$name]:null; + } + }else{ + if(strpos($name,'.')){ + list($name1,$name2) = explode('.',$name); + return isset($_SESSION[$name1][$name2])?$_SESSION[$name1][$name2]:null; + }else{ + return isset($_SESSION[$name])?$_SESSION[$name]:null; + } + } + }elseif(is_null($value)){ // 删除session + if($prefix){ + unset($_SESSION[$prefix][$name]); + }else{ + unset($_SESSION[$name]); + } + }else{ // 设置session + if($prefix){ + if (!is_array($_SESSION[$prefix])) { + $_SESSION[$prefix] = array(); + } + $_SESSION[$prefix][$name] = $value; + }else{ + $_SESSION[$name] = $value; + } + } +} + +/** + * Cookie 设置、获取、删除 + * @param string $name cookie名称 + * @param mixed $value cookie值 + * @param mixed $options cookie参数 + * @return mixed + */ +function cookie($name, $value='', $option=null) { + // 默认设置 + $config = array( + 'prefix' => C('COOKIE_PREFIX'), // cookie 名称前缀 + 'expire' => C('COOKIE_EXPIRE'), // cookie 保存时间 + 'path' => C('COOKIE_PATH'), // cookie 保存路径 + 'domain' => C('COOKIE_DOMAIN'), // cookie 有效域名 + ); + // 参数设置(会覆盖黙认设置) + if (!is_null($option)) { + if (is_numeric($option)) + $option = array('expire' => $option); + elseif (is_string($option)) + parse_str($option, $option); + $config = array_merge($config, array_change_key_case($option)); + } + // 清除指定前缀的所有cookie + if (is_null($name)) { + if (empty($_COOKIE)) + return; + // 要删除的cookie前缀,不指定则删除config设置的指定前缀 + $prefix = empty($value) ? $config['prefix'] : $value; + if (!empty($prefix)) {// 如果前缀为空字符串将不作处理直接返回 + foreach ($_COOKIE as $key => $val) { + if (0 === stripos($key, $prefix)) { + setcookie($key, '', time() - 3600, $config['path'], $config['domain']); + unset($_COOKIE[$key]); + } + } + } + return; + } + $name = $config['prefix'] . $name; + if ('' === $value) { + if(isset($_COOKIE[$name])){ + $value = $_COOKIE[$name]; + if(0===strpos($value,'think:')){ + $value = substr($value,6); + return array_map('urldecode',json_decode(MAGIC_QUOTES_GPC?stripslashes($value):$value,true)); + }else{ + return $value; + } + }else{ + return null; + } + } else { + if (is_null($value)) { + setcookie($name, '', time() - 3600, $config['path'], $config['domain']); + unset($_COOKIE[$name]); // 删除指定cookie + } else { + // 设置cookie + if(is_array($value)){ + $value = 'think:'.json_encode(array_map('urlencode',$value)); + } + $expire = !empty($config['expire']) ? time() + intval($config['expire']) : 0; + setcookie($name, $value, $expire, $config['path'], $config['domain']); + $_COOKIE[$name] = $value; + } + } +} + +/** + * 加载动态扩展文件 + * @return void + */ +function load_ext_file() { + // 加载自定义外部文件 + if(C('LOAD_EXT_FILE')) { + $files = explode(',',C('LOAD_EXT_FILE')); + foreach ($files as $file){ + $file = COMMON_PATH.'Common/'.$file.'.php'; + if(is_file($file)) include $file; + } + } + // 加载自定义的动态配置文件 + if(C('LOAD_EXT_CONFIG')) { + $configs = C('LOAD_EXT_CONFIG'); + if(is_string($configs)) $configs = explode(',',$configs); + foreach ($configs as $key=>$config){ + $file = COMMON_PATH.'Conf/'.$config.'.php'; + if(is_file($file)) { + is_numeric($key)?C(include $file):C($key,include $file); + } + } + } +} + +/** + * 获取客户端IP地址 + * @param integer $type 返回类型 0 返回IP地址 1 返回IPV4地址数字 + * @return mixed + */ +function get_client_ip($type = 0) { + $type = $type ? 1 : 0; + static $ip = NULL; + if ($ip !== NULL) return $ip[$type]; + if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) { + $arr = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']); + $pos = array_search('unknown',$arr); + if(false !== $pos) unset($arr[$pos]); + $ip = trim($arr[0]); + }elseif (isset($_SERVER['HTTP_CLIENT_IP'])) { + $ip = $_SERVER['HTTP_CLIENT_IP']; + }elseif (isset($_SERVER['REMOTE_ADDR'])) { + $ip = $_SERVER['REMOTE_ADDR']; + } + // IP地址合法验证 + $long = sprintf("%u",ip2long($ip)); + $ip = $long ? array($ip, $long) : array('0.0.0.0', 0); + return $ip[$type]; +} + +/** + * 发送HTTP状态 + * @param integer $code 状态码 + * @return void + */ +function send_http_status($code) { + static $_status = array( + // Success 2xx + 200 => 'OK', + // Redirection 3xx + 301 => 'Moved Permanently', + 302 => 'Moved Temporarily ', // 1.1 + // Client Error 4xx + 400 => 'Bad Request', + 403 => 'Forbidden', + 404 => 'Not Found', + // Server Error 5xx + 500 => 'Internal Server Error', + 503 => 'Service Unavailable', + ); + if(isset($_status[$code])) { + header('HTTP/1.1 '.$code.' '.$_status[$code]); + // 确保FastCGI模式下正常 + header('Status:'.$code.' '.$_status[$code]); + } +} + +// 过滤表单中的表达式 +function filter_exp(&$value){ + if (in_array(strtolower($value),array('exp','or'))){ + $value .= ' '; + } +} diff --git a/ThinkPHP/Conf/Mode/common.php b/ThinkPHP/Conf/Mode/common.php new file mode 100644 index 0000000000000000000000000000000000000000..1b6c374280625640526b8c2b4c753dfeb60c6d91 --- /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( + array( + 'Think\App' => CORE_PATH . 'App'.EXT, + '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, + 'Think\Action' => CORE_PATH . 'Action'.EXT, + 'Think\View' => CORE_PATH . 'View'.EXT, + ), + COMMON_PATH.'Conf/alias.php', + ), + + // 函数和类文件 + 'core' => array( + THINK_PATH.'Common/functions.php', + COMMON_PATH.'Common/function.php', + CORE_PATH . 'App'.EXT, + CORE_PATH . 'Action'.EXT, + CORE_PATH . 'View'.EXT + ), + // 行为扩展定义 + 'extends' => array( + 'app_init' => array( + ), + 'app_begin' => array( + 'Think\Behavior\ReadHtmlCache', // 读取静态缓存 + ), + 'app_end' => array( + 'Think\Behavior\ShowPageTrace', // 页面Trace显示 + ), + 'path_info' => array(), + 'action_begin' => array(), + 'action_end' => array(), + 'view_begin' => array(), + 'view_parse' => array( + 'Think\Behavior\ParseTemplate', // 模板解析 支持PHP、内置模板引擎和第三方模板引擎 + ), + 'template_filter'=> array( + 'Think\Behavior\ContentReplace', // 模板输出替换 + ), + 'view_filter' => array( + 'Think\Behavior\TokenBuild', // 表单令牌 + 'Think\Behavior\WriteHtmlCache', // 写入静态缓存 + ), + 'view_end' => array(), + ), + 'tags' => array( + COMMON_PATH.'Conf/tags.php', + ), +); \ No newline at end of file diff --git a/ThinkPHP/Conf/convention.php b/ThinkPHP/Conf/convention.php new file mode 100644 index 0000000000000000000000000000000000000000..0572c82f6e0aee87f016e33b09e250a28fee32bc --- /dev/null +++ b/ThinkPHP/Conf/convention.php @@ -0,0 +1,144 @@ + +// +---------------------------------------------------------------------- + +/** + * 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_SUB_DOMAIN_DEPLOY' => false, // 是否开启子域名部署 + 'APP_SUB_DOMAIN_RULES' => array(), // 子域名部署规则 + 'APP_SUB_DOMAIN_DENY' => array(), // 子域名禁用列表 + 'ACTION_SUFFIX' => '', // 操作方法后缀 + 'MULTI_MODULE' => true, // 是否允许多模块 如果为false 则必须设置 DEFAULT_MODULE + 'MODULE_DENY_LIST' => array('Common','Runtime'), + 'CONTROLLER_LEVEL' => 1, + 'STORAGE_TYPE' => 'File', + + /* Cookie设置 */ + 'COOKIE_EXPIRE' => 0, // Coodie有效期 + 'COOKIE_DOMAIN' => '', // Cookie有效域名 + 'COOKIE_PATH' => '/', // Cookie路径 + 'COOKIE_PREFIX' => '', // Cookie前缀 避免冲突 + + /* 默认设定 */ + 'DEFAULT_M_LAYER' => 'Model', // 默认的模型层名称 + 'DEFAULT_C_LAYER' => 'Controller', // 默认的控制器层名称 + 'DEFAULT_V_LAYER' => 'View', // 默认的视图层名称 + 'DEFAULT_APP' => '@', // 默认项目名称,@表示当前项目 + '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', // 默认参数过滤方法 用于 $this->_get('变量名');$this->_post('变量名')... + + /* 数据库设置 */ + '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执行日志记录 + + /* 数据缓存设置 */ + '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方法 + + /* 日志设置 */ + '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的提交变量 + + /* 模板引擎设置 */ + '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_DENY_SUFFIX' => 'ico|png|gif|jpg', // URL禁止访问的后缀设置 + 'URL_PARAMS_BIND' => true, // URL变量绑定到Action方法参数 + 'URL_404_REDIRECT' => '', // 404 跳转页面 部署模式有效 + 'URL_ROUTER_ON' => false, // 是否开启URL路由 + 'URL_ROUTE_RULES' => array(), // 默认路由规则 针对模块 + + /* 系统变量名称设置 */ + '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_URL_PARAMS' => '_URL_', // PATHINFO URL参数变量 + 'VAR_TEMPLATE' => 't', // 默认模板切换变量 + 'VAR_FILTERS' => 'filter_exp', // 全局系统变量的默认过滤方法 多个用逗号分割 + + 'OUTPUT_ENCODE' => false, // 页面压缩输出 + 'HTTP_CACHE_CONTROL' => 'private', // 网页缓存控制 + +); diff --git a/Conf/debug.php b/ThinkPHP/Conf/debug.php similarity index 49% rename from Conf/debug.php rename to ThinkPHP/Conf/debug.php index 5254d1397948e6babd38e6d66c8f1b49c0cf509e..c4b8a5c407ce2a24d64587c1680aa49764895cf1 100644 --- a/Conf/debug.php +++ b/ThinkPHP/Conf/debug.php @@ -1,36 +1,32 @@ - -// +---------------------------------------------------------------------- -// $Id: debug.php 3071 2012-07-15 07:59:23Z liu21st@gmail.com $ - -/** - +------------------------------------------------------------------------------ - * 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 覆盖 -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, // 显示错误信息 + +// +---------------------------------------------------------------------- + +/** + * 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 覆盖 +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, // 显示错误信息 ); \ No newline at end of file diff --git a/Extend/README.txt b/ThinkPHP/Extend/README.txt similarity index 96% rename from Extend/README.txt rename to ThinkPHP/Extend/README.txt index 1c150dfeb3760f5c89aad12214ba39b3357401bf..935dd6c818579746201a6f290514b646de899fdf 100644 --- a/Extend/README.txt +++ b/ThinkPHP/Extend/README.txt @@ -1,24 +1,24 @@ - -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 第三方类库目录 - + +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/LICENSE.txt b/ThinkPHP/LICENSE.txt similarity index 98% rename from LICENSE.txt rename to ThinkPHP/LICENSE.txt index 8c43602b9d0df9190edb0ad1af2e146f61915fe6..0275e8463ca68619356fccca057520b75156eea6 100644 --- a/LICENSE.txt +++ b/ThinkPHP/LICENSE.txt @@ -1,32 +1,32 @@ - -ThinkPHP遵循Apache2开源协议发布,并提供免费使用。 -版权所有Copyright © 2006-2012 by ThinkPHP (http://thinkphp.cn) -All rights reserved。 -ThinkPHP® 商标和著作权所有者为上海顶想信息科技有限公司。 - -Apache Licence是著名的非盈利开源组织Apache采用的协议。 -该协议和BSD类似,鼓励代码共享和尊重原作者的著作权, -允许代码修改,再作为开源或商业软件发布。需要满足 -的条件: -1. 需要给代码的用户一份Apache Licence ; -2. 如果你修改了代码,需要在被修改的文件中说明; -3. 在延伸的代码中(修改和有源代码衍生的代码中)需要 -带有原来代码中的协议,商标,专利声明和其他原来作者规 -定需要包含的说明; -4. 如果再发布的产品中包含一个Notice文件,则在Notice文 -件中需要带有本协议内容。你可以在Notice中增加自己的 -许可,但不可以表现为对Apache Licence构成更改。 -具体的协议参考:http://www.apache.org/licenses/LICENSE-2.0 - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. + +ThinkPHP遵循Apache2开源协议发布,并提供免费使用。 +版权所有Copyright © 2006-2012 by ThinkPHP (http://thinkphp.cn) +All rights reserved。 +ThinkPHP® 商标和著作权所有者为上海顶想信息科技有限公司。 + +Apache Licence是著名的非盈利开源组织Apache采用的协议。 +该协议和BSD类似,鼓励代码共享和尊重原作者的著作权, +允许代码修改,再作为开源或商业软件发布。需要满足 +的条件: +1. 需要给代码的用户一份Apache Licence ; +2. 如果你修改了代码,需要在被修改的文件中说明; +3. 在延伸的代码中(修改和有源代码衍生的代码中)需要 +带有原来代码中的协议,商标,专利声明和其他原来作者规 +定需要包含的说明; +4. 如果再发布的产品中包含一个Notice文件,则在Notice文 +件中需要带有本协议内容。你可以在Notice中增加自己的 +许可,但不可以表现为对Apache Licence构成更改。 +具体的协议参考:http://www.apache.org/licenses/LICENSE-2.0 + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/ThinkPHP/Lang/en-us.php b/ThinkPHP/Lang/en-us.php new file mode 100644 index 0000000000000000000000000000000000000000..f7c651219a4a79290f19d9d649dd9d7f2734ae6d --- /dev/null +++ b/ThinkPHP/Lang/en-us.php @@ -0,0 +1,54 @@ + +// +---------------------------------------------------------------------- + +/** + * ThinkPHP English language package + * @category Think + * @package Lang + * @author liu21st + * @version $Id: zh-cn.php 3034 2012-10-17 21:14:00Z yangweijiester@gmail.com $ + */ +return array( + /* 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 new file mode 100644 index 0000000000000000000000000000000000000000..9abfcd572933967f8c8a4d72ff1094a4e56844db --- /dev/null +++ b/ThinkPHP/Lang/zh-cn.php @@ -0,0 +1,53 @@ + +// +---------------------------------------------------------------------- + +/** + * ThinkPHP 简体中文语言包 + * @category Think + * @package Lang + * @author liu21st + */ +return array( + /* 核心语言变量 */ + '_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/Lib/Core/Action.class.php b/ThinkPHP/Library/Think/Action.class.php similarity index 36% rename from Lib/Core/Action.class.php rename to ThinkPHP/Library/Think/Action.class.php index 1b20b2dda92d0ef037eb17eb01c22f5b0a9e6f23..98a93eaf91340e7caef47cb30ddf5bd4bc6e234a 100644 --- a/Lib/Core/Action.class.php +++ b/ThinkPHP/Library/Think/Action.class.php @@ -1,440 +1,315 @@ - -// +---------------------------------------------------------------------- -// $Id: Action.class.php 3087 2012-07-28 12:29:23Z liu21st@gmail.com $ - -/** - +------------------------------------------------------------------------------ - * ThinkPHP Action控制器基类 抽象类 - +------------------------------------------------------------------------------ - * @category Think - * @package Think - * @subpackage Core - * @author liu21st - * @version $Id: Action.class.php 3087 2012-07-28 12:29:23Z liu21st@gmail.com $ - +------------------------------------------------------------------------------ - */ -abstract class Action { - - // 视图实例对象 - protected $view = null; - // 当前Action名称 - private $name = ''; - // 控制器参数 - 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 输出内容 - +---------------------------------------------------------- - * @return void - +---------------------------------------------------------- - */ - protected function display($templateFile='',$charset='',$contentType='',$content='') { - $this->view->display($templateFile,$charset,$contentType,$content); - } - - /** - +---------------------------------------------------------- - * 输出内容文本可以包括Html - +---------------------------------------------------------- - * @access protected - +---------------------------------------------------------- - * @param string $content 输出内容 - * @param string $charset 模板输出字符集 - * @param string $contentType 输出类型 - +---------------------------------------------------------- - * @return mixed - +---------------------------------------------------------- - */ - protected function show($content,$charset='',$contentType='') { - return $this->view->show($content,$charset,$contentType); - } - - /** - +---------------------------------------------------------- - * 获取输出页面内容 - * 调用内置的模板引擎fetch方法, - +---------------------------------------------------------- - * @access protected - +---------------------------------------------------------- - * @param string $templateFile 指定要调用的模板文件 - * 默认为空 由系统自动定位模板文件 - +---------------------------------------------------------- - * @return string - +---------------------------------------------------------- - */ - protected function fetch($templateFile='') { - return $this->view->fetch($templateFile); - } - - /** - +---------------------------------------------------------- - * 创建静态页面 - +---------------------------------------------------------- - * @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),0777,true); - if(false === file_put_contents($htmlfile,$content)) - throw_exception(L('_CACHE_WRITE_ERROR_').':'.$htmlfile); - return $content; - } - - /** - +---------------------------------------------------------- - * 模板变量赋值 - +---------------------------------------------------------- - * @access protected - +---------------------------------------------------------- - * @param mixed $name 要显示的模板变量 - * @param mixed $value 变量的值 - +---------------------------------------------------------- - * @return void - +---------------------------------------------------------- - */ - protected function assign($name,$value='') { - $this->view->assign($name,$value); - } - - public function __set($name,$value) { - $this->view->assign($name,$value); - } - - /** - +---------------------------------------------------------- - * 取得模板显示变量的值 - +---------------------------------------------------------- - * @access protected - +---------------------------------------------------------- - * @param string $name 模板显示变量 - +---------------------------------------------------------- - * @return mixed - +---------------------------------------------------------- - */ - public function __get($name) { - return $this->view->get($name); - } - - /** - +---------------------------------------------------------- - * 魔术方法 有不存在的操作的时候执行 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @param string $method 方法名 - * @param array $args 参数 - +---------------------------------------------------------- - * @return mixed - +---------------------------------------------------------- - */ - public function __call($method,$args) { - if( 0 === strcasecmp($method,ACTION_NAME)) { - if(method_exists($this,'_empty')) { - // 如果定义了_empty操作 则调用 - $this->_empty($method,$args); - }elseif(file_exists_case(C('TEMPLATE_NAME'))){ - // 检查是否存在默认模版 如果有直接输出模版 - $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')){ - $params = $_GET[C('VAR_URL_PARAMS')]; - $input = array_merge($input,$params); - } - break; - case '_request': $input =& $_REQUEST;break; - case '_session': $input =& $_SESSION;break; - case '_cookie': $input =& $_COOKIE;break; - case '_server': $input =& $_SERVER;break; - case '_globals': $input =& $GLOBALS;break; - default: - throw_exception(__CLASS__.':'.$method.L('_METHOD_NOT_EXIST_')); - } - if(!isset($args[0])) { // 获取全局变量 - $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; - } - return $data; - } - } - - /** - +---------------------------------------------------------- - * 操作错误跳转的快捷方法 - +---------------------------------------------------------- - * @access protected - +---------------------------------------------------------- - * @param string $message 错误信息 - * @param string $jumpUrl 页面跳转地址 - * @param Boolean|array $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 Boolean|array $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'); - if(strtoupper($type)=='JSON') { - // 返回JSON数据格式到客户端 包含状态信息 - header('Content-Type:text/html; charset=utf-8'); - exit(json_encode($data)); - }elseif(strtoupper($type)=='XML'){ - // 返回xml格式数据 - header('Content-Type:text/xml; charset=utf-8'); - exit(xml_encode($data)); - }elseif(strtoupper($type)=='EVAL'){ - // 返回可执行的js脚本 - header('Content-Type:text/html; charset=utf-8'); - exit($data); - }else{ - // TODO 增加其它格式 - } - } - - /** - +---------------------------------------------------------- - * 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 Boolean|array $ajax 是否为Ajax方式 - +---------------------------------------------------------- - * @access private - +---------------------------------------------------------- - * @return void - +---------------------------------------------------------- - */ - private function dispatchJump($message,$status=1,$jumpUrl='',$ajax=false) { - if($ajax || $this->isAjax()) {// AJAX提交 - $data = is_array($ajax)?$ajax:$this->view->get(); - $data['info'] = $message; - $data['status'] = $status; - $data['url'] = $jumpUrl; - $this->ajaxReturn($data); - } - if(!empty($jumpUrl)) $this->assign('jumpUrl',$jumpUrl); - // 提示标题 - $this->assign('msgTitle',$status? L('_OPERATION_SUCCESS_') : L('_OPERATION_FAIL_')); - //如果设置了关闭窗口,则提示完毕后自动关闭窗口 - if($this->view->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(!$this->view->get('waitSecond')) $this->assign('waitSecond','1'); - // 默认操作成功自动返回操作前页面 - if(!$this->view->get('jumpUrl')) $this->assign("jumpUrl",$_SERVER["HTTP_REFERER"]); - $this->display(C('TMPL_ACTION_SUCCESS')); - }else{ - $this->assign('error',$message);// 提示信息 - //发生错误时候默认停留3秒 - if(!$this->view->get('waitSecond')) $this->assign('waitSecond','3'); - // 默认发生错误的话自动返回上页 - if(!$this->view->get('jumpUrl')) $this->assign('jumpUrl',"javascript:history.back(-1);"); - $this->display(C('TMPL_ACTION_ERROR')); - // 中止执行 避免出错后继续执行 - exit ; - } - } - - /** - +---------------------------------------------------------- - * 析构方法 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - */ - public function __destruct() { - // 保存日志 - if(C('LOG_RECORD')) Log::save(); - // 执行后续操作 - tag('action_end'); - } -} \ No newline at end of file + +// +---------------------------------------------------------------------- +namespace Think; +/** + * 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('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(); + }elseif(function_exists('__hack_action')) { + // hack 方式定义扩展操作 + __hack_action(); + }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 : + // 用于扩展其他返回格式数据 + 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'); + } +} diff --git a/Lib/Core/App.class.php b/ThinkPHP/Library/Think/App.class.php similarity index 65% rename from Lib/Core/App.class.php rename to ThinkPHP/Library/Think/App.class.php index 946b3c04499f8808c04921602b1681785dc85433..bb96f8883a0c1f26af7486f83fa1500b52b9c727 100644 --- a/Lib/Core/App.class.php +++ b/ThinkPHP/Library/Think/App.class.php @@ -1,235 +1,176 @@ - -// +---------------------------------------------------------------------- -// $Id: App.class.php 3075 2012-07-17 05:59:27Z liu21st@gmail.com $ - -/** - +------------------------------------------------------------------------------ - * ThinkPHP 应用程序类 执行应用过程管理 - * 可以在模式扩展中重新定义 但是必须具有Run方法接口 - +------------------------------------------------------------------------------ - * @category Think - * @package Think - * @subpackage Core - * @author liu21st - * @version $Id: App.class.php 3075 2012-07-17 05:59:27Z liu21st@gmail.com $ - +------------------------------------------------------------------------------ - */ -class App { - - /** - +---------------------------------------------------------- - * 应用程序初始化 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @return void - +---------------------------------------------------------- - */ - static public function init() { - // 设置系统时区 - date_default_timezone_set(C('DEFAULT_TIMEZONE')); - // 加载动态项目公共文件和配置 - load_ext_file(); - // URL调度 - Dispatcher::dispatch(); - - // 定义当前请求的系统常量 - define('NOW_TIME',$_SERVER['REQUEST_TIME']); - define('REQUEST_METHOD',$_SERVER['REQUEST_METHOD']); - define('IS_GET', REQUEST_METHOD =='GET' ? true : false); - define('IS_POST', REQUEST_METHOD =='POST' ? true : false); - define('IS_PUT', REQUEST_METHOD =='PUT' ? true : false); - define('IS_DELETE', REQUEST_METHOD =='DELETE' ? true : false); - define('IS_AJAX', ((isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH'] == 'xmlhttprequest')) || !empty($_POST[C('VAR_AJAX_SUBMIT')]) || !empty($_GET[C('VAR_AJAX_SUBMIT')])) ? true : false); - - if(defined('GROUP_NAME')) { - // 加载分组配置文件 - if(is_file(CONF_PATH.GROUP_NAME.'/config.php')) - C(include CONF_PATH.GROUP_NAME.'/config.php'); - // 加载分组函数文件 - if(is_file(COMMON_PATH.GROUP_NAME.'/function.php')) - include COMMON_PATH.GROUP_NAME.'/function.php'; - } - // 页面压缩输出支持 - if(!ini_get('zlib.output_compression') && C('OUTPUT_ENCODE')) ob_start('ob_gzhandler'); - // 系统变量安全过滤 - if(C('VAR_FILTERS')) { - $filters = explode(',',C('VAR_FILTERS')); - foreach($filters as $filter){ - // 全局参数过滤 - $_POST = array_map($filter,$_POST); - $_GET = array_map($filter,$_GET); - } - } - - /* 获取模板主题名称 */ - $templateSet = C('DEFAULT_THEME'); - if(C('TMPL_DETECT_THEME')) {// 自动侦测模板主题 - $t = C('VAR_TEMPLATE'); - if (isset($_GET[$t])){ - $templateSet = $_GET[$t]; - }elseif(cookie('think_template')){ - $templateSet = cookie('think_template'); - } - // 主题不存在时仍改回使用默认主题 - if(!is_dir(TMPL_PATH.$templateSet)) - $templateSet = C('DEFAULT_THEME'); - cookie('think_template',$templateSet); - } - /* 模板相关目录常量 */ - define('THEME_NAME', $templateSet); // 当前模板主题名称 - $group = defined('GROUP_NAME')?GROUP_NAME.'/':''; - define('THEME_PATH', TMPL_PATH.$group.(THEME_NAME?THEME_NAME.'/':'')); - define('APP_TMPL_PATH',__ROOT__.'/'.APP_NAME.(APP_NAME?'/':'').basename(TMPL_PATH).'/'.$group.(THEME_NAME?THEME_NAME.'/':'')); - C('TEMPLATE_NAME',THEME_PATH.MODULE_NAME.(defined('GROUP_NAME')?C('TMPL_FILE_DEPR'):'/').ACTION_NAME.C('TMPL_TEMPLATE_SUFFIX')); - C('CACHE_PATH',CACHE_PATH.$group); - //动态配置 TMPL_EXCEPTION_FILE,改为绝对地址 - C('TMPL_EXCEPTION_FILE',realpath(C('TMPL_EXCEPTION_FILE'))); - return ; - } - - /** - +---------------------------------------------------------- - * 执行应用程序 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @return void - +---------------------------------------------------------- - * @throws ThinkExecption - +---------------------------------------------------------- - */ - static public function exec() { - if(!preg_match('/^[A-Za-z](\w)*$/',MODULE_NAME)){ // 安全检测 - $module = false; - }else{ - //创建Action控制器实例 - $group = defined('GROUP_NAME') ? GROUP_NAME.'/' : ''; - $module = A($group.MODULE_NAME); - } - - if(!$module) { - if('4e5e5d7364f443e28fbf0d3ae744a59a' == MODULE_NAME) { - header("Content-type:image/png"); - exit(base64_decode(App::logo())); - } - if(function_exists('__hack_module')) { - // hack 方式定义扩展模块 返回Action对象 - $module = __hack_module(); - if(!is_object($module)) { - // 不再继续执行 直接返回 - return ; - } - }else{ - // 是否定义Empty模块 - $module = A($group.'Empty'); - if(!$module){ - _404(L('_MODULE_NOT_EXIST_').':'.MODULE_NAME); - } - } - } - // 获取当前操作名 支持动态路由 - $action = C('ACTION_NAME')?C('ACTION_NAME'):ACTION_NAME; - C('TEMPLATE_NAME',THEME_PATH.MODULE_NAME.(defined('GROUP_NAME')?C('TMPL_FILE_DEPR'):'/').$action.C('TMPL_TEMPLATE_SUFFIX')); - $action .= C('ACTION_SUFFIX'); - try{ - if(!preg_match('/^[A-Za-z](\w)*$/',$action)){ - // 非法操作 - throw new ReflectionException(); - } - //执行当前操作 - $method = new ReflectionMethod($module, $action); - if($method->isPublic()) { - $class = new ReflectionClass($module); - // 前置操作 - if($class->hasMethod('_before_'.$action)) { - $before = $class->getMethod('_before_'.$action); - if($before->isPublic()) { - $before->invoke($module); - } - } - // URL参数绑定检测 - if(C('URL_PARAMS_BIND') && $method->getNumberOfParameters()>0){ - switch($_SERVER['REQUEST_METHOD']) { - case 'POST': - $vars = $_POST; - break; - case 'PUT': - parse_str(file_get_contents('php://input'), $vars); - break; - default: - $vars = $_GET; - } - $params = $method->getParameters(); - foreach ($params as $param){ - $name = $param->getName(); - if(isset($vars[$name])) { - $args[] = $vars[$name]; - }elseif($param->isDefaultValueAvailable()){ - $args[] = $param->getDefaultValue(); - }else{ - throw_exception(L('_PARAM_ERROR_').':'.$name); - } - } - $method->invokeArgs($module,$args); - }else{ - $method->invoke($module); - } - // 后置操作 - if($class->hasMethod('_after_'.$action)) { - $after = $class->getMethod('_after_'.$action); - if($after->isPublic()) { - $after->invoke($module); - } - } - }else{ - // 操作方法不是Public 抛出异常 - throw new ReflectionException(); - } - } catch (ReflectionException $e) { - // 方法调用发生异常后 引导到__call方法处理 - $method = new ReflectionMethod($module,'__call'); - $method->invokeArgs($module,array($action,'')); - } - return ; - } - - /** - +---------------------------------------------------------- - * 运行应用实例 入口文件使用的快捷方法 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @return void - +---------------------------------------------------------- - */ - static public function run() { - // 项目初始化标签 - tag('app_init'); - App::init(); - // 项目开始标签 - tag('app_begin'); - // Session初始化 - session(C('SESSION_OPTIONS')); - // 记录应用初始化时间 - G('initTime'); - App::exec(); - // 项目结束标签 - tag('app_end'); - // 保存日志记录 - if(C('LOG_RECORD')) Log::save(); - return ; - } - - static public function logo(){ - return 'iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyBpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBXaW5kb3dzIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjVERDVENkZGQjkyNDExRTE5REY3RDQ5RTQ2RTRDQUJCIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjVERDVENzAwQjkyNDExRTE5REY3RDQ5RTQ2RTRDQUJCIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6NURENUQ2RkRCOTI0MTFFMTlERjdENDlFNDZFNENBQkIiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NURENUQ2RkVCOTI0MTFFMTlERjdENDlFNDZFNENBQkIiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz5fx6IRAAAMCElEQVR42sxae3BU1Rk/9+69+8xuNtkHJAFCSIAkhMgjCCJQUi0GtEIVbP8Qq9LH2No6TmfaztjO2OnUdvqHFMfOVFTqIK0vUEEeqUBARCsEeYQkEPJoEvIiELLvvc9z+p27u2F3s5tsBB1OZiebu5dzf7/v/L7f952zMM8cWIwY+Mk2ulCp92Fnq3XvnzArr2NZnYNldDp0Gw+/OEQ4+obQn5D+4Ubb22+YOGsWi/Todh8AHglKEGkEsnHBQ162511GZFgW6ZCBM9/W4H3iNSQqIe09O196dLKX7d1O39OViP/wthtkND62if/wj/DbMpph8BY/m9xy8BoBmQk+mHqZQGNy4JYRwCoRbwa8l4JXw6M+orJxpU0U6ToKy/5bQsAiTeokGKkTx46RRxxEUgrwGgF4MWNNEJCGgYTvpgnY1IJWg5RzfqLgvcIgktX0i8dmMlFA8qCQ5L0Z/WObPLUxT1i4lWSYDISoEfBYGvM+LlMQQdkLHoWRRZ8zYQI62Thswe5WTORGwNXDcGjqeOA9AF7B8rhzsxMBEoJ8oJKaqPu4hblHMCMPwl9XeNWyb8xkB/DDGYKfMAE6aFL7xesZ389JlgG3XHEMI6UPDOP6JHHu67T2pwNPI69mCP4rEaBDUAJaKc/AOuXiwH07VCS3w5+UQMAuF/WqGI+yFIwVNBwemBD4r0wgQiKoFZa00sEYTwss32lA1tPwVxtc8jQ5/gWCwmGCyUD8vRT0sHBFW4GJDvZmrJFWRY1EkrGA6ZB8/10fOZSSj0E6F+BSP7xidiIzhBmKB09lEwHPkG+UQIyEN44EBiT5vrv2uJXyPQqSqO930fxvcvwbR/+JAkD9EfASgI9EHlp6YiHO4W+cAB20SnrFqxBbNljiXf1Pl1K2S0HCWfiog3YlAD5RGwwxK6oUjTweuVigLjyB0mX410mAFnMoVK1lvvUvgt8fUJH0JVyjuvcmg4dE5mUiFtD24AZ4qBVELxXKS+pMxN43kSdzNwudJ+bQbLlmnxvPOQoCugSap1GnSRoG8KOiKbH+rIA0lEeSAg3y6eeQ6XI2nrYnrPM89bUTgI0Pdqvl50vlNbtZxDUBcLBK0kPd5jPziyLdojJIN0pq5/mdzwL4UVvVInV5ncQEPNOUxa9d0TU+CW5l+FoI0GSDKHVVSOs+0KOsZoxwOzSZNFGv0mQ9avyLCh2Hpm+70Y0YJoJVgmQv822wnDC8Miq6VjJ5IFed0QD1YiAbT+nQE8v/RMZfmgmcCRHIIu7Bmcp39oM9fqEychcA747KxQ/AEyqQonl7hATtJmnhO2XYtgcia01aSbVMenAXrIomPcLgEBA4liGBzFZAT8zBYqW6brI67wg8sFVhxBhwLwBP2+tqBQqqK7VJKGh/BRrfTr6nWL7nYBaZdBJHqrX3kPEPap56xwE/GvjJTRMADeMCdcGpGXL1Xh4ZL8BDOlWkUpegfi0CeDzeA5YITzEnddv+IXL+UYCmqIvqC9UlUC/ki9FipwVjunL3yX7dOTLeXmVMAhbsGporPfyOBTm/BJ23gTVehsvXRnSewagUfpBXF3p5pygKS7OceqTjb7h2vjr/XKm0ZofKSI2Q/J102wHzatZkJPYQ5JoKsuK+EoHJakVzubzuLQDepCKllTZi9AG0DYg9ZLxhFaZsOu7bvlmVI5oPXJMQJcHxHClSln1apFTvAimeg48u0RWFeZW4lVcjbQWZuIQK1KozZfIDO6CSQmQQXdpBaiKZyEWThVK1uEc6v7V7uK0ysduExPZx4vysDR+4SelhBYm0R6LBuR4PXts8MYMcJPsINo4YZCDLj0sgB0/vLpPXvA2Tn42Cv5rsLulGubzW0sEd3d4W/mJt2Kck+DzDMijfPLOjyrDhXSh852B+OvflqAkoyXO1cYfujtc/i3jJSAwhgfFlp20laMLOku/bC7prgqW7lCn4auE5NhcXPd3M7x70+IceSgZvNljCd9k3fLjYsPElqLR14PXQZqD2ZNkkrAB79UeJUebFQmXpf8ZcAQt2XrMQdyNUVBqZoUzAFyp3V3xi/MubUA/mCT4Fhf038PC8XplhWnCmnK/ZzyC2BSTRSqKVOuY2kB8Jia0lvvRIVoP+vVWJbYarf6p655E2/nANBMCWkgD49DA0VAMyI1OLFMYCXiU9bmzi9/y5i/vsaTpHPHidTofzLbM65vMPva9HlovgXp0AvjtaqYMfDD0/4mAsYE92pxa+9k1QgCnRVObCpojpzsKTPvayPetTEgBdwnssjuc0kOBFX+q3HwRQxdrOLAqeYRjkMk/trTSu2Z9Lik7CfF0AvjtqAhS4NHobGXUnB5DQs8hG8p/wMX1r4+8xkmyvQ50JVq72TVeXbz3HvpWaQJi57hJYTw4kGbtS+C2TigQUtZUX+X27QQq2ePBZBru/0lxTm8fOOQ5yaZOZMAV+he4FqIMB+LQB0UgMSajANX29j+vbmly8ipRvHeSQoQOkM5iFXcPQCVwDMs5RBCQmaPOyvbNd6uwvQJ183BZQG3Zc+Eiv7vQOKu8YeDmMcJlt2ckyftVeMIGLBCmdMHl/tFILYwGPjXWO3zOfSq/+om+oa7Mlh2fpSsRGLp7RAW3FUVjNHgiMhyE6zBFjM2BdkdJGO7nP1kJXWAtBuBpPIAu7f+hhu7bFXIuC5xWrf0X2xreykOsUyKkF2gwadbrXDcXrfKxR43zGcSj4t/cCgr+a1iy6EjE5GYktUCl9fwfMeylyooGF48bN2IGLTw8x7StS7sj8TF9FmPGWQhm3rRR+o9lhvjJvSYAdfDUevI1M6bnX/OwWaDMOQ8RPgKRo0eulBTdT8AW2kl8e9L7UHghHwMfLiZPNoSpx0yugpQZaFqKWqxVSM3a2pN1SAhC2jf94I7ybBI7EL5A2Wvu5ht3xsoEt4+Ay/abXgCQAxyOeDsDlTCQzy75ohcGgv9Tra9uiymRUYTLrswOLlCdfAQf7HPDQQ4ErAH5EDXB9cMxWYpjtXApRncojS0sbV/cCgHTHwGNBJy+1PQE2x56FpaVR7wfQGZ37V+V+19EiHNvR6q1fRUjqvbjbMq1/qfHxbTrE10ePY2gPFk48D2CVMTf1AF4PXvyYR9dV6Wf7H413m3xTWQvYGhQ7mfYwA5mAX+18Vue05v/8jG/fZX/IW5MKPKtjSYlt0ellxh+/BOCPAwYaeVr0QofZFxJWVWC8znG70au6llVmktsF0bfHF6k8fvZ5esZJbwHwwnjg59tXz6sL/P0NUZDuSNu1mnJ8Vab17+cy005A9wtOpp3i0bZdpJLUil00semAwN45LgEViZYe3amNye0B6A9chviSlzXVsFtyN5/1H3gaNmMpn8Fz0GpYFp6Zw615H/LpUuRQQDMCL82n5DpBSawkvzIdN2ypiT8nSLth8Pk9jnjwdFzH3W4XW6KMBfwB569NdcGX93mC16tTflcArcYUc/mFuYbV+8zY0SAjAVoNErNgWjtwumJ3wbn/HlBFYdxHvSkJJEc+Ngal9opSwyo9YlITX2C/P/+gf8sxURSLR+mcZUmeqaS9wrh6vxW5zxFCOqFi90RbDWq/YwZmnu1+a6OvdpvRqkNxxe44lyl4OobEnpKA6Uox5EfH9xzPs/HRKrTPWdIQrK1VZDU7ETiD3Obpl+8wPPCRBbkbwNtpW9AbBe5L1SMlj3tdTxk/9W47JUmqS5HU+JzYymUKXjtWVmT9RenIhgXc+nroWLyxXJhmL112OdB8GCsk4f8oZJucnvmmtR85mBn10GZ0EKSCMUSAR3ukcXd5s7LvLD3me61WkuTCpJzYAyRurMB44EdEJzTfU271lUJC03YjXJXzYOGZwN4D8eB5jlfLrdWfzGRW7icMPfiSO6Oe7s20bmhdgLX4Z23B+s3JgQESzUDiMboSzDMHFpNMwccGePauhfwjzwnI2wu9zKGgEFg80jcZ7MHllk07s1H+5yojtUQTlH4nFdLKTGwDmPbIklOb1L1zO4T6N8NCuDLFLS/C63c0eNRimZ++s5BMBHxU11jHchI9oFVUxRh/eMDzHEzGYu0Lg8gJ7oS/tFCwoic44fyUtix0n/46vP4bf+//BRgAYwDDar4ncHIAAAAASUVORK5CYII='; - } + +// +---------------------------------------------------------------------- +namespace Think; +/** + * ThinkPHP 应用程序类 执行应用过程管理 + * 可以在模式扩展中重新定义 但是必须具有Run方法接口 + * @category Think + * @package Think + * @subpackage Core + * @author liu21st + */ +class App { + + /** + * 应用程序初始化 + * @access public + * @return void + */ + static public function init() { + // 加载动态项目公共文件和配置 + load_ext_file(); + // URL调度 + Dispatcher::dispatch(); + + // 定义当前请求的系统常量 + define('NOW_TIME', $_SERVER['REQUEST_TIME']); + define('REQUEST_METHOD',$_SERVER['REQUEST_METHOD']); + define('IS_GET', REQUEST_METHOD =='GET' ? true : false); + define('IS_POST', REQUEST_METHOD =='POST' ? true : false); + define('IS_PUT', REQUEST_METHOD =='PUT' ? true : false); + define('IS_DELETE', REQUEST_METHOD =='DELETE' ? true : false); + define('IS_AJAX', ((isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') || !empty($_POST[C('VAR_AJAX_SUBMIT')]) || !empty($_GET[C('VAR_AJAX_SUBMIT')])) ? true : false); + + // URL调度结束标签 + tag('url_dispatch'); + + // 日志目录转换为绝对路径 + C('LOG_PATH',realpath(LOG_PATH).'/'); + // TMPL_EXCEPTION_FILE 改为绝对地址 + C('TMPL_EXCEPTION_FILE',realpath(C('TMPL_EXCEPTION_FILE'))); + return ; + } + + /** + * 执行应用程序 + * @access public + * @return void + */ + static public function exec() { + if(!preg_match('/^[A-Za-z](\/|\w)*$/',CONTROLLER_NAME)){ // 安全检测 + $module = false; + }else{ + //创建Action控制器实例 + $module = A(CONTROLLER_NAME); + } + + if(!$module) { + 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('Empty'); + if(!$module){ + E(L('_CONTROLLER_NOT_EXIST_').':'.CONTROLLER_NAME); + } + } + } + // 获取当前操作名 支持动态路由 + $action = C('ACTION_NAME')?C('ACTION_NAME'):ACTION_NAME; + $action .= C('ACTION_SUFFIX'); + try{ + if(!preg_match('/^[A-Za-z](\w)*$/',$action)){ + // 非法操作 + throw new \ReflectionException(); + } + //执行当前操作 + $method = new \ReflectionMethod($module, $action); + if($method->isPublic() && !$method->isStatic()) { + $class = new \ReflectionClass($module); + // 前置操作 + if($class->hasMethod('_before_'.$action)) { + $before = $class->getMethod('_before_'.$action); + if($before->isPublic()) { + $before->invoke($module); + } + } + // URL参数绑定检测 + if(C('URL_PARAMS_BIND') && $method->getNumberOfParameters()>0){ + switch($_SERVER['REQUEST_METHOD']) { + case 'POST': + $vars = array_merge($_GET,$_POST); + break; + case 'PUT': + parse_str(file_get_contents('php://input'), $vars); + break; + default: + $vars = $_GET; + } + $params = $method->getParameters(); + foreach ($params as $param){ + $name = $param->getName(); + if(isset($vars[$name])) { + $args[] = $vars[$name]; + }elseif($param->isDefaultValueAvailable()){ + $args[] = $param->getDefaultValue(); + }else{ + E(L('_PARAM_ERROR_').':'.$name); + } + } + $method->invokeArgs($module,$args); + }else{ + $method->invoke($module); + } + // 后置操作 + if($class->hasMethod('_after_'.$action)) { + $after = $class->getMethod('_after_'.$action); + if($after->isPublic()) { + $after->invoke($module); + } + } + }else{ + // 操作方法不是Public 抛出异常 + throw new \ReflectionException(); + } + } catch (\ReflectionException $e) { + // 方法调用发生异常后 引导到__call方法处理 + $method = new \ReflectionMethod($module,'__call'); + $method->invokeArgs($module,array($action,'')); + } + return ; + } + + /** + * 运行应用实例 入口文件使用的快捷方法 + * @access public + * @return void + */ + static public function run() { + // 项目初始化标签 + tag('app_init'); + App::init(); + // 项目开始标签 + tag('app_begin'); + // Session初始化 + if(!IS_CLI){ + session(C('SESSION_OPTIONS')); + } + // 记录应用初始化时间 + G('initTime'); + App::exec(); + // 项目结束标签 + tag('app_end'); + return ; + } + + static public function logo(){ + return 'iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyBpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBXaW5kb3dzIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjVERDVENkZGQjkyNDExRTE5REY3RDQ5RTQ2RTRDQUJCIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjVERDVENzAwQjkyNDExRTE5REY3RDQ5RTQ2RTRDQUJCIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6NURENUQ2RkRCOTI0MTFFMTlERjdENDlFNDZFNENBQkIiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NURENUQ2RkVCOTI0MTFFMTlERjdENDlFNDZFNENBQkIiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz5fx6IRAAAMCElEQVR42sxae3BU1Rk/9+69+8xuNtkHJAFCSIAkhMgjCCJQUi0GtEIVbP8Qq9LH2No6TmfaztjO2OnUdvqHFMfOVFTqIK0vUEEeqUBARCsEeYQkEPJoEvIiELLvvc9z+p27u2F3s5tsBB1OZiebu5dzf7/v/L7f952zMM8cWIwY+Mk2ulCp92Fnq3XvnzArr2NZnYNldDp0Gw+/OEQ4+obQn5D+4Ubb22+YOGsWi/Todh8AHglKEGkEsnHBQ162511GZFgW6ZCBM9/W4H3iNSQqIe09O196dLKX7d1O39OViP/wthtkND62if/wj/DbMpph8BY/m9xy8BoBmQk+mHqZQGNy4JYRwCoRbwa8l4JXw6M+orJxpU0U6ToKy/5bQsAiTeokGKkTx46RRxxEUgrwGgF4MWNNEJCGgYTvpgnY1IJWg5RzfqLgvcIgktX0i8dmMlFA8qCQ5L0Z/WObPLUxT1i4lWSYDISoEfBYGvM+LlMQQdkLHoWRRZ8zYQI62Thswe5WTORGwNXDcGjqeOA9AF7B8rhzsxMBEoJ8oJKaqPu4hblHMCMPwl9XeNWyb8xkB/DDGYKfMAE6aFL7xesZ389JlgG3XHEMI6UPDOP6JHHu67T2pwNPI69mCP4rEaBDUAJaKc/AOuXiwH07VCS3w5+UQMAuF/WqGI+yFIwVNBwemBD4r0wgQiKoFZa00sEYTwss32lA1tPwVxtc8jQ5/gWCwmGCyUD8vRT0sHBFW4GJDvZmrJFWRY1EkrGA6ZB8/10fOZSSj0E6F+BSP7xidiIzhBmKB09lEwHPkG+UQIyEN44EBiT5vrv2uJXyPQqSqO930fxvcvwbR/+JAkD9EfASgI9EHlp6YiHO4W+cAB20SnrFqxBbNljiXf1Pl1K2S0HCWfiog3YlAD5RGwwxK6oUjTweuVigLjyB0mX410mAFnMoVK1lvvUvgt8fUJH0JVyjuvcmg4dE5mUiFtD24AZ4qBVELxXKS+pMxN43kSdzNwudJ+bQbLlmnxvPOQoCugSap1GnSRoG8KOiKbH+rIA0lEeSAg3y6eeQ6XI2nrYnrPM89bUTgI0Pdqvl50vlNbtZxDUBcLBK0kPd5jPziyLdojJIN0pq5/mdzwL4UVvVInV5ncQEPNOUxa9d0TU+CW5l+FoI0GSDKHVVSOs+0KOsZoxwOzSZNFGv0mQ9avyLCh2Hpm+70Y0YJoJVgmQv822wnDC8Miq6VjJ5IFed0QD1YiAbT+nQE8v/RMZfmgmcCRHIIu7Bmcp39oM9fqEychcA747KxQ/AEyqQonl7hATtJmnhO2XYtgcia01aSbVMenAXrIomPcLgEBA4liGBzFZAT8zBYqW6brI67wg8sFVhxBhwLwBP2+tqBQqqK7VJKGh/BRrfTr6nWL7nYBaZdBJHqrX3kPEPap56xwE/GvjJTRMADeMCdcGpGXL1Xh4ZL8BDOlWkUpegfi0CeDzeA5YITzEnddv+IXL+UYCmqIvqC9UlUC/ki9FipwVjunL3yX7dOTLeXmVMAhbsGporPfyOBTm/BJ23gTVehsvXRnSewagUfpBXF3p5pygKS7OceqTjb7h2vjr/XKm0ZofKSI2Q/J102wHzatZkJPYQ5JoKsuK+EoHJakVzubzuLQDepCKllTZi9AG0DYg9ZLxhFaZsOu7bvlmVI5oPXJMQJcHxHClSln1apFTvAimeg48u0RWFeZW4lVcjbQWZuIQK1KozZfIDO6CSQmQQXdpBaiKZyEWThVK1uEc6v7V7uK0ysduExPZx4vysDR+4SelhBYm0R6LBuR4PXts8MYMcJPsINo4YZCDLj0sgB0/vLpPXvA2Tn42Cv5rsLulGubzW0sEd3d4W/mJt2Kck+DzDMijfPLOjyrDhXSh852B+OvflqAkoyXO1cYfujtc/i3jJSAwhgfFlp20laMLOku/bC7prgqW7lCn4auE5NhcXPd3M7x70+IceSgZvNljCd9k3fLjYsPElqLR14PXQZqD2ZNkkrAB79UeJUebFQmXpf8ZcAQt2XrMQdyNUVBqZoUzAFyp3V3xi/MubUA/mCT4Fhf038PC8XplhWnCmnK/ZzyC2BSTRSqKVOuY2kB8Jia0lvvRIVoP+vVWJbYarf6p655E2/nANBMCWkgD49DA0VAMyI1OLFMYCXiU9bmzi9/y5i/vsaTpHPHidTofzLbM65vMPva9HlovgXp0AvjtaqYMfDD0/4mAsYE92pxa+9k1QgCnRVObCpojpzsKTPvayPetTEgBdwnssjuc0kOBFX+q3HwRQxdrOLAqeYRjkMk/trTSu2Z9Lik7CfF0AvjtqAhS4NHobGXUnB5DQs8hG8p/wMX1r4+8xkmyvQ50JVq72TVeXbz3HvpWaQJi57hJYTw4kGbtS+C2TigQUtZUX+X27QQq2ePBZBru/0lxTm8fOOQ5yaZOZMAV+he4FqIMB+LQB0UgMSajANX29j+vbmly8ipRvHeSQoQOkM5iFXcPQCVwDMs5RBCQmaPOyvbNd6uwvQJ183BZQG3Zc+Eiv7vQOKu8YeDmMcJlt2ckyftVeMIGLBCmdMHl/tFILYwGPjXWO3zOfSq/+om+oa7Mlh2fpSsRGLp7RAW3FUVjNHgiMhyE6zBFjM2BdkdJGO7nP1kJXWAtBuBpPIAu7f+hhu7bFXIuC5xWrf0X2xreykOsUyKkF2gwadbrXDcXrfKxR43zGcSj4t/cCgr+a1iy6EjE5GYktUCl9fwfMeylyooGF48bN2IGLTw8x7StS7sj8TF9FmPGWQhm3rRR+o9lhvjJvSYAdfDUevI1M6bnX/OwWaDMOQ8RPgKRo0eulBTdT8AW2kl8e9L7UHghHwMfLiZPNoSpx0yugpQZaFqKWqxVSM3a2pN1SAhC2jf94I7ybBI7EL5A2Wvu5ht3xsoEt4+Ay/abXgCQAxyOeDsDlTCQzy75ohcGgv9Tra9uiymRUYTLrswOLlCdfAQf7HPDQQ4ErAH5EDXB9cMxWYpjtXApRncojS0sbV/cCgHTHwGNBJy+1PQE2x56FpaVR7wfQGZ37V+V+19EiHNvR6q1fRUjqvbjbMq1/qfHxbTrE10ePY2gPFk48D2CVMTf1AF4PXvyYR9dV6Wf7H413m3xTWQvYGhQ7mfYwA5mAX+18Vue05v/8jG/fZX/IW5MKPKtjSYlt0ellxh+/BOCPAwYaeVr0QofZFxJWVWC8znG70au6llVmktsF0bfHF6k8fvZ5esZJbwHwwnjg59tXz6sL/P0NUZDuSNu1mnJ8Vab17+cy005A9wtOpp3i0bZdpJLUil00semAwN45LgEViZYe3amNye0B6A9chviSlzXVsFtyN5/1H3gaNmMpn8Fz0GpYFp6Zw615H/LpUuRQQDMCL82n5DpBSawkvzIdN2ypiT8nSLth8Pk9jnjwdFzH3W4XW6KMBfwB569NdcGX93mC16tTflcArcYUc/mFuYbV+8zY0SAjAVoNErNgWjtwumJ3wbn/HlBFYdxHvSkJJEc+Ngal9opSwyo9YlITX2C/P/+gf8sxURSLR+mcZUmeqaS9wrh6vxW5zxFCOqFi90RbDWq/YwZmnu1+a6OvdpvRqkNxxe44lyl4OobEnpKA6Uox5EfH9xzPs/HRKrTPWdIQrK1VZDU7ETiD3Obpl+8wPPCRBbkbwNtpW9AbBe5L1SMlj3tdTxk/9W47JUmqS5HU+JzYymUKXjtWVmT9RenIhgXc+nroWLyxXJhmL112OdB8GCsk4f8oZJucnvmmtR85mBn10GZ0EKSCMUSAR3ukcXd5s7LvLD3me61WkuTCpJzYAyRurMB44EdEJzTfU271lUJC03YjXJXzYOGZwN4D8eB5jlfLrdWfzGRW7icMPfiSO6Oe7s20bmhdgLX4Z23B+s3JgQESzUDiMboSzDMHFpNMwccGePauhfwjzwnI2wu9zKGgEFg80jcZ7MHllk07s1H+5yojtUQTlH4nFdLKTGwDmPbIklOb1L1zO4T6N8NCuDLFLS/C63c0eNRimZ++s5BMBHxU11jHchI9oFVUxRh/eMDzHEzGYu0Lg8gJ7oS/tFCwoic44fyUtix0n/46vP4bf+//BRgAYwDDar4ncHIAAAAASUVORK5CYII='; + } } \ No newline at end of file diff --git a/Lib/Core/Behavior.class.php b/ThinkPHP/Library/Think/Behavior.class.php similarity index 62% rename from Lib/Core/Behavior.class.php rename to ThinkPHP/Library/Think/Behavior.class.php index 90aa22d6614c5ba76ce3e8fdc2bd0e1503f4dc38..e1997f647fe8b3b4e9f3bfd1e0de30c79d9f990b 100644 --- a/Lib/Core/Behavior.class.php +++ b/ThinkPHP/Library/Think/Behavior.class.php @@ -1,67 +1,54 @@ - -// +---------------------------------------------------------------------- -// $Id: Behavior.class.php 2702 2012-02-02 12:35:01Z liu21st $ - -/** - +------------------------------------------------------------------------------ - * ThinkPHP Behavior基础类 - +------------------------------------------------------------------------------ - * @category Think - * @package Think - * @subpackage Util - * @author liu21st - * @version $Id: Behavior.class.php 2702 2012-02-02 12:35:01Z liu21st $ - +------------------------------------------------------------------------------ - */ -abstract class Behavior { - - // 行为参数 和配置参数设置相同 - protected $options = array(); - - /** - +---------------------------------------------------------- - * 架构函数 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - */ - public function __construct() { - if(!empty($this->options)) { - foreach ($this->options as $name=>$val){ - if(NULL !== C($name)) { // 参数已设置 则覆盖行为参数 - $this->options[$name] = C($name); - }else{ // 参数未设置 则传入默认值到配置 - C($name,$val); - } - } - array_change_key_case($this->options); - } - } - - // 获取行为参数 - public function __get($name){ - return $this->options[strtolower($name)]; - } - - /** - +---------------------------------------------------------- - * 执行行为 run方法是Behavior唯一的接口 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @param mixed $params 行为参数 - +---------------------------------------------------------- - * @return void - +---------------------------------------------------------- - */ - abstract public function run(&$params); - + +// +---------------------------------------------------------------------- +namespace Think; +/** + * ThinkPHP Behavior基础类 + * @category Think + * @package Think + * @subpackage Core + * @author liu21st + */ +abstract class Behavior { + + // 行为参数 和配置参数设置相同 + protected $options = array(); + + /** + * 架构函数 + * @access public + */ + public function __construct() { + if(!empty($this->options)) { + foreach ($this->options as $name=>$val){ + if(NULL !== C($name)) { // 参数已设置 则覆盖行为参数 + $this->options[$name] = C($name); + }else{ // 参数未设置 则传入默认值到配置 + C($name,$val); + } + } + array_change_key_case($this->options); + } + } + + // 获取行为参数 + public function __get($name){ + return $this->options[strtolower($name)]; + } + + /** + * 执行行为 run方法是Behavior唯一的接口 + * @access public + * @param mixed $params 行为参数 + * @return void + */ + abstract public function run(&$params); + } \ No newline at end of file diff --git a/Lib/Behavior/ContentReplaceBehavior.class.php b/ThinkPHP/Library/Think/Behavior/ContentReplaceBehavior.class.php similarity index 52% rename from Lib/Behavior/ContentReplaceBehavior.class.php rename to ThinkPHP/Library/Think/Behavior/ContentReplaceBehavior.class.php index dc82c699fd0be48d75b84ec9be22bd5f83efa6ec..0c8a1a1df08ed825e1cfdc7685f3e57f6226174b 100644 --- a/Lib/Behavior/ContentReplaceBehavior.class.php +++ b/ThinkPHP/Library/Think/Behavior/ContentReplaceBehavior.class.php @@ -1,61 +1,57 @@ - -// +---------------------------------------------------------------------- -// $Id: ContentReplaceBehavior.class.php 3001 2012-06-15 03:39:19Z liu21st@gmail.com $ - -defined('THINK_PATH') or exit(); -/** - +------------------------------------------------------------------------------ - * 系统行为扩展 模板内容输出替换 - +------------------------------------------------------------------------------ - */ -class ContentReplaceBehavior extends Behavior { - // 行为参数定义 - protected $options = array( - 'TMPL_PARSE_STRING'=>array(), - ); - - // 行为扩展的执行入口必须是run - public function run(&$content){ - $content = $this->templateContentReplace($content); - } - - /** - +---------------------------------------------------------- - * 模板内容替换 - +---------------------------------------------------------- - * @access protected - +---------------------------------------------------------- - * @param string $content 模板内容 - +---------------------------------------------------------- - * @return string - +---------------------------------------------------------- - */ - protected function templateContentReplace($content) { - // 系统默认的特殊变量替换 - $replace = array( - '__TMPL__' => APP_TMPL_PATH, // 项目模板目录 - '__ROOT__' => __ROOT__, // 当前网站地址 - '__APP__' => __APP__, // 当前项目地址 - '__GROUP__' => defined('GROUP_NAME')?__GROUP__:__APP__, - '__ACTION__' => __ACTION__, // 当前操作地址 - '__SELF__' => __SELF__, // 当前页面地址 - '__URL__' => __URL__, - '../Public' => APP_TMPL_PATH.'Public',// 项目公共模板目录 - '__PUBLIC__' => __ROOT__.'/Public',// 站点公共目录 - ); - // 允许用户自定义模板的字符串替换 - if(is_array(C('TMPL_PARSE_STRING')) ) - $replace = array_merge($replace,C('TMPL_PARSE_STRING')); - $content = str_replace(array_keys($replace),array_values($replace),$content); - return $content; - } - + +// +---------------------------------------------------------------------- +namespace Think\Behavior; +use Think\Behavior; +defined('THINK_PATH') or exit(); +/** + * 系统行为扩展:模板内容输出替换 + * @category Think + * @package Think + * @subpackage Behavior + * @author liu21st + */ +class ContentReplaceBehavior extends Behavior { + // 行为参数定义 + protected $options = array( + 'TMPL_PARSE_STRING' => array(), + ); + + // 行为扩展的执行入口必须是run + public function run(&$content){ + $content = $this->templateContentReplace($content); + } + + /** + * 模板内容替换 + * @access protected + * @param string $content 模板内容 + * @return string + */ + protected function templateContentReplace($content) { + // 系统默认的特殊变量替换 + $replace = array( + '__ROOT__' => __ROOT__, // 当前网站地址 + '__APP__' => __APP__, // 当前项目地址 + '__MODULE__' => __MODULE__, + '__ACTION__' => __ACTION__, // 当前操作地址 + '__SELF__' => __SELF__, // 当前页面地址 + '__CONTROLLER__'=> __CONTROLLER__, + '__URL__' => __CONTROLLER__, + '__PUBLIC__' => __ROOT__.'/Public',// 站点公共目录 + ); + // 允许用户自定义模板的字符串替换 + if(is_array(C('TMPL_PARSE_STRING')) ) + $replace = array_merge($replace,C('TMPL_PARSE_STRING')); + $content = str_replace(array_keys($replace),array_values($replace),$content); + return $content; + } + } \ No newline at end of file diff --git a/Lib/Behavior/ParseTemplateBehavior.class.php b/ThinkPHP/Library/Think/Behavior/ParseTemplateBehavior.class.php similarity index 35% rename from Lib/Behavior/ParseTemplateBehavior.class.php rename to ThinkPHP/Library/Think/Behavior/ParseTemplateBehavior.class.php index 393bc33df90e70264e8af00bf93c5a5281aa9115..ac1dc57a759dad7cd37c77ccb827d7156d9aec0d 100644 --- a/Lib/Behavior/ParseTemplateBehavior.class.php +++ b/ThinkPHP/Library/Think/Behavior/ParseTemplateBehavior.class.php @@ -1,113 +1,124 @@ - -// +---------------------------------------------------------------------- -// $Id: ParseTemplateBehavior.class.php 3087 2012-07-28 12:29:23Z liu21st@gmail.com $ - -defined('THINK_PATH') or exit(); -/** - +------------------------------------------------------------------------------ - * 系统行为扩展 模板解析 - +------------------------------------------------------------------------------ - */ -class ParseTemplateBehavior extends Behavior { - // 行为参数定义(默认值) 可在项目配置中覆盖 - protected $options = array( - // 布局设置 - 'TMPL_ENGINE_TYPE' => 'Think', // 默认模板引擎 以下设置仅对使用Think模板引擎有效 - 'TMPL_CACHFILE_SUFFIX' => '.php', // 默认模板缓存后缀 - 'TMPL_DENY_FUNC_LIST' => 'echo,exit', // 模板引擎禁用函数 - 'TMPL_DENY_PHP' =>false, // 默认模板引擎是否禁用PHP原生代码 - 'TMPL_L_DELIM' => '{', // 模板引擎普通标签开始标记 - 'TMPL_R_DELIM' => '}', // 模板引擎普通标签结束标记 - 'TMPL_VAR_IDENTIFY' => 'array', // 模板变量识别。留空自动判断,参数为'obj'则表示对象 - 'TMPL_STRIP_SPACE' => true, // 是否去除模板文件里面的html空格与换行 - 'TMPL_CACHE_ON' => true, // 是否开启模板编译缓存,设为false则每次都会重新编译 - 'TMPL_CACHE_TIME' => 0, // 模板缓存有效期 0 为永久,(以数字为值,单位:秒) - 'TMPL_LAYOUT_ITEM' => '{__CONTENT__}', // 布局模板的内容替换标识 - 'LAYOUT_ON' => false, // 是否启用布局 - 'LAYOUT_NAME' => 'layout', // 当前布局名称 默认为layout - - // Think模板引擎标签库相关设定 - 'TAGLIB_BEGIN' => '<', // 标签库标签开始标记 - 'TAGLIB_END' => '>', // 标签库标签结束标记 - 'TAGLIB_LOAD' => true, // 是否使用内置标签库之外的其它标签库,默认自动检测 - 'TAGLIB_BUILD_IN' => 'cx', // 内置标签库名称(标签使用不必指定标签库名称),以逗号分隔 注意解析顺序 - 'TAGLIB_PRE_LOAD' => '', // 需要额外加载的标签库(须指定标签库名称),多个以逗号分隔 - ); - - // 行为扩展的执行入口必须是run - public function run(&$_data){ - $engine = strtolower(C('TMPL_ENGINE_TYPE')); - $_content = empty($_data['content'])?$_data['file']:$_data['content']; - if('think'==$engine){ // 采用Think模板引擎 - if(empty($_data['content']) && $this->checkCache($_data['file'])) { // 缓存有效 - // 分解变量并载入模板缓存 - extract($_data['var'], EXTR_OVERWRITE); - //载入模版缓存文件 - include C('CACHE_PATH').md5($_data['file']).C('TMPL_CACHFILE_SUFFIX'); - }else{ - $tpl = Think::instance('ThinkTemplate'); - // 编译并加载模板文件 - $tpl->fetch($_content,$_data['var']); - } - }else{ - // 调用第三方模板引擎解析和输出 - $class = 'Template'.ucwords($engine); - if(is_file(CORE_PATH.'Driver/Template/'.$class.'.class.php')) { - // 内置驱动 - $path = CORE_PATH; - }else{ // 扩展驱动 - $path = EXTEND_PATH; - } - if(require_cache($path.'Driver/Template/'.$class.'.class.php')) { - $tpl = new $class; - $tpl->fetch($_content,$_data['var']); - }else { // 类没有定义 - throw_exception(L('_NOT_SUPPERT_').': ' . $class); - } - } - } - - /** - +---------------------------------------------------------- - * 检查缓存文件是否有效 - * 如果无效则需要重新编译 - +---------------------------------------------------------- - * @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; - } - // 开启布局模板 - if(C('LAYOUT_ON')) { - $layoutFile = THEME_PATH.C('LAYOUT_NAME').C('TMPL_TEMPLATE_SUFFIX'); - if(filemtime($layoutFile) > filemtime($tmplCacheFile)) { - return false; - } - } - // 缓存有效 - return true; - } -} \ No newline at end of file + +// +---------------------------------------------------------------------- +namespace Think\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模板引擎有效 + 'TMPL_CACHFILE_SUFFIX' => '.php', // 默认模板缓存后缀 + 'TMPL_DENY_FUNC_LIST' => 'echo,exit', // 模板引擎禁用函数 + 'TMPL_DENY_PHP' => false, // 默认模板引擎是否禁用PHP原生代码 + 'TMPL_L_DELIM' => '{', // 模板引擎普通标签开始标记 + 'TMPL_R_DELIM' => '}', // 模板引擎普通标签结束标记 + 'TMPL_VAR_IDENTIFY' => 'array', // 模板变量识别。留空自动判断,参数为'obj'则表示对象 + 'TMPL_STRIP_SPACE' => true, // 是否去除模板文件里面的html空格与换行 + 'TMPL_CACHE_ON' => true, // 是否开启模板编译缓存,设为false则每次都会重新编译 + 'TMPL_CACHE_PREFIX' => '', // 模板缓存前缀标识,可以动态改变 + 'TMPL_CACHE_TIME' => 0, // 模板缓存有效期 0 为永久,(以数字为值,单位:秒) + 'TMPL_LAYOUT_ITEM' => '{__CONTENT__}', // 布局模板的内容替换标识 + 'LAYOUT_ON' => false, // 是否启用布局 + 'LAYOUT_NAME' => 'layout', // 当前布局名称 默认为layout + + // Think模板引擎标签库相关设定 + 'TAGLIB_BEGIN' => '<', // 标签库标签开始标记 + 'TAGLIB_END' => '>', // 标签库标签结束标记 + 'TAGLIB_LOAD' => true, // 是否使用内置标签库之外的其它标签库,默认自动检测 + 'TAGLIB_BUILD_IN' => 'cx', // 内置标签库名称(标签使用不必指定标签库名称),以逗号分隔 注意解析顺序 + 'TAGLIB_PRE_LOAD' => '', // 需要额外加载的标签库(须指定标签库名称),多个以逗号分隔 + ); + + // 行为扩展的执行入口必须是run + public function run(&$_data){ + $engine = strtolower(C('TMPL_ENGINE_TYPE')); + $_content = empty($_data['content'])?$_data['file']:$_data['content']; + $_data['prefix'] = !empty($_data['prefix'])?$_data['prefix']:C('TMPL_CACHE_PREFIX'); + if('think'==$engine){ // 采用Think模板引擎 + if((!empty($_data['content']) && $this->checkContentCache($_data['content'],$_data['prefix'])) + || $this->checkCache($_data['file'],$_data['prefix'])) { // 缓存有效 + // 分解变量并载入模板缓存 + extract($_data['var'], EXTR_OVERWRITE); + //载入模版缓存文件 + Storage::load(C('CACHE_PATH').$_data['prefix'].md5($_content).C('TMPL_CACHFILE_SUFFIX'),'tpl'); + }else{ + $tpl = Think::instance('Think\\Template'); + // 编译并加载模板文件 + $tpl->fetch($_content,$_data['var'],$_data['prefix']); + } + }else{ + // 调用第三方模板引擎解析和输出 + $class = 'Think\\Template\\Driver\\'.ucwords($engine); + if(class_exists($class)) { + $tpl = new $class; + $tpl->fetch($_content,$_data['var']); + }else { // 类没有定义 + E(L('_NOT_SUPPERT_').': ' . $class); + } + } + } + + /** + * 检查缓存文件是否有效 + * 如果无效则需要重新编译 + * @access public + * @param string $tmplTemplateFile 模板文件名 + * @return boolean + */ + protected function checkCache($tmplTemplateFile,$prefix='') { + if (!C('TMPL_CACHE_ON')) // 优先对配置设定检测 + return false; + $tmplCacheFile = C('CACHE_PATH').$prefix.md5($tmplTemplateFile).C('TMPL_CACHFILE_SUFFIX'); + if(!Storage::has($tmplCacheFile,'tpl')){ + return false; + }elseif (filemtime($tmplTemplateFile) > Storage::get($tmplCacheFile,'mtime','tpl')) { + // 模板文件如果有更新则缓存需要更新 + return false; + }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) > Storage::get($tmplCacheFile,'mtime','tpl')) { + return false; + } + } + // 缓存有效 + return true; + } + + /** + * 检查缓存内容是否有效 + * 如果无效则需要重新编译 + * @access public + * @param string $tmplContent 模板内容 + * @return boolean + */ + protected function checkContentCache($tmplContent,$prefix='') { + if(Storage::has(C('CACHE_PATH').$prefix.md5($tmplContent).C('TMPL_CACHFILE_SUFFIX'),'tpl')){ + return true; + }else{ + return false; + } + } +} diff --git a/Lib/Behavior/ReadHtmlCacheBehavior.class.php b/ThinkPHP/Library/Think/Behavior/ReadHtmlCacheBehavior.class.php similarity index 62% rename from Lib/Behavior/ReadHtmlCacheBehavior.class.php rename to ThinkPHP/Library/Think/Behavior/ReadHtmlCacheBehavior.class.php index a1358015df1d109fa0a0f18447086ca60232ee74..56aff6989cbfd2cc785f01760084bfc4183bee72 100644 --- a/Lib/Behavior/ReadHtmlCacheBehavior.class.php +++ b/ThinkPHP/Library/Think/Behavior/ReadHtmlCacheBehavior.class.php @@ -1,127 +1,135 @@ - -// +---------------------------------------------------------------------- -// $Id: ReadHtmlCacheBehavior.class.php 3001 2012-06-15 03:39:19Z liu21st@gmail.com $ - -defined('THINK_PATH') or exit(); -/** - +------------------------------------------------------------------------------ - * 系统行为扩展 静态缓存读取 - +------------------------------------------------------------------------------ - */ -class ReadHtmlCacheBehavior extends Behavior { - protected $options = array( - 'HTML_CACHE_ON'=>false, - 'HTML_CACHE_TIME'=>60, - 'HTML_CACHE_RULES'=>array(), - 'HTML_FILE_SUFFIX'=>'.html', - ); - - // 行为扩展的执行入口必须是run - public function run(&$params){ - // 开启静态缓存 - if(C('HTML_CACHE_ON')) { - $cacheTime = $this->requireHtmlCache(); - if( false !== $cacheTime && $this->checkHTMLCache(HTML_FILE_NAME,$cacheTime)) { //静态页面有效 - // 读取静态页面输出 - readfile(HTML_FILE_NAME); - exit(); - } - } - } - - // 判断是否需要静态缓存 - static private function requireHtmlCache() { - // 分析当前的静态规则 - $htmls = C('HTML_CACHE_RULES'); // 读取静态规则 - if(!empty($htmls)) { - $htmls = array_change_key_case($htmls); - // 静态规则文件定义格式 actionName=>array('静态规则','缓存时间','附加规则') - // 'read'=>array('{id},{name}',60,'md5') 必须保证静态规则的唯一性 和 可判断性 - // 检测静态规则 - $moduleName = strtolower(MODULE_NAME); - $actionName = strtolower(ACTION_NAME); - if(isset($htmls[$moduleName.':'.$actionName])) { - $html = $htmls[$moduleName.':'.$actionName]; // 某个模块的操作的静态规则 - }elseif(isset($htmls[$moduleName.':'])){// 某个模块的静态规则 - $html = $htmls[$moduleName.':']; - }elseif(isset($htmls[$actionName])){ - $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']) && $this->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); - // {ID|FUN} GET变量的简写 - $rule = preg_replace('/{(\w+)\|(\w+)}/e',"\\2(\$_GET['\\1'])",$rule); - $rule = preg_replace('/{(\w+)}/e',"\$_GET['\\1']",$rule); - // 特殊系统变量 - $rule = str_ireplace( - array('{:app}','{:module}','{:action}','{:group}'), - array(APP_NAME,MODULE_NAME,ACTION_NAME,defined('GROUP_NAME')?GROUP_NAME:''), - $rule); - // {|FUN} 单独使用函数 - $rule = preg_replace('/{|(\w+)}/e',"\\1()",$rule); - if(!empty($html[2])) $rule = $html[2]($rule); // 应用附加函数 - $cacheTime = isset($html[1])?$html[1]:C('HTML_CACHE_TIME'); // 缓存有效期 - // 当前缓存文件 - define('HTML_FILE_NAME',HTML_PATH . $rule.C('HTML_FILE_SUFFIX')); - return $cacheTime; - } - } - // 无需缓存 - return false; - } - - /** - +---------------------------------------------------------- - * 检查静态HTML文件是否有效 - * 如果无效需要重新更新 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @param string $cacheFile 静态文件名 - * @param integer $cacheTime 缓存有效期 - +---------------------------------------------------------- - * @return boolen - +---------------------------------------------------------- - */ - static public function checkHTMLCache($cacheFile='',$cacheTime='') { - if(!is_file($cacheFile)){ - return false; - }elseif (filemtime(C('TEMPLATE_NAME')) > filemtime($cacheFile)) { - // 模板文件如果更新静态文件需要更新 - return false; - }elseif(!is_numeric($cacheTime) && function_exists($cacheTime)){ - return $cacheTime($cacheFile); - }elseif ($cacheTime != 0 && time() > filemtime($cacheFile)+$cacheTime) { - // 文件是否在有效期 - return false; - } - //静态文件有效 - 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 + +// +---------------------------------------------------------------------- +namespace Think\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( + 'HTML_CACHE_ON' => false, + 'HTML_CACHE_TIME' => 60, + 'HTML_CACHE_RULES' => array(), + 'HTML_FILE_SUFFIX' => '.html', + ); + + // 行为扩展的执行入口必须是run + public function run(&$params){ + // 开启静态缓存 + if(C('HTML_CACHE_ON')) { + $cacheTime = $this->requireHtmlCache(); + if( false !== $cacheTime && $this->checkHTMLCache(HTML_FILE_NAME,$cacheTime)) { //静态页面有效 + // 读取静态页面输出 + echo Storage::read(HTML_FILE_NAME,'html'); + exit(); + } + } + } + + // 判断是否需要静态缓存 + static private function requireHtmlCache() { + // 分析当前的静态规则 + $htmls = C('HTML_CACHE_RULES'); // 读取静态规则 + if(!empty($htmls)) { + $htmls = array_change_key_case($htmls); + // 静态规则文件定义格式 actionName=>array('静态规则','缓存时间','附加规则') + // 'read'=>array('{id},{name}',60,'md5') 必须保证静态规则的唯一性 和 可判断性 + // 检测静态规则 + $moduleName = strtolower(CONTROLLER_NAME); + $actionName = strtolower(ACTION_NAME); + if(isset($htmls[$moduleName.':'.$actionName])) { + $html = $htmls[$moduleName.':'.$actionName]; // 某个模块的操作的静态规则 + }elseif(isset($htmls[$moduleName.':'])){// 某个模块的静态规则 + $html = $htmls[$moduleName.':']; + }elseif(isset($htmls[$actionName])){ + $html = $htmls[$actionName]; // 所有操作的静态规则 + }elseif(isset($htmls['*'])){ + $html = $htmls['*']; // 全局静态规则 + }elseif(isset($htmls['empty:index']) && !class_exists(CONTROLLER_NAME.'Action')){ + $html = $htmls['empty:index']; // 空模块静态规则 + }elseif(isset($htmls[$moduleName.':_empty']) && self::isEmptyAction(CONTROLLER_NAME,ACTION_NAME)){ + $html = $htmls[$moduleName.':_empty']; // 空操作静态规则 + } + if(!empty($html)) { + // 解读静态规则 + $rule = $html[0]; + // 以$_开头的系统变量 + $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_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}','{:controller}','{:action}','{:module}'), + array(APP_NAME,CONTROLLER_NAME,ACTION_NAME,MODULE_NAME), + $rule); + // {|FUN} 单独使用函数 + $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'); // 缓存有效期 + // 当前缓存文件 + define('HTML_FILE_NAME',HTML_PATH . $rule.C('HTML_FILE_SUFFIX')); + return $cacheTime; + } + } + // 无需缓存 + return false; + } + + /** + * 检查静态HTML文件是否有效 + * 如果无效需要重新更新 + * @access public + * @param string $cacheFile 静态文件名 + * @param integer $cacheTime 缓存有效期 + * @return boolean + */ + static public function checkHTMLCache($cacheFile='',$cacheTime='') { + if(!is_file($cacheFile)){ + return false; + }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 > Storage::get($cacheFile,'mtime','html')+$cacheTime) { + // 文件是否在有效期 + return false; + } + //静态文件有效 + return true; + } + + //检测是否是空操作 + static private function isEmptyAction($module,$action) { + $className = $module.'Action'; + $class = new $className; + return !method_exists($class,$action); + } + +} diff --git a/Lib/Behavior/ShowPageTraceBehavior.class.php b/ThinkPHP/Library/Think/Behavior/ShowPageTraceBehavior.class.php similarity index 63% rename from Lib/Behavior/ShowPageTraceBehavior.class.php rename to ThinkPHP/Library/Think/Behavior/ShowPageTraceBehavior.class.php index d227b5fde759137672e36bcb0e52f5eb46121837..b6d8e38782eaf5b498a22a9095c080fed4ef8bcb 100644 --- a/Lib/Behavior/ShowPageTraceBehavior.class.php +++ b/ThinkPHP/Library/Think/Behavior/ShowPageTraceBehavior.class.php @@ -1,122 +1,130 @@ - -// +---------------------------------------------------------------------- -// $Id: ShowPageTraceBehavior.class.php 3059 2012-07-05 04:37:06Z liu21st@gmail.com $ - -defined('THINK_PATH') or exit(); -/** - +------------------------------------------------------------------------------ - * 系统行为扩展 页面Trace显示输出 - +------------------------------------------------------------------------------ - */ -class ShowPageTraceBehavior extends Behavior { - // 行为参数定义 - protected $options = array( - 'SHOW_PAGE_TRACE'=> false, // 显示页面Trace信息 - 'TRACE_PAGE_TABS'=> array('BASE'=>'基本','FILE'=>'文件','INFO'=>'流程','ERR'=>'错误','SQL'=>'SQL','DEBUG'=>'调试'), // 页面Trace可定制的选项卡 - 'PAGE_TRACE_SAVE'=> false, - ); - - // 行为扩展的执行入口必须是run - public function run(&$params){ - if(!IS_AJAX && C('SHOW_PAGE_TRACE')) { - echo $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:// 调试信息 - $trace[$title] = isset($debug[$name])?$debug[$name]:''; - } - } - 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,$log,$base); - // 调用Trace页面模板 - ob_start(); - include C('TMPL_TRACE_FILE')?C('TMPL_TRACE_FILE'):THINK_PATH.'Tpl/page_trace.tpl'; - return ob_get_clean(); - } - - /** - +---------------------------------------------------------- - * 获取运行时间 - +---------------------------------------------------------- - */ - 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 )'; - } - -} \ No newline at end of file + +// +---------------------------------------------------------------------- +namespace Think\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 { + // 行为参数定义 + 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(!IS_AJAX && C('SHOW_PAGE_TRACE')) { + echo $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]:''; + } + } + } + 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); + // 调用Trace页面模板 + ob_start(); + include C('TMPL_TRACE_FILE')?C('TMPL_TRACE_FILE'):THINK_PATH.'Tpl/page_trace.tpl'; + return ob_get_clean(); + } + + /** + * 获取运行时间 + */ + 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 )'; + } +} diff --git a/Lib/Behavior/ShowRuntimeBehavior.class.php b/ThinkPHP/Library/Think/Behavior/ShowRuntimeBehavior.class.php similarity index 72% rename from Lib/Behavior/ShowRuntimeBehavior.class.php rename to ThinkPHP/Library/Think/Behavior/ShowRuntimeBehavior.class.php index 88c981cf1f3c0d400c4e8cf6c7929f68d6b74b38..ef74ee88552c1ecf2f629bbe80740cda896afc2f 100644 --- a/Lib/Behavior/ShowRuntimeBehavior.class.php +++ b/ThinkPHP/Library/Think/Behavior/ShowRuntimeBehavior.class.php @@ -1,87 +1,85 @@ - -// +---------------------------------------------------------------------- -// $Id: ShowRuntimeBehavior.class.php 3001 2012-06-15 03:39:19Z liu21st@gmail.com $ - -defined('THINK_PATH') or exit(); -/** - +------------------------------------------------------------------------------ - * 系统行为扩展 运行时间信息显示 - +------------------------------------------------------------------------------ - */ -class ShowRuntimeBehavior extends Behavior { - // 行为参数定义 - protected $options = array( - 'SHOW_RUN_TIME' => false, // 运行时间显示 - 'SHOW_ADV_TIME' => false, // 显示详细的运行时间 - 'SHOW_DB_TIMES' => false, // 显示数据库查询和写入次数 - 'SHOW_CACHE_TIMES' => false, // 显示缓存操作次数 - 'SHOW_USE_MEM' => false, // 显示内存开销 - 'SHOW_LOAD_FILE' => false, // 显示加载文件数 - 'SHOW_FUN_TIMES' => false , // 显示函数调用次数 - ); - - // 行为扩展的执行入口必须是run - public function run(&$content){ - if(C('SHOW_RUN_TIME')){ - if(false !== strpos($content,'{__NORUNTIME__}')) { - $content = str_replace('{__NORUNTIME__}','',$content); - }else{ - $runtime = $this->showTime(); - if(strpos($content,'{__RUNTIME__}')) - $content = str_replace('{__RUNTIME__}',$runtime,$content); - else - $content .= $runtime; - } - }else{ - $content = str_replace(array('{__NORUNTIME__}','{__RUNTIME__}'),'',$content); - } - } - - /** - +---------------------------------------------------------- - * 显示运行时间、数据库操作、缓存次数、内存使用信息 - +---------------------------------------------------------- - * @access private - +---------------------------------------------------------- - * @return string - +---------------------------------------------------------- - */ - private function showTime() { - // 显示运行时间 - G('beginTime',$GLOBALS['_beginTime']); - G('viewEndTime'); - $showTime = 'Process: '.G('beginTime','viewEndTime').'s '; - if(C('SHOW_ADV_TIME')) { - // 显示详细运行时间 - $showTime .= '( Load:'.G('beginTime','loadTime').'s Init:'.G('loadTime','initTime').'s Exec:'.G('initTime','viewStartTime').'s Template:'.G('viewStartTime','viewEndTime').'s )'; - } - if(C('SHOW_DB_TIMES') && class_exists('Db',false) ) { - // 显示数据库操作次数 - $showTime .= ' | DB :'.N('db_query').' queries '.N('db_write').' writes '; - } - if(C('SHOW_CACHE_TIMES') && class_exists('Cache',false)) { - // 显示缓存读写次数 - $showTime .= ' | Cache :'.N('cache_read').' gets '.N('cache_write').' writes '; - } - if(MEMORY_LIMIT_ON && C('SHOW_USE_MEM')) { - // 显示内存开销 - $showTime .= ' | UseMem:'. number_format((memory_get_usage() - $GLOBALS['_startUseMems'])/1024).' kb'; - } - if(C('SHOW_LOAD_FILE')) { - $showTime .= ' | LoadFile:'.count(get_included_files()); - } - if(C('SHOW_FUN_TIMES')) { - $fun = get_defined_functions(); - $showTime .= ' | CallFun:'.count($fun['user']).','.count($fun['internal']); - } - return $showTime; - } + +// +---------------------------------------------------------------------- +namespace Think\Behavior; +use Think\Behavior; +defined('THINK_PATH') or exit(); +/** + * 系统行为扩展:运行时间信息显示 + * @category Think + * @package Think + * @subpackage Behavior + * @author liu21st + */ +class ShowRuntimeBehavior extends Behavior { + // 行为参数定义 + protected $options = array( + 'SHOW_RUN_TIME' => false, // 运行时间显示 + 'SHOW_ADV_TIME' => false, // 显示详细的运行时间 + 'SHOW_DB_TIMES' => false, // 显示数据库查询和写入次数 + 'SHOW_CACHE_TIMES' => false, // 显示缓存操作次数 + 'SHOW_USE_MEM' => false, // 显示内存开销 + 'SHOW_LOAD_FILE' => false, // 显示加载文件数 + 'SHOW_FUN_TIMES' => false , // 显示函数调用次数 + ); + + // 行为扩展的执行入口必须是run + public function run(&$content){ + if(C('SHOW_RUN_TIME')){ + if(false !== strpos($content,'{__NORUNTIME__}')) { + $content = str_replace('{__NORUNTIME__}','',$content); + }else{ + $runtime = $this->showTime(); + if(strpos($content,'{__RUNTIME__}')) + $content = str_replace('{__RUNTIME__}',$runtime,$content); + else + $content .= $runtime; + } + }else{ + $content = str_replace(array('{__NORUNTIME__}','{__RUNTIME__}'),'',$content); + } + } + + /** + * 显示运行时间、数据库操作、缓存次数、内存使用信息 + * @access private + * @return string + */ + private function showTime() { + // 显示运行时间 + G('beginTime',$GLOBALS['_beginTime']); + G('viewEndTime'); + $showTime = 'Process: '.G('beginTime','viewEndTime').'s '; + if(C('SHOW_ADV_TIME')) { + // 显示详细运行时间 + $showTime .= '( Load:'.G('beginTime','loadTime').'s Init:'.G('loadTime','initTime').'s Exec:'.G('initTime','viewStartTime').'s Template:'.G('viewStartTime','viewEndTime').'s )'; + } + if(C('SHOW_DB_TIMES') && class_exists('Db',false) ) { + // 显示数据库操作次数 + $showTime .= ' | DB :'.N('db_query').' queries '.N('db_write').' writes '; + } + if(C('SHOW_CACHE_TIMES') && class_exists('Cache',false)) { + // 显示缓存读写次数 + $showTime .= ' | Cache :'.N('cache_read').' gets '.N('cache_write').' writes '; + } + if(MEMORY_LIMIT_ON && C('SHOW_USE_MEM')) { + // 显示内存开销 + $showTime .= ' | UseMem:'. number_format((memory_get_usage() - $GLOBALS['_startUseMems'])/1024).' kb'; + } + if(C('SHOW_LOAD_FILE')) { + $showTime .= ' | LoadFile:'.count(get_included_files()); + } + if(C('SHOW_FUN_TIMES')) { + $fun = get_defined_functions(); + $showTime .= ' | CallFun:'.count($fun['user']).','.count($fun['internal']); + } + return $showTime; + } } \ No newline at end of file diff --git a/Lib/Behavior/TokenBuildBehavior.class.php b/ThinkPHP/Library/Think/Behavior/TokenBuildBehavior.class.php similarity index 67% rename from Lib/Behavior/TokenBuildBehavior.class.php rename to ThinkPHP/Library/Think/Behavior/TokenBuildBehavior.class.php index d069b80da2b6c157c5902bf4d9c6dad6ad9efbb8..049053ab56b8527e83886f6663ca9f737157fa74 100644 --- a/Lib/Behavior/TokenBuildBehavior.class.php +++ b/ThinkPHP/Library/Think/Behavior/TokenBuildBehavior.class.php @@ -1,60 +1,62 @@ - -// +---------------------------------------------------------------------- -// $Id: TokenBuildBehavior.class.php 3083 2012-07-22 16:05:45Z liu21st@gmail.com $ - -defined('THINK_PATH') or exit(); -/** - +------------------------------------------------------------------------------ - * 系统行为扩展 表单令牌生成 - +------------------------------------------------------------------------------ - */ -class TokenBuildBehavior extends Behavior { - // 行为参数定义 - protected $options = array( - 'TOKEN_ON' => false, // 开启令牌验证 - 'TOKEN_NAME' => '__hash__', // 令牌验证的表单隐藏字段名称 - 'TOKEN_TYPE' => 'md5', // 令牌验证哈希规则 - 'TOKEN_RESET' => true, // 令牌错误后是否重置 - ); - - public function run(&$content){ - if(C('TOKEN_ON')) { - if(strpos($content,'{__TOKEN__}')) { - // 指定表单令牌隐藏域位置 - $content = str_replace('{__TOKEN__}',$this->buildToken(),$content); - }elseif(preg_match('/<\/form(\s*)>/is',$content,$match)) { - // 智能生成表单令牌隐藏域 - $content = str_replace($match[0],$this->buildToken().$match[0],$content); - } - }else{ - $content = str_replace('{__TOKEN__}','',$content); - } - } - - // 创建表单令牌 - private function buildToken() { - $tokenName = C('TOKEN_NAME'); - $tokenType = C('TOKEN_TYPE'); - if(!isset($_SESSION[$tokenName])) { - $_SESSION[$tokenName] = array(); - } - // 标识当前页面唯一性 - $tokenKey = md5($_SERVER['REQUEST_URI']); - if(isset($_SESSION[$tokenName][$tokenKey])) {// 相同页面不重复生成session - $tokenValue = $_SESSION[$tokenName][$tokenKey]; - }else{ - $tokenValue = $tokenType(microtime(TRUE)); - $_SESSION[$tokenName][$tokenKey] = $tokenValue; - } - $token = ''; - return $token; - } + +// +---------------------------------------------------------------------- +namespace Think\Behavior; +use Think\Behavior; +defined('THINK_PATH') or exit(); +/** + * 系统行为扩展:表单令牌生成 + * @category Think + * @package Think + * @subpackage Behavior + * @author liu21st + */ +class TokenBuildBehavior extends Behavior { + // 行为参数定义 + protected $options = array( + 'TOKEN_ON' => false, // 开启令牌验证 + 'TOKEN_NAME' => '__hash__', // 令牌验证的表单隐藏字段名称 + 'TOKEN_TYPE' => 'md5', // 令牌验证哈希规则 + 'TOKEN_RESET' => true, // 令牌错误后是否重置 + ); + + public function run(&$content){ + if(C('TOKEN_ON')) { + if(strpos($content,'{__TOKEN__}')) { + // 指定表单令牌隐藏域位置 + $content = str_replace('{__TOKEN__}',$this->buildToken(),$content); + }elseif(preg_match('/<\/form(\s*)>/is',$content,$match)) { + // 智能生成表单令牌隐藏域 + $content = str_replace($match[0],$this->buildToken().$match[0],$content); + } + }else{ + $content = str_replace('{__TOKEN__}','',$content); + } + } + + // 创建表单令牌 + private function buildToken() { + $tokenName = C('TOKEN_NAME'); + $tokenType = C('TOKEN_TYPE'); + if(!isset($_SESSION[$tokenName])) { + $_SESSION[$tokenName] = array(); + } + // 标识当前页面唯一性 + $tokenKey = md5($_SERVER['REQUEST_URI']); + if(isset($_SESSION[$tokenName][$tokenKey])) {// 相同页面不重复生成session + $tokenValue = $_SESSION[$tokenName][$tokenKey]; + }else{ + $tokenValue = $tokenType(microtime(TRUE)); + $_SESSION[$tokenName][$tokenKey] = $tokenValue; + } + $token = ''; + return $token; + } } \ No newline at end of file diff --git a/Lib/Behavior/WriteHtmlCacheBehavior.class.php b/ThinkPHP/Library/Think/Behavior/WriteHtmlCacheBehavior.class.php similarity index 54% rename from Lib/Behavior/WriteHtmlCacheBehavior.class.php rename to ThinkPHP/Library/Think/Behavior/WriteHtmlCacheBehavior.class.php index 8db63a4bd83fb26116699758caa2aa4ea94dfe3f..221fa419cffced3756e59cb5c439e8cae5ad1c2c 100644 --- a/Lib/Behavior/WriteHtmlCacheBehavior.class.php +++ b/ThinkPHP/Library/Think/Behavior/WriteHtmlCacheBehavior.class.php @@ -1,34 +1,31 @@ - -// +---------------------------------------------------------------------- -// $Id: WriteHtmlCacheBehavior.class.php 3001 2012-06-15 03:39:19Z liu21st@gmail.com $ - -defined('THINK_PATH') or exit(); -/** - +------------------------------------------------------------------------------ - * 系统行为扩展 静态缓存写入 - * 增加配置参数如下: - +------------------------------------------------------------------------------ - */ -class WriteHtmlCacheBehavior extends Behavior { - - // 行为扩展的执行入口必须是run - 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),0777,true); - if( false === file_put_contents( HTML_FILE_NAME , $content )) - throw_exception(L('_CACHE_WRITE_ERROR_').':'.HTML_FILE_NAME); - } - } -} \ No newline at end of file + +// +---------------------------------------------------------------------- +namespace Think\Behavior; +use Think\Behavior; +use Think\Storage; +defined('THINK_PATH') or exit(); +/** + * 系统行为扩展:静态缓存写入 + * @category Think + * @package Think + * @subpackage Behavior + * @author liu21st + */ +class WriteHtmlCacheBehavior extends Behavior { + + // 行为扩展的执行入口必须是run + public function run(&$content){ + if(C('HTML_CACHE_ON') && defined('HTML_FILE_NAME')) { + //静态文件写入 + Storage::put(HTML_FILE_NAME , $content,'html'); + } + } +} diff --git a/Lib/Core/Cache.class.php b/ThinkPHP/Library/Think/Cache.class.php similarity index 46% rename from Lib/Core/Cache.class.php rename to ThinkPHP/Library/Think/Cache.class.php index c2d3474988a6574296dcf74b578b7e6eb6229336..ef9e5d846de03b5af94f8cb9383b9f2db2f7616a 100644 --- a/Lib/Core/Cache.class.php +++ b/ThinkPHP/Library/Think/Cache.class.php @@ -1,144 +1,132 @@ - -// +---------------------------------------------------------------------- -// $Id: Cache.class.php 2702 2012-02-02 12:35:01Z liu21st $ - -/** - +------------------------------------------------------------------------------ - * 缓存管理类 - +------------------------------------------------------------------------------ - * @category Think - * @package Think - * @subpackage Util - * @author liu21st - * @version $Id: Cache.class.php 2702 2012-02-02 12:35:01Z liu21st $ - +------------------------------------------------------------------------------ - */ -class Cache { - - /** - +---------------------------------------------------------- - * 是否连接 - +---------------------------------------------------------- - * @var string - * @access protected - +---------------------------------------------------------- - */ - protected $connected ; - - /** - +---------------------------------------------------------- - * 操作句柄 - +---------------------------------------------------------- - * @var string - * @access protected - +---------------------------------------------------------- - */ - protected $handler ; - - /** - +---------------------------------------------------------- - * 缓存连接参数 - +---------------------------------------------------------- - * @var integer - * @access protected - +---------------------------------------------------------- - */ - protected $options = array(); - - /** - +---------------------------------------------------------- - * 连接缓存 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @param string $type 缓存类型 - * @param array $options 配置数组 - +---------------------------------------------------------- - * @return object - +---------------------------------------------------------- - * @throws ThinkExecption - +---------------------------------------------------------- - */ - public function connect($type='',$options=array()) { - if(empty($type)) $type = C('DATA_CACHE_TYPE'); - $type = strtolower(trim($type)); - $class = 'Cache'.ucwords($type); - if(is_file(CORE_PATH.'Driver/Cache/'.$class.'.class.php')) { - // 内置驱动 - $path = CORE_PATH; - }else{ // 扩展驱动 - $path = EXTEND_PATH; - } - if(require_cache($path.'Driver/Cache/'.$class.'.class.php')) - $cache = new $class($options); - else - throw_exception(L('_CACHE_TYPE_INVALID_').':'.$type); - return $cache; - } - - public function __get($name) { - return $this->get($name); - } - - public function __set($name,$value) { - return $this->set($name,$value); - } - - public function __unset($name) { - $this->rm($name); - } - public function setOptions($name,$value) { - $this->options[$name] = $value; - } - - public function getOptions($name) { - return $this->options[$name]; - } - - /** - +---------------------------------------------------------- - * 取得缓存类实例 - +---------------------------------------------------------- - * @static - * @access public - +---------------------------------------------------------- - * @return mixed - +---------------------------------------------------------- - */ - static function getInstance() { - $param = func_get_args(); - return get_instance_of(__CLASS__,'connect',$param); - } - - // 队列缓存 - protected function queue($key) { - static $_handler = array( - 'file'=>array('F','F'), - 'xcache'=>array('xcache_get','xcache_set'), - 'apc'=>array('apc_fetch','apc_store'), - ); - $queue = isset($this->options['queue'])?$this->options['queue']:'file'; - $fun = $_handler[$queue]; - $value = $fun[0]('think_queue'); - if(!$value) { - $value = array(); - } - // 进列 - array_push($value,$key); - if(count($value) > $this->options['length']) { - // 出列 - $key = array_shift($value); - // 删除缓存 - $this->rm($key); - } - return $fun[1]('think_queue',$value); - } + +// +---------------------------------------------------------------------- +namespace Think; +/** + * 缓存管理类 + * @category Think + * @package Think + * @subpackage Core + * @author liu21st + */ +class Cache { + + /** + * 操作句柄 + * @var string + * @access protected + */ + protected $handler ; + + /** + * 缓存连接参数 + * @var integer + * @access protected + */ + protected $options = array(); + + /** + * 连接缓存 + * @access public + * @param string $type 缓存类型 + * @param array $options 配置数组 + * @return object + */ + public function connect($type='',$options=array()) { + if(empty($type)) $type = C('DATA_CACHE_TYPE'); + $type = strtolower(trim($type)); + $class = 'Think\\Cache\\Driver\\'.ucwords($type); + if(class_exists($class)) + $cache = new $class($options); + else + 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); + } + + public function __set($name,$value) { + return $this->set($name,$value); + } + + public function __unset($name) { + $this->rm($name); + } + public function setOptions($name,$value) { + $this->options[$name] = $value; + } + + public function getOptions($name) { + return $this->options[$name]; + } + + /** + * 队列缓存 + * @access protected + * @param string $key 队列名 + * @return mixed + */ + // + protected function queue($key) { + static $_handler = array( + 'file' => array('F','F'), + 'xcache'=> array('xcache_get','xcache_set'), + 'apc' => array('apc_fetch','apc_store'), + ); + $queue = isset($this->options['queue'])?$this->options['queue']:'file'; + $fun = isset($_handler[$queue])?$_handler[$queue]:$_handler['file']; + $queue_name=isset($this->options['queue_name'])?$this->options['queue_name']:'think_queue'; + $value = $fun[0]($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_DEUBG){ + //调试模式下,记录出列次数 + N($queue_name.'_out_times',1,true); + } + } + return $fun[1]($queue_name,$value); + } + + public function __call($method,$args){ + //调用缓存类型自己的方法 + if(method_exists($this->handler, $method)){ + return call_user_func_array(array($this->handler,$method), $args); + }else{ + E(__CLASS__.':'.$method.L('_METHOD_NOT_EXIST_')); + return; + } + } } \ No newline at end of file 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 0000000000000000000000000000000000000000..1e9662a627df7b9123bdf83a872df697128c7282 --- /dev/null +++ b/ThinkPHP/Library/Think/Cache/Driver/Apachenote.class.php @@ -0,0 +1,128 @@ + +// +---------------------------------------------------------------------- +namespace Think\Cache\Driver; +use Think\Cache; +defined('THINK_PATH') or exit(); +/** + * Apachenote缓存驱动 + * @category Extend + * @package Extend + * @subpackage Driver + * @author liu21st + */ +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 0000000000000000000000000000000000000000..c708b287629e12aa2d9ca103c5d92051c519140d --- /dev/null +++ b/ThinkPHP/Library/Think/Cache/Driver/Apc.class.php @@ -0,0 +1,90 @@ + +// +---------------------------------------------------------------------- +namespace Think\Cache\Driver; +use Think\Cache; +defined('THINK_PATH') or exit(); +/** + * Apc缓存驱动 + * @category Extend + * @package Extend + * @subpackage Driver.Cache + * @author liu21st + */ +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 0000000000000000000000000000000000000000..93905597ce72908f33a4ef612c864dbc58d5244b --- /dev/null +++ b/ThinkPHP/Library/Think/Cache/Driver/Db.class.php @@ -0,0 +1,142 @@ + +// +---------------------------------------------------------------------- +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`) + * ); + * @category Extend + * @package Extend + * @subpackage Driver.Cache + * @author liu21st + */ +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 0000000000000000000000000000000000000000..1561ce92d351f0762218d5587151324ba04a39c8 --- /dev/null +++ b/ThinkPHP/Library/Think/Cache/Driver/Eaccelerator.class.php @@ -0,0 +1,81 @@ + +// +---------------------------------------------------------------------- +namespace Think\Cache\Driver; +use Think\Cache; +defined('THINK_PATH') or exit(); +/** + * Eaccelerator缓存驱动 + * @category Extend + * @package Extend + * @subpackage Driver.Cache + * @author liu21st + */ +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/Lib/Driver/Cache/CacheFile.class.php b/ThinkPHP/Library/Think/Cache/Driver/File.class.php similarity index 50% rename from Lib/Driver/Cache/CacheFile.class.php rename to ThinkPHP/Library/Think/Cache/Driver/File.class.php index 4f2601b1a97dac32283de8ec1717cc6cd5560923..8b5c7022f962d474c10c16276ac8b531a7cf9d6b 100644 --- a/Lib/Driver/Cache/CacheFile.class.php +++ b/ThinkPHP/Library/Think/Cache/Driver/File.class.php @@ -1,248 +1,185 @@ - -// +---------------------------------------------------------------------- -// $Id: CacheFile.class.php 3001 2012-06-15 03:39:19Z liu21st@gmail.com $ - -defined('THINK_PATH') or exit(); -/** - +------------------------------------------------------------------------------ - * 文件类型缓存类 - +------------------------------------------------------------------------------ - * @category Think - * @package Think - * @subpackage Util - * @author liu21st - * @version $Id: CacheFile.class.php 3001 2012-06-15 03:39:19Z liu21st@gmail.com $ - +------------------------------------------------------------------------------ - */ -class CacheFile extends Cache { - - /** - +---------------------------------------------------------- - * 缓存存储前缀 - +---------------------------------------------------------- - * @var string - * @access protected - +---------------------------------------------------------- - */ - protected $prefix='~@'; - - /** - +---------------------------------------------------------- - * 架构函数 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - */ - public function __construct($options='') { - if(!empty($options)) { - $this->options = $options; - } - $this->options['temp'] = !empty($options['temp'])?$options['temp']:C('DATA_CACHE_PATH'); - $this->options['expire'] = isset($options['expire'])?$options['expire']:C('DATA_CACHE_TIME'); - $this->options['length'] = isset($options['length'])?$options['length']:0; - if(substr($this->options['temp'], -1) != '/') $this->options['temp'] .= '/'; - $this->connected = is_dir($this->options['temp']) && is_writeable($this->options['temp']); - $this->init(); - } - - /** - +---------------------------------------------------------- - * 初始化检查 - +---------------------------------------------------------- - * @access private - +---------------------------------------------------------- - * @return boolen - +---------------------------------------------------------- - */ - private function init() { - $stat = stat($this->options['temp']); - $dir_perms = $stat['mode'] & 0007777; // Get the permission bits. - $file_perms = $dir_perms & 0000666; // Remove execute bits for files. - - // 创建项目缓存目录 - if (!is_dir($this->options['temp'])) { - if (! mkdir($this->options['temp'])) - return false; - chmod($this->options['temp'], $dir_perms); - } - } - - /** - +---------------------------------------------------------- - * 是否连接 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @return boolen - +---------------------------------------------------------- - */ - private function isConnected() { - return $this->connected; - } - - /** - +---------------------------------------------------------- - * 取得变量的存储文件名 - +---------------------------------------------------------- - * @access private - +---------------------------------------------------------- - * @param string $name 缓存变量名 - +---------------------------------------------------------- - * @return string - +---------------------------------------------------------- - */ - private function filename($name) { - $name = md5($name); - if(C('DATA_CACHE_SUBDIR')) { - // 使用子目录 - $dir =''; - for($i=0;$ioptions['temp'].$dir)) { - mkdir($this->options['temp'].$dir,0777,true); - } - $filename = $dir.$this->prefix.$name.'.php'; - }else{ - $filename = $this->prefix.$name.'.php'; - } - return $this->options['temp'].$filename; - } - - /** - +---------------------------------------------------------- - * 读取缓存 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @param string $name 缓存变量名 - +---------------------------------------------------------- - * @return mixed - +---------------------------------------------------------- - */ - public function get($name) { - $filename = $this->filename($name); - if (!$this->isConnected() || !is_file($filename)) { - return false; - } - N('cache_read',1); - $content = file_get_contents($filename); - if( false !== $content) { - $expire = (int)substr($content,8, 12); - if($expire != 0 && time() > filemtime($filename) + $expire) { - //缓存过期删除缓存文件 - unlink($filename); - return false; - } - if(C('DATA_CACHE_CHECK')) {//开启数据校验 - $check = substr($content,20, 32); - $content = substr($content,52, -3); - if($check != md5($content)) {//校验错误 - return false; - } - }else { - $content = substr($content,20, -3); - } - 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 int $expire 有效时间 0为永久 - +---------------------------------------------------------- - * @return boolen - +---------------------------------------------------------- - */ - public function set($name,$value,$expire=null) { - N('cache_write',1); - if(is_null($expire)) { - $expire = $this->options['expire']; - } - $filename = $this->filename($name); - $data = serialize($value); - if( C('DATA_CACHE_COMPRESS') && function_exists('gzcompress')) { - //数据压缩 - $data = gzcompress($data,3); - } - if(C('DATA_CACHE_CHECK')) {//开启数据校验 - $check = md5($data); - }else { - $check = ''; - } - $data = ""; - $result = file_put_contents($filename,$data); - if($result) { - if($this->options['length']>0) { - // 记录缓存队列 - $this->queue($name); - } - clearstatcache(); - return true; - }else { - return false; - } - } - - /** - +---------------------------------------------------------- - * 删除缓存 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @param string $name 缓存变量名 - +---------------------------------------------------------- - * @return boolen - +---------------------------------------------------------- - */ - public function rm($name) { - return unlink($this->filename($name)); - } - - /** - +---------------------------------------------------------- - * 清除缓存 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @param string $name 缓存变量名 - +---------------------------------------------------------- - * @return boolen - +---------------------------------------------------------- - */ - public function clear() { - $path = $this->options['temp']; - if ( $dir = opendir( $path ) ) { - while ( $file = readdir( $dir ) ) { - $check = is_dir( $file ); - if ( !$check ) - unlink( $path . $file ); - } - closedir( $dir ); - return true; - } - } - + +// +---------------------------------------------------------------------- +namespace Think\Cache\Driver; +use Think\Cache; +defined('THINK_PATH') or exit(); +/** + * 文件类型缓存类 + * @category Think + * @package Think + * @subpackage Driver.Cache + * @author liu21st + */ +class File extends Cache { + + /** + * 架构函数 + * @access public + */ + public function __construct($options=array()) { + if(!empty($options)) { + $this->options = $options; + } + $this->options['temp'] = !empty($options['temp'])? $options['temp'] : C('DATA_CACHE_PATH'); + $this->options['prefix'] = isset($options['prefix'])? $options['prefix'] : C('DATA_CACHE_PREFIX'); + $this->options['expire'] = isset($options['expire'])? $options['expire'] : C('DATA_CACHE_TIME'); + $this->options['length'] = isset($options['length'])? $options['length'] : 0; + if(substr($this->options['temp'], -1) != '/') $this->options['temp'] .= '/'; + $this->init(); + } + + /** + * 初始化检查 + * @access private + * @return boolen + */ + private function init() { + // 创建项目缓存目录 + if (!is_dir($this->options['temp'])) { + mkdir($this->options['temp']); + } + } + + /** + * 取得变量的存储文件名 + * @access private + * @param string $name 缓存变量名 + * @return string + */ + private function filename($name) { + $name = md5($name); + if(C('DATA_CACHE_SUBDIR')) { + // 使用子目录 + $dir =''; + for($i=0;$ioptions['temp'].$dir)) { + mkdir($this->options['temp'].$dir,0755,true); + } + $filename = $dir.$this->options['prefix'].$name.'.php'; + }else{ + $filename = $this->options['prefix'].$name.'.php'; + } + return $this->options['temp'].$filename; + } + + /** + * 读取缓存 + * @access public + * @param string $name 缓存变量名 + * @return mixed + */ + public function get($name) { + $filename = $this->filename($name); + if (!is_file($filename)) { + return false; + } + N('cache_read',1); + $content = file_get_contents($filename); + if( false !== $content) { + $expire = (int)substr($content,8, 12); + if($expire != 0 && time() > filemtime($filename) + $expire) { + //缓存过期删除缓存文件 + unlink($filename); + return false; + } + if(C('DATA_CACHE_CHECK')) {//开启数据校验 + $check = substr($content,20, 32); + $content = substr($content,52, -3); + if($check != md5($content)) {//校验错误 + return false; + } + }else { + $content = substr($content,20, -3); + } + 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 int $expire 有效时间 0为永久 + * @return boolen + */ + public function set($name,$value,$expire=null) { + N('cache_write',1); + if(is_null($expire)) { + $expire = $this->options['expire']; + } + $filename = $this->filename($name); + $data = serialize($value); + if( C('DATA_CACHE_COMPRESS') && function_exists('gzcompress')) { + //数据压缩 + $data = gzcompress($data,3); + } + if(C('DATA_CACHE_CHECK')) {//开启数据校验 + $check = md5($data); + }else { + $check = ''; + } + $data = ""; + $result = file_put_contents($filename,$data); + if($result) { + if($this->options['length']>0) { + // 记录缓存队列 + $this->queue($name); + } + clearstatcache(); + return true; + }else { + return false; + } + } + + /** + * 删除缓存 + * @access public + * @param string $name 缓存变量名 + * @return boolen + */ + public function rm($name) { + return unlink($this->filename($name)); + } + + /** + * 清除缓存 + * @access public + * @param string $name 缓存变量名 + * @return boolen + */ + public function clear() { + $path = $this->options['temp']; + $files = scandir($path); + if($files){ + foreach($files as $file){ + if ($file != '.' && $file != '..' && is_dir($path.$file) ){ + array_map( 'unlink', glob( $path.$file.'/*.*' ) ); + }elseif(is_file($path.$file)){ + unlink( $path . $file ); + } + } + return true; + } + return false; + } } \ No newline at end of file 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 0000000000000000000000000000000000000000..bb4c40c51e9e3df54178d8e4272c723fa0219a4c --- /dev/null +++ b/ThinkPHP/Library/Think/Cache/Driver/Memcache.class.php @@ -0,0 +1,107 @@ + +// +---------------------------------------------------------------------- +namespace Think\Cache\Driver; +use Think\Cache; +defined('THINK_PATH') or exit(); +/** + * Memcache缓存驱动 + * @category Extend + * @package Extend + * @subpackage Driver.Cache + * @author liu21st + */ +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/Redis.class.php b/ThinkPHP/Library/Think/Cache/Driver/Redis.class.php new file mode 100644 index 0000000000000000000000000000000000000000..d5a63f521646dac7abe17a8dda19547ba4347952 --- /dev/null +++ b/ThinkPHP/Library/Think/Cache/Driver/Redis.class.php @@ -0,0 +1,112 @@ + +// +---------------------------------------------------------------------- +namespace Think\Cache\Driver; +use Think\Cache; +defined('THINK_PATH') or exit(); + +/** + * Redis缓存驱动 + * 要求安装phpredis扩展:https://github.com/nicolasff/phpredis + * @category Extend + * @package Extend + * @subpackage Driver.Cache + * @author 尘缘 <130775@qq.com> + */ +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 0000000000000000000000000000000000000000..a265889dc3aa737cb14ea41a8bf56b722093d617 --- /dev/null +++ b/ThinkPHP/Library/Think/Cache/Driver/Shmop.class.php @@ -0,0 +1,190 @@ + +// +---------------------------------------------------------------------- +namespace Think\Cache\Driver; +use Think\Cache; +defined('THINK_PATH') or exit(); +/** + * Shmop缓存驱动 + * @category Extend + * @package Extend + * @subpackage Driver.Cache + * @author liu21st + */ +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 0000000000000000000000000000000000000000..5f0d08555964da95f86b23fcf318518e65b20a3e --- /dev/null +++ b/ThinkPHP/Library/Think/Cache/Driver/Sqlite.class.php @@ -0,0 +1,123 @@ + +// +---------------------------------------------------------------------- +namespace Think\Cache\Driver; +use Think\Cache; +defined('THINK_PATH') or exit(); +/** + * Sqlite缓存驱动 + * @category Extend + * @package Extend + * @subpackage Driver.Cache + * @author liu21st + */ +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 0000000000000000000000000000000000000000..bb2df568cc847988183d061a16b327b971c6e636 --- /dev/null +++ b/ThinkPHP/Library/Think/Cache/Driver/Wincache.class.php @@ -0,0 +1,83 @@ + +// +---------------------------------------------------------------------- +namespace Think\Cache\Driver; +use Think\Cache; +defined('THINK_PATH') or exit(); +/** + * Wincache缓存驱动 + * @category Extend + * @package Extend + * @subpackage Driver.Cache + * @author liu21st + */ +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 0000000000000000000000000000000000000000..6a030c5e576da6ffa6d9a132d6f72d0786464ab9 --- /dev/null +++ b/ThinkPHP/Library/Think/Cache/Driver/Xcache.class.php @@ -0,0 +1,85 @@ + +// +---------------------------------------------------------------------- +namespace Think\Cache\Driver; +use Think\Cache; +defined('THINK_PATH') or exit(); +/** + * Xcache缓存驱动 + * @category Extend + * @package Extend + * @subpackage Driver.Cache + * @author liu21st + */ +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/Lib/Core/Db.class.php b/ThinkPHP/Library/Think/Db.class.php similarity index 52% rename from Lib/Core/Db.class.php rename to ThinkPHP/Library/Think/Db.class.php index 2b707be31325880df3a0a8725870c8d65647b619..7d79e12dee2013db889a7ca5ac0851aee55fd21e 100644 --- a/Lib/Core/Db.class.php +++ b/ThinkPHP/Library/Think/Db.class.php @@ -1,1035 +1,927 @@ - -// +---------------------------------------------------------------------- -// $Id: Db.class.php 3089 2012-07-31 07:59:29Z liu21st@gmail.com $ - -/** - +------------------------------------------------------------------------------ - * ThinkPHP 数据库中间层实现类 - +------------------------------------------------------------------------------ - * @category Think - * @package Think - * @subpackage Db - * @author liu21st - * @version $Id: Db.class.php 3089 2012-07-31 07:59:29Z liu21st@gmail.com $ - +------------------------------------------------------------------------------ - */ -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'); - // 查询表达式 - protected $selectSql = 'SELECT%DISTINCT% %FIELD% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%%ORDER%%LIMIT% %UNION%'; - - /** - +---------------------------------------------------------- - * 取得数据库类实例 - +---------------------------------------------------------- - * @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 - +---------------------------------------------------------- - * @throws ThinkExecption - +---------------------------------------------------------- - */ - 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(is_file(CORE_PATH.'Driver/Db/'.$class.'.class.php')) { - // 内置驱动 - $path = CORE_PATH; - }else{ // 扩展驱动 - $path = EXTEND_PATH; - } - // 检查驱动类 - if(require_cache($path.'Driver/Db/'.$class.'.class.php')) { - $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){ - $value = $this->parseValue($val); - if(is_scalar($value)) // 过滤非标量数据 - $set[] = $this->parseKey($key).'='.$value; - } - return ' SET '.implode(',',$set); - } - - /** - +---------------------------------------------------------- - * 字段名分析 - +---------------------------------------------------------- - * @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{ // 使用数组或者对象条件表达式 - if(isset($where['_logic'])) { - // 定义逻辑运算规则 例如 OR XOR AND NOT - $operate = ' '.strtoupper($where['_logic']).' '; - unset($where['_logic']); - }else{ - // 默认进行 AND 运算 - $operate = ' AND '; - } - foreach ($where as $key=>$val){ - $whereStr .= '( '; - 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'; - $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); - if(in_array(strtoupper(trim($val[$count-1])),array('AND','OR','XOR'))) { - $rule = strtoupper(trim($val[$count-1])); - $count = $count -1; - }else{ - $rule = 'AND'; - } - for($i=0;$i<$count;$i++) { - $data = is_array($val[$i])?$val[$i][1]:$val[$i]; - if('exp'==strtolower($val[$i][0])) { - $whereStr .= '('.$key.' '.$data.') '.$rule.' '; - }else{ - $op = is_array($val[$i])?$this->comparison[strtolower($val[$i][0])]:'='; - $whereStr .= '('.$key.' '.$op.' '.$this->parseValue($data).') '.$rule.' '; - } - } - $whereStr = substr($whereStr,0,-4); - } - }else { - //对字符串类型字段采用模糊匹配 - 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 = 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:''; - } - - /** - +---------------------------------------------------------- - * 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){ - $value = $this->parseValue($val); - if(is_scalar($value)) { // 过滤非标量数据 - $values[] = $value; - $fields[] = $this->parseKey($key); - } - } - $sql = ($replace?'REPLACE':'INSERT').' INTO '.$this->parseTable($options['table']).' ('.implode(',', $fields).') VALUES ('.implode(',', $values).')'; - $sql .= $this->parseLock(isset($options['lock'])?$options['lock']:false); - return $this->execute($sql); - } - - /** - +---------------------------------------------------------- - * 通过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); - } - - /** - +---------------------------------------------------------- - * 更新记录 - +---------------------------------------------------------- - * @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(isset($options['where'])?$options['where']:'') - .$this->parseOrder(isset($options['order'])?$options['order']:'') - .$this->parseLimit(isset($options['limit'])?$options['limit']:'') - .$this->parseLock(isset($options['lock'])?$options['lock']:false); - 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(isset($options['where'])?$options['where']:'') - .$this->parseOrder(isset($options['order'])?$options['order']:'') - .$this->parseLimit(isset($options['limit'])?$options['limit']:'') - .$this->parseLock(isset($options['lock'])?$options['lock']:false); - return $this->execute($sql); - } - - /** - +---------------------------------------------------------- - * 查找记录 - +---------------------------------------------------------- - * @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['type']); - if(false !== $value) { - return $value; - } - } - $result = $this->query($sql); - if($cache && false !== $result ) { // 查询缓存写入 - S($key,$result,$cache['expire'],$cache['type']); - } - 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,0,'',array('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%'), - array( - $this->parseTable($options['table']), - $this->parseDistinct(isset($options['distinct'])?$options['distinct']:false), - $this->parseField(isset($options['field'])?$options['field']:'*'), - $this->parseJoin(isset($options['join'])?$options['join']:''), - $this->parseWhere(isset($options['where'])?$options['where']:''), - $this->parseGroup(isset($options['group'])?$options['group']:''), - $this->parseHaving(isset($options['having'])?$options['having']:''), - $this->parseOrder(isset($options['order'])?$options['order']:''), - $this->parseLimit(isset($options['limit'])?$options['limit']:''), - $this->parseUnion(isset($options['union'])?$options['union']:'') - ),$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); - } - - 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 数据库中间层实现类 + * @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($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_')); + // 数据库类型 + $this->dbType = ucwords(strtolower($db_config['dbms'])); + $class = 'Think\\Db\\Driver\\'. $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 { + // 类没有定义 + 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')); + } + 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))){ + 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])?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)) { + 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_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 0000000000000000000000000000000000000000..c985065320dbe24e9c0c4866de945dfb66d3d889 --- /dev/null +++ b/ThinkPHP/Library/Think/Db/Driver/Ibase.class.php @@ -0,0 +1,339 @@ + +// +---------------------------------------------------------------------- +namespace Think\Db\Driver; +use Think\Db; +defined('THINK_PATH') or exit(); +/** + * Firebird数据库驱动 + * @category Extend + * @package Extend + * @subpackage Driver.Db + * @author 剑雷 + */ +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 ThinkExecption + */ + 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 0000000000000000000000000000000000000000..4acfff67544e9c220f79e0c2b53cc0e7037c1dc7 --- /dev/null +++ b/ThinkPHP/Library/Think/Db/Driver/Mongo.class.php @@ -0,0 +1,757 @@ + +// +---------------------------------------------------------------------- +namespace Think\Db\Driver; +use Think\Db; +defined('THINK_PATH') or exit(); +/** + * Mongo数据库驱动 必须配合MongoModel使用 + * @category Extend + * @package Extend + * @subpackage Driver.Db + * @author liu21st + */ +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 0000000000000000000000000000000000000000..6a67138c9fb95fd894e819f91d7a7091d3932c68 --- /dev/null +++ b/ThinkPHP/Library/Think/Db/Driver/Mssql.class.php @@ -0,0 +1,335 @@ + +// +---------------------------------------------------------------------- +namespace Think\Db\Driver; +use Think\Db; +defined('THINK_PATH') or exit(); +/** + * MSsql数据库驱动 要求sqlserver2005 + * @category Extend + * @package Extend + * @subpackage Driver.Db + * @author liu21st + */ +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/Lib/Driver/Db/DbMysql.class.php b/ThinkPHP/Library/Think/Db/Driver/Mysql.class.php similarity index 59% rename from Lib/Driver/Db/DbMysql.class.php rename to ThinkPHP/Library/Think/Db/Driver/Mysql.class.php index cbd36f0e1d370f56546826b2a6f341ca3de90b2c..77b8ab0ee2cf883b3bb9eb3f47e6f34d21f74eb5 100644 --- a/Lib/Driver/Db/DbMysql.class.php +++ b/ThinkPHP/Library/Think/Db/Driver/Mysql.class.php @@ -1,433 +1,351 @@ - -// +---------------------------------------------------------------------- -// $Id: DbMysql.class.php 3059 2012-07-05 04:37:06Z liu21st@gmail.com $ - -defined('THINK_PATH') or exit(); -define('CLIENT_MULTI_RESULTS', 131072); -/** - +------------------------------------------------------------------------------ - * Mysql数据库驱动类 - +------------------------------------------------------------------------------ - * @category Think - * @package Think - * @subpackage Db - * @author liu21st - * @version $Id: DbMysql.class.php 3059 2012-07-05 04:37:06Z liu21st@gmail.com $ - +------------------------------------------------------------------------------ - */ -class DbMysql extends Db{ - - /** - +---------------------------------------------------------- - * 架构函数 读取数据库配置信息 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @param array $config 数据库配置数组 - +---------------------------------------------------------- - */ - public function __construct($config=''){ - if ( !extension_loaded('mysql') ) { - throw_exception(L('_NOT_SUPPERT_').':mysql'); - } - if(!empty($config)) { - $this->config = $config; - if(empty($this->config['params'])) { - $this->config['params'] = ''; - } - } - } - - /** - +---------------------------------------------------------- - * 连接数据库方法 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @throws ThinkExecption - +---------------------------------------------------------- - */ - public function connect($config='',$linkNum=0,$force=false) { - if ( !isset($this->linkID[$linkNum]) ) { - if(empty($config)) $config = $this->config; - // 处理不带端口号的socket连接情况 - $host = $config['hostname'].($config['hostport']?":{$config['hostport']}":''); - // 是否长连接 - $pconnect = !empty($config['params']['persist'])? $config['params']['persist']:$this->pconnect; - if($pconnect) { - $this->linkID[$linkNum] = mysql_pconnect( $host, $config['username'], $config['password'],CLIENT_MULTI_RESULTS); - }else{ - $this->linkID[$linkNum] = mysql_connect( $host, $config['username'], $config['password'],true,CLIENT_MULTI_RESULTS); - } - if ( !$this->linkID[$linkNum] || (!empty($config['database']) && !mysql_select_db($config['database'], $this->linkID[$linkNum])) ) { - throw_exception(mysql_error()); - } - $dbVersion = mysql_get_server_info($this->linkID[$linkNum]); - if ($dbVersion >= '4.1') { - //使用UTF8存取数据库 需要mysql 4.1.0以上支持 - mysql_query("SET NAMES '".C('DB_CHARSET')."'", $this->linkID[$linkNum]); - } - //设置 sql_model - if($dbVersion >'5.0.1'){ - mysql_query("SET sql_mode=''",$this->linkID[$linkNum]); - } - // 标记连接成功 - $this->connected = true; - // 注销数据库连接配置信息 - if(1 != C('DB_DEPLOY_TYPE')) unset($this->config); - } - return $this->linkID[$linkNum]; - } - - /** - +---------------------------------------------------------- - * 释放查询结果 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - */ - public function free() { - mysql_free_result($this->queryID); - $this->queryID = null; - } - - /** - +---------------------------------------------------------- - * 执行查询 返回数据集 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @param string $str sql指令 - +---------------------------------------------------------- - * @return mixed - +---------------------------------------------------------- - * @throws ThinkExecption - +---------------------------------------------------------- - */ - public function query($str) { - if(0===stripos($str, 'call')){ // 存储过程查询支持 - $this->close(); - } - $this->initConnect(false); - if ( !$this->_linkID ) return false; - $this->queryStr = $str; - //释放前次的查询结果 - if ( $this->queryID ) { $this->free(); } - N('db_query',1); - // 记录开始执行时间 - G('queryStartTime'); - $this->queryID = mysql_query($str, $this->_linkID); - $this->debug(); - if ( false === $this->queryID ) { - $this->error(); - return false; - } else { - $this->numRows = mysql_num_rows($this->queryID); - return $this->getAll(); - } - } - - /** - +---------------------------------------------------------- - * 执行语句 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @param string $str sql指令 - +---------------------------------------------------------- - * @return integer - +---------------------------------------------------------- - * @throws ThinkExecption - +---------------------------------------------------------- - */ - 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 = mysql_query($str, $this->_linkID) ; - $this->debug(); - if ( false === $result) { - $this->error(); - return false; - } else { - $this->numRows = mysql_affected_rows($this->_linkID); - $this->lastInsID = mysql_insert_id($this->_linkID); - return $this->numRows; - } - } - - /** - +---------------------------------------------------------- - * 启动事务 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @return void - +---------------------------------------------------------- - * @throws ThinkExecption - +---------------------------------------------------------- - */ - public function startTrans() { - $this->initConnect(true); - if ( !$this->_linkID ) return false; - //数据rollback 支持 - if ($this->transTimes == 0) { - mysql_query('START TRANSACTION', $this->_linkID); - } - $this->transTimes++; - return ; - } - - /** - +---------------------------------------------------------- - * 用于非自动提交状态下面的查询提交 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @return boolen - +---------------------------------------------------------- - * @throws ThinkExecption - +---------------------------------------------------------- - */ - public function commit() { - if ($this->transTimes > 0) { - $result = mysql_query('COMMIT', $this->_linkID); - $this->transTimes = 0; - if(!$result){ - throw_exception($this->error()); - } - } - return true; - } - - /** - +---------------------------------------------------------- - * 事务回滚 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @return boolen - +---------------------------------------------------------- - * @throws ThinkExecption - +---------------------------------------------------------- - */ - public function rollback() { - if ($this->transTimes > 0) { - $result = mysql_query('ROLLBACK', $this->_linkID); - $this->transTimes = 0; - if(!$result){ - throw_exception($this->error()); - } - } - return true; - } - - /** - +---------------------------------------------------------- - * 获得所有的查询数据 - +---------------------------------------------------------- - * @access private - +---------------------------------------------------------- - * @return array - +---------------------------------------------------------- - * @throws ThinkExecption - +---------------------------------------------------------- - */ - private function getAll() { - //返回数据集 - $result = array(); - if($this->numRows >0) { - while($row = mysql_fetch_assoc($this->queryID)){ - $result[] = $row; - } - mysql_data_seek($this->queryID,0); - } - return $result; - } - - /** - +---------------------------------------------------------- - * 取得数据表的字段信息 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - */ - public function getFields($tableName) { - $result = $this->query('SHOW COLUMNS FROM '.$this->parseKey($tableName)); - $info = array(); - if($result) { - foreach ($result as $key => $val) { - $info[$val['Field']] = array( - 'name' => $val['Field'], - 'type' => $val['Type'], - 'notnull' => (bool) ($val['Null'] === ''), // not null is empty, null is yes - 'default' => $val['Default'], - 'primary' => (strtolower($val['Key']) == 'pri'), - 'autoinc' => (strtolower($val['Extra']) == 'auto_increment'), - ); - } - } - return $info; - } - - /** - +---------------------------------------------------------- - * 取得数据库的表信息 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - */ - public function getTables($dbName='') { - if(!empty($dbName)) { - $sql = 'SHOW TABLES FROM '.$dbName; - }else{ - $sql = 'SHOW TABLES '; - } - $result = $this->query($sql); - $info = array(); - foreach ($result as $key => $val) { - $info[$key] = current($val); - } - return $info; - } - - /** - +---------------------------------------------------------- - * 替换记录 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @param mixed $data 数据 - * @param array $options 参数表达式 - +---------------------------------------------------------- - * @return false | integer - +---------------------------------------------------------- - */ - public function replace($data,$options=array()) { - foreach ($data as $key=>$val){ - $value = $this->parseValue($val); - if(is_scalar($value)) { // 过滤非标量数据 - $values[] = $value; - $fields[] = $this->parseKey($key); - } - } - $sql = 'REPLACE INTO '.$this->parseTable($options['table']).' ('.implode(',', $fields).') VALUES ('.implode(',', $values).')'; - return $this->execute($sql); - } - - /** - +---------------------------------------------------------- - * 插入记录 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @param mixed $datas 数据 - * @param array $options 参数表达式 - * @param boolean $replace 是否replace - +---------------------------------------------------------- - * @return false | integer - +---------------------------------------------------------- - */ - public function insertAll($datas,$options=array(),$replace=false) { - if(!is_array($datas[0])) return false; - $fields = array_keys($datas[0]); - array_walk($fields, array($this, 'parseKey')); - $values = array(); - foreach ($datas as $data){ - $value = array(); - foreach ($data as $key=>$val){ - $val = $this->parseValue($val); - if(is_scalar($val)) { // 过滤非标量数据 - $value[] = $val; - } - } - $values[] = '('.implode(',', $value).')'; - } - $sql = ($replace?'REPLACE':'INSERT').' INTO '.$this->parseTable($options['table']).' ('.implode(',', $fields).') VALUES '.implode(',',$values); - return $this->execute($sql); - } - - /** - +---------------------------------------------------------- - * 关闭数据库 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - */ - public function close() { - if ($this->_linkID){ - mysql_close($this->_linkID); - } - $this->_linkID = null; - } - - /** - +---------------------------------------------------------- - * 数据库错误信息 - * 并显示当前的SQL语句 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @return string - +---------------------------------------------------------- - */ - public function error() { - $this->error = mysql_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) { - if($this->_linkID) { - return mysql_real_escape_string($str,$this->_linkID); - }else{ - return mysql_escape_string($str); - } - } - - /** - +---------------------------------------------------------- - * 字段和表名处理添加` - +---------------------------------------------------------- - * @access protected - +---------------------------------------------------------- - * @param string $key - +---------------------------------------------------------- - * @return string - +---------------------------------------------------------- - */ - protected function parseKey(&$key) { - $key = trim($key); - if(!preg_match('/[,\'\"\*\(\)`.\s]/',$key)) { - $key = '`'.$key.'`'; - } - return $key; - } + +// +---------------------------------------------------------------------- +namespace Think\Db\Driver; +use Think\Db; +defined('THINK_PATH') or exit(); + +/** + * Mysql数据库驱动类 + * @category Think + * @package Think + * @subpackage Driver.Db + * @author liu21st + */ +class Mysql extends Db{ + + /** + * 架构函数 读取数据库配置信息 + * @access public + * @param array $config 数据库配置数组 + */ + public function __construct($config=''){ + if ( !extension_loaded('mysql') ) { + E(L('_NOT_SUPPERT_').':mysql'); + } + if(!empty($config)) { + $this->config = $config; + if(empty($this->config['params'])) { + $this->config['params'] = ''; + } + } + } + + /** + * 连接数据库方法 + * @access public + * @throws ThinkExecption + */ + public function connect($config='',$linkNum=0,$force=false) { + if ( !isset($this->linkID[$linkNum]) ) { + if(empty($config)) $config = $this->config; + // 处理不带端口号的socket连接情况 + $host = $config['hostname'].($config['hostport']?":{$config['hostport']}":''); + // 是否长连接 + $pconnect = !empty($config['params']['persist'])? $config['params']['persist']:$this->pconnect; + if($pconnect) { + $this->linkID[$linkNum] = mysql_pconnect( $host, $config['username'], $config['password'],131072); + }else{ + $this->linkID[$linkNum] = mysql_connect( $host, $config['username'], $config['password'],true,131072); + } + if ( !$this->linkID[$linkNum] || (!empty($config['database']) && !mysql_select_db($config['database'], $this->linkID[$linkNum])) ) { + E(mysql_error()); + } + $dbVersion = mysql_get_server_info($this->linkID[$linkNum]); + //使用UTF8存取数据库 + mysql_query("SET NAMES '".C('DB_CHARSET')."'", $this->linkID[$linkNum]); + //设置 sql_model + if($dbVersion >'5.0.1'){ + mysql_query("SET sql_mode=''",$this->linkID[$linkNum]); + } + // 标记连接成功 + $this->connected = true; + // 注销数据库连接配置信息 + if(1 != C('DB_DEPLOY_TYPE')) unset($this->config); + } + return $this->linkID[$linkNum]; + } + + /** + * 释放查询结果 + * @access public + */ + public function free() { + mysql_free_result($this->queryID); + $this->queryID = null; + } + + /** + * 执行查询 返回数据集 + * @access public + * @param string $str sql指令 + * @return mixed + */ + public function query($str) { + if(0===stripos($str, 'call')){ // 存储过程查询支持 + $this->close(); + $this->connected = false; + } + $this->initConnect(false); + if ( !$this->_linkID ) return false; + $this->queryStr = $str; + //释放前次的查询结果 + if ( $this->queryID ) { $this->free(); } + N('db_query',1); + // 记录开始执行时间 + G('queryStartTime'); + $this->queryID = mysql_query($str, $this->_linkID); + $this->debug(); + if ( false === $this->queryID ) { + $this->error(); + return false; + } else { + $this->numRows = mysql_num_rows($this->queryID); + return $this->getAll(); + } + } + + /** + * 执行语句 + * @access public + * @param string $str sql指令 + * @return integer|false + */ + 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 = mysql_query($str, $this->_linkID) ; + $this->debug(); + if ( false === $result) { + $this->error(); + return false; + } else { + $this->numRows = mysql_affected_rows($this->_linkID); + $this->lastInsID = mysql_insert_id($this->_linkID); + return $this->numRows; + } + } + + /** + * 启动事务 + * @access public + * @return void + */ + public function startTrans() { + $this->initConnect(true); + if ( !$this->_linkID ) return false; + //数据rollback 支持 + if ($this->transTimes == 0) { + mysql_query('START TRANSACTION', $this->_linkID); + } + $this->transTimes++; + return ; + } + + /** + * 用于非自动提交状态下面的查询提交 + * @access public + * @return boolen + */ + public function commit() { + if ($this->transTimes > 0) { + $result = mysql_query('COMMIT', $this->_linkID); + $this->transTimes = 0; + if(!$result){ + $this->error(); + return false; + } + } + return true; + } + + /** + * 事务回滚 + * @access public + * @return boolen + */ + public function rollback() { + if ($this->transTimes > 0) { + $result = mysql_query('ROLLBACK', $this->_linkID); + $this->transTimes = 0; + if(!$result){ + $this->error(); + return false; + } + } + return true; + } + + /** + * 获得所有的查询数据 + * @access private + * @return array + */ + private function getAll() { + //返回数据集 + $result = array(); + if($this->numRows >0) { + while($row = mysql_fetch_assoc($this->queryID)){ + $result[] = $row; + } + mysql_data_seek($this->queryID,0); + } + return $result; + } + + /** + * 取得数据表的字段信息 + * @access public + * @return array + */ + public function getFields($tableName) { + $result = $this->query('SHOW COLUMNS FROM '.$this->parseKey($tableName)); + $info = array(); + if($result) { + foreach ($result as $key => $val) { + $info[$val['Field']] = array( + 'name' => $val['Field'], + 'type' => $val['Type'], + 'notnull' => (bool) (strtoupper($val['Null']) === 'NO'), // 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='') { + 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; + } + + /** + * 替换记录 + * @access public + * @param mixed $data 数据 + * @param array $options 参数表达式 + * @return false | integer + */ + public function replace($data,$options=array()) { + foreach ($data as $key=>$val){ + $value = $this->parseValue($val); + if(is_scalar($value)) { // 过滤非标量数据 + $values[] = $value; + $fields[] = $this->parseKey($key); + } + } + $sql = 'REPLACE INTO '.$this->parseTable($options['table']).' ('.implode(',', $fields).') VALUES ('.implode(',', $values).')'; + return $this->execute($sql); + } + + /** + * 插入记录 + * @access public + * @param mixed $datas 数据 + * @param array $options 参数表达式 + * @param boolean $replace 是否replace + * @return false | integer + */ + public function insertAll($datas,$options=array(),$replace=false) { + if(!is_array($datas[0])) return false; + $fields = array_keys($datas[0]); + array_walk($fields, array($this, 'parseKey')); + $values = array(); + foreach ($datas as $data){ + $value = array(); + foreach ($data as $key=>$val){ + $val = $this->parseValue($val); + if(is_scalar($val)) { // 过滤非标量数据 + $value[] = $val; + } + } + $values[] = '('.implode(',', $value).')'; + } + $sql = ($replace?'REPLACE':'INSERT').' INTO '.$this->parseTable($options['table']).' ('.implode(',', $fields).') VALUES '.implode(',',$values); + return $this->execute($sql); + } + + /** + * 关闭数据库 + * @access public + * @return void + */ + public function close() { + if ($this->_linkID){ + mysql_close($this->_linkID); + } + $this->_linkID = null; + } + + /** + * 数据库错误信息 + * 并显示当前的SQL语句 + * @access public + * @return string + */ + public function error() { + $this->error = mysql_errno().':'.mysql_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) { + if($this->_linkID) { + return mysql_real_escape_string($str,$this->_linkID); + }else{ + return mysql_escape_string($str); + } + } + + /** + * 字段和表名处理添加` + * @access protected + * @param string $key + * @return string + */ + protected function parseKey(&$key) { + $key = trim($key); + if(!preg_match('/[,\'\"\*\(\)`.\s]/',$key)) { + $key = '`'.$key.'`'; + } + return $key; + } } \ No newline at end of file diff --git a/Lib/Driver/Db/DbMysqli.class.php b/ThinkPHP/Library/Think/Db/Driver/Mysqli.class.php similarity index 57% rename from Lib/Driver/Db/DbMysqli.class.php rename to ThinkPHP/Library/Think/Db/Driver/Mysqli.class.php index cc3d055b8db901b46975d5eb6debe9aa60e37325..4b9fdba53d2804573fdb142c0832efcd4135f264 100644 --- a/Lib/Driver/Db/DbMysqli.class.php +++ b/ThinkPHP/Library/Think/Db/Driver/Mysqli.class.php @@ -1,431 +1,346 @@ - -// +---------------------------------------------------------------------- -// $Id: DbMysqli.class.php 3059 2012-07-05 04:37:06Z liu21st@gmail.com $ - -defined('THINK_PATH') or exit(); -/** - +------------------------------------------------------------------------------ - * Mysqli数据库驱动类 - +------------------------------------------------------------------------------ - * @category Think - * @package Think - * @subpackage Db - * @author liu21st - * @version $Id: DbMysqli.class.php 3059 2012-07-05 04:37:06Z liu21st@gmail.com $ - +------------------------------------------------------------------------------ - */ -class DbMysqli extends Db{ - - /** - +---------------------------------------------------------- - * 架构函数 读取数据库配置信息 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @param array $config 数据库配置数组 - +---------------------------------------------------------- - */ - public function __construct($config=''){ - if ( !extension_loaded('mysqli') ) { - throw_exception(L('_NOT_SUPPERT_').':mysqli'); - } - if(!empty($config)) { - $this->config = $config; - if(empty($this->config['params'])) { - $this->config['params'] = ''; - } - } - } - - /** - +---------------------------------------------------------- - * 连接数据库方法 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @throws ThinkExecption - +---------------------------------------------------------- - */ - public function connect($config='',$linkNum=0) { - if ( !isset($this->linkID[$linkNum]) ) { - if(empty($config)) $config = $this->config; - $this->linkID[$linkNum] = new mysqli($config['hostname'],$config['username'],$config['password'],$config['database'],$config['hostport']?intval($config['hostport']):3306); - if (mysqli_connect_errno()) throw_exception(mysqli_connect_error()); - $dbVersion = $this->linkID[$linkNum]->server_version; - if ($dbVersion >= '4.1') { - // 设置数据库编码 需要mysql 4.1.0以上支持 - $this->linkID[$linkNum]->query("SET NAMES '".C('DB_CHARSET')."'"); - } - //设置 sql_model - if($dbVersion >'5.0.1'){ - $this->linkID[$linkNum]->query("SET sql_mode=''"); - } - // 标记连接成功 - $this->connected = true; - //注销数据库安全信息 - if(1 != C('DB_DEPLOY_TYPE')) unset($this->config); - } - return $this->linkID[$linkNum]; - } - - /** - +---------------------------------------------------------- - * 释放查询结果 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - */ - public function free() { - $this->queryID->free_result(); - $this->queryID = null; - } - - /** - +---------------------------------------------------------- - * 执行查询 返回数据集 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @param string $str sql指令 - +---------------------------------------------------------- - * @return mixed - +---------------------------------------------------------- - * @throws ThinkExecption - +---------------------------------------------------------- - */ - 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 = $this->_linkID->query($str); - // 对存储过程改进 - if( $this->_linkID->more_results() ){ - while (($res = $this->_linkID->next_result()) != NULL) { - $res->free_result(); - } - } - $this->debug(); - if ( false === $this->queryID ) { - $this->error(); - return false; - } else { - $this->numRows = $this->queryID->num_rows; - $this->numCols = $this->queryID->field_count; - return $this->getAll(); - } - } - - /** - +---------------------------------------------------------- - * 执行语句 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @param string $str sql指令 - +---------------------------------------------------------- - * @return integer - +---------------------------------------------------------- - * @throws ThinkExecption - +---------------------------------------------------------- - */ - 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 = $this->_linkID->query($str); - $this->debug(); - if ( false === $result ) { - $this->error(); - return false; - } else { - $this->numRows = $this->_linkID->affected_rows; - $this->lastInsID = $this->_linkID->insert_id; - return $this->numRows; - } - } - - /** - +---------------------------------------------------------- - * 启动事务 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @return void - +---------------------------------------------------------- - * @throws ThinkExecption - +---------------------------------------------------------- - */ - public function startTrans() { - $this->initConnect(true); - //数据rollback 支持 - if ($this->transTimes == 0) { - $this->_linkID->autocommit(false); - } - $this->transTimes++; - return ; - } - - /** - +---------------------------------------------------------- - * 用于非自动提交状态下面的查询提交 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @return boolen - +---------------------------------------------------------- - * @throws ThinkExecption - +---------------------------------------------------------- - */ - public function commit() { - if ($this->transTimes > 0) { - $result = $this->_linkID->commit(); - $this->_linkID->autocommit( true); - $this->transTimes = 0; - if(!$result){ - throw_exception($this->error()); - } - } - return true; - } - - /** - +---------------------------------------------------------- - * 事务回滚 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @return boolen - +---------------------------------------------------------- - * @throws ThinkExecption - +---------------------------------------------------------- - */ - public function rollback() { - if ($this->transTimes > 0) { - $result = $this->_linkID->rollback(); - $this->transTimes = 0; - if(!$result){ - throw_exception($this->error()); - } - } - return true; - } - - /** - +---------------------------------------------------------- - * 获得所有的查询数据 - +---------------------------------------------------------- - * @access private - +---------------------------------------------------------- - * @param string $sql sql语句 - +---------------------------------------------------------- - * @return array - +---------------------------------------------------------- - */ - private function getAll() { - //返回数据集 - $result = array(); - if($this->numRows>0) { - //返回数据集 - for($i=0;$i<$this->numRows ;$i++ ){ - $result[$i] = $this->queryID->fetch_assoc(); - } - $this->queryID->data_seek(0); - } - return $result; - } - - /** - +---------------------------------------------------------- - * 取得数据表的字段信息 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @throws ThinkExecption - +---------------------------------------------------------- - */ - public function getFields($tableName) { - $result = $this->query('SHOW COLUMNS FROM '.$this->parseKey($tableName)); - $info = array(); - if($result) { - foreach ($result as $key => $val) { - $info[$val['Field']] = array( - 'name' => $val['Field'], - 'type' => $val['Type'], - 'notnull' => (bool) ($val['Null'] === ''), // not null is empty, null is yes - 'default' => $val['Default'], - 'primary' => (strtolower($val['Key']) == 'pri'), - 'autoinc' => (strtolower($val['Extra']) == 'auto_increment'), - ); - } - } - return $info; - } - - /** - +---------------------------------------------------------- - * 取得数据表的字段信息 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @throws ThinkExecption - +---------------------------------------------------------- - */ - public function getTables($dbName='') { - $sql = !empty($dbName)?'SHOW TABLES FROM '.$dbName:'SHOW TABLES '; - $result = $this->query($sql); - $info = array(); - if($result) { - foreach ($result as $key => $val) { - $info[$key] = current($val); - } - } - return $info; - } - - /** - +---------------------------------------------------------- - * 替换记录 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @param mixed $data 数据 - * @param array $options 参数表达式 - +---------------------------------------------------------- - * @return false | integer - +---------------------------------------------------------- - */ - public function replace($data,$options=array()) { - foreach ($data as $key=>$val){ - $value = $this->parseValue($val); - if(is_scalar($value)) { // 过滤非标量数据 - $values[] = $value; - $fields[] = $this->parseKey($key); - } - } - $sql = 'REPLACE INTO '.$this->parseTable($options['table']).' ('.implode(',', $fields).') VALUES ('.implode(',', $values).')'; - return $this->execute($sql); - } - - /** - +---------------------------------------------------------- - * 插入记录 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @param mixed $datas 数据 - * @param array $options 参数表达式 - * @param boolean $replace 是否replace - +---------------------------------------------------------- - * @return false | integer - +---------------------------------------------------------- - */ - public function insertAll($datas,$options=array(),$replace=false) { - if(!is_array($datas[0])) return false; - $fields = array_keys($datas[0]); - array_walk($fields, array($this, 'parseKey')); - $values = array(); - foreach ($datas as $data){ - $value = array(); - foreach ($data as $key=>$val){ - $val = $this->parseValue($val); - if(is_scalar($val)) { // 过滤非标量数据 - $value[] = $val; - } - } - $values[] = '('.implode(',', $value).')'; - } - $sql = ($replace?'REPLACE':'INSERT').' INTO '.$this->parseTable($options['table']).' ('.implode(',', $fields).') VALUES '.implode(',',$values); - return $this->execute($sql); - } - - /** - +---------------------------------------------------------- - * 关闭数据库 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - */ - public function close() { - if ($this->_linkID){ - $this->_linkID->close(); - } - $this->_linkID = null; - } - - /** - +---------------------------------------------------------- - * 数据库错误信息 - * 并显示当前的SQL语句 - +---------------------------------------------------------- - * @static - * @access public - +---------------------------------------------------------- - * @return string - +---------------------------------------------------------- - */ - public function error() { - $this->error = $this->_linkID->error; - if('' != $this->queryStr){ - $this->error .= "\n [ SQL语句 ] : ".$this->queryStr; - } - trace($this->error,'','ERR'); - return $this->error; - } - - /** - +---------------------------------------------------------- - * SQL指令安全过滤 - +---------------------------------------------------------- - * @static - * @access public - +---------------------------------------------------------- - * @param string $str SQL指令 - +---------------------------------------------------------- - * @return string - +---------------------------------------------------------- - */ - public function escapeString($str) { - if($this->_linkID) { - return $this->_linkID->real_escape_string($str); - }else{ - return addslashes($str); - } - } - - /** - +---------------------------------------------------------- - * 字段和表名处理添加` - +---------------------------------------------------------- - * @access protected - +---------------------------------------------------------- - * @param string $key - +---------------------------------------------------------- - * @return string - +---------------------------------------------------------- - */ - protected function parseKey(&$key) { - $key = trim($key); - if(!preg_match('/[,\'\"\*\(\)`.\s]/',$key)) { - $key = '`'.$key.'`'; - } - return $key; - } + +// +---------------------------------------------------------------------- +namespace Think\Db\Driver; +use Think\Db; +defined('THINK_PATH') or exit(); +/** + * Mysqli数据库驱动类 + * @category Think + * @package Think + * @subpackage Driver.Db + * @author liu21st + */ +class Mysqli extends Db{ + + /** + * 架构函数 读取数据库配置信息 + * @access public + * @param array $config 数据库配置数组 + */ + public function __construct($config=''){ + if ( !extension_loaded('mysqli') ) { + E(L('_NOT_SUPPERT_').':mysqli'); + } + if(!empty($config)) { + $this->config = $config; + if(empty($this->config['params'])) { + $this->config['params'] = ''; + } + } + } + + /** + * 连接数据库方法 + * @access public + * @throws ThinkExecption + */ + 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()) E(mysqli_connect_error()); + $dbVersion = $this->linkID[$linkNum]->server_version; + + // 设置数据库编码 + $this->linkID[$linkNum]->query("SET NAMES '".C('DB_CHARSET')."'"); + //设置 sql_model + if($dbVersion >'5.0.1'){ + $this->linkID[$linkNum]->query("SET sql_mode=''"); + } + // 标记连接成功 + $this->connected = true; + //注销数据库安全信息 + if(1 != C('DB_DEPLOY_TYPE')) unset($this->config); + } + return $this->linkID[$linkNum]; + } + + /** + * 释放查询结果 + * @access public + */ + public function free() { + $this->queryID->free_result(); + $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 = $this->_linkID->query($str); + // 对存储过程改进 + if( $this->_linkID->more_results() ){ + while (($res = $this->_linkID->next_result()) != NULL) { + $res->free_result(); + } + } + $this->debug(); + if ( false === $this->queryID ) { + $this->error(); + return false; + } else { + $this->numRows = $this->queryID->num_rows; + $this->numCols = $this->queryID->field_count; + return $this->getAll(); + } + } + + /** + * 执行语句 + * @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 = $this->_linkID->query($str); + $this->debug(); + if ( false === $result ) { + $this->error(); + return false; + } else { + $this->numRows = $this->_linkID->affected_rows; + $this->lastInsID = $this->_linkID->insert_id; + return $this->numRows; + } + } + + /** + * 启动事务 + * @access public + * @return void + */ + public function startTrans() { + $this->initConnect(true); + //数据rollback 支持 + if ($this->transTimes == 0) { + $this->_linkID->autocommit(false); + } + $this->transTimes++; + return ; + } + + /** + * 用于非自动提交状态下面的查询提交 + * @access public + * @return boolen + */ + public function commit() { + if ($this->transTimes > 0) { + $result = $this->_linkID->commit(); + $this->_linkID->autocommit( true); + $this->transTimes = 0; + if(!$result){ + $this->error(); + return false; + } + } + return true; + } + + /** + * 事务回滚 + * @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 + * @param string $sql sql语句 + * @return array + */ + private function getAll() { + //返回数据集 + $result = array(); + if($this->numRows>0) { + //返回数据集 + for($i=0;$i<$this->numRows ;$i++ ){ + $result[$i] = $this->queryID->fetch_assoc(); + } + $this->queryID->data_seek(0); + } + return $result; + } + + /** + * 取得数据表的字段信息 + * @access public + * @return array + */ + public function getFields($tableName) { + $result = $this->query('SHOW COLUMNS FROM '.$this->parseKey($tableName)); + $info = array(); + if($result) { + foreach ($result as $key => $val) { + $info[$val['Field']] = array( + 'name' => $val['Field'], + 'type' => $val['Type'], + 'notnull' => (bool) ($val['Null'] === ''), // not null is empty, null is yes + 'default' => $val['Default'], + 'primary' => (strtolower($val['Key']) == 'pri'), + 'autoinc' => (strtolower($val['Extra']) == 'auto_increment'), + ); + } + } + return $info; + } + + /** + * 取得数据表的字段信息 + * @access public + * @return array + */ + public function getTables($dbName='') { + $sql = !empty($dbName)?'SHOW TABLES FROM '.$dbName:'SHOW TABLES '; + $result = $this->query($sql); + $info = array(); + if($result) { + foreach ($result as $key => $val) { + $info[$key] = current($val); + } + } + return $info; + } + + /** + * 替换记录 + * @access public + * @param mixed $data 数据 + * @param array $options 参数表达式 + * @return false | integer + */ + public function replace($data,$options=array()) { + foreach ($data as $key=>$val){ + $value = $this->parseValue($val); + if(is_scalar($value)) { // 过滤非标量数据 + $values[] = $value; + $fields[] = $this->parseKey($key); + } + } + $sql = 'REPLACE INTO '.$this->parseTable($options['table']).' ('.implode(',', $fields).') VALUES ('.implode(',', $values).')'; + return $this->execute($sql); + } + + /** + * 插入记录 + * @access public + * @param mixed $datas 数据 + * @param array $options 参数表达式 + * @param boolean $replace 是否replace + * @return false | integer + */ + public function insertAll($datas,$options=array(),$replace=false) { + if(!is_array($datas[0])) return false; + $fields = array_keys($datas[0]); + array_walk($fields, array($this, 'parseKey')); + $values = array(); + foreach ($datas as $data){ + $value = array(); + foreach ($data as $key=>$val){ + $val = $this->parseValue($val); + if(is_scalar($val)) { // 过滤非标量数据 + $value[] = $val; + } + } + $values[] = '('.implode(',', $value).')'; + } + $sql = ($replace?'REPLACE':'INSERT').' INTO '.$this->parseTable($options['table']).' ('.implode(',', $fields).') VALUES '.implode(',',$values); + return $this->execute($sql); + } + + /** + * 关闭数据库 + * @access public + * @return volid + */ + public function close() { + if ($this->_linkID){ + $this->_linkID->close(); + } + $this->_linkID = null; + } + + /** + * 数据库错误信息 + * 并显示当前的SQL语句 + * @static + * @access public + * @return string + */ + public function error() { + $this->error = $this->_linkID->errno.':'.$this->_linkID->error; + if('' != $this->queryStr){ + $this->error .= "\n [ SQL语句 ] : ".$this->queryStr; + } + trace($this->error,'','ERR'); + return $this->error; + } + + /** + * SQL指令安全过滤 + * @static + * @access public + * @param string $str SQL指令 + * @return string + */ + public function escapeString($str) { + if($this->_linkID) { + return $this->_linkID->real_escape_string($str); + }else{ + return addslashes($str); + } + } + + /** + * 字段和表名处理添加` + * @access protected + * @param string $key + * @return string + */ + protected function parseKey(&$key) { + $key = trim($key); + if(!preg_match('/[,\'\"\*\(\)`.\s]/',$key)) { + $key = '`'.$key.'`'; + } + return $key; + } } \ No newline at end of file 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 0000000000000000000000000000000000000000..e4e9312e3cbc03b270ac07b2428a9b543f6c2951 --- /dev/null +++ b/ThinkPHP/Library/Think/Db/Driver/Oracle.class.php @@ -0,0 +1,338 @@ + +// +---------------------------------------------------------------------- +namespace Think\Db\Driver; +use Think\Db; +defined('THINK_PATH') or exit(); +/** + * Oracle数据库驱动 + * @category Extend + * @package Extend + * @subpackage Driver.Db + * @author ZhangXuehun + */ +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 0000000000000000000000000000000000000000..42e737248ce709ed7b25265ac0f73bf989dac4f1 --- /dev/null +++ b/ThinkPHP/Library/Think/Db/Driver/Pdo.class.php @@ -0,0 +1,478 @@ + +// +---------------------------------------------------------------------- +namespace Think\Db\Driver; +use Think\Db; +use PDO; +defined('THINK_PATH') or exit(); +/** + * PDO数据库驱动 + * @category Extend + * @package Extend + * @subpackage Driver.Db + * @author liu21st + */ +class Pdo extends Db{ + + protected $PDOStatement = null; + private $table = ''; + + /** + * 架构函数 读取数据库配置信息 + * @access public + * @param array $config 数据库配置数组 + */ + public function __construct($config=''){ + if ( !class_exists('PDO') ) { + throw_exception(L('_NOT_SUPPERT_').':PDO'); + } + 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()); + $result = $this->PDOStatement->execute($bind); + $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) . "'"); + } + }//modify by wyfeng at 2009.08.28 + //释放前次的查询结果 + 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()); + } + $result = $this->PDOStatement->execute($bind); + $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 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 0000000000000000000000000000000000000000..3d252d073cf28baac2fb59b935f1d43caed335f7 --- /dev/null +++ b/ThinkPHP/Library/Think/Db/Driver/Pgsql.class.php @@ -0,0 +1,301 @@ + +// +---------------------------------------------------------------------- +namespace Think\Db\Driver; +use Think\Db; +defined('THINK_PATH') or exit(); +/** + * Pgsql数据库驱动 + * @category Extend + * @package Extend + * @subpackage Driver.Db + * @author liu21st + */ +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 0000000000000000000000000000000000000000..7f56ca103a21ceedd856b5b136226f1b07daa47c --- /dev/null +++ b/ThinkPHP/Library/Think/Db/Driver/Sqlite.class.php @@ -0,0 +1,286 @@ + +// +---------------------------------------------------------------------- +namespace Think\Db\Driver; +use Think\Db; +defined('THINK_PATH') or exit(); +/** + * Sqlite数据库驱动 + * @category Extend + * @package Extend + * @subpackage Driver.Db + * @author liu21st + */ +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 0000000000000000000000000000000000000000..136cf939706a1d6a4821942ee270c7966af2ef79 --- /dev/null +++ b/ThinkPHP/Library/Think/Db/Driver/Sqlsrv.class.php @@ -0,0 +1,353 @@ + +// +---------------------------------------------------------------------- +namespace Think\Db\Driver; +use Think\Db; +defined('THINK_PATH') or exit(); +/** + * Sqlsrv数据库驱动 + * @category Extend + * @package Extend + * @subpackage Driver.Db + * @author liu21st + */ +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 0000000000000000000000000000000000000000..19044183dfa2aac02318618180df4fd2ddc5c8e5 --- /dev/null +++ b/ThinkPHP/Library/Think/Dispatcher.class.php @@ -0,0 +1,279 @@ + +// +---------------------------------------------------------------------- +namespace Think; +/** + * ThinkPHP内置的Dispatcher类 + * 完成URL解析、路由和调度 + * @category Think + * @package Think + * @subpackage Core + * @author liu21st + */ +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配置 + $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]); + $controller = array_pop($array); + if(!empty($controller)) { + $_GET[$varController] = $controller; + $domainController = true; + } + if(!empty($array)) { + $_GET[$varModule] = array_pop($array); + define('BIND_MODULE',$_GET[$varModule]); + $domainModule = true; + } + if(isset($rule[1])) { // 传入参数 + parse_str($rule[1],$parms); + $_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'],'/')); + // URL后缀 + define('__EXT__', strtolower(pathinfo($_SERVER['PATH_INFO'],PATHINFO_EXTENSION))); + $paths = explode($depr,trim($_SERVER['PATH_INFO'],'/'),2); + if (C('MULTI_MODULE') && !isset($_GET[$varModule])){ // 获取模块 + $_GET[$varModule] = preg_replace('/\.' . __EXT__ . '$/i', '',array_shift($paths)); + $_SERVER['PATH_INFO'] = implode($depr, $paths); + } + + // URL常量 + define('__SELF__',strip_tags($_SERVER['REQUEST_URI'])); + + // 获取模块名称 + define('MODULE_NAME', self::getModule($varModule)); + // 检测模块是否存在 + if( MODULE_NAME && !in_array(MODULE_NAME,C('MODULE_DENY_LIST')) && 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')) + C('tags', include MODULE_PATH.'Conf/tags.php'); + // 加载模块函数文件 + if(is_file(MODULE_PATH.'Common/function.php')) + include MODULE_PATH.'Common/function.php'; + }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(!Route::check()){ // 检测路由规则 如果没有则按默认规则调度URL + tag('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,$_SERVER['PATH_INFO']); + + 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(); + 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)); + // 获取实际的操作名 + 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); + } + +} \ No newline at end of file diff --git a/Conf/alias.php b/ThinkPHP/Library/Think/Exception.class.php similarity index 47% rename from Conf/alias.php rename to ThinkPHP/Library/Think/Exception.class.php index 0d26303900c7d4358aad7d6055c2a49c486a0948..ee35f2fd2122f3c2208e266ef3a7e0323b2250fd 100644 --- a/Conf/alias.php +++ b/ThinkPHP/Library/Think/Exception.class.php @@ -1,24 +1,20 @@ - -// +---------------------------------------------------------------------- -// $Id: alias.php 3001 2012-06-15 03:39:19Z liu21st@gmail.com $ - -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 + +// +---------------------------------------------------------------------- +namespace Think; +/** + * ThinkPHP系统异常基类 + * @category Think + * @package Think + * @subpackage Core + * @author liu21st + */ +class Exception extends \Exception { +} \ No newline at end of file diff --git a/Lib/Core/Log.class.php b/ThinkPHP/Library/Think/Log.class.php similarity index 38% rename from Lib/Core/Log.class.php rename to ThinkPHP/Library/Think/Log.class.php index 730b0cebd0378ffe787aeb13769b0ea5d358e89b..25cebfe5ad5f99a7c30940827cc934632502d39b 100644 --- a/Lib/Core/Log.class.php +++ b/ThinkPHP/Library/Think/Log.class.php @@ -1,135 +1,106 @@ - -// +---------------------------------------------------------------------- -// $Id: Log.class.php 3034 2012-06-20 16:07:41Z liu21st@gmail.com $ - -/** - +------------------------------------------------------------------------------ - * 日志处理类 - +------------------------------------------------------------------------------ - * @category Think - * @package Think - * @subpackage Core - * @author liu21st - * @version $Id: Log.class.php 3034 2012-06-20 16:07:41Z liu21st@gmail.com $ - +------------------------------------------------------------------------------ - */ -class Log { - - // 日志级别 从上到下,由低到高 - const EMERG = 'EMERG'; // 严重错误: 导致系统崩溃无法使用 - const ALERT = 'ALERT'; // 警戒性错误: 必须被立即修改的错误 - const CRIT = 'CRIT'; // 临界值错误: 超过临界值的错误,例如一天24小时,而输入的是25小时这样 - const ERR = 'ERR'; // 一般错误: 一般性错误 - const WARN = 'WARN'; // 警告性错误: 需要发出警告的错误 - const NOTICE = 'NOTIC'; // 通知: 程序可以运行但是还不够完美的错误 - const INFO = 'INFO'; // 信息: 程序输出信息 - const DEBUG = 'DEBUG'; // 调试: 调试信息 - const SQL = 'SQL'; // SQL:SQL语句 注意只在调试模式开启时有效 - - // 日志记录方式 - const SYSTEM = 0; - const MAIL = 1; - const FILE = 3; - const SAPI = 4; - - // 日志信息 - static $log = array(); - - // 日期格式 - static $format = '[ c ]'; - - /** - +---------------------------------------------------------- - * 记录日志 并且会过滤未经设置的级别 - +---------------------------------------------------------- - * @static - * @access public - +---------------------------------------------------------- - * @param string $message 日志信息 - * @param string $level 日志级别 - * @param boolean $record 是否强制记录 - +---------------------------------------------------------- - * @return void - +---------------------------------------------------------- - */ - static function record($message,$level=self::ERR,$record=false) { - if($record || false !== strpos(C('LOG_LEVEL'),$level)) { - self::$log[] = "{$level}: {$message}\r\n"; - } - } - - /** - +---------------------------------------------------------- - * 日志保存 - +---------------------------------------------------------- - * @static - * @access public - +---------------------------------------------------------- - * @param integer $type 日志记录方式 - * @param string $destination 写入目标 - * @param string $extra 额外参数 - +---------------------------------------------------------- - * @return void - +---------------------------------------------------------- - */ - static function save($type='',$destination='',$extra='') { - if(empty(self::$log)) return ; - $type = $type?$type:C('LOG_TYPE'); - if(self::FILE == $type) { // 文件方式记录日志信息 - if(empty($destination)) - $destination = 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'); - } - $now = date(self::$format); - error_log($now.' '.get_client_ip().' '.$_SERVER['REQUEST_URI']."\r\n".implode('',self::$log)."\r\n", $type,$destination ,$extra); - // 保存后清空日志缓存 - self::$log = array(); - //clearstatcache(); - } - - /** - +---------------------------------------------------------- - * 日志直接写入 - +---------------------------------------------------------- - * @static - * @access public - +---------------------------------------------------------- - * @param string $message 日志信息 - * @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 = 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'); - } - error_log("{$now} {$level}: {$message}\r\n", $type,$destination,$extra ); - //clearstatcache(); - } + +// +---------------------------------------------------------------------- +namespace Think; +/** + * 日志处理类 + * @category Think + * @package Think + * @subpackage Core + * @author liu21st + */ +class Log { + + // 日志级别 从上到下,由低到高 + const EMERG = 'EMERG'; // 严重错误: 导致系统崩溃无法使用 + const ALERT = 'ALERT'; // 警戒性错误: 必须被立即修改的错误 + const CRIT = 'CRIT'; // 临界值错误: 超过临界值的错误,例如一天24小时,而输入的是25小时这样 + const ERR = 'ERR'; // 一般错误: 一般性错误 + const WARN = 'WARN'; // 警告性错误: 需要发出警告的错误 + const NOTICE = 'NOTIC'; // 通知: 程序可以运行但是还不够完美的错误 + const INFO = 'INFO'; // 信息: 程序输出信息 + const DEBUG = 'DEBUG'; // 调试: 调试信息 + const SQL = 'SQL'; // SQL:SQL语句 注意只在调试模式开启时有效 + + // 日志信息 + static protected $log = array(); + + // 日志存储 + static protected $storage = null; + + // 日志初始化 + static public function init($config=array()){ + $type = isset($config['type'])?$config['type']:'File'; + $class = 'Think\\Log\\Driver\\'. ucwords($type); + unset($config['type']); + self::$storage = new $class($config); + } + + /** + * 记录日志 并且会过滤未经设置的级别 + * @static + * @access public + * @param string $message 日志信息 + * @param string $level 日志级别 + * @param boolean $record 是否强制记录 + * @return void + */ + static function record($message,$level=self::ERR,$record=false) { + if($record || false !== strpos(C('LOG_LEVEL'),$level)) { + self::$log[] = "{$level}: {$message}\r\n"; + } + } + + /** + * 日志保存 + * @static + * @access public + * @param integer $type 日志记录方式 + * @param string $destination 写入目标 + * @param string $extra 额外参数 + * @return void + */ + static function save($type='',$destination='',$extra='') { + if(empty(self::$log)) return ; + + 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(); + } + $message = implode('',self::$log); + self::$storage->write($message,$destination); + // 保存后清空日志缓存 + self::$log = array(); + } + + /** + * 日志直接写入 + * @static + * @access public + * @param string $message 日志信息 + * @param string $level 日志级别 + * @param integer $type 日志记录方式 + * @param string $destination 写入目标 + * @return void + */ + 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(); + } + 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 0000000000000000000000000000000000000000..677edadb39ec5119e987de392185ca5d0a3094f0 --- /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/Lib/Core/Model.class.php b/ThinkPHP/Library/Think/Model.class.php similarity index 60% rename from Lib/Core/Model.class.php rename to ThinkPHP/Library/Think/Model.class.php index 8fd2164eed4bde627c6db3d65a9f5068753f9eaa..bf776cc4040d2b11ed9543dee75fa1f54f1fee88 100644 --- a/Lib/Core/Model.class.php +++ b/ThinkPHP/Library/Think/Model.class.php @@ -1,1758 +1,1574 @@ - -// +---------------------------------------------------------------------- -// $Id: Model.class.php 3092 2012-08-02 03:49:53Z luofei614@gmail.com $ - -/** - +------------------------------------------------------------------------------ - * ThinkPHP Model模型类 - * 实现了ORM和ActiveRecords模式 - +------------------------------------------------------------------------------ - * @category Think - * @package Think - * @subpackage Core - * @author liu21st - * @version $Id: Model.class.php 3092 2012-08-02 03:49:53Z luofei614@gmail.com $ - +------------------------------------------------------------------------------ - */ -class Model { - // 操作状态 - const MODEL_INSERT = 1; // 插入模型数据 - const MODEL_UPDATE = 2; // 更新模型数据 - const MODEL_BOTH = 3; // 包含上面两种方式 - const MUST_VALIDATE = 1;// 必须验证 - const EXISTS_VAILIDATE = 0;// 表单存在字段则验证 - const VALUE_VAILIDATE = 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'); - - /** - +---------------------------------------------------------- - * 架构函数 - * 取得DB类的实例对象 字段检查 - +---------------------------------------------------------- - * @param string $name 模型名称 - * @param string $tablePrefix 表前缀 - * @param mixed $connection 数据库连接信息 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - */ - 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_VERISON'); - 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_VERISON')) $this->fields['_version'] = C('DB_FIELD_VERISON'); - - // 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); - if(false === $this->_before_update($data,$options)) { - return false; - } - if(!isset($options['where']) ) { - // 如果存在主键数据 则自动作为更新条件 - if(isset($data[$this->getPk()])) { - $pk = $this->getPk(); - $where[$pk] = $data[$pk]; - $options['where'] = $where; - $pkValue = $data[$pk]; - unset($data[$pk]); - }else{ - // 如果没有任何更新条件则不执行 - $this->error = L('_OPERATION_WRONG_'); - return false; - } - } - $result = $this->db->update($data,$options); - if(false !== $result) { - if(isset($pkValue)) $data[$pk] = $pkValue; - $this->_after_update($data,$options); - } - return $result; - } - // 更新数据前的回调方法 - 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; - } - if(is_numeric($options) || is_string($options)) { - // 根据主键删除记录 - $pk = $this->getPk(); - if(strpos($options,',')) { - $where[$pk] = array('IN', $options); - }else{ - $where[$pk] = $options; - } - $pkValue = $where[$pk]; - $options = array(); - $options['where'] = $where; - } - // 分析表达式 - $options = $this->_parseOptions($options); - $result= $this->db->delete($options); - if(false !== $result) { - $data = array(); - if(isset($pkValue)) $data[$pk] = $pkValue; - $this->_after_delete($data,$options); - } - // 返回删除记录个数 - 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 proteced - +---------------------------------------------------------- - * @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(); - if(!empty($options['alias'])) { - $options['table'] .= ' '.$options['alias']; - } - // 记录操作的模型名称 - $options['model'] = $this->name; - // 字段类型验证 - if(isset($options['where']) && is_array($options['where']) && !empty($this->fields)) { - // 对数组查询条件进行字段类型检查 - foreach ($options['where'] as $key=>$val){ - $key = trim($key); - if(in_array($key,$this->fields,true)){ - if(is_scalar($val)) { - $this->_parseType($options['where'],$key); - } - }elseif('_' != substr($key,0,1) && false === strpos($key,'.') && false === strpos($key,'|') && false === strpos($key,'&')){ - unset($options['where'][$key]); - } - } - } - - // 表达式过滤 - $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) { - $fieldType = strtolower($this->fields['_type'][$key]); - if(false === strpos($fieldType,'bigint') && false !== strpos($fieldType,'int')) { - $data[$key] = intval($data[$key]); - }elseif(false !== strpos($fieldType,'float') || false !== strpos($fieldType,'double')){ - $data[$key] = floatval($data[$key]); - }elseif(false !== strpos($fieldType,'bool')){ - $data[$key] = (bool)$data[$key]; - } - } - - /** - +---------------------------------------------------------- - * 查询数据 - +---------------------------------------------------------- - * @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); - return $this->data; - } - // 查询成功的回调方法 - protected function _after_find(&$result,$options) {} - - /** - +---------------------------------------------------------- - * 处理字段映射 - +---------------------------------------------------------- - * @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,',')) { // 多字段 - $resultSet = $this->db->select($options); - if(!empty($resultSet)) { - $_field = explode(',', $field); - $field = array_keys($resultSet[0]); - $move = $_field[0]==$_field[1]?false:true; - $key = array_shift($field); - $key2 = array_shift($field); - $cols = array(); - $count = count($_field); - foreach ($resultSet as $result){ - $name = $result[$key]; - if($move) { // 删除键值记录 - unset($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->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->insert_fields)) { - $fields = $this->insert_fields; - }elseif($type == self::MODEL_UPDATE && isset($this->update_fields)) { - $fields = $this->update_fields; - } - if(isset($fields)) { - if(is_string($fields)) { - $fields = explode(',',$fields); - } - foreach ($data as $key=>$val){ - if(!in_array($key,$fields)) { - unset($data[$key]); - } - } - } - - // 数据自动验证 - if(!$this->autoValidation($data,$type)) return false; - - // 表单令牌验证 - if(C('TOKEN_ON') && !$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) { - if(C('TOKEN_ON')){ - $name = C('TOKEN_NAME'); - if(!isset($data[$name]) || !isset($_SESSION[$name])) { // 令牌数据无效 - return false; - } - - // 令牌验证 - list($key,$value) = explode('_',$data[$name]); - if($_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-z0-9]+[\/=\?%\-&_~`@[\]\':+!]*([^<>\"\"])*$/', - '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 '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_VAILIDATE; - $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_VAILIDATE: // 值不为空的时候才验证 - 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->field($this->getPk())->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'){ - switch(strtolower(trim($type))) { - case 'in': // 验证是否在某个指定范围之内 逗号分隔字符串或者数组 - $range = is_array($rule)?$rule:explode(',',$rule); - return in_array($value ,$range); - case 'between': // 验证是否在某个范围 - if (is_array($rule)){ - $min = $rule[0]; - $max = $rule[1]; - }else{ - list($min,$max) = explode(',',$rule); - } - return $value>=$min && $value<=$max; - case 'equal': // 验证是否等于某个值 - return $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 $_SERVER['REQUEST_TIME'] >= $start && $_SERVER['REQUEST_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预处理 - $sql = vsprintf($sql,$parse); - }else{ - if(strpos($sql,'__TABLE__')) - $sql = str_replace('__TABLE__',$this->getTableName(),$sql); - } - $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]) && $_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=''){ - $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); - } - $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 $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模式 + * @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;// 表单值不为空则验证 + + // 当前数据库操作对象 + 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 $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)) { + 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]; + } + 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])){ + $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) { + 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(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 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)){ + $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 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)){ + E(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{ + 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 $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/Lib/Behavior/CheckRouteBehavior.class.php b/ThinkPHP/Library/Think/Route.class.php similarity index 61% rename from Lib/Behavior/CheckRouteBehavior.class.php rename to ThinkPHP/Library/Think/Route.class.php index 576f02c76dd6750b05952b3590d974aa7f9bd047..3e169a546e8e4202c21be1e8a073ade42c084958 100644 --- a/Lib/Behavior/CheckRouteBehavior.class.php +++ b/ThinkPHP/Library/Think/Route.class.php @@ -1,211 +1,255 @@ - -// +---------------------------------------------------------------------- -// $Id: CheckRouteBehavior.class.php 3001 2012-06-15 03:39:19Z liu21st@gmail.com $ - -defined('THINK_PATH') or exit(); -/** - +------------------------------------------------------------------------------ - * 系统行为扩展 路由检测 - +------------------------------------------------------------------------------ - */ -class CheckRouteBehavior extends Behavior { - // 行为参数定义(默认值) 可在项目配置中覆盖 - protected $options = array( - 'URL_ROUTER_ON' => false, // 是否开启URL路由 - 'URL_ROUTE_RULES' => array(), // 默认路由规则,注:分组配置无法替代 - ); - - // 行为扩展的执行入口必须是run - public function run(&$return){ - // 优先检测是否存在PATH_INFO - $regx = trim($_SERVER['PATH_INFO'],'/'); - if(empty($regx)) return $return = true; - // 是否开启路由使用 - if(!C('URL_ROUTER_ON')) return $return = false; - // 路由定义文件优先于config中的配置定义 - $routes = C('URL_ROUTE_RULES'); - // 路由处理 - if(!empty($routes)) { - $depr = C('URL_PATHINFO_DEPR'); - // 分隔符替换 确保路由定义使用统一的分隔符 - $regx = str_replace($depr,'/',$regx); - foreach ($routes as $rule=>$route){ - if(0===strpos($rule,'/') && preg_match($rule,$regx,$matches)) { // 正则路由 - return $return = $this->parseRegex($matches,$route,$regx); - }else{ // 规则路由 - $len1= substr_count($regx,'/'); - $len2 = substr_count($rule,'/'); - if($len1>=$len2) { - if('$' == substr($rule,-1,1)) {// 完整匹配 - if($len1 != $len2) { - continue; - }else{ - $rule = substr($rule,0,-1); - } - } - $match = $this->checkUrlMatch($regx,$rule); - if($match) return $return = $this->parseRule($rule,$route,$regx); - } - } - } - } - $return = false; - } - - // 检测URL和规则路由是否匹配 - private function checkUrlMatch($regx,$rule) { - $m1 = explode('/',$regx); - $m2 = explode('/',$rule); - $match = true; // 是否匹配 - foreach ($m2 as $key=>$val){ - if(':' == substr($val,0,1)) {// 动态变量 - if(strpos($val,'\\')) { - $type = substr($val,-1); - if('d'==$type && !is_numeric($m1[$key])) { - $match = false; - break; - } - }elseif(strpos($val,'^')){ - $array = explode('|',substr(strstr($val,'^'),1)); - if(in_array($m1[$key],$array)) { - $match = false; - break; - } - } - }elseif(0 !== strcasecmp($val,$m1[$key])){ - $match = false; - break; - } - } - return $match; - } - - // 解析规范的路由地址 - // 地址格式 [分组/模块/操作?]参数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']); - 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); - } - } - 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 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){ - if(0===strpos($item,':')) { // 动态变量获取 - if($pos = strpos($item,'^') ) { - $var = substr($item,1,$pos-1); - }elseif(strpos($item,'\\')){ - $var = substr($item,1,-2); - }else{ - $var = substr($item,1); - } - $matches[$var] = array_shift($paths); - }else{ // 过滤URL中的静态变量 - array_shift($paths); - } - } - if(0=== strpos($url,'/') || 0===strpos($url,'http')) { // 路由重定向跳转 - if(strpos($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); - // 解析路由地址里面的动态参数 - $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($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); - } - 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 function parseRegex($matches,$route,$regx) { - // 获取路由地址规则 - $url = is_array($route)?$route[0]:$route; - $url = preg_replace('/:(\d+)/e','$matches[\\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 = $this->parseUrl($url); - // 解析剩余的URL参数 - $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); - } - return true; - } + +// +---------------------------------------------------------------------- +namespace Think; +/** + * ThinkPHP内置路由解析类 + * @category Think + * @package Think + * @subpackage Core + * @author liu21st + */ +class Route { + + // 路由检测 + public static function check(){ + // 优先检测是否存在PATH_INFO + $regx = trim($_SERVER['PATH_INFO'],'/'); + if(empty($regx)) return true; + // 是否开启路由使用 + if(!C('URL_ROUTER_ON')) return false; + // 路由定义文件优先于config中的配置定义 + $routes = C('URL_ROUTE_RULES'); + // 路由处理 + if(!empty($routes)) { + $depr = C('URL_PATHINFO_DEPR'); + // 分隔符替换 确保路由定义使用统一的分隔符 + $regx = str_replace($depr,'/',$regx); + foreach ($routes as $rule=>$route){ + if(0===strpos($rule,'/') && preg_match($rule,$regx.(defined('__EXT__')?'.'.__EXT__:''),$matches)) { // 正则路由 + if($route instanceof \Closure) { + // 执行闭包并中止 + self::invokeRegx($route, $matches); + exit; + } + return $return = self::parseRegex($matches,$route,$regx); + }else{ // 规则路由 + $len1 = substr_count($regx,'/'); + $len2 = substr_count($rule,'/'); + if($len1>=$len2) { + 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 $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(':' == substr($val,0,1)) {// 动态变量 + if(strpos($val,'\\')) { + $type = substr($val,-1); + if('d'==$type && !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] = $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){ + if(0===strpos($item,':')) { // 动态变量获取 + if($pos = strpos($item,'^') ) { + $var = substr($item,1,$pos-1); + }elseif(strpos($item,'\\')){ + $var = substr($item,1,-2); + }else{ + $var = substr($item,1); + } + $matches[$var] = array_shift($paths); + }else{ // 过滤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($matach) use(&$var){$var[strtolower($match[1])]=strip_tags($match[2]);}, $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){ + $name = $param->getName(); + 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 0000000000000000000000000000000000000000..05110c77da2741d92109f71a5294c657abe93e92 --- /dev/null +++ b/ThinkPHP/Library/Think/Session/Driver/Db.class.php @@ -0,0 +1,188 @@ + +// +---------------------------------------------------------------------- +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`) + * ); + * @category Extend + * @package Extend + * @subpackage Driver.Session + * @author liu21st + */ +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 0000000000000000000000000000000000000000..28d12816d4a46949c89804ceb2109a7dd6495d74 --- /dev/null +++ b/ThinkPHP/Library/Think/Storage.class.php @@ -0,0 +1,41 @@ + +// +---------------------------------------------------------------------- +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()) { + $type = $type? $type : C('STORAGE_TYPE'); + $class = 'Think\\Storage\\Driver\\'.ucwords($type); + self::$handler = new $class($options); + } + + static public function __callstatic($method,$args){ + //调用缓存类型自己的方法 + if(method_exists(self::$handler, $method)){ + return call_user_func_array(array(self::$handler,$method), $args); + } + } +} \ No newline at end of file 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 0000000000000000000000000000000000000000..a9e73767e6df43789a8d4ddcfeff222badeaf38c --- /dev/null +++ b/ThinkPHP/Library/Think/Storage/Driver/File.class.php @@ -0,0 +1,114 @@ + +// +---------------------------------------------------------------------- +namespace Think\Storage\Driver; +use Think\Storage; +// 本地文件写入存储类 +class File extends Storage{ + + /** + * 架构函数 + * @access public + */ + public function __construct() { + } + + /** + * 文件内容读取 + * @access public + * @param string $filename 文件名 + * @return string + */ + public function read($filename,$type=''){ + return $this->get($filename,'content'); + } + + /** + * 文件写入 + * @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{ + 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).$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=''){ + return unlink($filename); + } + + /** + * 读取文件信息 + * @access public + * @param string $filename 文件名 + * @param string $name 信息名 mtime或者content + * @return boolean + */ + public function get($filename,$name,$type=''){ + if(!is_file($filename)) return false; + $content= file_get_contents($filename); + $info = array( + 'mtime' => filemtime($filename), + 'content' => $content + ); + return $info[$name]; + } +} diff --git a/Lib/Template/ThinkTemplate.class.php b/ThinkPHP/Library/Think/Template.class.php similarity index 53% rename from Lib/Template/ThinkTemplate.class.php rename to ThinkPHP/Library/Think/Template.class.php index efa5bfd32a2f241308809dc5a64353f0a4ba5fcb..ba48a8aca07f8c2857707a2f5eaa288b372247ce 100644 --- a/Lib/Template/ThinkTemplate.class.php +++ b/ThinkPHP/Library/Think/Template.class.php @@ -1,699 +1,698 @@ - -// +---------------------------------------------------------------------- -// $Id: ThinkTemplate.class.php 3087 2012-07-28 12:29:23Z liu21st@gmail.com $ - -/** - +------------------------------------------------------------------------------ - * ThinkPHP内置模板引擎类 - * 支持XML标签和普通标签的模板解析 - * 编译型模板引擎 支持动态缓存 - +------------------------------------------------------------------------------ - * @category Think - * @package Think - * @subpackage Template - * @author liu21st - * @version $Id: ThinkTemplate.class.php 3087 2012-07-28 12:29:23Z liu21st@gmail.com $ - +------------------------------------------------------------------------------ - */ -class ThinkTemplate { - - // 模板页面中引入的标签库列表 - protected $tagLib = array(); - // 当前模板文件 - protected $templateFile = ''; - // 模板变量 - public $tVar = array(); - public $config = array(); - private $literal = array(); - - /** - +---------------------------------------------------------- - * 架构函数 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @param array $config 模板引擎配置数组 - +---------------------------------------------------------- - */ - 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; - } - - // 加载模板 - public function fetch($templateFile,$templateVar) { - $this->tVar = $templateVar; - $templateCacheFile = $this->loadTemplate($templateFile); - // 模板阵列变量分解成为独立变量 - extract($templateVar, EXTR_OVERWRITE); - //载入模版缓存文件 - include $templateCacheFile; - } - - /** - +---------------------------------------------------------- - * 加载主模板并缓存 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @param string $tmplTemplateFile 模板文件 - +---------------------------------------------------------- - * @return string - +---------------------------------------------------------- - * @throws ThinkExecption - +---------------------------------------------------------- - */ - public function loadTemplate ($tmplTemplateFile) { - if(is_file($tmplTemplateFile)) { - $this->templateFile = $tmplTemplateFile; - // 读取模板文件内容 - $tmplContent = file_get_contents($tmplTemplateFile); - }else{ - $tmplContent = $tmplTemplateFile; - } - // 根据模版文件名定位缓存文件 - $tmplCacheFile = $this->config['cache_path'].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); - // 检测分组目录 - if(!is_dir($this->config['cache_path'])) - mkdir($this->config['cache_path'],0777,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'].')(\S.+?)('.$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标签 - $layout = $matches[1]; - $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']); - 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)); - } - } - return $content; - } - - // 解析模板中的include标签 - protected function parseInclude($content) { - // 解析布局 - $content = $this->parseLayout($content); - // 读取模板中的布局标签 - $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]; - $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']); - $file = $array['file']; - unset($array['file']); - $content = str_replace($matches[0][$i],$this->parseIncludeItem($file,$array),$content); - } - } - return $content; - } - - /** - +---------------------------------------------------------- - * 替换页面中的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; - } - - /** - +---------------------------------------------------------- - * 搜索模板页面中包含的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标签 - $tagLibs = $matches[1]; - $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']); - $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); - if(!import($className)) { - if(is_file(EXTEND_PATH.'Driver/TagLib/'.$className.'.class.php')) { - // 扩展标签库优先识别 - $file = EXTEND_PATH.'Driver/TagLib/'.$className.'.class.php'; - }else{ - // 系统目录下面的标签库 - $file = CORE_PATH.'Driver/TagLib/'.$className.'.class.php'; - } - require_cache($file); - } - $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(.*?)'; - 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); - $name = substr($tagStr,1); - if('$' == $flag){ //解析模板变量 格式 {$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); - //非法变量过滤 不允许在变量里面使用 -> - //TODO:还需要继续完善 - //if(preg_match('/->/is',$var)) return ''; - 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]; - }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 public - +---------------------------------------------------------- - * @param string $tmplPublicName 公共模板文件名 - * @param array $vars 要传递的变量列表 - +---------------------------------------------------------- - * @return string - +---------------------------------------------------------- - */ - protected function parseIncludeItem($tmplPublicName,$vars=array()){ - if(substr($tmplPublicName,0,1)=='$') - //支持加载变量文件名 - $tmplPublicName = $this->get(substr($tmplPublicName,1)); - $array = explode(',',$tmplPublicName); - $parseStr = ''; - foreach ($array as $tmplPublicName){ - if(false === strpos($tmplPublicName,$this->config['template_suffix'])) { - // 解析规则为 模板主题:模块:操作 不支持 跨项目和跨分组调用 - $path = explode(':',$tmplPublicName); - $action = array_pop($path); - $module = !empty($path)?array_pop($path):MODULE_NAME; - if(!empty($path)) {// 设置模板主题 - $path = dirname(THEME_PATH).'/'.array_pop($path).'/'; - }else{ - $path = THEME_PATH; - } - $depr = defined('GROUP_NAME')?C('TMPL_FILE_DEPR'):'/'; - $tmplPublicName = $path.$module.$depr.$action.$this->config['template_suffix']; - } - // 获取模板文件内容 - $parseStr .= file_get_contents($tmplPublicName); - } - foreach ($vars as $key=>$val) { - $parseStr = str_replace('['.$key.']',$val,$parseStr); - } - //再次对包含文件进行模板分析 - return $this->parseInclude($parseStr); - } - -} \ No newline at end of file + +// +---------------------------------------------------------------------- +namespace Think; +/** + * ThinkPHP内置模板引擎类 + * 支持XML标签和普通标签的模板解析 + * 编译型模板引擎 支持动态缓存 + * @category Think + * @package Think + * @subpackage Template + * @author liu21st + */ +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,'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']; + $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($tagLib,$tag,$that){ + return $that->parseXmlTag($tagLib,$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($tagLib,$tag,$that){ + return $that->parseXmlTag($tagLib,$tag,$matches[1],$matches[2]); + },$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(ini_get('magic_quotes_sybase')) + $attr = str_replace('\"','\'',$attr); + $tLib = Think::instance('Think\\Template\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(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($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(),$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 0000000000000000000000000000000000000000..802074f7c1551d7ece5797cdbd4ad99fc02cfba6 --- /dev/null +++ b/ThinkPHP/Library/Think/Template/Driver/Ease.class.php @@ -0,0 +1,46 @@ + +// +---------------------------------------------------------------------- +namespace Think\Template\Driver; +defined('THINK_PATH') or exit(); +/** + * EaseTemplate模板引擎驱动 + * @category Extend + * @package Extend + * @subpackage Driver.Template + * @author liu21st + */ +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.php b/ThinkPHP/Library/Think/Template/Driver/Lite.class.php similarity index 36% rename from ThinkPHP.php rename to ThinkPHP/Library/Think/Template/Driver/Lite.class.php index bff15eb0d61acd9a7bad17e48616f4b4fa602d7b..6476c08afb7c57a2ecc681727835ad054fbcdd56 100644 --- a/ThinkPHP.php +++ b/ThinkPHP/Library/Think/Template/Driver/Lite.class.php @@ -1,33 +1,44 @@ - -// +---------------------------------------------------------------------- -// $Id: ThinkPHP.php 2791 2012-02-29 10:08:57Z liu21st $ - -// ThinkPHP 入口文件 - -//记录开始运行时间 -$GLOBALS['_beginTime'] = microtime(TRUE); -// 记录内存初始使用 -define('MEMORY_LIMIT_ON',function_exists('memory_get_usage')); -if(MEMORY_LIMIT_ON) $GLOBALS['_startUseMems'] = memory_get_usage(); -defined('APP_PATH') or define('APP_PATH', dirname($_SERVER['SCRIPT_FILENAME']).'/'); -defined('RUNTIME_PATH') or define('RUNTIME_PATH',APP_PATH.'Runtime/'); -defined('APP_DEBUG') or define('APP_DEBUG',false); // 是否调试模式 -$runtime = defined('MODE_NAME')?'~'.strtolower(MODE_NAME).'_runtime.php':'~runtime.php'; -defined('RUNTIME_FILE') or define('RUNTIME_FILE',RUNTIME_PATH.$runtime); -if(!APP_DEBUG && is_file(RUNTIME_FILE)) { - // 部署模式直接载入运行缓存 - require RUNTIME_FILE; -}else{ - // 系统目录定义 - defined('THINK_PATH') or define('THINK_PATH', dirname(__FILE__).'/'); - // 加载运行时文件 - require THINK_PATH.'Common/runtime.php'; + +// +---------------------------------------------------------------------- +namespace Think\Template\Driver; +defined('THINK_PATH') or exit(); +/** + * TemplateLite模板引擎驱动 + * @category Extend + * @package Extend + * @subpackage Driver.Template + * @author liu21st + */ +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 0000000000000000000000000000000000000000..b36576e607849b3ca0fc3ca9cabcece8559dd73b --- /dev/null +++ b/ThinkPHP/Library/Think/Template/Driver/Mobile.class.php @@ -0,0 +1,33 @@ + +// +---------------------------------------------------------------------- +namespace Think\Template\Driver; +defined('THINK_PATH') or exit(); +/** + * MobileTemplate模板引擎驱动 + * @category Extend + * @package Extend + * @subpackage Driver.Template + * @author luofei614 + */ +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 0000000000000000000000000000000000000000..ead810b16f6701456984c1b80b9642638c1ba295 --- /dev/null +++ b/ThinkPHP/Library/Think/Template/Driver/Smart.class.php @@ -0,0 +1,45 @@ + +// +---------------------------------------------------------------------- +namespace Think\Template\Driver; +defined('THINK_PATH') or exit(); +/** + * Smart模板引擎驱动 + * @category Extend + * @package Extend + * @subpackage Driver.Template + * @author liu21st + */ +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/Conf/tags.php b/ThinkPHP/Library/Think/Template/Driver/Smarty.class.php similarity index 36% rename from Conf/tags.php rename to ThinkPHP/Library/Think/Template/Driver/Smarty.class.php index 508c4492603c7d92cefe6f1fb2d4bc5462efffd0..610c68b087d21d5b7985b35e1852bb46fd53c73a 100644 --- a/Conf/tags.php +++ b/ThinkPHP/Library/Think/Template/Driver/Smarty.class.php @@ -1,43 +1,46 @@ - -// +---------------------------------------------------------------------- -// $Id: tags.php 2726 2012-02-11 13:34:24Z liu21st $ - -// 系统默认的核心行为扩展列表文件 -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_template'=>array( - 'LocationTemplate', // 自动定位模板文件 - ), - 'view_parse'=>array( - 'ParseTemplate', // 模板解析 支持PHP、内置模板引擎和第三方模板引擎 - ), - 'view_filter'=>array( - 'ContentReplace', // 模板输出替换 - 'TokenBuild', // 表单令牌 - 'WriteHtmlCache', // 写入静态缓存 - 'ShowRuntime', // 运行时间显示 - ), - 'view_end'=>array( - 'ShowPageTrace', // 页面Trace显示 - ), -); \ No newline at end of file + +// +---------------------------------------------------------------------- +namespace Think\Template\Driver; +defined('THINK_PATH') or exit(); +/** + * Smarty模板引擎驱动 + * @category Extend + * @package Extend + * @subpackage Driver.Template + * @author liu21st + */ +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/Lib/Template/TagLib.class.php b/ThinkPHP/Library/Think/Template/TagLib.class.php similarity index 61% rename from Lib/Template/TagLib.class.php rename to ThinkPHP/Library/Think/Template/TagLib.class.php index 84b59b9113b1ccbdd3c3d4a32f90ddca6c7a28c8..1098e44292f651a0fb17d9ccb5c7563eb52e303c 100644 --- a/Lib/Template/TagLib.class.php +++ b/ThinkPHP/Library/Think/Template/TagLib.class.php @@ -1,268 +1,234 @@ - -// +---------------------------------------------------------------------- -// $Id: TagLib.class.php 2929 2012-05-02 06:45:47Z liu21st@gmail.com $ - -/** - +------------------------------------------------------------------------------ - * ThinkPHP标签库TagLib解析基类 - +------------------------------------------------------------------------------ - * @category Think - * @package Think - * @subpackage Template - * @author liu21st - * @version $Id: TagLib.class.php 2929 2012-05-02 06:45:47Z liu21st@gmail.com $ - +------------------------------------------------------------------------------ - */ -class TagLib { - - /** - +---------------------------------------------------------- - * 标签库定义XML文件 - +---------------------------------------------------------- - * @var string - * @access protected - +---------------------------------------------------------- - */ - protected $xml = ''; - protected $tags = array();// 标签定义 - /** - +---------------------------------------------------------- - * 标签库名称 - +---------------------------------------------------------- - * @var string - * @access protected - +---------------------------------------------------------- - */ - protected $tagLib =''; - - /** - +---------------------------------------------------------- - * 标签库标签列表 - +---------------------------------------------------------- - * @var string - * @access protected - +---------------------------------------------------------- - */ - protected $tagList = array(); - - /** - +---------------------------------------------------------- - * 标签库分析数组 - +---------------------------------------------------------- - * @var string - * @access protected - +---------------------------------------------------------- - */ - protected $parse = array(); - - /** - +---------------------------------------------------------- - * 标签库是否有效 - +---------------------------------------------------------- - * @var string - * @access protected - +---------------------------------------------------------- - */ - protected $valid = false; - - /** - +---------------------------------------------------------- - * 当前模板对象 - +---------------------------------------------------------- - * @var object - * @access protected - +---------------------------------------------------------- - */ - protected $tpl; - - protected $comparison = array(' nheq '=>' !== ',' heq '=>' === ',' neq '=>' != ',' eq '=>' == ',' egt '=>' >= ',' gt '=>' > ',' elt '=>' <= ',' lt '=>' < '); - - /** - +---------------------------------------------------------- - * 架构函数 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - */ - public function __construct() { - $this->tagLib = strtolower(substr(get_class($this),6)); - $this->tpl = Think::instance('ThinkTemplate'); - } - - /** - +---------------------------------------------------------- - * TagLib标签属性分析 返回标签属性数组 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @param string $tagStr 标签内容 - +---------------------------------------------------------- - * @return array - +---------------------------------------------------------- - */ - public function parseXmlAttr($attr,$tag) { - //XML解析安全过滤 - $attr = str_replace('&','___', $attr); - $xml = ''; - $xml = simplexml_load_string($xml); - if(!$xml) { - throw_exception(L('_XML_TAG_ERROR_').' : '.$attr); - } - $xml = (array)($xml->tag->attributes()); - $array = array_change_key_case($xml['@attributes']); - if($array) { - $attrs = explode(',',$this->tags[strtolower($tag)]['attr']); - foreach($attrs as $name) { - if( isset($array[$name])) { - $array[$name] = str_replace('___','&',$array[$name]); - } - } - return $array; - } - } - - /** - +---------------------------------------------------------- - * 解析条件表达式 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @param string $condition 表达式标签内容 - +---------------------------------------------------------- - * @return array - +---------------------------------------------------------- - */ - public function parseCondition($condition) { - $condition = str_ireplace(array_keys($this->comparison),array_values($this->comparison),$condition); - $condition = preg_replace('/\$(\w+):(\w+)\s/is','$\\1->\\2 ',$condition); - switch(strtolower(C('TMPL_VAR_IDENTIFY'))) { - case 'array': // 识别为数组 - $condition = preg_replace('/\$(\w+)\.(\w+)\s/is','$\\1["\\2"] ',$condition); - break; - case 'obj': // 识别为对象 - $condition = preg_replace('/\$(\w+)\.(\w+)\s/is','$\\1->\\2 ',$condition); - break; - default: // 自动判断数组或对象 只支持二维 - $condition = preg_replace('/\$(\w+)\.(\w+)\s/is','(is_array($\\1)?$\\1["\\2"]:$\\1->\\2) ',$condition); - } - return $condition; - } - - /** - +---------------------------------------------------------- - * 自动识别构建变量 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @param string $name 变量描述 - +---------------------------------------------------------- - * @return string - +---------------------------------------------------------- - */ - public function autoBuildVar($name) { - if('Think.' == substr($name,0,6)){ - // 特殊变量 - return $this->parseThinkVar($name); - }elseif(strpos($name,'.')) { - $vars = explode('.',$name); - $var = array_shift($vars); - switch(strtolower(C('TMPL_VAR_IDENTIFY'))) { - case 'array': // 识别为数组 - $name = '$'.$var; - foreach ($vars as $key=>$val){ - if(0===strpos($val,'$')) { - $name .= '["{'.$val.'}"]'; - }else{ - $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(strpos($name,':')){ - // 额外的对象方式支持 - $name = '$'.str_replace(':','->',$name); - }elseif(!defined($name)) { - $name = '$'.$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[\''.$vars[2].'\']';break; - case 'GET': $parseStr = '$_GET[\''.$vars[2].'\']';break; - case 'POST': $parseStr = '$_POST[\''.$vars[2].'\']';break; - case 'COOKIE': - if(isset($vars[3])) { - $parseStr = '$_COOKIE[\''.$vars[2].'\'][\''.$vars[3].'\']'; - }elseif(C('COOKIE_PREFIX')){ - $parseStr = '$_COOKIE[\''.C('COOKIE_PREFIX').$vars[2].'\']'; - }else{ - $parseStr = '$_COOKIE[\''.$vars[2].'\']'; - } - break; - case 'SESSION': - if(isset($vars[3])) { - $parseStr = '$_SESSION[\''.$vars[2].'\'][\''.$vars[3].'\']'; - }elseif(C('SESSION_PREFIX')){ - $parseStr = '$_SESSION[\''.C('SESSION_PREFIX').'\'][\''.$vars[2].'\']'; - }else{ - $parseStr = '$_SESSION[\''.$vars[2].'\']'; - } - break; - case 'ENV': $parseStr = '$_ENV[\''.$vars[2].'\']';break; - case 'REQUEST': $parseStr = '$_REQUEST[\''.$vars[2].'\']';break; - case 'CONST': $parseStr = strtoupper($vars[2]);break; - case 'LANG': $parseStr = 'L("'.$vars[2].'")';break; - case 'CONFIG': $parseStr = 'C("'.$vars[2].'")';break; - } - }else if(count($vars)==2){ - switch($vars[1]){ - case 'NOW': $parseStr = "date('Y-m-d g:i a',time())";break; - case 'VERSION': $parseStr = 'THINK_VERSION';break; - case 'TEMPLATE':$parseStr = 'C("TEMPLATE_NAME")';break; - case 'LDELIM': $parseStr = 'C("TMPL_L_DELIM")';break; - case 'RDELIM': $parseStr = 'C("TMPL_R_DELIM")';break; - default: if(defined($vars[1])) $parseStr = $vars[1]; - } - } - return $parseStr; - } - - // 获取标签定义 - public function getTags(){ - return $this->tags; - } + +// +---------------------------------------------------------------------- +namespace Think\Template; +/** + * ThinkPHP标签库TagLib解析基类 + * @category Think + * @package Think + * @subpackage Template + * @author liu21st + */ +class TagLib { + + /** + * 标签库定义XML文件 + * @var string + * @access protected + */ + protected $xml = ''; + protected $tags = array();// 标签定义 + /** + * 标签库名称 + * @var string + * @access protected + */ + protected $tagLib =''; + + /** + * 标签库标签列表 + * @var string + * @access protected + */ + protected $tagList = array(); + + /** + * 标签库分析数组 + * @var string + * @access protected + */ + protected $parse = array(); + + /** + * 标签库是否有效 + * @var string + * @access protected + */ + protected $valid = false; + + /** + * 当前模板对象 + * @var object + * @access protected + */ + protected $tpl; + + protected $comparison = array(' nheq '=>' !== ',' heq '=>' === ',' neq '=>' != ',' eq '=>' == ',' egt '=>' >= ',' gt '=>' > ',' elt '=>' <= ',' lt '=>' < '); + + /** + * 架构函数 + * @access public + */ + public function __construct() { + $this->tagLib = strtolower(substr(get_class($this),6)); + $this->tpl = \Think\Think::instance('Think\\Template'); + } + + /** + * TagLib标签属性分析 返回标签属性数组 + * @access public + * @param string $tagStr 标签内容 + * @return array + */ + public function parseXmlAttr($attr,$tag) { + //XML解析安全过滤 + $attr = str_replace('&','___', $attr); + $xml = ''; + $xml = simplexml_load_string($xml); + if(!$xml) { + 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)){ + E(L('_PARAM_ERROR_').':'.$name); + } + } + return $array; + } + } + + /** + * 解析条件表达式 + * @access public + * @param string $condition 表达式标签内容 + * @return array + */ + public function parseCondition($condition) { + $condition = str_ireplace(array_keys($this->comparison),array_values($this->comparison),$condition); + $condition = preg_replace('/\$(\w+):(\w+)\s/is','$\\1->\\2 ',$condition); + switch(strtolower(C('TMPL_VAR_IDENTIFY'))) { + case 'array': // 识别为数组 + $condition = preg_replace('/\$(\w+)\.(\w+)\s/is','$\\1["\\2"] ',$condition); + break; + case 'obj': // 识别为对象 + $condition = preg_replace('/\$(\w+)\.(\w+)\s/is','$\\1->\\2 ',$condition); + break; + default: // 自动判断数组或对象 只支持二维 + $condition = preg_replace('/\$(\w+)\.(\w+)\s/is','(is_array($\\1)?$\\1["\\2"]:$\\1->\\2) ',$condition); + } + if(false !== strpos($condition, '$Think')) + $condition = preg_replace_callback('/(\$Think.*?)\s/is', array($this, 'parseThinkVar'), $condition); + return $condition; + } + + /** + * 自动识别构建变量 + * @access public + * @param string $name 变量描述 + * @return string + */ + public function autoBuildVar($name) { + if('Think.' == substr($name,0,6)){ + // 特殊变量 + return $this->parseThinkVar($name); + }elseif(strpos($name,'.')) { + $vars = explode('.',$name); + $var = array_shift($vars); + switch(strtolower(C('TMPL_VAR_IDENTIFY'))) { + case 'array': // 识别为数组 + $name = '$'.$var; + foreach ($vars as $key=>$val){ + if(0===strpos($val,'$')) { + $name .= '["{'.$val.'}"]'; + }else{ + $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(strpos($name,':')){ + // 额外的对象方式支持 + $name = '$'.str_replace(':','->',$name); + }elseif(!defined($name)) { + $name = '$'.$name; + } + return $name; + } + + /** + * 用于标签属性里面的特殊模板变量解析 + * 格式 以 Think. 打头的变量属于特殊模板变量 + * @access public + * @param string $varStr 变量字符串 + * @return string + */ + public function parseThinkVar($varStr){ + if(is_array($varStr)){//用于正则替换回调函数 + $varStr = $varStr[1]; + } + $vars = explode('.',$varStr); + $vars[1] = strtoupper(trim($vars[1])); + $parseStr = ''; + if(count($vars)>=3){ + $vars[2] = trim($vars[2]); + switch($vars[1]){ + case 'SERVER': $parseStr = '$_SERVER[\''.$vars[2].'\']';break; + case 'GET': $parseStr = '$_GET[\''.$vars[2].'\']';break; + case 'POST': $parseStr = '$_POST[\''.$vars[2].'\']';break; + case 'COOKIE': + if(isset($vars[3])) { + $parseStr = '$_COOKIE[\''.$vars[2].'\'][\''.$vars[3].'\']'; + }elseif(C('COOKIE_PREFIX')){ + $parseStr = '$_COOKIE[\''.C('COOKIE_PREFIX').$vars[2].'\']'; + }else{ + $parseStr = '$_COOKIE[\''.$vars[2].'\']'; + } + break; + case 'SESSION': + if(isset($vars[3])) { + $parseStr = '$_SESSION[\''.$vars[2].'\'][\''.$vars[3].'\']'; + }elseif(C('SESSION_PREFIX')){ + $parseStr = '$_SESSION[\''.C('SESSION_PREFIX').'\'][\''.$vars[2].'\']'; + }else{ + $parseStr = '$_SESSION[\''.$vars[2].'\']'; + } + break; + case 'ENV': $parseStr = '$_ENV[\''.$vars[2].'\']';break; + case 'REQUEST': $parseStr = '$_REQUEST[\''.$vars[2].'\']';break; + case 'CONST': $parseStr = strtoupper($vars[2]);break; + case 'LANG': $parseStr = 'L("'.$vars[2].'")';break; + case 'CONFIG': $parseStr = 'C("'.$vars[2].'")';break; + } + }else if(count($vars)==2){ + switch($vars[1]){ + case 'NOW': $parseStr = "date('Y-m-d g:i a',time())";break; + case 'VERSION': $parseStr = 'THINK_VERSION';break; + case 'TEMPLATE':$parseStr = 'C("TEMPLATE_NAME")';break; + case 'LDELIM': $parseStr = 'C("TMPL_L_DELIM")';break; + case 'RDELIM': $parseStr = 'C("TMPL_R_DELIM")';break; + default: if(defined($vars[1])) $parseStr = $vars[1]; + } + } + return $parseStr; + } + + // 获取标签定义 + public function getTags(){ + return $this->tags; + } } \ No newline at end of file diff --git a/ThinkPHP/Library/Think/Template/TagLib/Article.class.php b/ThinkPHP/Library/Think/Template/TagLib/Article.class.php new file mode 100644 index 0000000000000000000000000000000000000000..0e28aea86cef43be45606fdc92554de69090dc06 --- /dev/null +++ b/ThinkPHP/Library/Think/Template/TagLib/Article.class.php @@ -0,0 +1,116 @@ + +// +---------------------------------------------------------------------- +namespace Think\Template\TagLib; +use Think\Template\TagLib; +/** + * ThinkCMS 系文档模型标签库 + */ +class Article extends TagLib{ + /** + * 定义标签列表 + * @var array + */ + protected $tags = array( + 'partlist' => array('attr' => 'id,field,page,name', 'close' => 1), //段落列表 + 'partpage' => array('attr' => 'id,listrow', 'close' => 0), //段落分页 + 'prev' => array('attr' => 'name,info', 'close' => 1), //获取上一篇文章信息 + 'next' => array('attr' => 'name,info', 'close' => 1), //获取下一篇文章信息 + 'page' => array('attr' => 'cate,listrow', 'close' => 0), //列表分页 + 'position' => array('attr' => 'pos,cate,limit,filed,name', 'close' => 1), //获取推荐位列表 + ); + + /* 推荐位列表 */ + public function _position($attr, $content){ + $tag = $this->parseXmlAttr($attr, 'next'); + $pos = $tag['pos']; + $cate = $tag['cate']; + $limit = empty($tag['limit']) ? 'null' : $tag['limit']; + $filed = empty($tag['filed']) ? 'true' : $tag['filed']; + $name = $tag['name']; + $parse = $parse = 'position('; + $parse .= $pos . ','; + $parse .= $cate . ','; + $parse .= $limit . ','; + $parse .= $filed . ');'; + $parse .= ' ?>'; + $parse .= ''; + $parse .= $content; + $parse .= ''; + return $parse; + } + + /* 列表数据分页 */ + public function _page($attr){ + $tag = $this->parseXmlAttr($attr, 'next'); + $cate = $tag['cate']; + $listrow = $tag['listrow']; + $parse = 'show();'; + $parse .= ' ?>'; + return $parse; + } + + /* 获取下一篇文章信息 */ + public function _next($attr, $content){ + $tag = $this->parseXmlAttr($attr, 'next'); + $name = $tag['name']; + $info = $tag['info']; + $parse = 'next($' . $info . ');'; + $parse .= ' ?>'; + $parse .= ''; + $parse .= $content; + $parse .= ''; + return $parse; + } + + /* 获取上一篇文章信息 */ + public function _prev($attr, $content){ + $tag = $this->parseXmlAttr($attr, 'prev'); + $name = $tag['name']; + $info = $tag['info']; + $parse = 'prev($' . $info . ');'; + $parse .= ' ?>'; + $parse .= ''; + $parse .= $content; + $parse .= ''; + return $parse; + } + + /* 段落数据分页 */ + public function _partpage($attr){ + $tag = $this->parseXmlAttr($attr, 'next'); + $id = $tag['id']; + $listrow = $tag['listrow']; + $parse = 'show();'; + $parse .= ' ?>'; + return $parse; + } + + /* 段落列表 */ + public function _partlist($attr, $content){ + $tag = $this->parseXmlAttr($attr, 'partlist'); + $id = $tag['id']; + $field = $tag['field']; + $name = $tag['name']; + $parse = 'part(' . $id . ', $page, \'' . $field . '\');'; + $parse .= ' ?>'; + $parse .= ''; + $parse .= $content; + $parse .= ''; + return $parse; + } +} \ No newline at end of file diff --git a/ThinkPHP/Library/Think/Template/TagLib/Attr.class.php b/ThinkPHP/Library/Think/Template/TagLib/Attr.class.php new file mode 100644 index 0000000000000000000000000000000000000000..0a7925f8d92dc43967f5b2e1df045449bd848485 --- /dev/null +++ b/ThinkPHP/Library/Think/Template/TagLib/Attr.class.php @@ -0,0 +1,383 @@ + +// +---------------------------------------------------------------------- +namespace Think\Template\TagLib; +use Think\Template\TagLib; +// 属性类型标签库 +class Attr extends TagLib{ + // 标签定义 + protected $tags = array( + // 标签定义: attr 属性列表 close 是否闭合(0 或者1 默认1) alias 标签别名 level 嵌套层次 + 'attr'=>array('attr'=>'var,complex,type,default','close'=>0), + ); + + // + public function _attr($attr,$content){ + $tag = $this->parseXmlAttr($attr,'attr'); + $var = $tag['var']; + $default = isset($tag['default'])?$tag['default']:1; + $read = isset($tag['read'])?$tag['read']:false; + if(!empty($tag['type'])) { + $parse = $this->_{$tag['type']}($var); + }else{ + $parse = ''.$this->_string($var,$default,$read); + $parse .= ''.$this->_num($var,$default,$read); + $parse .= ''.$this->_bool($var,$default,$read); + $parse .= ''.$this->_textarea($var,$default,$read); + $parse .= ''.$this->_text($var,$default,$read); + $parse .= ''.$this->_editor($var,$default,$read); + $parse .= ''.$this->_file($var,$read); + $parse .= ''.$this->_files($var,$read); + $parse .= ''.$this->_radio($var,$default,$read); + $parse .= ''.$this->_checkbox($var,$default,$read); + $parse .= ''.$this->_select($var,$default,$read); + $parse .= ''.$this->_image($var,$read); + $parse .= ''.$this->_images($var,$read); + $parse .= ''.$this->_date($var,$default,$read); + $parse .= ''.$this->_zone($var,$read); + $parse .= ''.$this->_html($var,$read); + $parse .= ''.$this->_dynamic($var,$read); + $parse .= ''.$this->_hidden($var,$read); + $parse .= ''.$this->_verify($var,$read); + $parse .= ''.$this->_password($var,$default,$read); + $parse .= ''.$this->_serialize($var,$read); + $parse .= ''.$this->_link($var,$read); + if(!empty($tag['complex'])) { + $parse .= ''.$this->_complex($var,$read); + } + $parse .= ''; + } + return $parse; + } + + // 验证码类型 + protected function _verify($var) { + $parse = ' '; + return $parse; + } + + // 密码类型 + protected function _password($var,$default) { + $value = $default?'{$'.$var.'.value}':''; + $parse = ' '; + return $parse; + } + + // 字符串类型 + protected function _string($var,$default,$read) { + $value = $default?'{$'.$var.'.value}':''; + if($read) { + $parse = $value; + }else{ + $parse = ' '; + } + return $parse; + } + + // 字符串类型 + protected function _link($var,$read) { + $value = '{$'.$var.'.value}'; + if($read) { + $parse = $value; + }else{ + $parse = ' '; + } + return $parse; + } + + // 数字类型 + protected function _num($var,$default,$read) { + $value = $default?'{$'.$var.'.value}':''; + if($read) { + $parse = $value; + }else{ + $parse = ' '; + } + return $parse; + } + + // 布尔类型 采用下拉列表模拟 + protected function _bool($var,$default,$read) { + if($read) { + $parse = ''; + $parse = ''; + }else{ + $parse = ' '; + } + return $parse; + } + + // 文本域类型 + protected function _textarea($var,$default,$read) { + $value = $default?'{$'.$var.'.value}':''; + if($read) { + $parse = $value; + }else{ + $parse = ' '; + } + return $parse; + } + + // 文本型 + protected function _text($var,$default,$read) { + $value = $default?'{$'.$var.'.value}':''; + if($read) { + $parse = $value; + }else{ + $parse = ' + '; + } + return $parse; + } + + // 编辑器型 + protected function _editor($var,$default,$read) { + $value = $default?'{$'.$var.'.value}':''; + if($read) { + $parse = $value; + }else{ + $parse = ' '; + } + return $parse; + } + + // 附件上传型 可配置 + protected function _file($var) { + $parse = '
{$'.$var.'.value|extension|showExt} {$'.$var.'.value}
'; + return $parse; + } + + // 多附件型 + protected function _files($var) { + $parse = '
+ $array = explode(\',\',$'.$var.'[\'value\']); + +
+ + + + + + . + + + + + {$attach|extension|showExt} {$attach} + +
+
'; + return $parse; + } + + // 单选型 + // 选项1,选项2,... + // 选项1:显示1,选项2:显示2,... + // @model.id 调用模型 + // :fun 函数 + protected function _radio($var,$default) { + $parse = ' + + $array = explode(\':\',$extra);$value = $array[0];$show = isset($array[1])?$array[1]:$array[0]; + checked':'').' value="{$value}" class="{$'.$var.'.readonly}" {$'.$var.'.readonly} /> {$show} + '; + return $parse; + } + + // 组合字段 + protected function _complex($var,$read) { + if($read) { + $parse = ' '; + }else{ + $parse = ' '; + } + return $parse; + } + + // 多选型 用多选下拉列表模拟 支持函数定义 + // 选项1,选项2,... + // 选项1:显示1,选项2:显示2,... + // @model.id 调用模型 + // :fun 函数 + protected function _checkbox($var,$default) { + $parse = ' + + + + + + + + +
选择{$'.$var.'.title}
+ +
+ + +
+
'; + return $parse; + } + + // 枚举型 采用下拉列表模拟 + // 选项1,选项2,... + // 选项1:显示1,选项2:显示2,... + // @model.id 调用模型 + // :fun 函数 + protected function _select($var,$default,$read) { + if($read) { + $parse = ' + $array = explode(\':\',$option);$value = $array[0];$show = isset($array[1])?$array[1]:$array[0]; + + '; + }else{ + $parse = ' '; + } + return $parse; + } + + // 序列化型 只支持字符串类型 + // 字段名1:显示名称:样式,... + protected function _serialize($var) { + $parse = ' + + $array = explode(\':\',$option);$var = $array[0];$show = isset($array[1])?$array[1]:\'\';$class = isset($array[2])?$array[2]:\'medium\';$value = $'.$var.'[\'value\'][$var]; + {$show} + '; + return $parse; + } + + // 图片型 支持配置 + protected function _image($var,$read) { + if($read) { + $parse = 'parse_str($'.$var.'[\'extra\'],$extra);$array = explode(\',\',$extra[\'thumbPrefix\']); + +   '; + }else{ + $parse = '
parse_str($'.$var.'[\'extra\'],$extra);$array = explode(\',\',$extra[\'thumbPrefix\']); + +   
'; + } + return $parse; + } + + // 多图型 + protected function _images($var) { + $parse = '
+ $array = explode(\',\',$'.$var.'[\'value\']); + +
  
+
'; + return $parse; + } + + // 日期型 + protected function _date($var,$default) { + $parse = ''; + return $parse; + } + + // 动态型 用方法控制输出显示 + protected function _dynamic($var) { + $parse = '$fun = $'.$var.'[\'extra\'];echo $fun($'.$var.'[\'value\']); '; + return $parse; + } + + // 地区联动 + protected function _zone($var) { + $parse = ' + + + + +
'; + return $parse; + } + + // 固定值 采用隐藏字段模拟 + protected function _hidden($var) { + $parse = ' '; + return $parse; + } + + // HTML型 + protected function _html($var) { + $parse = '{$'.$var.'.value}'; + return $parse; + } +} +?> \ No newline at end of file diff --git a/Lib/Driver/TagLib/TagLibCx.class.php b/ThinkPHP/Library/Think/Template/TagLib/Cx.class.php similarity index 49% rename from Lib/Driver/TagLib/TagLibCx.class.php rename to ThinkPHP/Library/Think/Template/TagLib/Cx.class.php index 108f67ebb6e440bddf9612e26132f89bdabec95b..455d60fc470bff94d15d9d195964c30cf121a982 100644 --- a/Lib/Driver/TagLib/TagLibCx.class.php +++ b/ThinkPHP/Library/Think/Template/TagLib/Cx.class.php @@ -1,717 +1,643 @@ - -// +---------------------------------------------------------------------- -// $Id: TagLibCx.class.php 3001 2012-06-15 03:39:19Z liu21st@gmail.com $ - -defined('THINK_PATH') or exit(); -/** - +------------------------------------------------------------------------------ - * CX标签库解析类 - +------------------------------------------------------------------------------ - * @category Think - * @package Think - * @subpackage Template - * @author liu21st - * @version $Id: TagLibCx.class.php 3001 2012-06-15 03:39:19Z liu21st@gmail.com $ - +------------------------------------------------------------------------------ - */ -class TagLibCx extends TagLib { - - // 标签定义 - protected $tags = array( - // 标签定义: attr 属性列表 close 是否闭合(0 或者1 默认1) alias 标签别名 level 嵌套层次 - 'php'=>array(), - 'volist'=>array('attr'=>'name,id,offset,length,key,mod','level'=>3,'alias'=>'iterate'), - 'foreach' =>array('attr'=>'name,item,key','level'=>3), - 'if'=>array('attr'=>'condition','level'=>2), - 'elseif'=>array('attr'=>'condition','close'=>0), - 'else'=>array('attr'=>'','close'=>0), - 'switch'=>array('attr'=>'name','level'=>2), - 'case'=>array('attr'=>'value,break'), - 'default'=>array('attr'=>'','close'=>0), - 'compare'=>array('attr'=>'name,value,type','level'=>3,'alias'=>'eq,equal,notequal,neq,gt,lt,egt,elt,heq,nheq'), - 'range'=>array('attr'=>'name,value,type','level'=>3,'alias'=>'in,notin,between,notbetween'), - 'empty'=>array('attr'=>'name','level'=>3), - 'notempty'=>array('attr'=>'name','level'=>3), - 'present'=>array('attr'=>'name','level'=>3), - 'notpresent'=>array('attr'=>'name','level'=>3), - 'defined'=>array('attr'=>'name','level'=>3), - 'notdefined'=>array('attr'=>'name','level'=>3), - 'import'=>array('attr'=>'file,href,type,value,basepath','close'=>0,'alias'=>'load,css,js'), - 'assign'=>array('attr'=>'name,value','close'=>0), - 'define'=>array('attr'=>'name,value','close'=>0), - 'for'=>array('attr'=>'start,end,name,comparison,step', 'level'=>3), - ); - - /** - +---------------------------------------------------------- - * php标签解析 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @param string $attr 标签属性 - * @param string $content 标签内容 - +---------------------------------------------------------- - * @return string - +---------------------------------------------------------- - */ - public function _php($attr,$content) { - $parseStr = ''; - return $parseStr; - } - - /** - +---------------------------------------------------------- - * volist标签解析 循环输出数据集 - * 格式: - * - * {user.username} - * {user.email} - * - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @param string $attr 标签属性 - * @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'); - $name = $tag['name']; - $id = $tag['id']; - $empty = isset($tag['empty'])?$tag['empty']:''; - $key = !empty($tag['key'])?$tag['key']:'i'; - $mod = isset($tag['mod'])?$tag['mod']:'2'; - // 允许使用函数设定数据集 {$vo.name} - $parseStr = 'autoBuildVar($name); - } - $parseStr .= 'if(is_array('.$name.')): $'.$key.' = 0;'; - if(isset($tag['length']) && '' !=$tag['length'] ) { - $parseStr .= ' $__LIST__ = array_slice('.$name.','.$tag['offset'].','.$tag['length'].',true);'; - }elseif(isset($tag['offset']) && '' !=$tag['offset']){ - $parseStr .= ' $__LIST__ = array_slice('.$name.','.$tag['offset'].',count('.$name.')-'.$tag['offset'].',true);'; - }else{ - $parseStr .= ' $__LIST__ = '.$name.';'; - } - $parseStr .= 'if( count($__LIST__)==0 ) : echo "'.$empty.'" ;'; - $parseStr .= 'else: '; - $parseStr .= 'foreach($__LIST__ as $key=>$'.$id.'): '; - $parseStr .= '$mod = ($'.$key.' % '.$mod.' );'; - $parseStr .= '++$'.$key.';?>'; - $parseStr .= $this->tpl->parse($content); - $parseStr .= ''; - $_iterateParseCache[$cacheIterateId] = $parseStr; - - if(!empty($parseStr)) { - return $parseStr; - } - return ; - } - - public function _foreach($attr,$content) { - static $_iterateParseCache = array(); - //如果已经解析过,则直接返回变量值 - $cacheIterateId = md5($attr.$content); - if(isset($_iterateParseCache[$cacheIterateId])) - return $_iterateParseCache[$cacheIterateId]; - $tag = $this->parseXmlAttr($attr,'foreach'); - $name= $tag['name']; - $item = $tag['item']; - $key = !empty($tag['key'])?$tag['key']:'key'; - $name= $this->autoBuildVar($name); - $parseStr = '$'.$item.'): ?>'; - $parseStr .= $this->tpl->parse($content); - $parseStr .= ''; - $_iterateParseCache[$cacheIterateId] = $parseStr; - if(!empty($parseStr)) { - return $parseStr; - } - return ; - } - - /** - +---------------------------------------------------------- - * if标签解析 - * 格式: - * - * - * - * - * 表达式支持 eq neq gt egt lt elt == > >= < <= or and || && - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @param string $attr 标签属性 - * @param string $content 标签内容 - +---------------------------------------------------------- - * @return string - +---------------------------------------------------------- - */ - public function _if($attr,$content) { - $tag = $this->parseXmlAttr($attr,'if'); - $condition = $this->parseCondition($tag['condition']); - $parseStr = ''.$content.''; - return $parseStr; - } - - /** - +---------------------------------------------------------- - * else标签解析 - * 格式:见if标签 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @param string $attr 标签属性 - * @param string $content 标签内容 - +---------------------------------------------------------- - * @return string - +---------------------------------------------------------- - */ - public function _elseif($attr,$content) { - $tag = $this->parseXmlAttr($attr,'elseif'); - $condition = $this->parseCondition($tag['condition']); - $parseStr = ''; - return $parseStr; - } - - /** - +---------------------------------------------------------- - * else标签解析 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @param string $attr 标签属性 - +---------------------------------------------------------- - * @return string - +---------------------------------------------------------- - */ - public function _else($attr) { - $parseStr = ''; - return $parseStr; - } - - /** - +---------------------------------------------------------- - * switch标签解析 - * 格式: - * - * 1 - * 2 - * other - * - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @param string $attr 标签属性 - * @param string $content 标签内容 - +---------------------------------------------------------- - * @return string - +---------------------------------------------------------- - */ - public function _switch($attr,$content) { - $tag = $this->parseXmlAttr($attr,'switch'); - $name = $tag['name']; - $varArray = explode('|',$name); - $name = array_shift($varArray); - $name = $this->autoBuildVar($name); - if(count($varArray)>0) - $name = $this->tpl->parseVarFunction($name,$varArray); - $parseStr = ''.$content.''; - return $parseStr; - } - - /** - +---------------------------------------------------------- - * case标签解析 需要配合switch才有效 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @param string $attr 标签属性 - * @param string $content 标签内容 - +---------------------------------------------------------- - * @return string - +---------------------------------------------------------- - */ - public function _case($attr,$content) { - $tag = $this->parseXmlAttr($attr,'case'); - $value = $tag['value']; - if('$' == substr($value,0,1)) { - $varArray = explode('|',$value); - $value = array_shift($varArray); - $value = $this->autoBuildVar(substr($value,1)); - if(count($varArray)>0) - $value = $this->tpl->parseVarFunction($value,$varArray); - $value = 'case '.$value.': '; - }elseif(strpos($value,'|')){ - $values = explode('|',$value); - $value = ''; - foreach ($values as $val){ - $value .= 'case "'.addslashes($val).'": '; - } - }else{ - $value = 'case "'.$value.'": '; - } - $parseStr = ''.$content; - $isBreak = isset($tag['break']) ? $tag['break'] : ''; - if('' ==$isBreak || $isBreak) { - $parseStr .= ''; - } - return $parseStr; - } - - /** - +---------------------------------------------------------- - * default标签解析 需要配合switch才有效 - * 使用: ddfdf - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @param string $attr 标签属性 - * @param string $content 标签内容 - +---------------------------------------------------------- - * @return string - +---------------------------------------------------------- - */ - public function _default($attr) { - $parseStr = ''; - return $parseStr; - } - - /** - +---------------------------------------------------------- - * compare标签解析 - * 用于值的比较 支持 eq neq gt lt egt elt heq nheq 默认是eq - * 格式: content - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @param string $attr 标签属性 - * @param string $content 标签内容 - +---------------------------------------------------------- - * @return string - +---------------------------------------------------------- - */ - public function _compare($attr,$content,$type='eq') { - $tag = $this->parseXmlAttr($attr,'compare'); - $name = $tag['name']; - $value = $tag['value']; - $type = isset($tag['type'])?$tag['type']:$type; - $type = $this->parseCondition(' '.$type.' '); - $varArray = explode('|',$name); - $name = array_shift($varArray); - $name = $this->autoBuildVar($name); - if(count($varArray)>0) - $name = $this->tpl->parseVarFunction($name,$varArray); - if('$' == substr($value,0,1)) { - $value = $this->autoBuildVar(substr($value,1)); - }else { - $value = '"'.$value.'"'; - } - $parseStr = ''.$content.''; - return $parseStr; - } - - public function _eq($attr,$content) { - return $this->_compare($attr,$content,'eq'); - } - - public function _equal($attr,$content) { - return $this->_compare($attr,$content,'eq'); - } - - public function _neq($attr,$content) { - return $this->_compare($attr,$content,'neq'); - } - - public function _notequal($attr,$content) { - return $this->_compare($attr,$content,'neq'); - } - - public function _gt($attr,$content) { - return $this->_compare($attr,$content,'gt'); - } - - public function _lt($attr,$content) { - return $this->_compare($attr,$content,'lt'); - } - - public function _egt($attr,$content) { - return $this->_compare($attr,$content,'egt'); - } - - public function _elt($attr,$content) { - return $this->_compare($attr,$content,'elt'); - } - - public function _heq($attr,$content) { - return $this->_compare($attr,$content,'heq'); - } - - public function _nheq($attr,$content) { - return $this->_compare($attr,$content,'nheq'); - } - - /** - +---------------------------------------------------------- - * range标签解析 - * 如果某个变量存在于某个范围 则输出内容 type= in 表示在范围内 否则表示在范围外 - * 格式: content - * example: content - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @param string $attr 标签属性 - * @param string $content 标签内容 - * @param string $type 比较类型 - +---------------------------------------------------------- - * @return string - +---------------------------------------------------------- - */ - public function _range($attr,$content,$type='in') { - $tag = $this->parseXmlAttr($attr,'range'); - $name = $tag['name']; - $value = $tag['value']; - $varArray = explode('|',$name); - $name = array_shift($varArray); - $name = $this->autoBuildVar($name); - if(count($varArray)>0) - $name = $this->tpl->parseVarFunction($name,$varArray); - - $type = isset($tag['type'])?$tag['type']:$type; - - if('$' == substr($value,0,1)) { - $value = $this->autoBuildVar(substr($value,1)); - $str = 'is_array('.$value.')?'.$value.':explode(\',\','.$value.')'; - }else{ - $value = '"'.$value.'"'; - $str = 'explode(\',\','.$value.')'; - } - if($type=='between') { - $parseStr = '= $_RANGE_VAR_[0] && '.$name.'<= $_RANGE_VAR_[1]):?>'.$content.''; - }elseif($type=='notbetween'){ - $parseStr = '$_RANGE_VAR_[1]):?>'.$content.''; - }else{ - $fun = ($type == 'in')? 'in_array' : '!in_array'; - $parseStr = ''.$content.''; - } - return $parseStr; - } - - // range标签的别名 用于in判断 - public function _in($attr,$content) { - return $this->_range($attr,$content,'in'); - } - - // range标签的别名 用于notin判断 - public function _notin($attr,$content) { - return $this->_range($attr,$content,'notin'); - } - - public function _between($attr,$content){ - return $this->_range($attr,$content,'between'); - } - - public function _notbetween($attr,$content){ - return $this->_range($attr,$content,'notbetween'); - } - - /** - +---------------------------------------------------------- - * present标签解析 - * 如果某个变量已经设置 则输出内容 - * 格式: content - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @param string $attr 标签属性 - * @param string $content 标签内容 - +---------------------------------------------------------- - * @return string - +---------------------------------------------------------- - */ - public function _present($attr,$content) { - $tag = $this->parseXmlAttr($attr,'present'); - $name = $tag['name']; - $name = $this->autoBuildVar($name); - $parseStr = ''.$content.''; - return $parseStr; - } - - /** - +---------------------------------------------------------- - * notpresent标签解析 - * 如果某个变量没有设置,则输出内容 - * 格式: content - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @param string $attr 标签属性 - * @param string $content 标签内容 - +---------------------------------------------------------- - * @return string - +---------------------------------------------------------- - */ - public function _notpresent($attr,$content) { - $tag = $this->parseXmlAttr($attr,'notpresent'); - $name = $tag['name']; - $name = $this->autoBuildVar($name); - $parseStr = ''.$content.''; - return $parseStr; - } - - /** - +---------------------------------------------------------- - * empty标签解析 - * 如果某个变量为empty 则输出内容 - * 格式: content - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @param string $attr 标签属性 - * @param string $content 标签内容 - +---------------------------------------------------------- - * @return string - +---------------------------------------------------------- - */ - public function _empty($attr,$content) { - $tag = $this->parseXmlAttr($attr,'empty'); - $name = $tag['name']; - $name = $this->autoBuildVar($name); - $parseStr = ''.$content.''; - return $parseStr; - } - - public function _notempty($attr,$content) { - $tag = $this->parseXmlAttr($attr,'notempty'); - $name = $tag['name']; - $name = $this->autoBuildVar($name); - $parseStr = ''.$content.''; - return $parseStr; - } - /** - * 判断是否已经定义了该常量 - * 已定义 - * @param $attr - * @param $content - * @return string - */ - public function _defined($attr,$content) { - $tag = $this->parseXmlAttr($attr,'defined'); - $name = $tag['name']; - $parseStr = ''.$content.''; - return $parseStr; - } - - public function _notdefined($attr,$content) { - $tag = $this->parseXmlAttr($attr,'_notdefined'); - $name = $tag['name']; - $parseStr = ''.$content.''; - return $parseStr; - } - - /** - +---------------------------------------------------------- - * import 标签解析 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @param string $attr 标签属性 - * @param string $content 标签内容 - * @param boolean $isFile 是否文件方式 - * @param string $type 类型 - +---------------------------------------------------------- - * @return string - +---------------------------------------------------------- - */ - public function _import($attr,$content,$isFile=false,$type='') { - $tag = $this->parseXmlAttr($attr,'import'); - $file = isset($tag['file'])?$tag['file']:$tag['href']; - $parseStr = ''; - $endStr = ''; - // 判断是否存在加载条件 允许使用函数判断(默认为isset) - if (isset($tag['value'])) { - $varArray = explode('|',$tag['value']); - $name = array_shift($varArray); - $name = $this->autoBuildVar($name); - if (!empty($varArray)) - $name = $this->tpl->parseVarFunction($name,$varArray); - else - $name = 'isset('.$name.')'; - $parseStr .= ''; - $endStr = ''; - } - if($isFile) { - // 根据文件名后缀自动识别 - $type = $type?$type:(!empty($tag['type'])?strtolower($tag['type']):null); - // 文件方式导入 - $array = explode(',',$file); - foreach ($array as $val){ - if (!$type || isset($reset)) { - $type = $reset = strtolower(substr(strrchr($val, '.'),1)); - } - switch($type) { - case 'js': - $parseStr .= ''; - break; - case 'css': - $parseStr .= ''; - break; - case 'php': - $parseStr .= ''; - break; - } - } - }else{ - // 命名空间导入模式 默认是js - $type = $type?$type:(!empty($tag['type'])?strtolower($tag['type']):'js'); - $basepath = !empty($tag['basepath'])?$tag['basepath']:__ROOT__.'/Public'; - // 命名空间方式导入外部文件 - $array = explode(',',$file); - foreach ($array as $val){ - switch($type) { - case 'js': - $parseStr .= ''; - break; - case 'css': - $parseStr .= ''; - break; - case 'php': - $parseStr .= ''; - break; - } - } - } - return $parseStr.$endStr; - } - - // import别名 采用文件方式加载(要使用命名空间必须用import) 例如 - public function _load($attr,$content) { - return $this->_import($attr,$content,true); - } - - // import别名使用 导入css文件 - public function _css($attr,$content) { - return $this->_import($attr,$content,true,'css'); - } - - // import别名使用 导入js文件 - public function _js($attr,$content) { - return $this->_import($attr,$content,true,'js'); - } - - /** - +---------------------------------------------------------- - * assign标签解析 - * 在模板中给某个变量赋值 支持变量赋值 - * 格式: - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @param string $attr 标签属性 - * @param string $content 标签内容 - +---------------------------------------------------------- - * @return string - +---------------------------------------------------------- - */ - public function _assign($attr,$content) { - $tag = $this->parseXmlAttr($attr,'assign'); - $name = $this->autoBuildVar($tag['name']); - if('$'==substr($tag['value'],0,1)) { - $value = $this->autoBuildVar(substr($tag['value'],1)); - }else{ - $value = '\''.$tag['value']. '\''; - } - $parseStr = ''; - return $parseStr; - } - - /** - +---------------------------------------------------------- - * define标签解析 - * 在模板中定义常量 支持变量赋值 - * 格式: - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @param string $attr 标签属性 - * @param string $content 标签内容 - +---------------------------------------------------------- - * @return string - +---------------------------------------------------------- - */ - public function _define($attr,$content) { - $tag = $this->parseXmlAttr($attr,'define'); - $name = '\''.$tag['name']. '\''; - if('$'==substr($tag['value'],0,1)) { - $value = $this->autoBuildVar(substr($tag['value'],1)); - }else{ - $value = '\''.$tag['value']. '\''; - } - $parseStr = ''; - return $parseStr; - } - - /** - +---------------------------------------------------------- - * for标签解析 - * 格式: - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @param string $attr 标签属性 - * @param string $content 标签内容 - +---------------------------------------------------------- - * @return string - +---------------------------------------------------------- - */ - public function _for($attr, $content){ - //设置默认值 - $start = 0; - $end = 0; - $step = 1; - $comparison = 'lt'; - $name = 'i'; - $rand = rand(); //添加随机数,防止嵌套变量冲突 - //获取属性 - foreach ($this->parseXmlAttr($attr, 'for') as $key => $value){ - $value = trim($value); - if(':'==substr($value,0,1)) - $value = substr($value,1); - elseif('$'==substr($value,0,1)) - $value = $this->autoBuildVar(substr($value,1)); - switch ($key){ - case 'start': $start = $value; break; - case 'end' : $end = $value; break; - case 'step': $step = $value; break; - case 'comparison':$comparison = $value;break; - case 'name':$name = $value;break; - } - } - - $parseStr = 'parseCondition('$'.$name.' '.$comparison.' $__FOR_END_'.$rand.'__').';$'.$name.'+='.$step.'){ ?>'; - $parseStr .= $content; - $parseStr .= ''; - return $parseStr; - } - -} \ No newline at end of file + +// +---------------------------------------------------------------------- +namespace Think\Template\TagLib; +use Think\Template\TagLib; +defined('THINK_PATH') or exit(); +/** + * CX标签库解析类 + * @category Think + * @package Think + * @subpackage Driver.Taglib + * @author liu21st + */ +class Cx extends TagLib { + + // 标签定义 + protected $tags = array( + // 标签定义: attr 属性列表 close 是否闭合(0 或者1 默认1) alias 标签别名 level 嵌套层次 + 'php' => array(), + 'volist' => array('attr'=>'name,id,offset,length,key,mod','level'=>3,'alias'=>'iterate'), + 'foreach' => array('attr'=>'name,item,key','level'=>3), + 'if' => array('attr'=>'condition','level'=>2), + 'elseif' => array('attr'=>'condition','close'=>0), + 'else' => array('attr'=>'','close'=>0), + 'switch' => array('attr'=>'name','level'=>2), + 'case' => array('attr'=>'value,break'), + 'default' => array('attr'=>'','close'=>0), + 'compare' => array('attr'=>'name,value,type','level'=>3,'alias'=>'eq,equal,notequal,neq,gt,lt,egt,elt,heq,nheq'), + 'range' => array('attr'=>'name,value,type','level'=>3,'alias'=>'in,notin,between,notbetween'), + 'empty' => array('attr'=>'name','level'=>3), + 'notempty' => array('attr'=>'name','level'=>3), + 'present' => array('attr'=>'name','level'=>3), + 'notpresent'=> array('attr'=>'name','level'=>3), + 'defined' => array('attr'=>'name','level'=>3), + 'notdefined'=> array('attr'=>'name','level'=>3), + 'import' => array('attr'=>'file,href,type,value,basepath','close'=>0,'alias'=>'load,css,js'), + 'assign' => array('attr'=>'name,value','close'=>0), + 'define' => array('attr'=>'name,value','close'=>0), + 'for' => array('attr'=>'start,end,name,comparison,step', 'level'=>3), + ); + + /** + * php标签解析 + * @access public + * @param string $attr 标签属性 + * @param string $content 标签内容 + * @return string + */ + public function _php($attr,$content) { + $parseStr = ''; + return $parseStr; + } + + /** + * volist标签解析 循环输出数据集 + * 格式: + * + * {user.username} + * {user.email} + * + * @access public + * @param string $attr 标签属性 + * @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'); + $name = $tag['name']; + $id = $tag['id']; + $empty = isset($tag['empty'])?$tag['empty']:''; + $key = !empty($tag['key'])?$tag['key']:'i'; + $mod = isset($tag['mod'])?$tag['mod']:'2'; + // 允许使用函数设定数据集 {$vo.name} + $parseStr = 'autoBuildVar($name); + } + $parseStr .= 'if(is_array('.$name.')): $'.$key.' = 0;'; + if(isset($tag['length']) && '' !=$tag['length'] ) { + $parseStr .= ' $__LIST__ = array_slice('.$name.','.$tag['offset'].','.$tag['length'].',true);'; + }elseif(isset($tag['offset']) && '' !=$tag['offset']){ + $parseStr .= ' $__LIST__ = array_slice('.$name.','.$tag['offset'].',null,true);'; + }else{ + $parseStr .= ' $__LIST__ = '.$name.';'; + } + $parseStr .= 'if( count($__LIST__)==0 ) : echo "'.$empty.'" ;'; + $parseStr .= 'else: '; + $parseStr .= 'foreach($__LIST__ as $key=>$'.$id.'): '; + $parseStr .= '$mod = ($'.$key.' % '.$mod.' );'; + $parseStr .= '++$'.$key.';?>'; + $parseStr .= $this->tpl->parse($content); + $parseStr .= ''; + $_iterateParseCache[$cacheIterateId] = $parseStr; + + if(!empty($parseStr)) { + return $parseStr; + } + return ; + } + + /** + * foreach标签解析 循环输出数据集 + * @access public + * @param string $attr 标签属性 + * @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'); + $name = $tag['name']; + $item = $tag['item']; + $key = !empty($tag['key'])?$tag['key']:'key'; + $name = $this->autoBuildVar($name); + $parseStr = '$'.$item.'): ?>'; + $parseStr .= $this->tpl->parse($content); + $parseStr .= ''; + $_iterateParseCache[$cacheIterateId] = $parseStr; + if(!empty($parseStr)) { + return $parseStr; + } + return ; + } + + /** + * if标签解析 + * 格式: + * + * + * + * + * 表达式支持 eq neq gt egt lt elt == > >= < <= or and || && + * @access public + * @param string $attr 标签属性 + * @param string $content 标签内容 + * @return string + */ + public function _if($attr,$content) { + $tag = $this->parseXmlAttr($attr,'if'); + $condition = $this->parseCondition($tag['condition']); + $parseStr = ''.$content.''; + return $parseStr; + } + + /** + * else标签解析 + * 格式:见if标签 + * @access public + * @param string $attr 标签属性 + * @param string $content 标签内容 + * @return string + */ + public function _elseif($attr,$content) { + $tag = $this->parseXmlAttr($attr,'elseif'); + $condition = $this->parseCondition($tag['condition']); + $parseStr = ''; + return $parseStr; + } + + /** + * else标签解析 + * @access public + * @param string $attr 标签属性 + * @return string + */ + public function _else($attr) { + $parseStr = ''; + return $parseStr; + } + + /** + * switch标签解析 + * 格式: + * + * 1 + * 2 + * other + * + * @access public + * @param string $attr 标签属性 + * @param string $content 标签内容 + * @return string + */ + public function _switch($attr,$content) { + $tag = $this->parseXmlAttr($attr,'switch'); + $name = $tag['name']; + $varArray = explode('|',$name); + $name = array_shift($varArray); + $name = $this->autoBuildVar($name); + if(count($varArray)>0) + $name = $this->tpl->parseVarFunction($name,$varArray); + $parseStr = ''.$content.''; + return $parseStr; + } + + /** + * case标签解析 需要配合switch才有效 + * @access public + * @param string $attr 标签属性 + * @param string $content 标签内容 + * @return string + */ + public function _case($attr,$content) { + $tag = $this->parseXmlAttr($attr,'case'); + $value = $tag['value']; + if('$' == substr($value,0,1)) { + $varArray = explode('|',$value); + $value = array_shift($varArray); + $value = $this->autoBuildVar(substr($value,1)); + if(count($varArray)>0) + $value = $this->tpl->parseVarFunction($value,$varArray); + $value = 'case '.$value.': '; + }elseif(strpos($value,'|')){ + $values = explode('|',$value); + $value = ''; + foreach ($values as $val){ + $value .= 'case "'.addslashes($val).'": '; + } + }else{ + $value = 'case "'.$value.'": '; + } + $parseStr = ''.$content; + $isBreak = isset($tag['break']) ? $tag['break'] : ''; + if('' ==$isBreak || $isBreak) { + $parseStr .= ''; + } + return $parseStr; + } + + /** + * default标签解析 需要配合switch才有效 + * 使用: ddfdf + * @access public + * @param string $attr 标签属性 + * @param string $content 标签内容 + * @return string + */ + public function _default($attr) { + $parseStr = ''; + return $parseStr; + } + + /** + * compare标签解析 + * 用于值的比较 支持 eq neq gt lt egt elt heq nheq 默认是eq + * 格式: content + * @access public + * @param string $attr 标签属性 + * @param string $content 标签内容 + * @return string + */ + public function _compare($attr,$content,$type='eq') { + $tag = $this->parseXmlAttr($attr,'compare'); + $name = $tag['name']; + $value = $tag['value']; + $type = isset($tag['type'])?$tag['type']:$type; + $type = $this->parseCondition(' '.$type.' '); + $varArray = explode('|',$name); + $name = array_shift($varArray); + $name = $this->autoBuildVar($name); + if(count($varArray)>0) + $name = $this->tpl->parseVarFunction($name,$varArray); + if('$' == substr($value,0,1)) { + $value = $this->autoBuildVar(substr($value,1)); + }else { + $value = '"'.$value.'"'; + } + $parseStr = ''.$content.''; + return $parseStr; + } + + public function _eq($attr,$content) { + return $this->_compare($attr,$content,'eq'); + } + + public function _equal($attr,$content) { + return $this->_compare($attr,$content,'eq'); + } + + public function _neq($attr,$content) { + return $this->_compare($attr,$content,'neq'); + } + + public function _notequal($attr,$content) { + return $this->_compare($attr,$content,'neq'); + } + + public function _gt($attr,$content) { + return $this->_compare($attr,$content,'gt'); + } + + public function _lt($attr,$content) { + return $this->_compare($attr,$content,'lt'); + } + + public function _egt($attr,$content) { + return $this->_compare($attr,$content,'egt'); + } + + public function _elt($attr,$content) { + return $this->_compare($attr,$content,'elt'); + } + + public function _heq($attr,$content) { + return $this->_compare($attr,$content,'heq'); + } + + public function _nheq($attr,$content) { + return $this->_compare($attr,$content,'nheq'); + } + + /** + * range标签解析 + * 如果某个变量存在于某个范围 则输出内容 type= in 表示在范围内 否则表示在范围外 + * 格式: content + * example: content + * @access public + * @param string $attr 标签属性 + * @param string $content 标签内容 + * @param string $type 比较类型 + * @return string + */ + public function _range($attr,$content,$type='in') { + $tag = $this->parseXmlAttr($attr,'range'); + $name = $tag['name']; + $value = $tag['value']; + $varArray = explode('|',$name); + $name = array_shift($varArray); + $name = $this->autoBuildVar($name); + if(count($varArray)>0) + $name = $this->tpl->parseVarFunction($name,$varArray); + + $type = isset($tag['type'])?$tag['type']:$type; + + if('$' == substr($value,0,1)) { + $value = $this->autoBuildVar(substr($value,1)); + $str = 'is_array('.$value.')?'.$value.':explode(\',\','.$value.')'; + }else{ + $value = '"'.$value.'"'; + $str = 'explode(\',\','.$value.')'; + } + if($type=='between') { + $parseStr = '= $_RANGE_VAR_[0] && '.$name.'<= $_RANGE_VAR_[1]):?>'.$content.''; + }elseif($type=='notbetween'){ + $parseStr = '$_RANGE_VAR_[1]):?>'.$content.''; + }else{ + $fun = ($type == 'in')? 'in_array' : '!in_array'; + $parseStr = ''.$content.''; + } + return $parseStr; + } + + // range标签的别名 用于in判断 + public function _in($attr,$content) { + return $this->_range($attr,$content,'in'); + } + + // range标签的别名 用于notin判断 + public function _notin($attr,$content) { + return $this->_range($attr,$content,'notin'); + } + + public function _between($attr,$content){ + return $this->_range($attr,$content,'between'); + } + + public function _notbetween($attr,$content){ + return $this->_range($attr,$content,'notbetween'); + } + + /** + * present标签解析 + * 如果某个变量已经设置 则输出内容 + * 格式: content + * @access public + * @param string $attr 标签属性 + * @param string $content 标签内容 + * @return string + */ + public function _present($attr,$content) { + $tag = $this->parseXmlAttr($attr,'present'); + $name = $tag['name']; + $name = $this->autoBuildVar($name); + $parseStr = ''.$content.''; + return $parseStr; + } + + /** + * notpresent标签解析 + * 如果某个变量没有设置,则输出内容 + * 格式: content + * @access public + * @param string $attr 标签属性 + * @param string $content 标签内容 + * @return string + */ + public function _notpresent($attr,$content) { + $tag = $this->parseXmlAttr($attr,'notpresent'); + $name = $tag['name']; + $name = $this->autoBuildVar($name); + $parseStr = ''.$content.''; + return $parseStr; + } + + /** + * empty标签解析 + * 如果某个变量为empty 则输出内容 + * 格式: content + * @access public + * @param string $attr 标签属性 + * @param string $content 标签内容 + * @return string + */ + public function _empty($attr,$content) { + $tag = $this->parseXmlAttr($attr,'empty'); + $name = $tag['name']; + $name = $this->autoBuildVar($name); + $parseStr = ''.$content.''; + return $parseStr; + } + + public function _notempty($attr,$content) { + $tag = $this->parseXmlAttr($attr,'notempty'); + $name = $tag['name']; + $name = $this->autoBuildVar($name); + $parseStr = ''.$content.''; + return $parseStr; + } + + /** + * 判断是否已经定义了该常量 + * 已定义 + * @param $attr + * @param $content + * @return string + */ + public function _defined($attr,$content) { + $tag = $this->parseXmlAttr($attr,'defined'); + $name = $tag['name']; + $parseStr = ''.$content.''; + return $parseStr; + } + + public function _notdefined($attr,$content) { + $tag = $this->parseXmlAttr($attr,'_notdefined'); + $name = $tag['name']; + $parseStr = ''.$content.''; + return $parseStr; + } + + /** + * import 标签解析 + * + * @access public + * @param string $attr 标签属性 + * @param string $content 标签内容 + * @param boolean $isFile 是否文件方式 + * @param string $type 类型 + * @return string + */ + public function _import($attr,$content,$isFile=false,$type='') { + $tag = $this->parseXmlAttr($attr,'import'); + $file = isset($tag['file'])?$tag['file']:$tag['href']; + $parseStr = ''; + $endStr = ''; + // 判断是否存在加载条件 允许使用函数判断(默认为isset) + if (isset($tag['value'])) { + $varArray = explode('|',$tag['value']); + $name = array_shift($varArray); + $name = $this->autoBuildVar($name); + if (!empty($varArray)) + $name = $this->tpl->parseVarFunction($name,$varArray); + else + $name = 'isset('.$name.')'; + $parseStr .= ''; + $endStr = ''; + } + if($isFile) { + // 根据文件名后缀自动识别 + $type = $type?$type:(!empty($tag['type'])?strtolower($tag['type']):null); + // 文件方式导入 + $array = explode(',',$file); + foreach ($array as $val){ + if (!$type || isset($reset)) { + $type = $reset = strtolower(substr(strrchr($val, '.'),1)); + } + switch($type) { + case 'js': + $parseStr .= ''; + break; + case 'css': + $parseStr .= ''; + break; + case 'php': + $parseStr .= ''; + break; + } + } + }else{ + // 命名空间导入模式 默认是js + $type = $type?$type:(!empty($tag['type'])?strtolower($tag['type']):'js'); + $basepath = !empty($tag['basepath'])?$tag['basepath']:__ROOT__.'/Public'; + // 命名空间方式导入外部文件 + $array = explode(',',$file); + foreach ($array as $val){ + list($val,$version) = explode('?',$val); + switch($type) { + case 'js': + $parseStr .= ''; + break; + case 'css': + $parseStr .= ''; + break; + case 'php': + $parseStr .= ''; + break; + } + } + } + return $parseStr.$endStr; + } + + // import别名 采用文件方式加载(要使用命名空间必须用import) 例如 + public function _load($attr,$content) { + return $this->_import($attr,$content,true); + } + + // import别名使用 导入css文件 + public function _css($attr,$content) { + return $this->_import($attr,$content,true,'css'); + } + + // import别名使用 导入js文件 + public function _js($attr,$content) { + return $this->_import($attr,$content,true,'js'); + } + + /** + * assign标签解析 + * 在模板中给某个变量赋值 支持变量赋值 + * 格式: + * @access public + * @param string $attr 标签属性 + * @param string $content 标签内容 + * @return string + */ + public function _assign($attr,$content) { + $tag = $this->parseXmlAttr($attr,'assign'); + $name = $this->autoBuildVar($tag['name']); + if('$'==substr($tag['value'],0,1)) { + $value = $this->autoBuildVar(substr($tag['value'],1)); + }else{ + $value = '\''.$tag['value']. '\''; + } + $parseStr = ''; + return $parseStr; + } + + /** + * define标签解析 + * 在模板中定义常量 支持变量赋值 + * 格式: + * @access public + * @param string $attr 标签属性 + * @param string $content 标签内容 + * @return string + */ + public function _define($attr,$content) { + $tag = $this->parseXmlAttr($attr,'define'); + $name = '\''.$tag['name']. '\''; + if('$'==substr($tag['value'],0,1)) { + $value = $this->autoBuildVar(substr($tag['value'],1)); + }else{ + $value = '\''.$tag['value']. '\''; + } + $parseStr = ''; + return $parseStr; + } + + /** + * for标签解析 + * 格式: + * @access public + * @param string $attr 标签属性 + * @param string $content 标签内容 + * @return string + */ + public function _for($attr, $content){ + //设置默认值 + $start = 0; + $end = 0; + $step = 1; + $comparison = 'lt'; + $name = 'i'; + $rand = rand(); //添加随机数,防止嵌套变量冲突 + //获取属性 + foreach ($this->parseXmlAttr($attr, 'for') as $key => $value){ + $value = trim($value); + if(':'==substr($value,0,1)) + $value = substr($value,1); + elseif('$'==substr($value,0,1)) + $value = $this->autoBuildVar(substr($value,1)); + switch ($key){ + case 'start': + $start = $value; break; + case 'end' : + $end = $value; break; + case 'step': + $step = $value; break; + case 'comparison': + $comparison = $value; break; + case 'name': + $name = $value; break; + } + } + + $parseStr = 'parseCondition('$'.$name.' '.$comparison.' $__FOR_END_'.$rand.'__').';$'.$name.'+='.$step.'){ ?>'; + $parseStr .= $content; + $parseStr .= ''; + return $parseStr; + } + + } 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 0000000000000000000000000000000000000000..03dec936d4c5b6b7465a6f7f49f2180f90deb607 --- /dev/null +++ b/ThinkPHP/Library/Think/Template/TagLib/Html.class.php @@ -0,0 +1,536 @@ + +// +---------------------------------------------------------------------- +namespace Think\Template\TagLib; +use Think\Template\TagLib; +defined('THINK_PATH') or exit(); +/** + * Html标签库驱动 + * @category Extend + * @package Extend + * @subpackage Driver.Taglib + * @author liu21st + */ +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 string $attr 标签属性 + * @return string|void + */ + public function _editor($attr,$content) { + $tag = $this->parseXmlAttr($attr,'editor'); + $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 string $attr 标签属性 + * @return string|void + */ + public function _imageBtn($attr) { + $tag = $this->parseXmlAttr($attr,'imageBtn'); + $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 string $attr 标签属性 + * @return string|void + */ + public function _imgLink($attr) { + $tag = $this->parseXmlAttr($attr,'imgLink'); + $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 string $attr 标签属性 + * @return string|void + */ + public function _select($attr) { + $tag = $this->parseXmlAttr($attr,'select'); + $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 string $attr 标签属性 + * @return string|void + */ + public function _checkbox($attr) { + $tag = $this->parseXmlAttr($attr,'checkbox'); + $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 string $attr 标签属性 + * @return string|void + */ + public function _radio($attr) { + $tag = $this->parseXmlAttr($attr,'radio'); + $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 string $attr 标签属性 + * @return string + */ + public function _grid($attr) { + $tag = $this->parseXmlAttr($attr,'grid'); + $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 string $attr 标签属性 + * @return string + */ + public function _list($attr) { + $tag = $this->parseXmlAttr($attr,'list'); + $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 0000000000000000000000000000000000000000..3dbb5f2f444d90f3e828b07d0e567cef1dd808d4 --- /dev/null +++ b/ThinkPHP/Library/Think/Think.class.php @@ -0,0 +1,274 @@ + +// +---------------------------------------------------------------------- + +namespace Think; +/** + * ThinkPHP Portal类 + * @category Think + * @package Think + * @subpackage Core + * @author liu21st + */ +class Think { + + // 类映射 + private static $_map = array(); + + // 实例化对象 + private static $_instance = array(); + + /** + * 应用程序初始化 + * @access public + * @return void + */ + static public function start() { + // 设定错误和异常处理 + register_shutdown_function(array('Think\Think','fatalError')); + set_error_handler(array('Think\Think','appError')); + set_exception_handler(array('Think\Think','appException')); + // 注册AUTOLOAD方法 + spl_autoload_register(array('Think\Think', 'autoload')); + + // 读取应用模式 + $mode = include THINK_PATH.'Conf/Mode/'.APP_MODE.'.php'; + + // 加载配置文件 + foreach ($mode['config'] as $key=>$file){ + is_numeric($key)?C(include $file):C($key,include $file); + } + + // 加载核心文件 + foreach ($mode['core'] as $file){ + if(is_file($file)) include $file; + } + + // 加载别名定义 + foreach($mode['alias'] as $alias){ + self::addMap(is_array($alias)?$alias:include $alias); + } + + // 加载模式系统行为定义 + if(isset($mode['extends'])) { + C('extends',is_array($mode['extends'])?$mode['extends']:include $mode['extends']); + } + + // 加载应用行为定义 + if(isset($mode['tags'])) { + C('tags', is_array($mode['tags'])?$mode['tags']:include $mode['tags']); + } + + // 加载框架底层语言包 + L(include THINK_PATH.'Lang/'.strtolower(C('DEFAULT_LANG')).'.php'); + + // 设置系统时区 + date_default_timezone_set(C('DEFAULT_TIMEZONE')); + + // 初始化文件存储方式 + Storage::connect(); + + // 检查项目目录结构 如果不存在则自动创建 + if(!is_dir(RUNTIME_PATH)) { + // 创建项目目录结构 + require THINK_PATH.'Common/build.php'; + } + + if(APP_DEBUG){ + // 调试模式加载系统默认的配置文件 + C(include THINK_PATH.'Conf/debug.php'); + // 读取调试模式的应用状态 + $status = C('APP_STATUS'); + // 加载对应的项目配置文件 + if(is_file(COMMON_PATH.'Conf/'.$status.'.php')) + // 允许项目增加开发模式配置定义 + C(include COMMON_PATH.'Conf/'.$status.'.php'); + } + + // 记录加载文件时间 + G('loadTime'); + // 运行应用 + App::run(); + } + + // 注册classmap + static public function addMap($class, $map=''){ + if(is_array($class)){ + self::$_map = array_merge(self::$_map, $class); + }else{ + self::$_map[$class] = $map; + } + } + + /** + * 类库自动加载 + * @param string $class 对象类名 + * @return void + */ + public static function autoload($class) { + // 检查是否存在映射 + if(isset(self::$_map[$class])) { + include self::$_map[$class]; + }else{ + $name = strstr($class, '\\', true); + $namespace = C('AUTOLOAD_NAMESPACE'); + if(isset($namespace[$name])){ // 注册的命名空间 + $path = dirname($namespace[$name]) . '/'; + }elseif(is_dir(LIB_PATH.$name)){ // Library目录下面的命名空间自动定位 + $path = LIB_PATH; + }else{ // 模块的命名空间 + $path = APP_PATH; + } + $filename = $path . str_replace('\\', '/', $class) . EXT; + if(is_file($filename)) { + // Win环境下面严格区分大小写 + if (IS_WIN && false === strpos(str_replace('/', '\\', realpath($filename)), $class . EXT)){ + return ; + } + include $filename; + } + } + } + + /** + * 取得对象实例 支持调用类的静态方法 + * @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(&$o, $method)); + else + self::$_instance[$identify] = $o; + } + else + self::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('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 行."; + 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(); + 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'); + } + } + // 包含异常页面模板 + include C('TMPL_EXCEPTION_FILE'); + exit; + } +} diff --git a/Lib/Core/View.class.php b/ThinkPHP/Library/Think/View.class.php similarity index 50% rename from Lib/Core/View.class.php rename to ThinkPHP/Library/Think/View.class.php index d82584f58d2bd3a275c198492534e4edff380392..11ac35ec2ffd2934e4bd63490c245620856a4053 100644 --- a/Lib/Core/View.class.php +++ b/ThinkPHP/Library/Think/View.class.php @@ -1,156 +1,213 @@ - -// +---------------------------------------------------------------------- -// $Id: View.class.php 3087 2012-07-28 12:29:23Z liu21st@gmail.com $ - -/** - +------------------------------------------------------------------------------ - * ThinkPHP 视图输出 - +------------------------------------------------------------------------------ - * @category Think - * @package Think - * @subpackage Core - * @author liu21st - * @version $Id: View.class.php 3087 2012-07-28 12:29:23Z liu21st@gmail.com $ - +------------------------------------------------------------------------------ - */ -class View { - protected $tVar = array(); // 模板输出变量 - - /** - +---------------------------------------------------------- - * 模板变量赋值 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @param mixed $name - * @param mixed $value - +---------------------------------------------------------- - */ - public function assign($name,$value=''){ - if(is_array($name)) { - $this->tVar = array_merge($this->tVar,$name); - }elseif(is_object($name)){ - foreach($name as $key =>$val) - $this->tVar[$key] = $val; - }else { - $this->tVar[$name] = $value; - } - } - - /** - +---------------------------------------------------------- - * 取得模板变量的值 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @param string $name - +---------------------------------------------------------- - * @return mixed - +---------------------------------------------------------- - */ - public function get($name=''){ - if('' === $name) { - return $this->tVar; - } - return isset($this->tVar[$name])?$this->tVar[$name]:false; - } - - /** - +---------------------------------------------------------- - * 加载模板和页面输出 可以返回输出内容 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @param string $templateFile 模板文件名 - * @param string $charset 模板输出字符集 - * @param string $contentType 输出类型 - * @param string $content 模板输出内容 - +---------------------------------------------------------- - * @return mixed - +---------------------------------------------------------- - */ - public function display($templateFile='',$charset='',$contentType='',$content='') { - G('viewStartTime'); - // 视图开始标签 - tag('view_begin',$templateFile); - // 解析并获取模板内容 - $content = $this->fetch($templateFile,$content); - // 输出模板内容 - $this->show($content,$charset,$contentType); - // 视图结束标签 - tag('view_end'); - } - - /** - +---------------------------------------------------------- - * 输出内容文本可以包括Html - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @param string $content 输出内容 - * @param string $charset 模板输出字符集 - * @param string $contentType 输出类型 - +---------------------------------------------------------- - * @return mixed - +---------------------------------------------------------- - */ - public function show($content,$charset='',$contentType=''){ - if(empty($charset)) $charset = C('DEFAULT_CHARSET'); - if(empty($contentType)) $contentType = C('TMPL_CONTENT_TYPE'); - // 网页字符编码 - header('Content-Type:'.$contentType.'; charset='.$charset); - header('Cache-control: private'); //支持页面回跳 - header('X-Powered-By:ThinkPHP'); - // 输出模板文件 - echo $content; - } - - /** - +---------------------------------------------------------- - * 解析和获取模板内容 用于输出 - +---------------------------------------------------------- - * @access public - +---------------------------------------------------------- - * @param string $templateFile 模板文件名 - * @param string $content 模板输出内容 - +---------------------------------------------------------- - * @return string - +---------------------------------------------------------- - */ - public function fetch($templateFile='',$content='') { - if(empty($content)) { - // 模板文件解析标签 - tag('view_template',$templateFile); - // 模板文件不存在直接返回 - if(!is_file($templateFile)) return NULL; - } - // 页面缓存 - ob_start(); - ob_implicit_flush(0); - if('php' == strtolower(C('TMPL_ENGINE_TYPE'))) { // 使用PHP原生模板 - // 模板阵列变量分解成为独立变量 - extract($this->tVar, EXTR_OVERWRITE); - // 直接载入PHP模板 - empty($content)?include $templateFile:eval('?>'.$content); - }else{ - // 视图解析标签 - $params = array('var'=>$this->tVar,'file'=>$templateFile,'content'=>$content); - tag('view_parse',$params); - } - // 获取并清空缓存 - $content = ob_get_clean(); - // 内容过滤标签 - tag('view_filter',$content); - // 输出模板文件 - return $content; - } - + +// +---------------------------------------------------------------------- +namespace Think; +/** + * ThinkPHP 视图类 + * @category Think + * @package Think + * @subpackage Core + * @author liu21st + */ +class View { + /** + * 模板输出变量 + * @var tVar + * @access protected + */ + protected $tVar = array(); + + /** + * 模板主题 + * @var theme + * @access protected + */ + protected $theme = ''; + + /** + * 模板变量赋值 + * @access public + * @param mixed $name + * @param mixed $value + */ + public function assign($name,$value=''){ + if(is_array($name)) { + $this->tVar = array_merge($this->tVar,$name); + }else { + $this->tVar[$name] = $value; + } + } + + /** + * 取得模板变量的值 + * @access public + * @param string $name + * @return mixed + */ + public function get($name=''){ + if('' === $name) { + return $this->tVar; + } + return isset($this->tVar[$name])?$this->tVar[$name]:false; + } + + /** + * 加载模板和页面输出 可以返回输出内容 + * @access public + * @param string $templateFile 模板文件名 + * @param string $charset 模板输出字符集 + * @param string $contentType 输出类型 + * @param string $content 模板输出内容 + * @param string $prefix 模板缓存前缀 + * @return mixed + */ + public function display($templateFile='',$charset='',$contentType='',$content='',$prefix='') { + G('viewStartTime'); + // 视图开始标签 + tag('view_begin',$templateFile); + // 解析并获取模板内容 + $content = $this->fetch($templateFile,$content,$prefix); + // 输出模板内容 + $this->render($content,$charset,$contentType); + // 视图结束标签 + tag('view_end'); + } + + /** + * 输出内容文本可以包括Html + * @access private + * @param string $content 输出内容 + * @param string $charset 模板输出字符集 + * @param string $contentType 输出类型 + * @return mixed + */ + private function render($content,$charset='',$contentType=''){ + if(empty($charset)) $charset = C('DEFAULT_CHARSET'); + if(empty($contentType)) $contentType = C('TMPL_CONTENT_TYPE'); + // 网页字符编码 + header('Content-Type:'.$contentType.'; charset='.$charset); + header('Cache-control: '.C('HTTP_CACHE_CONTROL')); // 页面缓存控制 + header('X-Powered-By:ThinkPHP'); + // 输出模板文件 + echo $content; + } + + /** + * 解析和获取模板内容 用于输出 + * @access public + * @param string $templateFile 模板文件名 + * @param string $content 模板输出内容 + * @param string $prefix 模板缓存前缀 + * @return string + */ + public function fetch($templateFile='',$content='',$prefix='') { + if(empty($content)) { + $templateFile = $this->parseTemplate($templateFile); + // 模板文件不存在直接返回 + if(!is_file($templateFile)) E(L('_TEMPLATE_NOT_EXIST_').':'.$templateFile); + } + // 页面缓存 + ob_start(); + ob_implicit_flush(0); + if('php' == strtolower(C('TMPL_ENGINE_TYPE'))) { // 使用PHP原生模板 + // 模板阵列变量分解成为独立变量 + extract($this->tVar, EXTR_OVERWRITE); + // 直接载入PHP模板 + empty($content)?include $templateFile:eval('?>'.$content); + }else{ + // 视图解析标签 + $params = array('var'=>$this->tVar,'file'=>$templateFile,'content'=>$content,'prefix'=>$prefix); + tag('view_parse',$params); + } + // 获取并清空缓存 + $content = ob_get_clean(); + // 内容过滤标签 + tag('view_filter',$content); + // 输出模板文件 + return $content; + } + + /** + * 自动定位模板文件 + * @access protected + * @param string $template 模板文件规则 + * @return string + */ + public function parseTemplate($template='') { + if(is_file($template)) { + return $template; + } + $depr = C('TMPL_FILE_DEPR'); + $template = str_replace(':', $depr, $template); + // 获取当前主题名称 + $theme = $this->getTemplateTheme(); + + // 获取当前模块 + $module = MODULE_NAME; + if(strpos($template,'@')){ // 跨分组调用模版文件 + list($module,$template) = explode('@',$template); + } + // 获取当前主题的模版路径 + if(C('VIEW_PATH')){ // 视图目录 + define('THEME_PATH', C('VIEW_PATH').$module.'/'.$theme); + }else{ // 模块视图 + define('THEME_PATH', APP_PATH.$module.'/'.C('DEFAULT_V_LAYER').'/'.$theme); + } + + // 分析模板文件规则 + if('' == $template) { + // 如果模板文件名为空 按照默认规则定位 + $template = CONTROLLER_NAME . $depr . ACTION_NAME; + }elseif(false === strpos($template, $depr)){ + $template = CONTROLLER_NAME . $depr . $template; + } + return THEME_PATH.$template.C('TMPL_TEMPLATE_SUFFIX'); + } + + /** + * 设置当前输出的模板主题 + * @access public + * @param mixed $theme 主题名称 + * @return View + */ + public function theme($theme){ + $this->theme = $theme; + return $this; + } + + /** + * 获取当前的模板主题 + * @access private + * @return string + */ + private function getTemplateTheme() { + if($this->theme) { // 指定模板主题 + $theme = $this->theme; + }else{ + /* 获取模板主题名称 */ + $theme = C('DEFAULT_THEME'); + if(C('TMPL_DETECT_THEME')) {// 自动侦测模板主题 + $t = C('VAR_TEMPLATE'); + if (isset($_GET[$t])){ + $theme = $_GET[$t]; + }elseif(cookie('think_template')){ + $theme = cookie('think_template'); + } + if(!in_array($theme,explode(',',C('THEME_LIST')))){ + $theme = C('DEFAULT_THEME'); + } + cookie('think_template',$theme,864000); + } + } + define('THEME_NAME', $theme); // 当前模板主题名称 + return $theme?$theme . '/':''; + } + } \ No newline at end of file diff --git a/README.txt b/ThinkPHP/README.txt similarity index 92% rename from README.txt rename to ThinkPHP/README.txt index b78a3bca18b3b80c20d01408ca5bec3c0a1cf96d..e4d1cb1c9bf8663e9c0045961bf0c7f583472aeb 100644 --- a/README.txt +++ b/ThinkPHP/README.txt @@ -1,127 +1,127 @@ -+------------------------------------------------------------------- -| 感谢您使用ThinkPHP开发框架 ^_^ -+------------------------------------------------------------------- -| 大道至简 开发由我 WE CAN DO IT,JUST THINK -+------------------------------------------------------------------- -| 版本信息:ThinkPHP 3.0 Release 2012/3/5 -+------------------------------------------------------------------- -| Copyright(c) 2006-2012 http://thinkphp.cn All rights reserved. -+------------------------------------------------------------------- - -[ 简介 ] -ThinkPHP 是一个免费开源的,快速、简单的面向对象的 轻量级PHP开发框架, -遵循Apache2开源协议发布,是为了敏捷WEB应用开发和简化企业应用开发而 -诞生的。ThinkPHP从诞生以来一直秉承简洁实用的设计原则,在保持出色的性 -能和至简的代码的同时,也注重易用性。并且拥有众多的原创功能和特性,在 -社区团队的积极参与下,在易用性、扩展性和性能方面不断优化和改进,众多 -的典型案例确保可以稳定用于商业以及门户级的开发。 - -经过6年的不断积累和重构,3.0版本在框架底层的定制和扩展方面趋于完善, -使得应用的开发范围和需求适应度更加扩大,能够满足不同程度的开发人员的 -需求。而且引入了全新的CBD(核心+行为+驱动)架构模式,旨在打造DIY框架 -和AOP编程体验,让ThinkPHP能够在不同方面都能快速满足项目和应用的需求, -并且正式引入SAE、REST和Mongo支持。 - -使用ThinkPHP,你可以更方便和快捷的开发和部署应用。当然不仅仅是企业级 -应用,任何PHP应用开发都可以从ThinkPHP的简单和快速的特性中受益。 -ThinkPHP本身具有很多的原创特性,并且倡导大道至简,开发由我的开发理念, -用最少的代码完成更多的功能,宗旨就是让WEB应用开发更简单、更快速。 -为此ThinkPHP会不断吸收和融入更好的技术以保证其新鲜和活力,提供WEB应 -用开发的最佳实践!经过6年来的不断重构和改进,ThinkPHP达到了一个新的 -阶段,能够满足企业开发中复杂的项目需求,足以达到企业级和门户级的开 -发标准。 - -[ 协议 ] -ThinkPHP遵循Apache2开源许可协议发布,意味着你可以免费使用ThinkPHP, -甚至允许把你的ThinkPHP应用采用商业闭源发布。 -具体参考LICENSE.txt内容 - -[ 特性 ] -CBD架构:ThinkPHP3.0版本引入了全新的CBD(核心+行为+驱动)架构模式, -打造框架底层DIY定制和类AOP编程体验。利用这一新的特性,开发人员可以 -方便地通过模式扩展为自己量身定制一套属于自己或者企业的开发框架。 -编译机制:独创的项目编译机制,有效减少OOP开发中文件加载的性能开销。 -改进后的项目编译机制,可以支持编译文件直接作为入口载入,并且支持常量 -外部载入,利于产品发布。 - -类库导入:采用基于类库包和命名空间的方式导入类库,让类库导入看起来更 -加简单清晰,而且还支持自动加载和别名导入。为了方便项目的跨平台移植, -系统还可以严格检查加载文件的大小写。 - -URL和路由:系统支持普通模式、PATHINFO模式、REWRITE模式和兼容模式的 -URL方式,支持不同的服务器和运行模式的部署,配合URL路由功能,让你随心 -所欲的构建需要的URL地址和进行SEO优化工作。支持灵活的规则路由和正则路 -由,以及路由重定向支持,带给开发人员更方便灵活的URL优化体验。 -调试模式:框架提供的调试模式可以方便用于开发过程的不同阶段,包括开发、 -测试和演示等任何需要的情况,不同的应用模式可以配置独立的项目配置文件。 -只是小小的性能牺牲就能满足调试开发过程中的日志和分析需要,并确保将来的 -部署顺利,一旦切换到部署模式则可以迅速提升性能。 - -ORM :简洁轻巧的ORM实现,配合简单的CURD以及AR模式,让开发效率无处不在。 - -数据库:支持包括Mysql、Sqlite、Pgsql、Oracle、SqlServer、Mongo等数据库, -并且内置分布式数据库和读写分离功能支持。系统支持多数据库连接和动态切换 -机制,犹如企业开发的一把利刃,跨数据库应用和分布式支持从此无忧。 - -查询语言:内建丰富的查询机制,包括组合查询、快捷查询、复合查询、区间 -查询、统计查询、定位查询、多表查询、子查询、动态查询和原生查询,让你的 -数据查询简洁高效。 - -动态模型:无需创建任何对应的模型类,轻松完成CURD操作,支持多种模型之间 -的动态切换,让你领略数据操作的无比畅快和最佳体验。 - -扩展模型:提供了丰富的扩展模型,包括:支持序列化字段、文本字段、只读字 -段、延迟写入、乐观锁、数据分表等高级特性的高级模型;可以轻松动态地创建 -数据库视图的视图模型;支持关联操作的关联模型;支持Mongo数据库的Mongo模 -型等等,都可以方便的使用。 - -模块分组:不用担心大项目的分工协调和部署问题,分组帮你解决跨项目的难题, -还可以支持对分组的二级域名部署支持。 - -模板引擎:系统内建了一款卓越的基于XML的编译型模板引擎,支持两种类型的 -模板标签,融合了Smarty和JSP标签库的思想,并内置布局模板功能和标签库扩展 -支持。通过驱动还可以支持Smarty、EaseTemplate、TemplateLite、Smart等其他第 -三方模板引擎。 - -AJAX支持:内置和客户端无关的AJAX数据返回方法,支持JSON、XML和EVAL类型 -返回客户端,而且可以扩展返回数据格式,系统不绑定任何AJAX类库,可随意使 -用自己熟悉的AJAX类库进行操作。 - -SAE支持:提供了新浪SAE平台的强力支持,具备“横跨性”和“平滑性”,支持本地化 -开发和调试以及部署切换,让你轻松过渡到SAE开发,打造全新的SAE开发体验。 - -RESTFul支持:REST模式提供了RESTFul支持,为你打造全新的URL设计和访问体验, -同时为接口应用提供了支持。 - -多语言支持:系统支持语言包功能,项目和分组都可以有单独的语言包,并且可以 -自动检测浏览器语言自动载入对应的语言包。 - -模式扩展:除了标准模式外,还提供了AMF、PHPRpc、Lite、Thin和Cli模式扩展支 -持,针对不同级别的应用开发提供最佳核心框架,还可以自定义模式扩展。 - -自动验证和完成:自动完成表单数据的验证和过滤,新版新增了IP验证和有效期验 -证等更多的验证方式,配合自动完成可以生成安全的数据对象。 - -字段类型检测:系统会自动缓存字段信息和字段类型,支持非法字段过滤和字段类 -型强制转换,确保数据写入和查询更安全。 - -缓存机制:系统支持包括文件方式、APC、Db、Memcache、Shmop、Sqlite、Redis、 -Eaccelerator和Xcache在内的动态数据缓存类型,以及可定制的静态缓存规则,并 -提供了快捷方法进行存取操作。 - -扩展机制:系统支持包括模式扩展、行为扩展、类库扩展、驱动扩展、模型扩展、 -控制器扩展、Widget扩展在内的强大灵活的扩展机制,让你不再受限于核心的不足 -和无所适从,随心DIY自己的框架和扩展应用,满足企业开发中更加复杂的项目需求。 - -[ 要求 ] -ThinkPHP3.0需要PHP5.2.0以上版本支持,可以运行在任何系统环境下面。 - -[ 安装 ] -ThinkPHP无需安装,下载ThinkPHP核心包或者完整版之后,把解压后的目录拷贝到 -你的WEB服务器或者WEB目录即可。 - -[ 鸣谢 ] -特别要鸣谢ThinkPHP团队和所有关注和支持ThinkPHP的用户。 - -[ 支持 ] -更多内容和支持请访问ThinkPHP官方网站http://thinkphp.cn/ 和论坛 http://bbs.thinkphp.cn。 \ No newline at end of file ++------------------------------------------------------------------- +| 感谢您使用ThinkPHP开发框架 ^_^ ++------------------------------------------------------------------- +| 大道至简 开发由我 WE CAN DO IT,JUST THINK ++------------------------------------------------------------------- +| 版本信息:ThinkPHP 3.2.0 Beta ++------------------------------------------------------------------- +| Copyright(c) 2006-2013 http://thinkphp.cn All rights reserved. ++------------------------------------------------------------------- + +[ 简介 ] +ThinkPHP 是一个免费开源的,快速、简单的面向对象的 轻量级PHP开发框架, +遵循Apache2开源协议发布,是为了敏捷WEB应用开发和简化企业应用开发而 +诞生的。ThinkPHP从诞生以来一直秉承简洁实用的设计原则,在保持出色的性 +能和至简的代码的同时,也注重易用性。并且拥有众多的原创功能和特性,在 +社区团队的积极参与下,在易用性、扩展性和性能方面不断优化和改进,众多 +的典型案例确保可以稳定用于商业以及门户级的开发。 + +经过6年的不断积累和重构,3.*版本在框架底层的定制和扩展方面趋于完善, +使得应用的开发范围和需求适应度更加扩大,能够满足不同程度的开发人员的 +需求。而且引入了全新的CBD(核心+行为+驱动)架构模式,旨在打造DIY框架 +和AOP编程体验,让ThinkPHP能够在不同方面都能快速满足项目和应用的需求, +并且正式引入SAE、REST和Mongo支持。 + +使用ThinkPHP,你可以更方便和快捷的开发和部署应用。当然不仅仅是企业级 +应用,任何PHP应用开发都可以从ThinkPHP的简单和快速的特性中受益。 +ThinkPHP本身具有很多的原创特性,并且倡导大道至简,开发由我的开发理念, +用最少的代码完成更多的功能,宗旨就是让WEB应用开发更简单、更快速。 +为此ThinkPHP会不断吸收和融入更好的技术以保证其新鲜和活力,提供WEB应 +用开发的最佳实践!经过6年来的不断重构和改进,ThinkPHP达到了一个新的 +阶段,能够满足企业开发中复杂的项目需求,足以达到企业级和门户级的开 +发标准。 + +[ 协议 ] +ThinkPHP遵循Apache2开源许可协议发布,意味着你可以免费使用ThinkPHP, +甚至允许把你的ThinkPHP应用采用商业闭源发布。 +具体参考LICENSE.txt内容 + +[ 特性 ] +CBD架构:ThinkPHP3.0版本引入了全新的CBD(核心+行为+驱动)架构模式, +打造框架底层DIY定制和类AOP编程体验。利用这一新的特性,开发人员可以 +方便地通过模式扩展为自己量身定制一套属于自己或者企业的开发框架。 +编译机制:独创的项目编译机制,有效减少OOP开发中文件加载的性能开销。 +改进后的项目编译机制,可以支持编译文件直接作为入口载入,并且支持常量 +外部载入,利于产品发布。 + +类库导入:采用基于类库包和命名空间的方式导入类库,让类库导入看起来更 +加简单清晰,而且还支持自动加载和别名导入。为了方便项目的跨平台移植, +系统还可以严格检查加载文件的大小写。 + +URL和路由:系统支持普通模式、PATHINFO模式、REWRITE模式和兼容模式的 +URL方式,支持不同的服务器和运行模式的部署,配合URL路由功能,让你随心 +所欲的构建需要的URL地址和进行SEO优化工作。支持灵活的规则路由和正则路 +由,以及路由重定向支持,带给开发人员更方便灵活的URL优化体验。 +调试模式:框架提供的调试模式可以方便用于开发过程的不同阶段,包括开发、 +测试和演示等任何需要的情况,不同的应用模式可以配置独立的项目配置文件。 +只是小小的性能牺牲就能满足调试开发过程中的日志和分析需要,并确保将来的 +部署顺利,一旦切换到部署模式则可以迅速提升性能。 + +ORM :简洁轻巧的ORM实现,配合简单的CURD以及AR模式,让开发效率无处不在。 + +数据库:支持包括Mysql、Sqlite、Pgsql、Oracle、SqlServer、Mongo等数据库, +并且内置分布式数据库和读写分离功能支持。系统支持多数据库连接和动态切换 +机制,犹如企业开发的一把利刃,跨数据库应用和分布式支持从此无忧。 + +查询语言:内建丰富的查询机制,包括组合查询、快捷查询、复合查询、区间 +查询、统计查询、定位查询、多表查询、子查询、动态查询和原生查询,让你的 +数据查询简洁高效。 + +动态模型:无需创建任何对应的模型类,轻松完成CURD操作,支持多种模型之间 +的动态切换,让你领略数据操作的无比畅快和最佳体验。 + +扩展模型:提供了丰富的扩展模型,包括:支持序列化字段、文本字段、只读字 +段、延迟写入、乐观锁、数据分表等高级特性的高级模型;可以轻松动态地创建 +数据库视图的视图模型;支持关联操作的关联模型;支持Mongo数据库的Mongo模 +型等等,都可以方便的使用。 + +模块分组:不用担心大项目的分工协调和部署问题,分组帮你解决跨项目的难题, +还可以支持对分组的二级域名部署支持。 + +模板引擎:系统内建了一款卓越的基于XML的编译型模板引擎,支持两种类型的 +模板标签,融合了Smarty和JSP标签库的思想,并内置布局模板功能和标签库扩展 +支持。通过驱动还可以支持Smarty、EaseTemplate、TemplateLite、Smart等其他第 +三方模板引擎。 + +AJAX支持:内置和客户端无关的AJAX数据返回方法,支持JSON、XML和EVAL类型 +返回客户端,而且可以扩展返回数据格式,系统不绑定任何AJAX类库,可随意使 +用自己熟悉的AJAX类库进行操作。 + +云引擎支持:提供了新浪SAE平台和百度BAE平台的强力支持,具备“横跨性”和“平滑性”,支持本地化 +开发和调试以及部署切换,让你轻松过渡,打造全新的开发体验。 + +RESTFul支持:REST模式提供了RESTFul支持,为你打造全新的URL设计和访问体验, +同时为接口应用提供了支持。 + +多语言支持:系统支持语言包功能,项目和分组都可以有单独的语言包,并且可以 +自动检测浏览器语言自动载入对应的语言包。 + +模式扩展:除了标准模式外,还提供了AMF、PHPRpc、Lite、Thin和Cli模式扩展支 +持,针对不同级别的应用开发提供最佳核心框架,还可以自定义模式扩展。 + +自动验证和完成:自动完成表单数据的验证和过滤,新版新增了IP验证和有效期验 +证等更多的验证方式,配合自动完成可以生成安全的数据对象。 + +字段类型检测:系统会自动缓存字段信息和字段类型,支持非法字段过滤和字段类 +型强制转换,确保数据写入和查询更安全。 + +缓存机制:系统支持包括文件方式、APC、Db、Memcache、Shmop、Sqlite、Redis、 +Eaccelerator和Xcache在内的动态数据缓存类型,以及可定制的静态缓存规则,并 +提供了快捷方法进行存取操作。 + +扩展机制:系统支持包括模式扩展、行为扩展、类库扩展、驱动扩展、模型扩展、 +控制器扩展、Widget扩展在内的强大灵活的扩展机制,让你不再受限于核心的不足 +和无所适从,随心DIY自己的框架和扩展应用,满足企业开发中更加复杂的项目需求。 + +[ 要求 ] +ThinkPHP3.1需要PHP5.2.0以上版本支持,可以运行在任何系统环境下面。 + +[ 安装 ] +ThinkPHP无需安装,下载ThinkPHP核心包或者完整版之后,把解压后的目录拷贝到 +你的WEB服务器或者WEB目录即可。 + +[ 鸣谢 ] +特别要鸣谢ThinkPHP团队和所有关注和支持ThinkPHP的用户。 + +[ 支持 ] +更多内容和支持请访问ThinkPHP官方网站http://thinkphp.cn/。 \ No newline at end of file diff --git a/ThinkPHP/ThinkPHP.php b/ThinkPHP/ThinkPHP.php new file mode 100644 index 0000000000000000000000000000000000000000..d287dae05345ea26c5ea3724a86fd5332281fb81 --- /dev/null +++ b/ThinkPHP/ThinkPHP.php @@ -0,0 +1,84 @@ + +// +---------------------------------------------------------------------- + +// ThinkPHP 入口文件 +if(version_compare(PHP_VERSION,'5.3.0','<')) die('require PHP > 5.3.0 !'); +// 记录开始运行时间 +$GLOBALS['_beginTime'] = microtime(TRUE); +// 记录内存初始使用 +define('MEMORY_LIMIT_ON',function_exists('memory_get_usage')); +if(MEMORY_LIMIT_ON) $GLOBALS['_startUseMems'] = memory_get_usage(); + +// 版本信息 +const THINK_VERSION = '3.2.0RC1'; + +// URL 模式定义 +const URL_COMMON = 0; //普通模式 +const URL_PATHINFO = 1; //PATHINFO模式 +const URL_REWRITE = 2; //REWRITE模式 +const URL_COMPAT = 3; // 兼容模式 + +// 类文件后缀 +const EXT = '.class.php'; + +// 系统常量定义 +defined('THINK_PATH') or define('THINK_PATH', dirname(__FILE__).'/'); +defined('APP_PATH') or define('APP_PATH', dirname($_SERVER['SCRIPT_FILENAME']).'/'); +defined('APP_DEBUG') or define('APP_DEBUG', false); // 是否调试模式 +defined('APP_MODE') or define('APP_MODE', 'common'); // 应用模式 默认为普通模式 +defined('RUNTIME_PATH') or define('RUNTIME_PATH', APP_PATH.'Runtime/'); +defined('LIB_PATH') or define('LIB_PATH', THINK_PATH.'Library/'); // 系统核心类库目录 +defined('CORE_PATH') or define('CORE_PATH', LIB_PATH.'Think/'); // 第三方类库目录 +defined('EXTEND_PATH') or define('EXTEND_PATH', THINK_PATH.'Extend/'); // 系统扩展目录 +defined('MODE_PATH') or define('MODE_PATH', EXTEND_PATH.'Mode/'); // 模式扩展目录 +defined('VENDOR_PATH') or define('VENDOR_PATH', LIB_PATH.'Vendor/'); // 第三方类库目录 +defined('COMMON_PATH') or define('COMMON_PATH', APP_PATH.'Common/'); // 项目公共目录 +defined('LANG_PATH') or define('LANG_PATH', COMMON_PATH.'Lang/'); // 项目语言目录 +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/'); // 项目模板缓存目录 + +// 系统信息 +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); + +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__')) { + $_root = rtrim(dirname(_PHP_FILE_),'/'); + define('__ROOT__', (($_root=='/' || $_root=='\\')?'':$_root)); + } +} + +// 加载公共函数 +require THINK_PATH.'Common/common.php'; +// 加载核心Think类 +require CORE_PATH.'Think'.EXT; +// 应用初始化 +Think\Think::start(); \ No newline at end of file diff --git a/ThinkPHP/Tpl/default_index.tpl b/ThinkPHP/Tpl/default_index.tpl new file mode 100644 index 0000000000000000000000000000000000000000..9ff2811a5d2e2415e2ab3d483c7fc54809c2af23 --- /dev/null +++ b/ThinkPHP/Tpl/default_index.tpl @@ -0,0 +1,9 @@ +show('

:)

欢迎使用 ThinkPHP

','utf-8'); + } +} \ No newline at end of file diff --git a/ThinkPHP/Tpl/dispatch_jump.tpl b/ThinkPHP/Tpl/dispatch_jump.tpl new file mode 100644 index 0000000000000000000000000000000000000000..585efa59fb0a612564738cd5c8558f9628e9ae7c --- /dev/null +++ b/ThinkPHP/Tpl/dispatch_jump.tpl @@ -0,0 +1,44 @@ + + + + +跳转提示 + + + +
+ +

:)

+

+ +

:(

+

+
+

+

+页面自动 跳转 等待时间: +

+
+ + + \ No newline at end of file diff --git a/ThinkPHP/Tpl/page_trace.tpl b/ThinkPHP/Tpl/page_trace.tpl new file mode 100644 index 0000000000000000000000000000000000000000..e06b3ea9260b9cfcd2ea6655b44180560c13ebef --- /dev/null +++ b/ThinkPHP/Tpl/page_trace.tpl @@ -0,0 +1,67 @@ +
+ + +
+
+ diff --git a/ThinkPHP/Tpl/think_exception.tpl b/ThinkPHP/Tpl/think_exception.tpl new file mode 100644 index 0000000000000000000000000000000000000000..84b27e9771c88c6c86ce64e212ee2613d07f179c --- /dev/null +++ b/ThinkPHP/Tpl/think_exception.tpl @@ -0,0 +1,53 @@ + + + +系统发生错误 + + + +
+

:(

+

+
+ +
+
+

错误位置

+
+
+

FILE:  LINE:

+
+
+ + +
+
+

TRACE

+
+
+

+
+
+ +
+
+ + + \ No newline at end of file diff --git a/logo.png b/ThinkPHP/logo.png similarity index 100% rename from logo.png rename to ThinkPHP/logo.png diff --git a/Tpl/default_index.tpl b/Tpl/default_index.tpl deleted file mode 100644 index ccf8830afc7fd775ee592b853cfbe8e123c1a214..0000000000000000000000000000000000000000 --- a/Tpl/default_index.tpl +++ /dev/null @@ -1,7 +0,0 @@ -show('
^_^ Hello,欢迎使用ThinkPHP
','utf-8'); - } -} \ No newline at end of file diff --git a/Tpl/dispatch_jump.tpl b/Tpl/dispatch_jump.tpl deleted file mode 100644 index 503aef2785070e299e1a06cb0a172d091b25269b..0000000000000000000000000000000000000000 --- a/Tpl/dispatch_jump.tpl +++ /dev/null @@ -1,41 +0,0 @@ - - - - - 跳转提示 - - - -
- -

:)

-

{$message}

- -

:(

-

{$error}

-
-

-

- 页面自动 跳转 等待时间: {$waitSecond} -

-
- - - diff --git a/Tpl/page_trace.tpl b/Tpl/page_trace.tpl deleted file mode 100644 index 23b5a4fef79c3a753ef8d6c3d365fab3bc2c2743..0000000000000000000000000000000000000000 --- a/Tpl/page_trace.tpl +++ /dev/null @@ -1,67 +0,0 @@ -
- - -
-
- \ No newline at end of file diff --git a/Tpl/think_exception.tpl b/Tpl/think_exception.tpl deleted file mode 100644 index f8a245253b23f0ae6ce0c240397d94d4500445ac..0000000000000000000000000000000000000000 --- a/Tpl/think_exception.tpl +++ /dev/null @@ -1,73 +0,0 @@ - - - -系统发生错误 - - - - - -
-

系统发生错误

-
您可以选择 [ 重试 ] [ 返回 ] 或者 [ 回到首页 ]
- -

错误位置: FILE:  LINE:

- -

[ 错误信息 ]

-

- -

[ TRACE ]

-

- -

- -
-
ThinkPHP { Fast & Simple OOP PHP Framework } -- [ WE CAN DO IT JUST THINK ] -
- - \ No newline at end of file diff --git a/index.php b/index.php new file mode 100644 index 0000000000000000000000000000000000000000..05461a272fa16f821ec86c80992b422b79484f75 --- /dev/null +++ b/index.php @@ -0,0 +1,13 @@ + +// +---------------------------------------------------------------------- + +define('APP_PATH','./Application/'); +require './ThinkPHP/ThinkPHP.php'; \ No newline at end of file