- * @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.= '' . $root . '>';
- 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.="$key>";
- }
- 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 .= "{$root}>";
+ 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 .= "{$key}>";
+ }
+ 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 = ' ';
+ return $parse;
+ }
+
+ // 多附件型
+ protected function _files($var) {
+ $parse = '
+ $array = explode(\',\',$'.$var.'[\'value\']);
+
+
+ ';
+ return $parse;
+ }
+
+ // 单选型
+ // 选项1,选项2,...
+ // 选项1:显示1,选项2:显示2,...
+ // @model.id 调用模型
+ // :fun 函数
+ protected function _radio($var,$default) {
+ $parse = '
+ ';
+ 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 = ' ';
+ 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 = ' ';
+ }
+ 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 = '