diff --git a/README.md b/README.md new file mode 100644 index 000000000..97390798f --- /dev/null +++ b/README.md @@ -0,0 +1,38 @@ +## 简介 + +ThinkPHP 是一个免费开源的,快速、简单的面向对象的 轻量级PHP开发框架 ,创立于2006年初,遵循Apache2开源协议发布,是为了敏捷WEB应用开发和简化企业应用开发而诞生的。ThinkPHP从诞生以来一直秉承简洁实用的设计原则,在保持出色的性能和至简的代码的同时,也注重易用性。并且拥有众多的原创功能和特性,在社区团队的积极参与下,在易用性、扩展性和性能方面不断优化和改进,已经成长为国内最领先和最具影响力的WEB应用开发框架,众多的典型案例确保可以稳定用于商业以及门户级的开发。 + +## 全面的WEB开发特性支持 + +最新的ThinkPHP为WEB应用开发提供了强有力的支持,这些支持包括: + +* MVC支持-基于模型(M)、视图(V)、控制器(C)的设计模式 +* ORM支持-提供了全功能和高性能的ORM支持,支持大部分数据库 +* 模板引擎支持-内置了高性能的基于标签库和XML标签的编译型模板引擎 +* RESTFul支持-REST模式提供了RESTFul支持,为你打造全新的URL设计和访问体验 +* SAE支持-提供了新浪SAE平台的强力支持,具备“横跨性”和“平滑性”,支持本地化开发和调试以及部署切换,打造全新的SAE开发体验 +* CLI支持-支持基于命令行的应用开发 +* AMF支持-支持Flex开发和Flash通讯,打造互联网富应用 +* PHPRPC支持-提供基于PHPRpc的WEBService解决方案 +* MongoDb支持-提供NoSQL的支持 +* 缓存支持-提供了包括文件、数据库、Memcache、Xcache、Redis等多种类型的缓存支持 + +## 大道至简的开发理念 + +ThinkPHP从诞生以来一直秉承大道至简的开发理念,无论从底层实现还是应用开发,我们都倡导用最少的代码完成相同的功能,正是由于对简单的执着和代码的修炼,让我们长期保持出色的性能和极速的开发体验。在主流PHP开发框架的评测数据中表现卓越,简单和快速开发是我们不变的宗旨。 + +## 安全性 + +框架在系统层面提供了众多的安全特性,确保你的网站和产品安全无忧。这些特性包括: + +* XSS安全防护 +* 表单自动验证 +* 强制数据类型转换 +* 输入数据过滤 +* 表单令牌验证 +* 防SQL注入 +* 图像上传检测 + +## 商业友好的开源协议 + +ThinkPHP遵循Apache2开源协议发布。Apache Licence是著名的非盈利开源组织Apache采用的协议。该协议和BSD类似,鼓励代码共享和尊重原作者的著作权,同样允许代码修改,再作为开源或商业软件发布。 \ No newline at end of file diff --git a/README.txt b/README.txt deleted file mode 100644 index 200b27d71..000000000 --- a/README.txt +++ /dev/null @@ -1,36 +0,0 @@ -ThinkPHP 是一个免费开源的,快速、简单的面向对象的 轻量级PHP开发框架 ,创立于2006年初,遵循Apache2开源协议发布,是为了敏捷WEB应用开发和简化企业应用开发而诞生的。ThinkPHP从诞生以来一直秉承简洁实用的设计原则,在保持出色的性能和至简的代码的同时,也注重易用性。并且拥有众多的原创功能和特性,在社区团队的积极参与下,在易用性、扩展性和性能方面不断优化和改进,已经成长为国内最领先和最具影响力的WEB应用开发框架,众多的典型案例确保可以稳定用于商业以及门户级的开发。 - -[ 全面的WEB开发特性支持 ] - -最新的ThinkPHP为WEB应用开发提供了强有力的支持,这些支持包括: - MVC支持-基于模型(M)、视图(V)、控制器(C)的设计模式 - ORM支持-提供了全功能和高性能的ORM支持,支持大部分数据库 - 模板引擎支持-内置了高性能的基于标签库和XML标签的编译型模板引擎 - RESTFul支持-REST模式提供了RESTFul支持,为你打造全新的URL设计和访问体验 - SAE支持-提供了新浪SAE平台的强力支持,具备“横跨性”和“平滑性”,支持本地化开发和调试以及部署切换,打造全新的SAE开发体验 - CLI支持-支持基于命令行的应用开发 - AMF支持-支持Flex开发和Flash通讯,打造互联网富应用 - PHPRPC支持-提供基于PHPRpc的WEBService解决方案 - MongoDb支持-提供NoSQL的支持 - 缓存支持-提供了包括文件、数据库、Memcache、Xcache、Redis等多种类型的缓存支持 - -[ 大道至简的开发理念 ] - -ThinkPHP从诞生以来一直秉承大道至简的开发理念,无论从底层实现还是应用开发,我们都倡导用最少的代码完成相同的功能,正是由于对简单的执着和代码的修炼,让我们长期保持出色的性能和极速的开发体验。在主流PHP开发框架的评测数据中表现卓越,简单和快速开发是我们不变的宗旨。 - - -[ 安全性 ] - -框架在系统层面提供了众多的安全特性,确保你的网站和产品安全无忧。这些特性包括: - - XSS安全防护 - 表单自动验证 - 强制数据类型转换 - 输入数据过滤 - 表单令牌验证 - 防SQL注入 - 图像上传检测 - -[ 商业友好的开源协议 ] - -ThinkPHP遵循Apache2开源协议发布。Apache Licence是著名的非盈利开源组织Apache采用的协议。该协议和BSD类似,鼓励代码共享和尊重原作者的著作权,同样允许代码修改,再作为开源或商业软件发布。 \ No newline at end of file diff --git a/ThinkPHP/Common/common.php b/ThinkPHP/Common/common.php index fd0207430..015852b99 100644 --- a/ThinkPHP/Common/common.php +++ b/ThinkPHP/Common/common.php @@ -16,6 +16,86 @@ * @author liu21st */ +/** + * 获取输入参数 支持过滤和默认值 + * 使用方法: + * + * I('id',0); 获取id参数 自动判断get或者post + * I('post.name','','htmlspecialchars'); 获取$_POST['name'] + * I('get.'); 获取$_GET + * + * @param string $name 变量的名称 支持指定类型 + * @param mixed $default 不存在的时候默认值 + * @param mixed $filter 参数过滤方法 + * @return mixed + */ +function I($name,$default='',$filter='') { + if(strpos($name,'.')) { // 指定参数来源 + list($method,$name) = explode('.',$name); + }else{ // 默认为自动判断 + $method = 'param'; + } + switch(strtolower($method)) { + case 'get' : $input =& $_GET;break; + case 'post' : $input =& $_POST;break; + case 'put' : parse_str(file_get_contents('php://input'), $input);break; + case 'param' : + switch($_SERVER['REQUEST_METHOD']) { + case 'POST': + $input = $_POST; + break; + case 'PUT': + parse_str(file_get_contents('php://input'), $input); + break; + default: + $input = $_GET; + } + if(C('VAR_URL_PARAMS')){ + $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: + return NULL; + } + // 全局过滤 + // array_walk_recursive($input,'filter_exp'); + if(C('VAR_FILTERS')) { + $_filters = explode(',',C('VAR_FILTERS')); + foreach($_filters as $_filter){ + // 全局参数过滤 + array_walk_recursive($input,$_filter); + } + } + if(empty($name)) { // 获取全部变量 + $data = $input; + }elseif(isset($input[$name])) { // 取值操作 + $data = $input[$name]; + $filters = isset($filter)?$filter:C('DEFAULT_FILTER'); + if($filters) { + $filters = explode(',',$filters); + foreach($filters as $filter){ + if(function_exists($filter)) { + $data = is_array($data)?array_map($filter,$data):$filter($data); // 参数过滤 + }else{ + $data = filter_var($data,is_int($filter)?$filter:filter_id($filter)); + if(false === $data) { + return isset($default)?$default:NULL; + } + } + } + } + }else{ // 变量默认值 + $data = isset($default)?$default:NULL; + } + return $data; +} + /** * 记录和统计时间(微秒)和内存使用情况 * 使用方法: @@ -264,7 +344,13 @@ function D($name='',$layer='') { $name = C('DEFAULT_APP').'/'.$layer.'/'.$name; } if(isset($_model[$name])) return $_model[$name]; - import($name.$layer); + $path = explode('/',$name); + if(count($path)>3 && 1 == C('APP_GROUP_MODE')) { // 独立分组 + $baseUrl = $path[0]== '@' ? dirname(BASE_LIB_PATH) : APP_PATH.'../'.$path[0].'/'.C('APP_GROUP_PATH').'/'; + import($path[2].'/'.$path[1].'/'.$path[3].$layer,$baseUrl); + }else{ + import($name.$layer); + } $class = basename($name.$layer); if(class_exists($class)) { $model = new $class(basename($name)); @@ -311,15 +397,19 @@ function A($name,$layer='',$common=false) { $name = '@/'.$layer.'/'.$name; } if(isset($_action[$name])) return $_action[$name]; - if($common){ // 独立分组情况下 加载公共目录类库 + $path = explode('/',$name); + if(count($path)>3 && 1 == C('APP_GROUP_MODE')) { // 独立分组 + $baseUrl = $path[0]== '@' ? dirname(BASE_LIB_PATH) : APP_PATH.'../'.$path[0].'/'.C('APP_GROUP_PATH').'/'; + import($path[2].'/'.$path[1].'/'.$path[3].$layer,$baseUrl); + }elseif($common) { // 加载公共类库目录 import(str_replace('@/','',$name).$layer,LIB_PATH); }else{ - import($name.$layer); - } + import($name.$layer); + } $class = basename($name.$layer); if(class_exists($class,false)) { - $action = new $class(); - $_action[$name] = $action; + $action = new $class(); + $_action[$name] = $action; return $action; }else { return false; diff --git a/ThinkPHP/Common/functions.php b/ThinkPHP/Common/functions.php index 8fc982de6..ae79f9f13 100644 --- a/ThinkPHP/Common/functions.php +++ b/ThinkPHP/Common/functions.php @@ -29,18 +29,10 @@ function halt($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; + ob_start(); + debug_print_backtrace(); + $e['trace'] = ob_get_clean(); } else { $e = $error; } @@ -70,7 +62,7 @@ function halt($error) { */ function throw_exception($msg, $type='ThinkException', $code=0) { if (class_exists($type, false)) - throw new $type($msg, $code, true); + throw new $type($msg, $code); else halt($msg); // 异常类型不存在则输出错误信息字串 } @@ -295,11 +287,13 @@ function U($url='',$vars='',$suffix=true,$redirect=false,$domain=false) { * @param string $name Widget名称 * @param array $data 传人的参数 * @param boolean $return 是否返回内容 + * @param string $path Widget所在路径 * @return void */ -function W($name, $data=array(), $return=false) { +function W($name, $data=array(), $return=false,$path='') { $class = $name . 'Widget'; - require_cache(BASE_LIB_PATH . 'Widget/' . $class . '.class.php'); + $path = empty($path) ? BASE_LIB_PATH : $path; + require_cache($path . 'Widget/' . $class . '.class.php'); if (!class_exists($class)) throw_exception(L('_CLASS_NOT_EXIST_') . ':' . $class); $widget = Think::instance($class); @@ -390,7 +384,11 @@ function S($name,$value='',$options=null) { }elseif(is_null($value)) { // 删除缓存 return $cache->rm($name); }else { // 缓存数据 - $expire = is_numeric($options)?$options:NULL; + if(is_array($options)) { + $expire = isset($options['expire'])?$options['expire']:NULL; + }else{ + $expire = is_numeric($options)?$options:NULL; + } return $cache->set($name, $value, $expire); } } @@ -483,31 +481,47 @@ function to_guid_string($mix) { /** * XML编码 * @param mixed $data 数据 - * @param string $encoding 数据编码 * @param string $root 根节点名 + * @param string $item 数字索引的子节点名 + * @param string $attr 根节点属性 + * @param string $id 数字索引子节点key转换的属性名 + * @param string $encoding 数据编码 * @return string */ -function xml_encode($data, $encoding='utf-8', $root='think') { - $xml = ''; - $xml .= '<' . $root . '>'; - $xml .= data_to_xml($data); - $xml .= ''; +function xml_encode($data, $root='think', $item='item', $attr='', $id='id', $encoding='utf-8') { + if(is_array($attr)){ + $_attr = array(); + foreach ($attr as $key => $value) { + $_attr[] = "{$key}=\"{$value}\""; + } + $attr = implode(' ', $_attr); + } + $attr = trim($attr); + $attr = empty($attr) ? '' : " {$attr}"; + $xml = ""; + $xml .= "<{$root}{$attr}>"; + $xml .= data_to_xml($data, $item, $id); + $xml .= ""; return $xml; } /** * 数据XML编码 - * @param mixed $data 数据 + * @param mixed $data 数据 + * @param string $item 数字索引时的节点名称 + * @param string $id 数字索引key转换为的属性名 * @return string */ -function data_to_xml($data) { - $xml = ''; +function data_to_xml($data, $item='item', $id='id') { + $xml = $attr = ''; 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 .= ""; + if(is_numeric($key)){ + $id && $attr = " {$id}=\"{$key}\""; + $key = $item; + } + $xml .= "<{$key}{$attr}>"; + $xml .= (is_array($val) || is_object($val)) ? data_to_xml($val, $item, $id) : $val; + $xml .= ""; } return $xml; } @@ -750,4 +764,4 @@ function filter_exp(&$value){ if (in_array(strtolower($value),array('exp','or'))){ $value .= ' '; } -} \ No newline at end of file +} diff --git a/ThinkPHP/Lib/Behavior/ShowPageTraceBehavior.class.php b/ThinkPHP/Lib/Behavior/ShowPageTraceBehavior.class.php index dc0f8380f..760d5b9a9 100644 --- a/ThinkPHP/Lib/Behavior/ShowPageTraceBehavior.class.php +++ b/ThinkPHP/Lib/Behavior/ShowPageTraceBehavior.class.php @@ -47,6 +47,7 @@ private function showTrace() { $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()), @@ -124,4 +125,4 @@ private function showTime() { // 显示详细运行时间 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 +} diff --git a/ThinkPHP/Lib/Core/App.class.php b/ThinkPHP/Lib/Core/App.class.php index 88934b7cb..5ab97e9de 100644 --- a/ThinkPHP/Lib/Core/App.class.php +++ b/ThinkPHP/Lib/Core/App.class.php @@ -25,6 +25,11 @@ class App { * @return void */ static public function init() { + // 页面压缩输出支持 + if(C('OUTPUT_ENCODE')){ + $zlib = ini_get('zlib.output_compression'); + if(empty($zlib)) ob_start('ob_gzhandler'); + } // 设置系统时区 date_default_timezone_set(C('DEFAULT_TIMEZONE')); // 加载动态项目公共文件和配置 @@ -43,11 +48,6 @@ static public function init() { // URL调度结束标签 tag('url_dispatch'); - // 页面压缩输出支持 - if(C('OUTPUT_ENCODE')){ - $zlib = ini_get('zlib.output_compression'); - if(empty($zlib)) ob_start('ob_gzhandler'); - } // 系统变量安全过滤 if(C('VAR_FILTERS')) { $filters = explode(',',C('VAR_FILTERS')); @@ -147,7 +147,7 @@ static public function exec() { if(C('URL_PARAMS_BIND') && $method->getNumberOfParameters()>0){ switch($_SERVER['REQUEST_METHOD']) { case 'POST': - $vars = $_POST; + $vars = array_merge($_GET,$_POST); break; case 'PUT': parse_str(file_get_contents('php://input'), $vars); @@ -215,4 +215,4 @@ static public function run() { static public function logo(){ return 'iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyBpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBXaW5kb3dzIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjVERDVENkZGQjkyNDExRTE5REY3RDQ5RTQ2RTRDQUJCIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjVERDVENzAwQjkyNDExRTE5REY3RDQ5RTQ2RTRDQUJCIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6NURENUQ2RkRCOTI0MTFFMTlERjdENDlFNDZFNENBQkIiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6NURENUQ2RkVCOTI0MTFFMTlERjdENDlFNDZFNENBQkIiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz5fx6IRAAAMCElEQVR42sxae3BU1Rk/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'; } -} \ No newline at end of file +} diff --git a/ThinkPHP/Lib/Core/Dispatcher.class.php b/ThinkPHP/Lib/Core/Dispatcher.class.php index a3134dbc5..2525eaeff 100644 --- a/ThinkPHP/Lib/Core/Dispatcher.class.php +++ b/ThinkPHP/Lib/Core/Dispatcher.class.php @@ -26,7 +26,7 @@ class Dispatcher { */ static public function dispatch() { $urlMode = C('URL_MODEL'); - if(!empty($_GET[C('VAR_PATHINFO')])) { // 判断URL里面是否有兼容模式参数 + if(isset($_GET[C('VAR_PATHINFO')])) { // 判断URL里面是否有兼容模式参数 $_SERVER['PATH_INFO'] = $_GET[C('VAR_PATHINFO')]; unset($_GET[C('VAR_PATHINFO')]); } @@ -75,7 +75,7 @@ static public function dispatch() { } } // 分析PATHINFO信息 - if(empty($_SERVER['PATH_INFO'])) { + if(!isset($_SERVER['PATH_INFO'])) { $types = explode(',',C('URL_PATHINFO_FETCH')); foreach ($types as $type){ if(0===strpos($type,':')) {// 支持函数判断 @@ -121,6 +121,8 @@ static public function dispatch() { $_GET = array_merge($var,$_GET); } define('__INFO__',$_SERVER['PATH_INFO']); + }else{ + define('__INFO__',''); } // URL常量 @@ -150,11 +152,13 @@ static public function dispatch() { C(include $config_path.'config.php'); // 加载分组别名定义 if(is_file($config_path.'alias.php')) - alias_import(include $config_path.'alias.php'); + alias_import(include $config_path.'alias.php'); + // 加载分组tags文件定义 + if(is_file($config_path.'tags.php')) + C('tags', include $config_path.'tags.php'); // 加载分组函数文件 if(is_file($common_path.'function.php')) include $common_path.'function.php'; - } define('MODULE_NAME',self::getModule(C('VAR_MODULE'))); define('ACTION_NAME',self::getAction(C('VAR_ACTION'))); @@ -249,4 +253,4 @@ static private function getGroup($var) { return strip_tags(C('URL_CASE_INSENSITIVE') ?ucfirst(strtolower($group)):$group); } -} \ No newline at end of file +} diff --git a/ThinkPHP/Lib/Core/Model.class.php b/ThinkPHP/Lib/Core/Model.class.php index 177707da4..f1364e76a 100644 --- a/ThinkPHP/Lib/Core/Model.class.php +++ b/ThinkPHP/Lib/Core/Model.class.php @@ -60,7 +60,7 @@ class Model { // 是否批处理验证 protected $patchValidate = false; // 链操作方法列表 - protected $methods = array('table','order','alias','having','group','lock','distinct','auto','filter','validate'); + protected $methods = array('table','order','alias','having','group','lock','distinct','auto','filter','validate','result'); /** * 架构函数 @@ -521,7 +521,7 @@ public function buildSql($options=array()) { /** * 分析表达式 - * @access proteced + * @access protected * @param array $options 表达式参数 * @return array */ @@ -546,7 +546,7 @@ protected function _parseOptions($options=array()) { $options['model'] = $this->name; // 字段类型验证 - if(isset($options['where']) && is_array($options['where']) && !empty($fields)) { + if(isset($options['where']) && is_array($options['where']) && !empty($fields) && !isset($options['join'])) { // 对数组查询条件进行字段类型检查 foreach ($options['where'] as $key=>$val){ $key = trim($key); @@ -554,7 +554,7 @@ protected function _parseOptions($options=array()) { if(is_scalar($val)) { $this->_parseType($options['where'],$key); } - }elseif('_' != substr($key,0,1) && false === strpos($key,'.') && false === strpos($key,'|') && false === strpos($key,'&')){ + }elseif('_' != substr($key,0,1) && false === strpos($key,'.') && false === strpos($key,'(') && false === strpos($key,'|') && false === strpos($key,'&')){ unset($options['where'][$key]); } } @@ -610,11 +610,29 @@ public function find($options=array()) { } $this->data = $resultSet[0]; $this->_after_find($this->data,$options); + if(!empty($this->options['result'])) { + return $this->returnResult($this->data,$this->options['result']); + } return $this->data; } // 查询成功的回调方法 protected function _after_find(&$result,$options) {} + protected function returnResult($data,$type=''){ + if ($type){ + if(is_callable($type)){ + return call_user_func($type,$data); + } + switch (strtolower($type)){ + case 'json': + return json_encode($data); + case 'xml': + return xml_encode($data); + } + } + return $data; + } + /** * 处理字段映射 * @access public diff --git a/ThinkPHP/Lib/Core/Think.class.php b/ThinkPHP/Lib/Core/Think.class.php index 4ced81495..7ff612551 100644 --- a/ThinkPHP/Lib/Core/Think.class.php +++ b/ThinkPHP/Lib/Core/Think.class.php @@ -245,7 +245,13 @@ static public function instance($class,$method='') { * @param mixed $e 异常对象 */ static public function appException($e) { - halt($e->__toString()); + $error = array(); + $error['message'] = $e->getMessage(); + $error['file'] = $e->getFile(); + $error['line'] = $e->getLine(); + $error['trace'] = $e->getTraceAsString(); + Log::record($error['message'],Log::ERR); + halt($error); } /** @@ -286,8 +292,10 @@ function_exists('halt')?halt($errorStr):exit('ERROR:'.$errorStr); // 致命错误捕获 static public function fatalError() { + Log::save(); if ($e = error_get_last()) { - Think::appError($e['type'],$e['message'],$e['file'],$e['line']); + ob_end_clean(); + function_exists('halt')?halt($e):exit('ERROR:'.$e['message']); } } diff --git a/ThinkPHP/Lib/Core/ThinkException.class.php b/ThinkPHP/Lib/Core/ThinkException.class.php index d3a234a9b..64dd38070 100644 --- a/ThinkPHP/Lib/Core/ThinkException.class.php +++ b/ThinkPHP/Lib/Core/ThinkException.class.php @@ -17,71 +17,4 @@ * @author liu21st */ class ThinkException extends Exception { - - /** - * 异常类型 - * @var string - * @access private - */ - private $type; - - // 是否存在多余调试信息 - private $extra; - - /** - * 架构函数 - * @access public - * @param string $message 异常信息 - */ - public function __construct($message,$code=0,$extra=false) { - parent::__construct($message,$code); - $this->type = get_class($this); - $this->extra = $extra; - } - - /** - * 异常输出 所有异常处理类均通过__toString方法输出错误 - * 每次异常都会写入系统日志 - * 该方法可以被子类重载 - * @access public - * @return array - */ - public function __toString() { - $trace = $this->getTrace(); - if($this->extra) - // 通过throw_exception抛出的异常要去掉多余的调试信息 - array_shift($trace); - $this->class = isset($trace[0]['class'])?$trace[0]['class']:''; - $this->function = isset($trace[0]['function'])?$trace[0]['function']:''; - $this->file = $trace[0]['file']; - $this->line = $trace[0]['line']; - $file = file($this->file); - $traceInfo = ''; - $time = date('y-m-d H:i:m'); - foreach($trace as $t) { - $traceInfo .= '['.$time.'] '.$t['file'].' ('.$t['line'].') '; - $traceInfo .= $t['class'].$t['type'].$t['function'].'('; - $traceInfo .= implode(', ', $t['args']); - $traceInfo .=")\n"; - } - $error['message'] = $this->message; - $error['type'] = $this->type; - $error['detail'] = L('_MODULE_').'['.MODULE_NAME.'] '.L('_ACTION_').'['.ACTION_NAME.']'."\n"; - $error['detail'] .= ($this->line-2).': '.$file[$this->line-3]; - $error['detail'] .= ($this->line-1).': '.$file[$this->line-2]; - $error['detail'] .= ''.($this->line).': '.$file[$this->line-1].''; - $error['detail'] .= ($this->line+1).': '.$file[$this->line]; - $error['detail'] .= ($this->line+2).': '.$file[$this->line+1]; - $error['class'] = $this->class; - $error['function'] = $this->function; - $error['file'] = $this->file; - $error['line'] = $this->line; - $error['trace'] = $traceInfo; - - // 记录 Exception 日志 - if(C('LOG_EXCEPTION_RECORD')) { - Log::Write('('.$this->type.') '.$this->message); - } - return $error ; - } } \ No newline at end of file diff --git a/ThinkPHP/Lib/Driver/Cache/CacheFile.class.php b/ThinkPHP/Lib/Driver/Cache/CacheFile.class.php index 3150e7270..8f5c30132 100644 --- a/ThinkPHP/Lib/Driver/Cache/CacheFile.class.php +++ b/ThinkPHP/Lib/Driver/Cache/CacheFile.class.php @@ -41,15 +41,9 @@ public function __construct($options=array()) { * @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); + mkdir($this->options['temp']); } } @@ -174,14 +168,17 @@ public function rm($name) { */ public function clear() { $path = $this->options['temp']; - if ( $dir = opendir( $path ) ) { - while ( $file = readdir( $dir ) ) { - $check = is_dir( $file ); - if ( !$check ) + $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 ); + } } - closedir( $dir ); return true; } + return false; } } \ No newline at end of file diff --git a/ThinkPHP/Lib/Driver/Db/DbMysql.class.php b/ThinkPHP/Lib/Driver/Db/DbMysql.class.php index 3a4f860d6..4d3a7835f 100644 --- a/ThinkPHP/Lib/Driver/Db/DbMysql.class.php +++ b/ThinkPHP/Lib/Driver/Db/DbMysql.class.php @@ -90,6 +90,7 @@ public function free() { public function query($str) { if(0===stripos($str, 'call')){ // 存储过程查询支持 $this->close(); + $this->connected = false; } $this->initConnect(false); if ( !$this->_linkID ) return false; @@ -217,7 +218,7 @@ public function getFields($tableName) { $info[$val['Field']] = array( 'name' => $val['Field'], 'type' => $val['Type'], - 'notnull' => (bool) ($val['Null'] === ''), // not null is empty, null is yes + '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'), @@ -311,7 +312,7 @@ public function close() { * @return string */ public function error() { - $this->error = mysql_error($this->_linkID); + $this->error = mysql_errno().':'.mysql_error($this->_linkID); if('' != $this->queryStr){ $this->error .= "\n [ SQL语句 ] : ".$this->queryStr; } diff --git a/ThinkPHP/Lib/Driver/Db/DbMysqli.class.php b/ThinkPHP/Lib/Driver/Db/DbMysqli.class.php index 5c738d9a0..a79606313 100644 --- a/ThinkPHP/Lib/Driver/Db/DbMysqli.class.php +++ b/ThinkPHP/Lib/Driver/Db/DbMysqli.class.php @@ -306,7 +306,7 @@ public function close() { * @return string */ public function error() { - $this->error = $this->_linkID->error; + $this->error = $this->_linkID->errno.':'.$this->_linkID->error; if('' != $this->queryStr){ $this->error .= "\n [ SQL语句 ] : ".$this->queryStr; } diff --git a/ThinkPHP/Lib/Driver/TagLib/TagLibCx.class.php b/ThinkPHP/Lib/Driver/TagLib/TagLibCx.class.php index 2e633dbbb..7f8c2a0b1 100644 --- a/ThinkPHP/Lib/Driver/TagLib/TagLibCx.class.php +++ b/ThinkPHP/Lib/Driver/TagLib/TagLibCx.class.php @@ -360,7 +360,7 @@ public function _range($attr,$content,$type='in') { if($type=='between') { $parseStr = '= $_RANGE_VAR_[0] && '.$name.'<= $_RANGE_VAR_[1]):?>'.$content.''; }elseif($type=='notbetween'){ - $parseStr = '$_RANGE_VAR_[1]):?>'.$content.''; + $parseStr = '$_RANGE_VAR_[1]):?>'.$content.''; }else{ $fun = ($type == 'in')? 'in_array' : '!in_array'; $parseStr = ''.$content.''; @@ -639,4 +639,4 @@ public function _for($attr, $content){ return $parseStr; } - } \ No newline at end of file + } diff --git a/ThinkPHP/ThinkPHP.php b/ThinkPHP/ThinkPHP.php index 9128a00f4..050992285 100644 --- a/ThinkPHP/ThinkPHP.php +++ b/ThinkPHP/ThinkPHP.php @@ -10,22 +10,27 @@ // +---------------------------------------------------------------------- // ThinkPHP 入口文件 -//记录开始运行时间 +// 记录开始运行时间 $GLOBALS['_beginTime'] = microtime(TRUE); // 记录内存初始使用 define('MEMORY_LIMIT_ON',function_exists('memory_get_usage')); if(MEMORY_LIMIT_ON) $GLOBALS['_startUseMems'] = memory_get_usage(); +// 系统目录定义 +defined('THINK_PATH') or define('THINK_PATH', dirname(__FILE__).'/'); defined('APP_PATH') or define('APP_PATH', dirname($_SERVER['SCRIPT_FILENAME']).'/'); -defined('RUNTIME_PATH') or define('RUNTIME_PATH',APP_PATH.'Runtime/'); +defined('RUNTIME_PATH') or define('RUNTIME_PATH',realpath(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; +if(defined('ENGINE_NAME')) { + defined('ENGINE_PATH') or define('ENGINE_PATH',THINK_PATH.'Extend/Engine/'); + require ENGINE_PATH.strtolower(ENGINE_NAME).'.php'; }else{ - // 系统目录定义 - defined('THINK_PATH') or define('THINK_PATH', dirname(__FILE__).'/'); - // 加载运行时文件 - require THINK_PATH.'Common/runtime.php'; -} \ No newline at end of file + $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{ + // 加载运行时文件 + require THINK_PATH.'Common/runtime.php'; + } +} diff --git a/ThinkPHP/Tpl/dispatch_jump.tpl b/ThinkPHP/Tpl/dispatch_jump.tpl index 2fe05a940..585efa59f 100644 --- a/ThinkPHP/Tpl/dispatch_jump.tpl +++ b/ThinkPHP/Tpl/dispatch_jump.tpl @@ -33,7 +33,7 @@ body{ background: #fff; font-family: '微软雅黑'; color: #333; font-size: 16p var wait = document.getElementById('wait'),href = document.getElementById('href').href; var interval = setInterval(function(){ var time = --wait.innerHTML; - if(time == 0) { + if(time <= 0) { location.href = href; clearInterval(interval); };