mirror of
https://gitee.com/fastadminnet/framework.git
synced 2026-09-04 06:11:37 +08:00
部分类库从Think命名空间移到Org
Think目录移入Library目录
This commit is contained in:
228
Library/Think/App.php
Normal file
228
Library/Think/App.php
Normal file
@@ -0,0 +1,228 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | TOPThink [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2011 http://topthink.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
// $Id$
|
||||
|
||||
namespace Think;
|
||||
|
||||
/**
|
||||
* ThinkApp 应用管理
|
||||
* @author liu21st <liu21st@gmail.com>
|
||||
*/
|
||||
class App {
|
||||
|
||||
static private $config = [];
|
||||
|
||||
/**
|
||||
* 执行应用程序
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
static public function run() {
|
||||
// 监听app_init
|
||||
Tag::listen('app_init');
|
||||
// 加载全局初始化文件
|
||||
if(is_file(APP_PATH.'init'.EXT)) {
|
||||
include APP_PATH.'init'.EXT;
|
||||
$config = Config::get();
|
||||
}else{
|
||||
// 检测项目(或模块)配置文件
|
||||
if(is_file(APP_PATH.'config'.EXT)) {
|
||||
$config = Config::set(include APP_PATH.'config'.EXT);
|
||||
}
|
||||
// 加载别名文件
|
||||
if(is_file(APP_PATH.'alias'.EXT)) {
|
||||
Loader::addMap(include APP_PATH.'alias'.EXT);
|
||||
}
|
||||
// 加载公共文件
|
||||
if(is_file(APP_PATH.'common'.EXT)) {
|
||||
include APP_PATH.'common'.EXT;
|
||||
}
|
||||
if(is_file(APP_PATH.'tags'.EXT)) {
|
||||
// 行为扩展文件
|
||||
Tag::import(include APP_PATH.'tags'.EXT);
|
||||
}
|
||||
}
|
||||
// 应用URL调度
|
||||
self::dispatch($config);
|
||||
|
||||
// 执行操作
|
||||
$instance = Loader::controller(CONTROLLER_NAME);
|
||||
if(!$instance) {
|
||||
E('[ '.MODULE_NAME.'\\Controller\\'.parse_name(CONTROLLER_NAME,1).'Controller ] not exists',404);
|
||||
}
|
||||
|
||||
// 获取当前操作名
|
||||
$action = ACTION_NAME.$config['action_suffix'];
|
||||
try{
|
||||
// 操作方法开始监听
|
||||
$call = [$instance,$action];
|
||||
Tag::listen('action_begin',$call);
|
||||
if(!preg_match('/^[A-Za-z](\w)*$/',$action)){
|
||||
// 非法操作
|
||||
throw new \ReflectionException();
|
||||
}
|
||||
//执行当前操作
|
||||
$method = new \ReflectionMethod($instance, $action);
|
||||
if($method->isPublic()) {
|
||||
// URL参数绑定检测
|
||||
if($config['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('_PARAM_ERROR_:'.$name);
|
||||
}
|
||||
}
|
||||
$method->invokeArgs($instance,$args);
|
||||
}else{
|
||||
$method->invoke($instance);
|
||||
}
|
||||
// 操作方法执行完成监听
|
||||
Tag::listen('action_end',$call);
|
||||
}else{
|
||||
// 操作方法不是Public 抛出异常
|
||||
throw new \ReflectionException();
|
||||
}
|
||||
} catch (\ReflectionException $e) {
|
||||
// 操作不存在
|
||||
if(method_exists($instance,'_empty')) {
|
||||
$method = new \ReflectionMethod($instance,'_empty');
|
||||
$method->invokeArgs($instance,[$action,'']);
|
||||
}else{
|
||||
E('[ '.(new \ReflectionClass($instance))->getName().':'.$action.' ] not exists ',404);
|
||||
}
|
||||
}
|
||||
// 监听app_end
|
||||
Tag::listen('app_end');
|
||||
return ;
|
||||
}
|
||||
|
||||
/**
|
||||
* URL调度
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
static public function dispatch($config) {
|
||||
$var_m = $config['var_module'];
|
||||
$var_c = $config['var_controller'];
|
||||
$var_a = $config['var_action'];
|
||||
$var_p = $config['var_pathinfo'];
|
||||
if(isset($_GET[$var_p])) { // 判断URL里面是否有兼容模式参数
|
||||
$_SERVER['PATH_INFO'] = $_GET[$var_p];
|
||||
unset($_GET[$var_p]);
|
||||
}elseif(IS_CLI){ // CLI模式下 index.php module/controller/action/params/...
|
||||
$_SERVER['PATH_INFO'] = isset($_SERVER['argv'][1])?$_SERVER['argv'][1]:'';
|
||||
}
|
||||
|
||||
// 检测子域名部署
|
||||
if(!IS_CLI) {
|
||||
Route::checkDomain();
|
||||
}
|
||||
|
||||
// 监听path_info
|
||||
Tag::listen('path_info');
|
||||
// 分析PATHINFO信息
|
||||
if(!isset($_SERVER['PATH_INFO']) && $_SERVER['SCRIPT_NAME'] != $_SERVER['PHP_SELF']) {
|
||||
$types = explode(',',$config['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'] = '';
|
||||
}
|
||||
$part = pathinfo($_SERVER['PATH_INFO']);
|
||||
define('__EXT__', isset($part['extension'])?strtolower($part['extension']):'');
|
||||
$_SERVER['PATH_INFO'] = trim(preg_replace('/\.('.trim($config['url_html_suffix'],'.').')$/i', '',$_SERVER['PATH_INFO']),'/');
|
||||
if($_SERVER['PATH_INFO']) {
|
||||
$paths = explode($config['pathinfo_depr'],$_SERVER['PATH_INFO']);
|
||||
// 获取URL中的模块名
|
||||
if($config['require_module'] && !isset($_GET[$var_m])) {
|
||||
$_GET[$var_m] = array_shift($paths);
|
||||
$_SERVER['PATH_INFO'] = implode('/',$paths);
|
||||
}
|
||||
}
|
||||
|
||||
// 获取模块名称
|
||||
define('MODULE_NAME',ucwords(strtolower(isset($_GET[$var_m])?$_GET[$var_m]:$config['default_module'])));
|
||||
|
||||
// 模块初始化
|
||||
if(MODULE_NAME && is_dir(APP_PATH.MODULE_NAME)) {
|
||||
define('MODULE_PATH',APP_PATH.MODULE_NAME.'/');
|
||||
Tag::listen('app_begin');
|
||||
// 加载模块初始化文件
|
||||
if(is_file(MODULE_PATH.'init'.EXT)) {
|
||||
include MODULE_PATH.'init'.EXT;
|
||||
$config = Config::get();
|
||||
}else{
|
||||
// 检测项目(或模块)配置文件
|
||||
if(is_file(MODULE_PATH.'config'.EXT)) {
|
||||
$config = Config::set(include MODULE_PATH.'config'.EXT);
|
||||
}
|
||||
if($config['app_status'] && is_file(MODULE_PATH.$config['app_status'].EXT)) {
|
||||
// 加载对应的项目配置文件
|
||||
$config = Config::set(include MODULE_PATH.$config['app_status'].EXT);
|
||||
}
|
||||
// 加载别名文件
|
||||
if(is_file(MODULE_PATH.'alias'.EXT)) {
|
||||
Loader::addMap(include MODULE_PATH.'alias'.EXT);
|
||||
}
|
||||
// 加载公共文件
|
||||
if(is_file(MODULE_PATH.'common'.EXT)) {
|
||||
include MODULE_PATH.'common'.EXT;
|
||||
}
|
||||
if(is_file(MODULE_PATH.'tags'.EXT)) {
|
||||
// 行为扩展文件
|
||||
Tag::import(include MODULE_PATH.'tags'.EXT);
|
||||
}
|
||||
}
|
||||
$var_c = $config['var_controller'];
|
||||
$var_a = $config['var_action'];
|
||||
}else{
|
||||
E('module not exists :'.MODULE_NAME,404);
|
||||
}
|
||||
// 路由检测和控制器、操作解析
|
||||
Route::check($_SERVER['PATH_INFO']);
|
||||
|
||||
// 获取控制器名
|
||||
define('CONTROLLER_NAME', strtolower(isset($_GET[$var_c])?$_GET[$var_c]:$config['default_controller']));
|
||||
|
||||
// 获取操作名
|
||||
define('ACTION_NAME', strtolower(isset($_GET[$var_a])?$_GET[$var_a]:$config['default_action']));
|
||||
|
||||
unset($_GET[$var_a],$_GET[$var_c],$_GET[$var_m]);
|
||||
//保证$_REQUEST正常取值
|
||||
$_REQUEST = array_merge($_POST,$_GET);
|
||||
}
|
||||
|
||||
}
|
||||
58
Library/Think/Auto.php
Normal file
58
Library/Think/Auto.php
Normal file
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | TOPThink [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2011 http://topthink.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
// $Id$
|
||||
namespace Think;
|
||||
class Auto {
|
||||
|
||||
protected $auto = [];
|
||||
|
||||
public function rule($rule){
|
||||
$this->auto = $rule;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动表单处理
|
||||
* @access public
|
||||
* @param array $data 创建数据
|
||||
* @return mixed
|
||||
*/
|
||||
public function operate($data) {
|
||||
// 自动填充
|
||||
if($this->auto) {
|
||||
foreach ($this->auto as $auto){
|
||||
// 填充因子定义格式
|
||||
// array('field','填充内容','附加规则',[额外参数])
|
||||
switch(trim($auto[2])) {
|
||||
case 'callback': // 使用回调方法
|
||||
$args = isset($auto[3])?(array)$auto[3]:[];
|
||||
if(isset($data[$auto[0]])) {
|
||||
array_unshift($args,$data[$auto[0]]);
|
||||
}
|
||||
$data[$auto[0]] = call_user_func_array($auto[1], $args);
|
||||
break;
|
||||
case 'field': // 用其它字段的值进行填充
|
||||
$data[$auto[0]] = $data[$auto[1]];
|
||||
break;
|
||||
case 'ignore': // 为空忽略
|
||||
if(''===$data[$auto[0]])
|
||||
unset($data[$auto[0]]);
|
||||
break;
|
||||
case 'string':
|
||||
default: // 默认作为字符串填充
|
||||
$data[$auto[0]] = $auto[1];
|
||||
}
|
||||
if(false === $data[$auto[0]] ) unset($data[$auto[0]]);
|
||||
}
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
63
Library/Think/Behavior/ContentReplace.php
Normal file
63
Library/Think/Behavior/ContentReplace.php
Normal file
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace Think\Behavior;
|
||||
use Think\Config;
|
||||
/**
|
||||
* 系统行为扩展:模板内容输出替换
|
||||
* @category Think
|
||||
* @package Think
|
||||
* @subpackage Behavior
|
||||
* @author liu21st <liu21st@gmail.com>
|
||||
*/
|
||||
class ContentReplace {
|
||||
|
||||
// 行为扩展的执行入口必须是run
|
||||
public function run(&$content){
|
||||
$content = $this->templateContentReplace($content);
|
||||
}
|
||||
|
||||
/**
|
||||
* 模板内容替换
|
||||
* @access protected
|
||||
* @param string $content 模板内容
|
||||
* @return string
|
||||
*/
|
||||
protected function templateContentReplace($content) {
|
||||
if(IS_CGI) {
|
||||
//CGI/FASTCGI模式下
|
||||
$_temp = explode('.php',$_SERVER['PHP_SELF']);
|
||||
$script_name = rtrim(str_replace($_SERVER['HTTP_HOST'],'',$_temp[0].'.php'),'/');
|
||||
}else {
|
||||
$script_name = rtrim($_SERVER['SCRIPT_NAME'],'/');
|
||||
}
|
||||
define('ROOT_URL', rtrim(dirname(str_replace("\\","\/",$script_name)),'/'));
|
||||
define('MODULE_URL', ROOT_URL.(Config::get('require_module')?'/'.MODULE_NAME:''));
|
||||
define('CONTROLLER_URL', MODULE_URL.(Config::get('require_controller')?'/'.CONTROLLER_NAME:''));
|
||||
define('ACTION_URL', CONTROLLER_URL.'/'.ACTION_NAME);
|
||||
|
||||
// 系统默认的特殊变量替换
|
||||
$replace = [
|
||||
'__ROOT__' => ROOT_URL, // 当前网站地址
|
||||
'__APP__' => MODULE_URL, // 当前项目地址
|
||||
'__CONTROLL__' => CONTROLLER_URL, // 当前操作地址
|
||||
'__URL__' => CONTROLLER_URL,
|
||||
'__ACTION__' => ACTION_URL, // 当前操作地址
|
||||
'__SELF__' => $_SERVER['PHP_SELF'], // 当前页面地址
|
||||
'__PUBLIC__' => ROOT_URL.'/Public',// 站点公共目录
|
||||
];
|
||||
// 允许用户自定义模板的字符串替换
|
||||
if(is_array(Config::get('tmpl_parse_string')) )
|
||||
$replace = array_merge($replace,Config::get('tmpl_parse_string'));
|
||||
$content = str_replace(array_keys($replace),array_values($replace),$content);
|
||||
return $content;
|
||||
}
|
||||
|
||||
}
|
||||
48
Library/Think/Behavior/LocationTemplate.php
Normal file
48
Library/Think/Behavior/LocationTemplate.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace Think\Behavior;
|
||||
|
||||
/**
|
||||
* 系统行为扩展:定位模板文件
|
||||
* @category Think
|
||||
* @package Think
|
||||
* @subpackage Behavior
|
||||
* @author liu21st <liu21st@gmail.com>
|
||||
*/
|
||||
class LocationTemplate {
|
||||
// 行为扩展的执行入口必须是run
|
||||
public function run(&$templateFile){
|
||||
// 自动定位模板文件
|
||||
if(!is_file($templateFile))
|
||||
$templateFile = $this->parseTemplateFile($templateFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动定位模板文件
|
||||
* @access private
|
||||
* @param string $templateFile 文件名
|
||||
* @return string
|
||||
*/
|
||||
private function parseTemplateFile($template) {
|
||||
$template = str_replace(':','/',$template);
|
||||
if(''==$template) {
|
||||
// 如果模板文件名为空 按照默认规则定位
|
||||
$template = CONTROLLER_NAME.'/'.ACTION_NAME;
|
||||
}elseif(false === strpos($template,'/')){
|
||||
$template = CONTROLLER_NAME.'/'.$template;
|
||||
}elseif(false === strpos($template,'.')) {
|
||||
$template = $template;
|
||||
}
|
||||
$templateFile = MODULE_PATH.'View/'.$template.'.html';
|
||||
return $templateFile;
|
||||
}
|
||||
}
|
||||
122
Library/Think/Behavior/ReadHtmlCache.php
Normal file
122
Library/Think/Behavior/ReadHtmlCache.php
Normal file
@@ -0,0 +1,122 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* 系统行为扩展:静态缓存读取
|
||||
* @category Think
|
||||
* @package Think
|
||||
* @subpackage Behavior
|
||||
* @author liu21st <liu21st@gmail.com>
|
||||
*/
|
||||
class ReadHtmlCacheBehavior {
|
||||
protected $options = [
|
||||
'HTML_CACHE_ON' => false,
|
||||
'HTML_CACHE_TIME' => 60,
|
||||
'HTML_CACHE_RULES' => [],
|
||||
'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(
|
||||
['{:app}','{:module}','{:action}','{:group}'],
|
||||
[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 && NOW_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);
|
||||
}
|
||||
|
||||
}
|
||||
89
Library/Think/Behavior/ShowPageTrace.php
Normal file
89
Library/Think/Behavior/ShowPageTrace.php
Normal file
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace Think\Behavior;
|
||||
use Think\Config;
|
||||
use Think\Log;
|
||||
use Think\Debug;
|
||||
/**
|
||||
* 系统行为扩展:页面Trace显示输出
|
||||
* @category Think
|
||||
* @package Think
|
||||
* @subpackage Behavior
|
||||
* @author liu21st <liu21st@gmail.com>
|
||||
*/
|
||||
class ShowPageTrace {
|
||||
|
||||
// 行为扩展的执行入口必须是run
|
||||
public function run(&$params){
|
||||
if(!IS_AJAX && Config::get('show_page_trace')) {
|
||||
echo $this->showTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示页面Trace信息
|
||||
* @access private
|
||||
*/
|
||||
private function showTrace() {
|
||||
// 系统默认显示信息
|
||||
$files = get_included_files();
|
||||
$info = [];
|
||||
foreach ($files as $key=>$file){
|
||||
$info[] = $file.' ( '.number_format(filesize($file)/1024,2).' KB )';
|
||||
}
|
||||
$trace = [];
|
||||
Debug::remark('START',$GLOBALS['startTime']);
|
||||
$base = [
|
||||
'请求信息' => date('Y-m-d H:i:s',$_SERVER['REQUEST_TIME']).' '.$_SERVER['SERVER_PROTOCOL'].' '.$_SERVER['REQUEST_METHOD'].' : '.$_SERVER['PHP_SELF'],
|
||||
'运行时间' => Debug::getUseTime('START','END',6).'s',
|
||||
'内存开销' => MEMORY_LIMIT_ON?G('START','END','m').'b':'不支持',
|
||||
'查询信息' => N('db_query').' queries '.N('db_write').' writes ',
|
||||
'文件加载' => count($files),
|
||||
'缓存信息' => N('cache_read').' gets '.N('cache_write').' writes ',
|
||||
'配置加载' => count(Config::get()),
|
||||
];
|
||||
// 读取项目定义的Trace文件
|
||||
$traceFile = MODULE_PATH.'trace.php';
|
||||
if(is_file($traceFile)) {
|
||||
$base = array_merge($base,include $traceFile);
|
||||
}
|
||||
$debug = Log::getLog();
|
||||
$tabs = Config::get('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 = [];
|
||||
foreach($array as $name){
|
||||
$result += isset($debug[$name])?$debug[$name]:[];
|
||||
}
|
||||
$trace[$title] = $result;
|
||||
}else{
|
||||
$trace[$title] = isset($debug[$name])?$debug[$name]:'';
|
||||
}
|
||||
}
|
||||
}
|
||||
unset($files,$info,$base,$debug);
|
||||
// 调用Trace页面模板
|
||||
ob_start();
|
||||
include Config::has('tmpl_trace_file')?Config::get('tmpl_trace_file'):THINK_PATH.'tpl/page_trace.tpl';
|
||||
return ob_get_clean();
|
||||
}
|
||||
}
|
||||
61
Library/Think/Behavior/TokenBuild.php
Normal file
61
Library/Think/Behavior/TokenBuild.php
Normal file
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | TOPThink [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2010 http://topthink.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
defined('THINK_PATH') or exit();
|
||||
/**
|
||||
* 系统行为扩展:表单令牌生成
|
||||
* @category Think
|
||||
* @package Think
|
||||
* @subpackage Behavior
|
||||
* @author liu21st <liu21st@gmail.com>
|
||||
*/
|
||||
class TokenBuildBehavior extends Behavior {
|
||||
// 行为参数定义
|
||||
protected $options = [
|
||||
'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] = [];
|
||||
}
|
||||
// 标识当前页面唯一性
|
||||
$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 = '<input type="hidden" name="'.$tokenName.'" value="'.$tokenKey.'_'.$tokenValue.'" />';
|
||||
return $token;
|
||||
}
|
||||
}
|
||||
38
Library/Think/Cache.php
Normal file
38
Library/Think/Cache.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkCache
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace Think;
|
||||
class Cache {
|
||||
|
||||
/**
|
||||
* 操作句柄
|
||||
* @var object
|
||||
* @access protected
|
||||
*/
|
||||
static protected $handler = null;
|
||||
|
||||
/**
|
||||
* 连接缓存
|
||||
* @access public
|
||||
* @param array $options 配置数组
|
||||
* @return object
|
||||
*/
|
||||
static public function connect($options=[]) {
|
||||
$type = !empty($options['type'])?$options['type']:'File';
|
||||
$class = 'Think\\Cache\\Driver\\'.ucwords($type);
|
||||
self::$handler = new $class($options);
|
||||
return self::$handler;
|
||||
}
|
||||
|
||||
static public function __callStatic($method, $params){
|
||||
return call_user_func_array(array(self::$handler, $method), $params);
|
||||
}
|
||||
|
||||
}
|
||||
101
Library/Think/Cache/Driver/Apc.php
Normal file
101
Library/Think/Cache/Driver/Apc.php
Normal file
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkCache
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace Think\Cache\Driver;
|
||||
|
||||
/**
|
||||
* Apc缓存驱动
|
||||
* @author liu21st <liu21st@gmail.com>
|
||||
*/
|
||||
class Apc {
|
||||
|
||||
protected $options = [
|
||||
'expire' => 0,
|
||||
'prefix' => '',
|
||||
'length' => 0,
|
||||
];
|
||||
|
||||
/**
|
||||
* 架构函数
|
||||
* @param array $options 缓存参数
|
||||
* @access public
|
||||
*/
|
||||
public function __construct($options=[]) {
|
||||
if(!function_exists('apc_cache_info')) {
|
||||
E('_NOT_SUPPERT_:Apc');
|
||||
}
|
||||
if(!empty($options)) {
|
||||
$this->options = array_merge($this->options,$options);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($name) {
|
||||
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) {
|
||||
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) {
|
||||
// 记录缓存队列
|
||||
$queue = apc_fetch('__info__');
|
||||
if(!$queue) {
|
||||
$queue = [];
|
||||
}
|
||||
if(false===array_search($name, $queue)) array_push($queue,$name);
|
||||
if(count($queue) > $this->options['length']) {
|
||||
// 出列
|
||||
$key = array_shift($queue);
|
||||
// 删除缓存
|
||||
apc_delete($key);
|
||||
}
|
||||
apc_store('__info__', $queue);
|
||||
}
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
144
Library/Think/Cache/Driver/Db.php
Normal file
144
Library/Think/Cache/Driver/Db.php
Normal file
@@ -0,0 +1,144 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkCache
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace Think\Cache\Driver;
|
||||
/**
|
||||
* 数据库方式缓存驱动
|
||||
* CREATE TABLE think_cache (
|
||||
* cachekey varchar(255) NOT NULL,
|
||||
* expire int(11) NOT NULL,
|
||||
* data blob,
|
||||
* datacrc int(32),
|
||||
* UNIQUE KEY `cachekey` (`cachekey`)
|
||||
* );
|
||||
* @author liu21st <liu21st@gmail.com>
|
||||
*/
|
||||
class Db {
|
||||
|
||||
protected $handler = null;
|
||||
protected $options = [
|
||||
'db' => '',
|
||||
'table' => '',
|
||||
'prefix' => '',
|
||||
'expire' => 0,
|
||||
'length' => 0,
|
||||
];
|
||||
|
||||
/**
|
||||
* 架构函数
|
||||
* @param array $options 缓存参数
|
||||
* @access public
|
||||
*/
|
||||
public function __construct($options=[]) {
|
||||
if(!empty($options)) {
|
||||
$this->options = array_merge($this->options,$options);
|
||||
}
|
||||
$this->handler = \Think\Db::instance();
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($name) {
|
||||
$name = $this->options['prefix'].addslashes($name);
|
||||
$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];
|
||||
$content = $result['data'];
|
||||
if(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);
|
||||
if(function_exists('gzcompress')) {
|
||||
//数据压缩
|
||||
$data = gzcompress($data,3);
|
||||
}
|
||||
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.'\' ,expire='.$expire.' WHERE `cachekey`=\''.$name.'\'');
|
||||
}else {
|
||||
//新增记录
|
||||
$result = $this->handler->execute('INSERT INTO '.$this->options['table'].' (`cachekey`,`data`,`expire`) VALUES (\''.$name.'\',\''.$data.'\','.$expire.')');
|
||||
}
|
||||
if($result) {
|
||||
if($this->options['length']>0) {
|
||||
// 记录缓存队列
|
||||
$result = $this->handler->query('SELECT `data`,`datacrc` FROM `'.$this->options['table'].'` WHERE `cachekey`=\'__info__\' AND `expire` =0 LIMIT 0,1');
|
||||
$queue = xcache_get('__info__');
|
||||
if(!$result) {
|
||||
$this->handler->execute('INSERT INTO '.$this->options['table'].' (`cachekey`,`data`,`expire`) VALUES (\'__info__\',\'\',0)');
|
||||
$queue = [];
|
||||
}else{
|
||||
$queue = unserialize($result[0]['data']);
|
||||
}
|
||||
if(false===array_search($name, $queue)) array_push($queue,$name);
|
||||
if(count($queue) > $this->options['length']) {
|
||||
// 出列
|
||||
$key = array_shift($queue);
|
||||
// 删除缓存
|
||||
$this->handler->execute('DELETE FROM `'.$this->options['table'].'` WHERE `cachekey`=\''.$key.'\'');
|
||||
}
|
||||
$this->handler->execute('UPDATE '.$this->options['table'].' SET data=\''.serialize($queue).'\' ,expire=0 WHERE `cachekey`=\'__info__\'');
|
||||
xcache_set('__info__', $queue);
|
||||
}
|
||||
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'].'`');
|
||||
}
|
||||
|
||||
}
|
||||
99
Library/Think/Cache/Driver/Eaccelerator.php
Normal file
99
Library/Think/Cache/Driver/Eaccelerator.php
Normal file
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkCache
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace Think\Cache\Driver;
|
||||
/**
|
||||
* Eaccelerator缓存驱动
|
||||
* @author liu21st <liu21st@gmail.com>
|
||||
*/
|
||||
class Eaccelerator {
|
||||
|
||||
protected $options = [
|
||||
'prefix' => '',
|
||||
'expire' => 0,
|
||||
'length' => 0,
|
||||
];
|
||||
|
||||
/**
|
||||
* 架构函数
|
||||
* @param array $options 缓存参数
|
||||
* @access public
|
||||
*/
|
||||
public function __construct($options=[]) {
|
||||
if(!empty($options)) {
|
||||
$this->options = array_merge($this->options,$options);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($name) {
|
||||
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) {
|
||||
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) {
|
||||
// 记录缓存队列
|
||||
$queue = eaccelerator_get('__info__');
|
||||
if(!$queue) {
|
||||
$queue = [];
|
||||
}
|
||||
if(false===array_search($name, $queue)) array_push($queue,$name);
|
||||
if(count($queue) > $this->options['length']) {
|
||||
// 出列
|
||||
$key = array_shift($queue);
|
||||
// 删除缓存
|
||||
eaccelerator_rm($key);
|
||||
}
|
||||
eaccelerator_put('__info__', $queue);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 删除缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @return boolen
|
||||
*/
|
||||
public function rm($name) {
|
||||
return eaccelerator_rm($this->options['prefix'].$name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除缓存
|
||||
* @access public
|
||||
* @return boolen
|
||||
*/
|
||||
public function clear() {
|
||||
return ;
|
||||
}
|
||||
}
|
||||
183
Library/Think/Cache/Driver/File.php
Normal file
183
Library/Think/Cache/Driver/File.php
Normal file
@@ -0,0 +1,183 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkCache
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace Think\Cache\Driver;
|
||||
|
||||
/**
|
||||
* 文件类型缓存类
|
||||
* @author liu21st <liu21st@gmail.com>
|
||||
*/
|
||||
class File {
|
||||
|
||||
protected $options = [
|
||||
'expire' => 0,
|
||||
'cache_subdir' => false,
|
||||
'path_level' => 1,
|
||||
'prefix' => '',
|
||||
'length' => 0,
|
||||
'temp' => '',
|
||||
'data_compress' => false,
|
||||
];
|
||||
|
||||
/**
|
||||
* 架构函数
|
||||
* @access public
|
||||
*/
|
||||
public function __construct($options=[]) {
|
||||
if(!empty($options)) {
|
||||
$this->options = array_merge($this->options,$options);
|
||||
}
|
||||
if(substr($this->options['temp'], -1) != '/') $this->options['temp'] .= '/';
|
||||
$this->init();
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化检查
|
||||
* @access private
|
||||
* @return boolen
|
||||
*/
|
||||
private function init() {
|
||||
// 创建项目缓存目录
|
||||
if (!is_dir($this->options['temp'])) {
|
||||
if (! mkdir($this->options['temp'],0755))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得变量的存储文件名
|
||||
* @access private
|
||||
* @param string $name 缓存变量名
|
||||
* @return string
|
||||
*/
|
||||
private function filename($name) {
|
||||
$name = md5($name);
|
||||
if($this->options['cache_subdir']) {
|
||||
// 使用子目录
|
||||
$dir = '';
|
||||
$len = $this->options['path_level'];
|
||||
for($i=0;$i<$len;$i++) {
|
||||
$dir .= $name{$i}.'/';
|
||||
}
|
||||
if(!is_dir($this->options['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;
|
||||
}
|
||||
$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;
|
||||
}
|
||||
$content = substr($content,20, -3);
|
||||
if($this->options['data_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) {
|
||||
if(is_null($expire)) {
|
||||
$expire = $this->options['expire'];
|
||||
}
|
||||
$filename = $this->filename($name);
|
||||
$data = serialize($value);
|
||||
if($this->options['data_compress'] && function_exists('gzcompress')) {
|
||||
//数据压缩
|
||||
$data = gzcompress($data,3);
|
||||
}
|
||||
$data = "<?php\n//".sprintf('%012d',$expire).$data."\n?>";
|
||||
$result = file_put_contents($filename,$data);
|
||||
if($result) {
|
||||
if($this->options['length']>0) {
|
||||
// 记录缓存队列
|
||||
$queue_file = dirname($filename).'/__info__.php';
|
||||
$queue = unserialize(file_get_contents($queue_file));
|
||||
if(!$queue) {
|
||||
$queue = [];
|
||||
}
|
||||
if(false===array_search($name, $queue)) array_push($queue,$name);
|
||||
if(count($queue) > $this->options['length']) {
|
||||
// 出列
|
||||
$key = array_shift($queue);
|
||||
// 删除缓存
|
||||
unlink($this->filename($key));
|
||||
}
|
||||
file_put_contents($queue_file, serialize($queue));
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
111
Library/Think/Cache/Driver/Memcache.php
Normal file
111
Library/Think/Cache/Driver/Memcache.php
Normal file
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkCache
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace Think\Cache\Driver;
|
||||
/**
|
||||
* Memcache缓存驱动
|
||||
* @author liu21st <liu21st@gmail.com>
|
||||
*/
|
||||
class Memcache {
|
||||
protected $handler = null;
|
||||
protected $options = [
|
||||
'host' => '127.0.0.1',
|
||||
'port' => 11211,
|
||||
'expire' => 0,
|
||||
'timeout' => false,
|
||||
'persistent' => false,
|
||||
'length' => 0,
|
||||
];
|
||||
|
||||
/**
|
||||
* 架构函数
|
||||
* @param array $options 缓存参数
|
||||
* @access public
|
||||
*/
|
||||
public function __construct($options=[]) {
|
||||
if ( !extension_loaded('memcache') ) {
|
||||
E('_NOT_SUPPERT_:memcache');
|
||||
}
|
||||
if(!empty($options)) {
|
||||
$this->options = array_merge($this->options,$options);
|
||||
}
|
||||
$func = $this->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) {
|
||||
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) {
|
||||
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) {
|
||||
// 记录缓存队列
|
||||
$queue = $this->handler->get('__info__');
|
||||
if(!$queue) {
|
||||
$queue = [];
|
||||
}
|
||||
if(false===array_search($name, $queue)) array_push($queue,$name);
|
||||
if(count($queue) > $this->options['length']) {
|
||||
// 出列
|
||||
$key = array_shift($queue);
|
||||
// 删除缓存
|
||||
$this->handler->delete($key);
|
||||
}
|
||||
$this->handler->set('__info__', $queue);
|
||||
}
|
||||
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();
|
||||
}
|
||||
}
|
||||
114
Library/Think/Cache/Driver/Redis.php
Normal file
114
Library/Think/Cache/Driver/Redis.php
Normal file
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkCache
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace Think\Cache\Driver;
|
||||
/**
|
||||
* Redis缓存驱动
|
||||
* 要求安装phpredis扩展:https://github.com/nicolasff/phpredis
|
||||
* @author 尘缘 <130775@qq.com>
|
||||
*/
|
||||
class Redis {
|
||||
protected $handler = null;
|
||||
protected $options = [
|
||||
'host' => '127.0.0.1',
|
||||
'port' => 6379,
|
||||
'timeout' => false,
|
||||
'expire' => 0,
|
||||
'persistent' => false,
|
||||
'length' => 0,
|
||||
];
|
||||
|
||||
/**
|
||||
* 架构函数
|
||||
* @param array $options 缓存参数
|
||||
* @access public
|
||||
*/
|
||||
public function __construct($options=[]) {
|
||||
if ( !extension_loaded('redis') ) {
|
||||
E('_NOT_SUPPERT_:redis');
|
||||
}
|
||||
if(!empty($options)) {
|
||||
$this->options = array_merge($this->options,$options);
|
||||
}
|
||||
$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) {
|
||||
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) {
|
||||
if(is_null($expire)) {
|
||||
$expire = $this->options['expire'];
|
||||
}
|
||||
$name = $this->options['prefix'].$name;
|
||||
if(is_int($expire)) {
|
||||
$result = $this->handler->setex($name, $expire, $value);
|
||||
}else{
|
||||
$result = $this->handler->set($name, $value);
|
||||
}
|
||||
if($result && $this->options['length']>0) {
|
||||
if($this->options['length']>0) {
|
||||
// 记录缓存队列
|
||||
$queue = $this->handler->get('__info__');
|
||||
if(!$queue) {
|
||||
$queue = [];
|
||||
}
|
||||
if(false===array_search($name, $queue)) array_push($queue,$name);
|
||||
if(count($queue) > $this->options['length']) {
|
||||
// 出列
|
||||
$key = array_shift($queue);
|
||||
// 删除缓存
|
||||
$this->handler->delete($key);
|
||||
}
|
||||
$this->handler->set('__info__', $queue);
|
||||
}
|
||||
}
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
||||
720
Library/Think/Cache/Driver/Secache.php
Normal file
720
Library/Think/Cache/Driver/Secache.php
Normal file
@@ -0,0 +1,720 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkCache
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace Think\Cache\Driver;
|
||||
/**
|
||||
* Secache缓存驱动
|
||||
* @author liu21st <liu21st@gmail.com>
|
||||
*/
|
||||
class Secache {
|
||||
|
||||
protected $handler = null;
|
||||
protected $options = [
|
||||
'project' => '',
|
||||
'temp' => '',
|
||||
'expire' => 0,
|
||||
'prefix' => '',
|
||||
'length' => 0,
|
||||
];
|
||||
|
||||
/**
|
||||
* 架构函数
|
||||
* @param array $options 缓存参数
|
||||
* @access public
|
||||
*/
|
||||
public function __construct($options=[]) {
|
||||
if(!empty($options)) {
|
||||
$this->options = array_merge($this->options,$options);
|
||||
}
|
||||
if(substr($this->options['temp'], -1) != '/') $this->options['temp'] .= '/';
|
||||
$this->handler = new SecacheClient;
|
||||
$this->handler->workat($this->options['temp'].$this->options['project']);
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($name) {
|
||||
$name = $this->options['prefix'].$name;
|
||||
$key = md5($name);
|
||||
$this->handler->fetch($key,$return);
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param mixed $value 存储数据
|
||||
* @param integer $expire 有效时间(秒)
|
||||
* @return boolen
|
||||
*/
|
||||
public function set($name, $value) {
|
||||
$name = $this->options['prefix'].$name;
|
||||
$key = md5($name);
|
||||
if($result = $this->handler->store($key, $value)) {
|
||||
if($this->options['length']>0) {
|
||||
// 记录缓存队列
|
||||
$queue = $this->handler->fetch(md5('__info__'));
|
||||
if(!$queue) {
|
||||
$queue = [];
|
||||
}
|
||||
if(false===array_search($key, $queue)) array_push($queue,$key);
|
||||
if(count($queue) > $this->options['length']) {
|
||||
// 出列
|
||||
$key = array_shift($queue);
|
||||
// 删除缓存
|
||||
$this->handler->delete($key);
|
||||
}
|
||||
$this->handler->store(md5('__info__'), $queue);
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @return boolen
|
||||
*/
|
||||
public function rm($name) {
|
||||
$name = $this->options['prefix'].$name;
|
||||
$key = md5($name);
|
||||
return $this->handler->delete($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除缓存
|
||||
* @access public
|
||||
* @return boolen
|
||||
*/
|
||||
public function clear() {
|
||||
return $this->handler->_format(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(!defined('SECACHE_SIZE')){
|
||||
define('SECACHE_SIZE','15M');
|
||||
}
|
||||
class SecacheClient{
|
||||
|
||||
var $idx_node_size = 40;
|
||||
var $data_base_pos = 262588; //40+20+24*16+16*16*16*16*4;
|
||||
var $schema_item_size = 24;
|
||||
var $header_padding = 20; //保留空间 放置php标记防止下载
|
||||
var $info_size = 20; //保留空间 4+16 maxsize|ver
|
||||
|
||||
//40起 添加20字节保留区域
|
||||
var $idx_seq_pos = 40; //id 计数器节点地址
|
||||
var $dfile_cur_pos = 44; //id 计数器节点地址
|
||||
var $idx_free_pos = 48; //id 空闲链表入口地址
|
||||
|
||||
var $idx_base_pos = 444; //40+20+24*16
|
||||
var $min_size = 10240; //10M最小值
|
||||
var $schema_struct = array('size','free','lru_head','lru_tail','hits','miss');
|
||||
var $ver = '$Rev: 3 $';
|
||||
var $name = '系统默认缓存(文件型)';
|
||||
|
||||
function workat($file){
|
||||
|
||||
$this->_file = $file.'.php';
|
||||
$this->_bsize_list = array(
|
||||
512=>10,
|
||||
3<<10=>10,
|
||||
8<<10=>10,
|
||||
20<<10=>4,
|
||||
30<<10=>2,
|
||||
50<<10=>2,
|
||||
80<<10=>2,
|
||||
96<<10=>2,
|
||||
128<<10=>2,
|
||||
224<<10=>2,
|
||||
256<<10=>2,
|
||||
512<<10=>1,
|
||||
1024<<10=>1,
|
||||
);
|
||||
|
||||
$this->_node_struct = array(
|
||||
'next'=>array(0,'V'),
|
||||
'prev'=>array(4,'V'),
|
||||
'data'=>array(8,'V'),
|
||||
'size'=>array(12,'V'),
|
||||
'lru_right'=>array(16,'V'),
|
||||
'lru_left'=>array(20,'V'),
|
||||
'key'=>array(24,'H*'),
|
||||
);
|
||||
|
||||
if(!file_exists($this->_file)){
|
||||
$this->create();
|
||||
}else{
|
||||
$this->_rs = fopen($this->_file,'rb+') or $this->trigger_error('Can\'t open the cachefile: '.realpath($this->_file),E_USER_ERROR);
|
||||
$this->_seek($this->header_padding);
|
||||
$info = unpack('V1max_size/a*ver',fread($this->_rs,$this->info_size));
|
||||
if($info['ver']!=$this->ver){
|
||||
$this->_format(true);
|
||||
}else{
|
||||
$this->max_size = $info['max_size'];
|
||||
}
|
||||
}
|
||||
|
||||
$this->idx_node_base = $this->data_base_pos+$this->max_size;
|
||||
$this->_block_size_list = array_keys($this->_bsize_list);
|
||||
sort($this->_block_size_list);
|
||||
return true;
|
||||
}
|
||||
|
||||
function create(){
|
||||
$this->_rs = fopen($this->_file,'wb+') or $this->trigger_error('Can\'t open the cachefile: '.realpath($this->_file),E_USER_ERROR);;
|
||||
fseek($this->_rs,0);
|
||||
fputs($this->_rs,'<'.'?php exit()?'.'>');
|
||||
return $this->_format();
|
||||
}
|
||||
|
||||
function _puts($offset,$data){
|
||||
if($offset < $this->max_size*1.5){
|
||||
$this->_seek($offset);
|
||||
return fputs($this->_rs,$data);
|
||||
}else{
|
||||
$this->trigger_error('Offset over quota:'.$offset,E_USER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
function _seek($offset){
|
||||
return fseek($this->_rs,$offset);
|
||||
}
|
||||
|
||||
function clear(){
|
||||
return $this->_format(true);
|
||||
}
|
||||
|
||||
function fetch($key,&$return){
|
||||
|
||||
if($this->lock(false)){
|
||||
$locked = true;
|
||||
}
|
||||
|
||||
if($this->search($key,$offset)){
|
||||
$info = $this->_get_node($offset);
|
||||
$schema_id = $this->_get_size_schema_id($info['size']);
|
||||
if($schema_id===false){
|
||||
if($locked) $this->unlock();
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->_seek($info['data']);
|
||||
$data = fread($this->_rs,$info['size']);
|
||||
$return = unserialize($data);
|
||||
|
||||
if($return===false){
|
||||
if($locked) $this->unlock();
|
||||
return false;
|
||||
}
|
||||
|
||||
if($locked){
|
||||
$this->_lru_push($schema_id,$info['offset']);
|
||||
$this->_set_schema($schema_id,'hits',$this->_get_schema($schema_id,'hits')+1);
|
||||
return $this->unlock();
|
||||
}else{
|
||||
return true;
|
||||
}
|
||||
}else{
|
||||
if($locked) $this->unlock();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* lock
|
||||
* 如果flock不管用,请继承本类,并重载此方法
|
||||
*
|
||||
* @param mixed $is_block 是否阻塞
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function lock($is_block,$whatever=false){
|
||||
return flock($this->_rs, $is_block?LOCK_EX:LOCK_EX+LOCK_NB);
|
||||
}
|
||||
|
||||
/**
|
||||
* unlock
|
||||
* 如果flock不管用,请继承本类,并重载此方法
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function unlock(){
|
||||
return flock($this->_rs, LOCK_UN);
|
||||
}
|
||||
|
||||
function delete($key,$pos=false){
|
||||
if($pos || $this->search($key,$pos)){
|
||||
if($info = $this->_get_node($pos)){
|
||||
//删除data区域
|
||||
if($info['prev']){
|
||||
$this->_set_node($info['prev'],'next',$info['next']);
|
||||
$this->_set_node($info['next'],'prev',$info['prev']);
|
||||
}else{ //改入口位置
|
||||
$this->_set_node($info['next'],'prev',0);
|
||||
$this->_set_node_root($key,$info['next']);
|
||||
}
|
||||
$this->_free_dspace($info['size'],$info['data']);
|
||||
$this->_lru_delete($info);
|
||||
$this->_free_node($pos);
|
||||
return $info['prev'];
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function store($key,$value){
|
||||
|
||||
if($this->lock(true)){
|
||||
//save data
|
||||
$data = serialize($value);
|
||||
$size = strlen($data);
|
||||
|
||||
//get list_idx
|
||||
$has_key = $this->search($key,$list_idx_offset);
|
||||
$schema_id = $this->_get_size_schema_id($size);
|
||||
if($schema_id===false){
|
||||
$this->unlock();
|
||||
return false;
|
||||
}
|
||||
if($has_key){
|
||||
$hdseq = $list_idx_offset;
|
||||
|
||||
$info = $this->_get_node($hdseq);
|
||||
if($schema_id == $this->_get_size_schema_id($info['size'])){
|
||||
$dataoffset = $info['data'];
|
||||
}else{
|
||||
//破掉原有lru
|
||||
$this->_lru_delete($info);
|
||||
if(!($dataoffset = $this->_dalloc($schema_id))){
|
||||
$this->unlock();
|
||||
return false;
|
||||
}
|
||||
$this->_free_dspace($info['size'],$info['data']);
|
||||
$this->_set_node($hdseq,'lru_left',0);
|
||||
$this->_set_node($hdseq,'lru_right',0);
|
||||
}
|
||||
|
||||
$this->_set_node($hdseq,'size',$size);
|
||||
$this->_set_node($hdseq,'data',$dataoffset);
|
||||
}else{
|
||||
|
||||
if(!($dataoffset = $this->_dalloc($schema_id))){
|
||||
$this->unlock();
|
||||
return false;
|
||||
}
|
||||
$hdseq = $this->_alloc_idx(array(
|
||||
'next'=>0,
|
||||
'prev'=>$list_idx_offset,
|
||||
'data'=>$dataoffset,
|
||||
'size'=>$size,
|
||||
'lru_right'=>0,
|
||||
'lru_left'=>0,
|
||||
'key'=>$key,
|
||||
));
|
||||
|
||||
if($list_idx_offset>0){
|
||||
$this->_set_node($list_idx_offset,'next',$hdseq);
|
||||
}else{
|
||||
$this->_set_node_root($key,$hdseq);
|
||||
}
|
||||
}
|
||||
|
||||
if($dataoffset>$this->max_size){
|
||||
$this->trigger_error('alloc datasize:'.$dataoffset,E_USER_WARNING);
|
||||
return false;
|
||||
}
|
||||
$this->_puts($dataoffset,$data);
|
||||
|
||||
$this->_set_schema($schema_id,'miss',$this->_get_schema($schema_id,'miss')+1);
|
||||
|
||||
$this->_lru_push($schema_id,$hdseq);
|
||||
$this->unlock();
|
||||
return true;
|
||||
}else{
|
||||
$this->trigger_error("Couldn't lock the file !",E_USER_WARNING);
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* search
|
||||
* 查找指定的key
|
||||
* 如果找到节点则$pos=节点本身 返回true
|
||||
* 否则 $pos=树的末端 返回false
|
||||
*
|
||||
* @param mixed $key
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
function search($key,&$pos){
|
||||
return $this->_get_pos_by_key($this->_get_node_root($key),$key,$pos);
|
||||
}
|
||||
|
||||
function _get_size_schema_id($size){
|
||||
foreach($this->_block_size_list as $k=>$block_size){
|
||||
if($size <= $block_size){
|
||||
return $k;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function _parse_str_size($str_size,$default){
|
||||
if(preg_match('/^([0-9]+)\s*([gmk]|)$/i',$str_size,$match)){
|
||||
switch(strtolower($match[2])){
|
||||
case 'g':
|
||||
if($match[1]>1){
|
||||
$this->trigger_error('Max cache size 1G',E_USER_ERROR);
|
||||
}
|
||||
$size = $match[1]<<30;
|
||||
break;
|
||||
case 'm':
|
||||
$size = $match[1]<<20;
|
||||
break;
|
||||
case 'k':
|
||||
$size = $match[1]<<10;
|
||||
break;
|
||||
default:
|
||||
$size = $match[1];
|
||||
}
|
||||
if($size<=0){
|
||||
$this->trigger_error('Error cache size '.$this->max_size,E_USER_ERROR);
|
||||
return false;
|
||||
}elseif($size<10485760){
|
||||
return 10485760;
|
||||
}else{
|
||||
return $size;
|
||||
}
|
||||
}else{
|
||||
return $default;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function _format($truncate=false){
|
||||
if($this->lock(true,true)){
|
||||
|
||||
if($truncate){
|
||||
$this->_seek(0);
|
||||
ftruncate($this->_rs,$this->idx_node_base);
|
||||
}
|
||||
|
||||
$this->max_size = $this->_parse_str_size(SECACHE_SIZE,15728640); //default:15m
|
||||
$this->_puts($this->header_padding,pack('V1a*',$this->max_size,$this->ver));
|
||||
|
||||
ksort($this->_bsize_list);
|
||||
$ds_offset = $this->data_base_pos;
|
||||
$i=0;
|
||||
foreach($this->_bsize_list as $size=>$count){
|
||||
|
||||
//将预分配的空间注册到free链表里
|
||||
$count *= min(3,floor($this->max_size/10485760));
|
||||
$next_free_node = 0;
|
||||
for($j=0;$j<$count;$j++){
|
||||
$this->_puts($ds_offset,pack('V',$next_free_node));
|
||||
$next_free_node = $ds_offset;
|
||||
$ds_offset+=intval($size);
|
||||
}
|
||||
|
||||
$code = pack(str_repeat('V1',count($this->schema_struct)),$size,$next_free_node,0,0,0,0);
|
||||
|
||||
$this->_puts(60+$i*$this->schema_item_size,$code);
|
||||
$i++;
|
||||
}
|
||||
$this->_set_dcur_pos($ds_offset);
|
||||
|
||||
$this->_puts($this->idx_base_pos,str_repeat("\0",262144));
|
||||
$this->_puts($this->idx_seq_pos,pack('V',1));
|
||||
$this->unlock();
|
||||
return true;
|
||||
}else{
|
||||
$this->trigger_error("Couldn't lock the file !",E_USER_ERROR);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function _get_node_root($key){
|
||||
$this->_seek(hexdec(substr($key,0,4))*4+$this->idx_base_pos);
|
||||
$a= fread($this->_rs,4);
|
||||
list(,$offset) = unpack('V',$a);
|
||||
return $offset;
|
||||
}
|
||||
|
||||
function _set_node_root($key,$value){
|
||||
return $this->_puts(hexdec(substr($key,0,4))*4+$this->idx_base_pos,pack('V',$value));
|
||||
}
|
||||
|
||||
function _set_node($pos,$key,$value){
|
||||
|
||||
if(!$pos){
|
||||
return false;
|
||||
}
|
||||
|
||||
if(isset($this->_node_struct[$key])){
|
||||
return $this->_puts($pos*$this->idx_node_size+$this->idx_node_base+$this->_node_struct[$key][0],pack($this->_node_struct[$key][1],$value));
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function _get_pos_by_key($offset,$key,&$pos){
|
||||
if(!$offset){
|
||||
$pos = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
$info = $this->_get_node($offset);
|
||||
|
||||
if($info['key']==$key){
|
||||
$pos = $info['offset'];
|
||||
return true;
|
||||
}elseif($info['next'] && $info['next']!=$offset){
|
||||
return $this->_get_pos_by_key($info['next'],$key,$pos);
|
||||
}else{
|
||||
$pos = $offset;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function _lru_delete($info){
|
||||
|
||||
if($info['lru_right']){
|
||||
$this->_set_node($info['lru_right'],'lru_left',$info['lru_left']);
|
||||
}else{
|
||||
$this->_set_schema($this->_get_size_schema_id($info['size']),'lru_tail',$info['lru_left']);
|
||||
}
|
||||
|
||||
if($info['lru_left']){
|
||||
$this->_set_node($info['lru_left'],'lru_right',$info['lru_right']);
|
||||
}else{
|
||||
$this->_set_schema($this->_get_size_schema_id($info['size']),'lru_head',$info['lru_right']);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function _lru_push($schema_id,$offset){
|
||||
$lru_head = $this->_get_schema($schema_id,'lru_head');
|
||||
$lru_tail = $this->_get_schema($schema_id,'lru_tail');
|
||||
|
||||
if((!$offset) || ($lru_head==$offset))return;
|
||||
|
||||
$info = $this->_get_node($offset);
|
||||
|
||||
$this->_set_node($info['lru_right'],'lru_left',$info['lru_left']);
|
||||
$this->_set_node($info['lru_left'],'lru_right',$info['lru_right']);
|
||||
|
||||
$this->_set_node($offset,'lru_right',$lru_head);
|
||||
$this->_set_node($offset,'lru_left',0);
|
||||
|
||||
$this->_set_node($lru_head,'lru_left',$offset);
|
||||
$this->_set_schema($schema_id,'lru_head',$offset);
|
||||
|
||||
if($lru_tail==0){
|
||||
$this->_set_schema($schema_id,'lru_tail',$offset);
|
||||
}elseif($lru_tail==$offset && $info['lru_left']){
|
||||
$this->_set_schema($schema_id,'lru_tail',$info['lru_left']);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function _get_node($offset){
|
||||
$this->_seek($offset*$this->idx_node_size + $this->idx_node_base);
|
||||
$info = unpack('V1next/V1prev/V1data/V1size/V1lru_right/V1lru_left/H*key',fread($this->_rs,$this->idx_node_size));
|
||||
$info['offset'] = $offset;
|
||||
return $info;
|
||||
}
|
||||
|
||||
function _lru_pop($schema_id){
|
||||
if($node = $this->_get_schema($schema_id,'lru_tail')){
|
||||
$info = $this->_get_node($node);
|
||||
if(!$info['data']){
|
||||
return false;
|
||||
}
|
||||
$this->delete($info['key'],$info['offset']);
|
||||
if(!$this->_get_schema($schema_id,'free')){
|
||||
$this->trigger_error('pop lru,But nothing free...',E_USER_ERROR);
|
||||
}
|
||||
return $info;
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function _dalloc($schema_id,$lru_freed=false){
|
||||
|
||||
if($free = $this->_get_schema($schema_id,'free')){ //如果lru里有链表
|
||||
$this->_seek($free);
|
||||
list(,$next) = unpack('V',fread($this->_rs,4));
|
||||
$this->_set_schema($schema_id,'free',$next);
|
||||
return $free;
|
||||
}elseif($lru_freed){
|
||||
$this->trigger_error('Bat lru poped freesize',E_USER_ERROR);
|
||||
return false;
|
||||
}else{
|
||||
$ds_offset = $this->_get_dcur_pos();
|
||||
$size = $this->_get_schema($schema_id,'size');
|
||||
|
||||
if($size+$ds_offset > $this->max_size){
|
||||
if($info = $this->_lru_pop($schema_id)){
|
||||
return $this->_dalloc($schema_id,$info);
|
||||
}else{
|
||||
$this->trigger_error('Can\'t alloc dataspace',E_USER_ERROR);
|
||||
return false;
|
||||
}
|
||||
}else{
|
||||
$this->_set_dcur_pos($ds_offset+$size);
|
||||
return $ds_offset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function _get_dcur_pos(){
|
||||
$this->_seek($this->dfile_cur_pos);
|
||||
list(,$ds_offset) = unpack('V',fread($this->_rs,4));
|
||||
return $ds_offset;
|
||||
}
|
||||
function _set_dcur_pos($pos){
|
||||
return $this->_puts($this->dfile_cur_pos,pack('V',$pos));
|
||||
}
|
||||
|
||||
function _free_dspace($size,$pos){
|
||||
|
||||
if($pos>$this->max_size){
|
||||
$this->trigger_error('free dspace over quota:'.$pos,E_USER_ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
$schema_id = $this->_get_size_schema_id($size);
|
||||
if($free = $this->_get_schema($schema_id,'free')){
|
||||
$this->_puts($free,pack('V1',$pos));
|
||||
}else{
|
||||
$this->_set_schema($schema_id,'free',$pos);
|
||||
}
|
||||
$this->_puts($pos,pack('V1',0));
|
||||
}
|
||||
|
||||
function _dfollow($pos,&$c){
|
||||
$c++;
|
||||
$this->_seek($pos);
|
||||
list(,$next) = unpack('V1',fread($this->_rs,4));
|
||||
if($next){
|
||||
return $this->_dfollow($next,$c);
|
||||
}else{
|
||||
return $pos;
|
||||
}
|
||||
}
|
||||
|
||||
function _free_node($pos){
|
||||
$this->_seek($this->idx_free_pos);
|
||||
list(,$prev_free_node) = unpack('V',fread($this->_rs,4));
|
||||
$this->_puts($pos*$this->idx_node_size+$this->idx_node_base,pack('V',$prev_free_node).str_repeat("\0",$this->idx_node_size-4));
|
||||
return $this->_puts($this->idx_free_pos,pack('V',$pos));
|
||||
}
|
||||
|
||||
function _alloc_idx($data){
|
||||
$this->_seek($this->idx_free_pos);
|
||||
list(,$list_pos) = unpack('V',fread($this->_rs,4));
|
||||
if($list_pos){
|
||||
|
||||
$this->_seek($list_pos*$this->idx_node_size+$this->idx_node_base);
|
||||
list(,$prev_free_node) = unpack('V',fread($this->_rs,4));
|
||||
$this->_puts($this->idx_free_pos,pack('V',$prev_free_node));
|
||||
|
||||
}else{
|
||||
$this->_seek($this->idx_seq_pos);
|
||||
list(,$list_pos) = unpack('V',fread($this->_rs,4));
|
||||
$this->_puts($this->idx_seq_pos,pack('V',$list_pos+1));
|
||||
}
|
||||
return $this->_create_node($list_pos,$data);
|
||||
}
|
||||
|
||||
function _create_node($pos,$data){
|
||||
$this->_puts($pos*$this->idx_node_size + $this->idx_node_base
|
||||
,pack('V1V1V1V1V1V1H*',$data['next'],$data['prev'],$data['data'],$data['size'],$data['lru_right'],$data['lru_left'],$data['key']));
|
||||
return $pos;
|
||||
}
|
||||
|
||||
function _set_schema($schema_id,$key,$value){
|
||||
$info = array_flip($this->schema_struct);
|
||||
return $this->_puts(60+$schema_id*$this->schema_item_size + $info[$key]*4,pack('V',$value));
|
||||
}
|
||||
|
||||
function _get_schema($id,$key){
|
||||
$info = array_flip($this->schema_struct);
|
||||
|
||||
$this->_seek(60+$id*$this->schema_item_size);
|
||||
unpack('V1'.implode('/V1',$this->schema_struct),fread($this->_rs,$this->schema_item_size));
|
||||
|
||||
$this->_seek(60+$id*$this->schema_item_size + $info[$key]*4);
|
||||
list(,$value) =unpack('V',fread($this->_rs,4));
|
||||
return $value;
|
||||
}
|
||||
|
||||
function _all_schemas(){
|
||||
$schema = [];
|
||||
for($i=0;$i<16;$i++){
|
||||
$this->_seek(60+$i*$this->schema_item_size);
|
||||
$info = unpack('V1'.implode('/V1',$this->schema_struct),fread($this->_rs,$this->schema_item_size));
|
||||
if($info['size']){
|
||||
$info['id'] = $i;
|
||||
$schema[$i] = $info;
|
||||
}else{
|
||||
return $schema;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function schemaStatus(){
|
||||
$return = [];
|
||||
foreach($this->_all_schemas() as $k=>$schemaItem){
|
||||
if($schemaItem['free']){
|
||||
$this->_dfollow($schemaItem['free'],$schemaItem['freecount']);
|
||||
}
|
||||
$return[] = $schemaItem;
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
function status(&$curBytes,&$totalBytes){
|
||||
$totalBytes = $curBytes = 0;
|
||||
$hits = $miss = 0;
|
||||
|
||||
$schemaStatus = $this->schemaStatus();
|
||||
$totalBytes = $this->max_size;
|
||||
$freeBytes = $this->max_size - $this->_get_dcur_pos();
|
||||
|
||||
foreach($schemaStatus as $schema){
|
||||
$freeBytes+=$schema['freecount']*$schema['size'];
|
||||
$miss += $schema['miss'];
|
||||
$hits += $schema['hits'];
|
||||
}
|
||||
$curBytes = $totalBytes-$freeBytes;
|
||||
|
||||
$return[] = array('name'=>'缓存命中','value'=>$hits);
|
||||
$return[] = array('name'=>'缓存未命中','value'=>$miss);
|
||||
return $return;
|
||||
}
|
||||
|
||||
function trigger_error($errstr,$errno){
|
||||
trigger_error($errstr,$errno);
|
||||
}
|
||||
|
||||
}
|
||||
97
Library/Think/Cache/Driver/Simple.php
Normal file
97
Library/Think/Cache/Driver/Simple.php
Normal file
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkCache
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace Think\Cache\Driver;
|
||||
/**
|
||||
* 文件类型缓存类
|
||||
* @author liu21st <liu21st@gmail.com>
|
||||
*/
|
||||
class Simple {
|
||||
|
||||
protected $options = [
|
||||
'prefix' => '',
|
||||
'temp' => '',
|
||||
];
|
||||
|
||||
/**
|
||||
* 架构函数
|
||||
* @access public
|
||||
*/
|
||||
public function __construct($options=[]) {
|
||||
if(!empty($options)) {
|
||||
$this->options = array_merge($this->options,$options);
|
||||
}
|
||||
if(substr($this->options['temp'], -1) != '/') $this->options['temp'] .= '/';
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得变量的存储文件名
|
||||
* @access private
|
||||
* @param string $name 缓存变量名
|
||||
* @return string
|
||||
*/
|
||||
private function filename($name) {
|
||||
return $this->options['temp'].$this->options['prefix'].md5($name).'.php';
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($name) {
|
||||
$filename = $this->filename($name);
|
||||
if (is_file($filename)) {
|
||||
return include $filename;
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @param mixed $value 存储数据
|
||||
* @param int $expire 有效时间 0为永久
|
||||
* @return boolen
|
||||
*/
|
||||
public function set($name,$value,$expire=null) {
|
||||
$filename = $this->filename($name);
|
||||
// 缓存数据
|
||||
$dir = dirname($filename);
|
||||
// 目录不存在则创建
|
||||
//if (!is_dir($dir))
|
||||
// mkdir($dir,0755,true);
|
||||
return file_put_contents($filename, ("<?php\treturn " . var_export($value, true) . ";?>"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除缓存
|
||||
* @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() {
|
||||
$filename = $this->filename('*');
|
||||
array_map("unlink", glob($filename));
|
||||
}
|
||||
}
|
||||
117
Library/Think/Cache/Driver/Sqlite.php
Normal file
117
Library/Think/Cache/Driver/Sqlite.php
Normal file
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkCache
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace Think\Cache\Driver;
|
||||
/**
|
||||
* Sqlite缓存驱动
|
||||
* @author liu21st <liu21st@gmail.com>
|
||||
*/
|
||||
class Sqlite {
|
||||
|
||||
protected $options = [
|
||||
'db' => ':memory:',
|
||||
'table' => 'sharedmemory',
|
||||
'prefix' => '',
|
||||
'expire' => 0,
|
||||
'length' => 0,
|
||||
'persistent' => false,
|
||||
];
|
||||
|
||||
/**
|
||||
* 架构函数
|
||||
* @param array $options 缓存参数
|
||||
* @access public
|
||||
*/
|
||||
public function __construct($options=[]) {
|
||||
if ( !extension_loaded('sqlite') ) {
|
||||
E('_NOT_SUPPERT_:sqlite');
|
||||
}
|
||||
if(!empty($options)) {
|
||||
$this->options = array_merge($this->options,$options);
|
||||
}
|
||||
$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) {
|
||||
$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(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) {
|
||||
$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(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 ;
|
||||
}
|
||||
}
|
||||
101
Library/Think/Cache/Driver/Wincache.php
Normal file
101
Library/Think/Cache/Driver/Wincache.php
Normal file
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkCache
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace Think\Cache\Driver;
|
||||
/**
|
||||
* Wincache缓存驱动
|
||||
* @author liu21st <liu21st@gmail.com>
|
||||
*/
|
||||
class Wincache {
|
||||
|
||||
protected $options = [
|
||||
'prefix' => '',
|
||||
'expire' => 0,
|
||||
'length' => 0,
|
||||
];
|
||||
|
||||
/**
|
||||
* 架构函数
|
||||
* @param array $options 缓存参数
|
||||
* @access public
|
||||
*/
|
||||
public function __construct($options=[]) {
|
||||
if ( !function_exists('wincache_ucache_info') ) {
|
||||
E('_NOT_SUPPERT_:WinCache');
|
||||
}
|
||||
if(!empty($options)) {
|
||||
$this->options = array_merge($this->options,$options);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($name) {
|
||||
$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) {
|
||||
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) {
|
||||
// 记录缓存队列
|
||||
$queue = wincache_ucache_get('__info__');
|
||||
if(!$queue) {
|
||||
$queue = [];
|
||||
}
|
||||
if(false===array_search($name, $queue)) array_push($queue,$name);
|
||||
if(count($queue) > $this->options['length']) {
|
||||
// 出列
|
||||
$key = array_shift($queue);
|
||||
// 删除缓存
|
||||
wincache_ucache_delete($key);
|
||||
}
|
||||
wincache_ucache_set('__info__', $queue);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @return boolen
|
||||
*/
|
||||
public function rm($name) {
|
||||
return wincache_ucache_delete($this->options['prefix'].$name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除缓存
|
||||
* @access public
|
||||
* @return boolen
|
||||
*/
|
||||
public function clear() {
|
||||
return ;
|
||||
}
|
||||
}
|
||||
104
Library/Think/Cache/Driver/Xcache.php
Normal file
104
Library/Think/Cache/Driver/Xcache.php
Normal file
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkCache
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace Think\Cache\Driver;
|
||||
/**
|
||||
* Xcache缓存驱动
|
||||
* @author liu21st <liu21st@gmail.com>
|
||||
*/
|
||||
class Xcache {
|
||||
|
||||
protected $options = [
|
||||
'prefix' => '',
|
||||
'expire' => 0,
|
||||
'length' => 0,
|
||||
];
|
||||
|
||||
/**
|
||||
* 架构函数
|
||||
* @param array $options 缓存参数
|
||||
* @access public
|
||||
*/
|
||||
public function __construct($options=[]) {
|
||||
if ( !function_exists('xcache_info') ) {
|
||||
E('_NOT_SUPPERT_:Xcache');
|
||||
}
|
||||
if(!empty($options)) {
|
||||
$this->options = array_merge($this->options,$options);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($name) {
|
||||
$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) {
|
||||
if(is_null($expire)) {
|
||||
$expire = $this->options['expire'] ;
|
||||
}
|
||||
$name = $this->options['prefix'].$name;
|
||||
if(xcache_set($name, $value, $expire)) {
|
||||
if($this->options['length']>0) {
|
||||
// 记录缓存队列
|
||||
$queue = xcache_get('__info__');
|
||||
if(!$queue) {
|
||||
$queue = [];
|
||||
}
|
||||
if(false===array_search($name, $queue)) array_push($queue,$name);
|
||||
if(count($queue) > $this->options['length']) {
|
||||
// 出列
|
||||
$key = array_shift($queue);
|
||||
// 删除缓存
|
||||
xcache_unset($key);
|
||||
}
|
||||
xcache_set('__info__', $queue);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除缓存
|
||||
* @access public
|
||||
* @param string $name 缓存变量名
|
||||
* @return boolen
|
||||
*/
|
||||
public function rm($name) {
|
||||
return xcache_unset($this->options['prefix'].$name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除缓存
|
||||
* @access public
|
||||
* @return boolen
|
||||
*/
|
||||
public function clear() {
|
||||
return ;
|
||||
}
|
||||
}
|
||||
89
Library/Think/Config.php
Normal file
89
Library/Think/Config.php
Normal file
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | TOPThink [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2011 http://topthink.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace Think;
|
||||
class Config {
|
||||
static private $_config = []; // 配置参数
|
||||
static private $_range = '_sys_'; // 参数作用域
|
||||
|
||||
// 设定配置参数的作用域
|
||||
static public function range($range){
|
||||
self::$_range = $range;
|
||||
}
|
||||
|
||||
// 解析其他格式的配置参数
|
||||
static public function parse($config,$type='',$range=''){
|
||||
if(empty($type)) {
|
||||
$type = substr(strrchr($config, '.'),1);
|
||||
}
|
||||
$class = '\Think\Config\Driver\\'.ucwords($type);
|
||||
self::set((new $class())->parse($config),'',$range);
|
||||
}
|
||||
|
||||
// 加载配置文件
|
||||
static public function load($file,$range=''){
|
||||
return self::set(include $file,'',$range);
|
||||
}
|
||||
|
||||
// 检测配置是否存在
|
||||
static public function has($name,$range=''){
|
||||
$range = $range?$range:self::$_range;
|
||||
$name = strtolower($name);
|
||||
// 优先执行设置获取或赋值
|
||||
if (!strpos($name, '.')) {
|
||||
return isset(self::$_config[$range][$name]);
|
||||
}
|
||||
// 二维数组设置和获取支持
|
||||
$name = explode('.', $name);
|
||||
return isset(self::$_config[$range][$name[0]][$name[1]]);
|
||||
}
|
||||
|
||||
// 获取配置参数 为空则获取所有配置
|
||||
static public function get($name=null,$range='') {
|
||||
$range = $range?$range:self::$_range;
|
||||
// 无参数时获取所有
|
||||
if (empty($name)) {
|
||||
return self::$_config[$range];
|
||||
}
|
||||
$name = strtolower($name);
|
||||
// 优先执行设置获取或赋值
|
||||
if (!strpos($name, '.')) {
|
||||
return isset(self::$_config[$range][$name]) ? self::$_config[$range][$name] : null;
|
||||
}
|
||||
// 二维数组设置和获取支持
|
||||
$name = explode('.', $name);
|
||||
return isset(self::$_config[$range][$name[0]][$name[1]]) ? self::$_config[$range][$name[0]][$name[1]] : null;
|
||||
}
|
||||
|
||||
// 设置配置参数 name为数组则为批量设置
|
||||
static public function set($name, $value=null,$range='') {
|
||||
$range = $range?$range:self::$_range;
|
||||
if(!isset(self::$_config[$range])) {
|
||||
self::$_config[$range] = [];
|
||||
}
|
||||
if (is_string($name)) {
|
||||
$name = strtolower($name);
|
||||
if (!strpos($name, '.')) {
|
||||
self::$_config[$range][$name] = $value;
|
||||
return;
|
||||
}
|
||||
// 二维数组设置和获取支持
|
||||
$name = explode('.', $name);
|
||||
self::$_config[$range][$name[0]][$name[1]] = $value;
|
||||
return;
|
||||
}
|
||||
// 批量设置
|
||||
if (is_array($name)){
|
||||
self::$_config[$range] = array_merge(self::$_config[$range], array_change_key_case($name));
|
||||
return self::$_config[$range];
|
||||
}
|
||||
return null; // 避免非法参数
|
||||
}
|
||||
}
|
||||
22
Library/Think/Config/Driver/Ini.php
Normal file
22
Library/Think/Config/Driver/Ini.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | TOPThink [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2013 http://topthink.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
// $Id$
|
||||
|
||||
namespace Think\Config\Driver;
|
||||
class Ini {
|
||||
public function parse($config){
|
||||
if(is_file($config)) {
|
||||
return parse_ini_file($config,true);
|
||||
}else{
|
||||
return parse_ini_string($config,true);
|
||||
}
|
||||
}
|
||||
}
|
||||
29
Library/Think/Config/Driver/Xml.php
Normal file
29
Library/Think/Config/Driver/Xml.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | TOPThink [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2013 http://topthink.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
// $Id$
|
||||
|
||||
namespace Think\Config\Driver;
|
||||
class Xml {
|
||||
public function parse($config){
|
||||
if(is_file($config)) {
|
||||
$content = simplexml_load_file($config);
|
||||
}else{
|
||||
$content = simplexml_load_string($config);
|
||||
}
|
||||
$result = (array)$content;
|
||||
foreach($result as $key=>$val){
|
||||
if(is_object($val)) {
|
||||
$result[$key] = (array)$val;
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
173
Library/Think/Controller.php
Normal file
173
Library/Think/Controller.php
Normal file
@@ -0,0 +1,173 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | TOPThink [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2011 http://topthink.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
// $Id$
|
||||
namespace Think;
|
||||
class Controller {
|
||||
// 视图类实例
|
||||
protected $view = null;
|
||||
|
||||
/**
|
||||
* 架构函数 初始化视图类 并采用内置模板引擎
|
||||
* @access public
|
||||
*/
|
||||
public function __construct(){
|
||||
// 模板引擎参数
|
||||
$config = [
|
||||
'tpl_path' => MODULE_PATH.'View/',
|
||||
'cache_path' => RUNTIME_PATH.'Cache/',
|
||||
];
|
||||
$this->view = new View();
|
||||
$this->view->engine('think',$config);
|
||||
//控制器初始化
|
||||
if(method_exists($this,'_initialize'))
|
||||
$this->_initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载模板和页面输出 可以返回输出内容
|
||||
* @access public
|
||||
* @param string $template 模板文件名
|
||||
* @param array $vars 模板输出变量
|
||||
* @param string $cacheId 模板缓存标识
|
||||
* @return mixed
|
||||
*/
|
||||
public function display($template='',$vars=[],$cacheId=''){
|
||||
$this->view->display($template,$vars,$cacheId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 渲染内容输出
|
||||
* @access public
|
||||
* @param string $content 内容
|
||||
* @param array $vars 模板输出变量
|
||||
* @return mixed
|
||||
*/
|
||||
public function show($content,$vars=[]){
|
||||
$this->view->http('http_render_content',true)->display($content,$vars);
|
||||
}
|
||||
|
||||
/**
|
||||
* 模板变量赋值
|
||||
* @access protected
|
||||
* @param mixed $name 要显示的模板变量
|
||||
* @param mixed $value 变量的值
|
||||
* @return void
|
||||
*/
|
||||
public function assign($name,$value=''){
|
||||
$this->view->assign($name,$value);
|
||||
}
|
||||
|
||||
public function __set($name,$value){
|
||||
return $this->assign($name,$value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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::listen('ajax_return',$data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 操作错误跳转的快捷方法
|
||||
* @access protected
|
||||
* @param string $message 错误信息
|
||||
* @param string $jumpUrl 页面跳转地址
|
||||
* @param mixed $ajax 是否为Ajax方式 当数字时指定跳转时间
|
||||
* @return void
|
||||
*/
|
||||
protected function error($message,$jumpUrl='',$ajax=false) {
|
||||
$this->dispatchJump($message,0,$jumpUrl,$ajax);
|
||||
}
|
||||
|
||||
/**
|
||||
* 操作成功跳转的快捷方法
|
||||
* @access protected
|
||||
* @param string $message 提示信息
|
||||
* @param string $jumpUrl 页面跳转地址
|
||||
* @param mixed $ajax 是否为Ajax方式 当数字时指定跳转时间
|
||||
* @return void
|
||||
*/
|
||||
protected function success($message,$jumpUrl='',$ajax=false) {
|
||||
$this->dispatchJump($message,1,$jumpUrl,$ajax);
|
||||
}
|
||||
|
||||
/**
|
||||
* 默认跳转操作 支持错误导向和正确跳转
|
||||
* 调用模板显示 默认为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:[];
|
||||
$data['info'] = $message;
|
||||
$data['status'] = $status;
|
||||
$data['url'] = $jumpUrl;
|
||||
$this->ajaxReturn($data);
|
||||
}
|
||||
if(is_int($ajax)) $this->view->assign('waitSecond',$ajax);
|
||||
if(!empty($jumpUrl)) $this->view->assign('jumpUrl',$jumpUrl);
|
||||
// 提示标题
|
||||
$this->view->assign('msgTitle',$status? L('_OPERATION_SUCCESS_') : L('_OPERATION_FAIL_'));
|
||||
$this->view->assign('status',$status); // 状态
|
||||
//保证输出不受静态缓存影响
|
||||
C('HTML_CACHE_ON',false);
|
||||
if($status) { //发送成功信息
|
||||
$this->view->assign('message',$message);// 提示信息
|
||||
// 成功操作后默认停留1秒
|
||||
$this->view->assign('waitSecond','1');
|
||||
// 默认操作成功自动返回操作前页面
|
||||
if(!$jumpUrl) $this->view->assign("jumpUrl",$_SERVER["HTTP_REFERER"]);
|
||||
$this->display(C('success_tmpl'));
|
||||
}else{
|
||||
$this->view->assign('error',$message);// 提示信息
|
||||
//发生错误时候默认停留3秒
|
||||
$this->view->assign('waitSecond','3');
|
||||
// 默认发生错误的话自动返回上页
|
||||
if(!$jumpUrl) $this->view->assign('jumpUrl',"javascript:history.back(-1);");
|
||||
$this->display(C('error_tmpl'));
|
||||
// 中止执行 避免出错后继续执行
|
||||
exit ;
|
||||
}
|
||||
}
|
||||
}
|
||||
29
Library/Think/Controller/Amf.php
Normal file
29
Library/Think/Controller/Amf.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace Think\Controller;
|
||||
abstract class Amf {
|
||||
|
||||
/**
|
||||
* PHPRpc控制器架构函数
|
||||
* @access public
|
||||
*/
|
||||
public function __construct() {
|
||||
//导入类库
|
||||
Think\Loader::import('Vendor.Zend.Amf.Server');
|
||||
//实例化AMF
|
||||
$server = new \Zend_Amf_Server();
|
||||
$server -> setClass($this);
|
||||
echo $server -> handle();
|
||||
return ;
|
||||
}
|
||||
|
||||
}
|
||||
34
Library/Think/Controller/Phprpc.php
Normal file
34
Library/Think/Controller/Phprpc.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace Think\Controller;
|
||||
abstract class Phprpc {
|
||||
|
||||
/**
|
||||
* PHPRpc控制器架构函数
|
||||
* @access public
|
||||
*/
|
||||
public function __construct() {
|
||||
//导入类库
|
||||
Think\Loader::import('Vendor.phpRPC.phprpc_server');
|
||||
//实例化phprpc
|
||||
$server = new \PHPRPC_Server();
|
||||
$server->add($this);
|
||||
if(APP_DEBUG) {
|
||||
$server->setDebugMode(true);
|
||||
}
|
||||
$server->setEnableGZIP(true);
|
||||
$server->start();
|
||||
//C('PHPRPC_COMMENT',$server->comment());
|
||||
echo $server->comment();
|
||||
}
|
||||
|
||||
}
|
||||
214
Library/Think/Controller/Rest.php
Normal file
214
Library/Think/Controller/Rest.php
Normal file
@@ -0,0 +1,214 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace Think\Controller;
|
||||
abstract class Rest {
|
||||
|
||||
protected $_method = ''; // 当前请求类型
|
||||
protected $_type = ''; // 当前资源类型
|
||||
// 输出类型
|
||||
protected $restMethodList = 'get|post|put|delete';
|
||||
protected $restDefaultMethod = 'get';
|
||||
protected $restTypeList = 'html|xml|json|rss';
|
||||
protected $restDefaultType = 'html';
|
||||
protected $restOutputType = [ // REST允许输出的资源类型列表
|
||||
'xml' => 'application/xml',
|
||||
'json' => 'application/json',
|
||||
'html' => 'text/html',
|
||||
];
|
||||
|
||||
/**
|
||||
* 架构函数 取得模板对象实例
|
||||
* @access public
|
||||
*/
|
||||
public function __construct() {
|
||||
// 资源类型检测
|
||||
if(''==__EXT__) { // 自动检测资源类型
|
||||
$this->_type = $this->getAcceptType();
|
||||
}elseif(!preg_match('/\('.$this->restTypeList.')$/i',__EXT__)) {
|
||||
// 资源类型非法 则用默认资源类型访问
|
||||
$this->_type = $this->restDefaultType;
|
||||
}else{
|
||||
$this->_type = __EXT__;
|
||||
}
|
||||
// 请求方式检测
|
||||
$method = strtolower($_SERVER['REQUEST_METHOD']);
|
||||
if(false === stripos($this->restMethodList,$method)) {
|
||||
// 请求方式非法 则用默认请求方法
|
||||
$method = $this->restDefaultMethod;
|
||||
}
|
||||
$this->_method = $method;
|
||||
}
|
||||
|
||||
/**
|
||||
* REST 调用
|
||||
* @access public
|
||||
* @param string $method 方法名
|
||||
* @param array $args 参数
|
||||
* @return mixed
|
||||
*/
|
||||
public function _empty($method,$args) {
|
||||
if(method_exists($this,$method.'_'.$this->_method.'_'.$this->_type)) { // RESTFul方法支持
|
||||
$fun = $method.'_'.$this->_method.'_'.$this->_type;
|
||||
}elseif($this->_method == $this->restDefaultMethod && method_exists($this,$method.'_'.$this->_type) ){
|
||||
$fun = $method.'_'.$this->_type;
|
||||
}elseif($this->_type == $this->restDefaultType && method_exists($this,$method.'_'.$this->_method) ){
|
||||
$fun = $method.'_'.$this->_method;
|
||||
}
|
||||
if(isset($fun)) {
|
||||
$this->$fun();
|
||||
}else{
|
||||
// 抛出异常
|
||||
E(L('_ERROR_ACTION_:').ACTION_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置页面输出的CONTENT_TYPE和编码
|
||||
* @access public
|
||||
* @param string $type content_type 类型对应的扩展名
|
||||
* @param string $charset 页面输出编码
|
||||
* @return void
|
||||
*/
|
||||
public function setContentType($type, $charset='utf-8'){
|
||||
if(headers_sent()) return;
|
||||
$type = strtolower($type);
|
||||
if(isset($this->restOutputType[$type])) //过滤content_type
|
||||
header('Content-Type: '.$this->restOutputType[$type].'; charset='.$charset);
|
||||
}
|
||||
|
||||
/**
|
||||
* 输出返回数据
|
||||
* @access protected
|
||||
* @param mixed $data 要返回的数据
|
||||
* @param String $type 返回类型 JSON XML
|
||||
* @param integer $code HTTP状态
|
||||
* @return void
|
||||
*/
|
||||
protected function response($data,$type='',$code=200) {
|
||||
$this->sendHttpStatus($code);
|
||||
exit($this->encodeData($data,strtolower($type)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 编码数据
|
||||
* @access protected
|
||||
* @param mixed $data 要返回的数据
|
||||
* @param String $type 返回类型 JSON XML
|
||||
* @return void
|
||||
*/
|
||||
protected function encodeData($data,$type='') {
|
||||
if(empty($data)) return '';
|
||||
if('json' == $type) {
|
||||
// 返回JSON数据格式到客户端 包含状态信息
|
||||
$data = json_encode($data);
|
||||
}elseif('xml' == $type){
|
||||
// 返回xml格式数据
|
||||
$data = xml_encode($data);
|
||||
}elseif('php'==$type){
|
||||
$data = serialize($data);
|
||||
}// 默认直接输出
|
||||
$this->setContentType($type);
|
||||
header('Content-Length: ' . strlen($data));
|
||||
return $data;
|
||||
}
|
||||
|
||||
// 发送Http状态信息
|
||||
protected function sendHttpStatus($status) {
|
||||
static $_status = [
|
||||
// Informational 1xx
|
||||
100 => 'Continue',
|
||||
101 => 'Switching Protocols',
|
||||
// Success 2xx
|
||||
200 => 'OK',
|
||||
201 => 'Created',
|
||||
202 => 'Accepted',
|
||||
203 => 'Non-Authoritative Information',
|
||||
204 => 'No Content',
|
||||
205 => 'Reset Content',
|
||||
206 => 'Partial Content',
|
||||
// Redirection 3xx
|
||||
300 => 'Multiple Choices',
|
||||
301 => 'Moved Permanently',
|
||||
302 => 'Moved Temporarily ', // 1.1
|
||||
303 => 'See Other',
|
||||
304 => 'Not Modified',
|
||||
305 => 'Use Proxy',
|
||||
// 306 is deprecated but reserved
|
||||
307 => 'Temporary Redirect',
|
||||
// Client Error 4xx
|
||||
400 => 'Bad Request',
|
||||
401 => 'Unauthorized',
|
||||
402 => 'Payment Required',
|
||||
403 => 'Forbidden',
|
||||
404 => 'Not Found',
|
||||
405 => 'Method Not Allowed',
|
||||
406 => 'Not Acceptable',
|
||||
407 => 'Proxy Authentication Required',
|
||||
408 => 'Request Timeout',
|
||||
409 => 'Conflict',
|
||||
410 => 'Gone',
|
||||
411 => 'Length Required',
|
||||
412 => 'Precondition Failed',
|
||||
413 => 'Request Entity Too Large',
|
||||
414 => 'Request-URI Too Long',
|
||||
415 => 'Unsupported Media Type',
|
||||
416 => 'Requested Range Not Satisfiable',
|
||||
417 => 'Expectation Failed',
|
||||
// Server Error 5xx
|
||||
500 => 'Internal Server Error',
|
||||
501 => 'Not Implemented',
|
||||
502 => 'Bad Gateway',
|
||||
503 => 'Service Unavailable',
|
||||
504 => 'Gateway Timeout',
|
||||
505 => 'HTTP Version Not Supported',
|
||||
509 => 'Bandwidth Limit Exceeded'
|
||||
];
|
||||
if(isset($_status[$code])) {
|
||||
header('HTTP/1.1 '.$code.' '.$_status[$code]);
|
||||
// 确保FastCGI模式下正常
|
||||
header('Status:'.$code.' '.$_status[$code]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前请求的Accept头信息
|
||||
* @return string
|
||||
*/
|
||||
protected function getAcceptType(){
|
||||
$type = [
|
||||
'html' => 'text/html,application/xhtml+xml,*/*',
|
||||
'xml' => 'application/xml,text/xml,application/x-xml',
|
||||
'json' => 'application/json,text/x-json,application/jsonrequest,text/json',
|
||||
'js' => 'text/javascript,application/javascript,application/x-javascript',
|
||||
'css' => 'text/css',
|
||||
'rss' => 'application/rss+xml',
|
||||
'yaml' => 'application/x-yaml,text/yaml',
|
||||
'atom' => 'application/atom+xml',
|
||||
'pdf' => 'application/pdf',
|
||||
'text' => 'text/plain',
|
||||
'png' => 'image/png',
|
||||
'jpg' => 'image/jpg,image/jpeg,image/pjpeg',
|
||||
'gif' => 'image/gif',
|
||||
'csv' => 'text/csv'
|
||||
];
|
||||
|
||||
foreach($type as $key=>$val){
|
||||
$array = explode(',',$val);
|
||||
foreach($array as $k=>$v){
|
||||
if(stristr($_SERVER['HTTP_ACCEPT'], $v)) {
|
||||
return $key;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
130
Library/Think/Cookie.php
Normal file
130
Library/Think/Cookie.php
Normal file
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | TOPThink [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2011 http://topthink.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
// $Id$
|
||||
namespace Think;
|
||||
class Cookie {
|
||||
|
||||
static protected $config = [
|
||||
'prefix' => '', // cookie 名称前缀
|
||||
'expire' => 0, // cookie 保存时间
|
||||
'path' => '/', // cookie 保存路径
|
||||
'domain' => '', // cookie 有效域名
|
||||
];
|
||||
|
||||
/**
|
||||
* Cookie初始化
|
||||
* @param array $config
|
||||
* @return void
|
||||
*/
|
||||
static public function init($config=[]){
|
||||
self::$config = array_merge(self::$config, array_change_key_case($config));
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置或者获取cookie作用域(前缀)
|
||||
* @param string $prefix
|
||||
* @return string|void
|
||||
*/
|
||||
static public function prefix($prefix=''){
|
||||
if(empty($prefix)) {
|
||||
return self::$config['prefix'];
|
||||
}else{
|
||||
self::$config['prefix'] = $prefix;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cookie 设置、获取、删除
|
||||
* @param string $name cookie名称
|
||||
* @param mixed $value cookie值
|
||||
* @param mixed $options cookie参数
|
||||
* @return mixed
|
||||
*/
|
||||
static public function set($name, $value='', $option=null) {
|
||||
// 参数设置(会覆盖黙认设置)
|
||||
if (!is_null($option)) {
|
||||
if (is_numeric($option))
|
||||
$option = ['expire' => $option];
|
||||
elseif (is_string($option))
|
||||
parse_str($option, $option);
|
||||
$config = array_merge(self::$config, array_change_key_case($option));
|
||||
}else{
|
||||
$config = self::$config;
|
||||
}
|
||||
$name = $config['prefix'] . $name;
|
||||
// 设置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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cookie获取
|
||||
* @param string $name cookie名称
|
||||
* @param string $prefix cookie前缀
|
||||
* @return mixed
|
||||
*/
|
||||
static public function get($name, $prefix='') {
|
||||
$prefix = $prefix?$prefix:self::$config['prefix'];
|
||||
$name = $prefix . $name;
|
||||
if(isset($_COOKIE[$name])){
|
||||
$value = $_COOKIE[$name];
|
||||
if(0===strpos($value,'think:')){
|
||||
$value = substr($value,6);
|
||||
return array_map('urldecode',json_decode($value,true));
|
||||
}else{
|
||||
return $value;
|
||||
}
|
||||
}else{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cookie删除
|
||||
* @param string $name cookie名称
|
||||
* @param string $prefix cookie前缀
|
||||
* @return mixed
|
||||
*/
|
||||
static public function delete($name, $prefix='') {
|
||||
$prefix = $prefix?$prefix:self::$config['prefix'];
|
||||
$name = $prefix . $name;
|
||||
setcookie($name, '', time() - 3600, self::$config['path'], self::$config['domain']);
|
||||
unset($_COOKIE[$name]); // 删除指定cookie
|
||||
}
|
||||
|
||||
/**
|
||||
* Cookie清空
|
||||
* @param string $prefix cookie前缀
|
||||
* @return mixed
|
||||
*/
|
||||
static public function clear($prefix='') {
|
||||
// 清除指定前缀的所有cookie
|
||||
if (empty($_COOKIE))
|
||||
return;
|
||||
// 要删除的cookie前缀,不指定则删除config设置的指定前缀
|
||||
$prefix = $prefix ? $prefix: self::$config['prefix'];
|
||||
if ($prefix) {// 如果前缀为空字符串将不作处理直接返回
|
||||
foreach ($_COOKIE as $key => $val) {
|
||||
if (0 === strpos($key, $prefix)) {
|
||||
setcookie($key, '', time() - 3600, self::$config['path'], self::$config['domain']);
|
||||
unset($_COOKIE[$key]);
|
||||
}
|
||||
}
|
||||
}else{
|
||||
unset($_COOKIE);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
102
Library/Think/Create.php
Normal file
102
Library/Think/Create.php
Normal file
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | TOPThink [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2013 http://topthink.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
// $Id$
|
||||
|
||||
namespace Think;
|
||||
class Create {
|
||||
static public function build($build) {
|
||||
// 锁定
|
||||
$lockfile = APP_PATH.'create.lock';
|
||||
if(is_writable($lockfile)) {
|
||||
return ;
|
||||
} else {
|
||||
if(!touch($lockfile)){
|
||||
header('Content-Type:text/html; charset=utf-8');
|
||||
exit('目录 [ '.APP_PATH.' ] 不可写!');
|
||||
}
|
||||
}
|
||||
foreach ($build as $module=>$list){
|
||||
if(!is_dir(APP_PATH.$module)) {// 创建模块目录
|
||||
mkdir(APP_PATH.$module);
|
||||
}
|
||||
// 创建配置文件和公共文件
|
||||
self::buildCommonFile($module);
|
||||
// 创建欢迎页面
|
||||
self::buildHelloController($module);
|
||||
|
||||
// 创建子目录和文件
|
||||
foreach($list as $path=>$file){
|
||||
if(is_int($path)) {
|
||||
// 生成文件
|
||||
if(!is_file(APP_PATH.$module.'/'.$file)) {
|
||||
file_put_contents(APP_PATH.$module.'/'.$file,"<?php\n");
|
||||
}
|
||||
}else{
|
||||
// 创建模块的子目录
|
||||
if(!is_dir(APP_PATH.$module.'/'.$path)){
|
||||
mkdir(APP_PATH.$module.'/'.$path);
|
||||
}
|
||||
foreach($file as $val){
|
||||
switch($path) {
|
||||
case 'Controller':// 控制器
|
||||
$filename = ucwords($val).$path;
|
||||
if(!is_file(APP_PATH.$module.'/'.$path.'/'.$filename.'.php')) {
|
||||
file_put_contents(APP_PATH.$module.'/'.$path.'/'.$filename.'.php',"<?php\nnamespace {$module}\\{$path};\nclass {$filename} {\n}");
|
||||
}
|
||||
break;
|
||||
case 'Model': // 模型
|
||||
$filename = ucwords($val).$path;
|
||||
if(!is_file(APP_PATH.$module.'/'.$path.'/'.$filename.'.php')) {
|
||||
file_put_contents(APP_PATH.$module.'/'.$path.'/'.$filename.'.php',"<?php\nnamespace {$module}\\{$path};\nclass {$filename} extends \Think\Model{\n}");
|
||||
}
|
||||
break;
|
||||
case 'View': // 视图
|
||||
break;
|
||||
default:
|
||||
$filename = ucwords($val).$path;
|
||||
if(!is_file(APP_PATH.$module.'/'.$path.'/'.$filename.'.php')) {
|
||||
file_put_contents(APP_PATH.$module.'/'.$path.'/'.$filename.'.php',"<?php\nnamespace {$module}\\{$path};\nclass {$filename} {\n}");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 解除锁定
|
||||
unlink($lockfile);
|
||||
}
|
||||
|
||||
// 创建欢迎页面
|
||||
static public function buildHelloController($module) {
|
||||
if(!is_file(APP_PATH.$module.'/Controller/IndexController.php')) {
|
||||
$content = file_get_contents(THINK_PATH.'Tpl/default_index.tpl');
|
||||
$content = str_replace('{$module}',$module,$content);
|
||||
if(!is_dir(APP_PATH.$module.'/Controller')) {
|
||||
mkdir(APP_PATH.$module.'/Controller');
|
||||
}
|
||||
file_put_contents(APP_PATH.$module.'/Controller/IndexController.php',$content);
|
||||
}
|
||||
}
|
||||
|
||||
// 创建模块公共文件
|
||||
static public function buildCommonFile($module){
|
||||
if(!is_file(APP_PATH.$module.'/common.php')) {
|
||||
file_put_contents(APP_PATH.$module.'/common.php',"<?php\n");
|
||||
}
|
||||
if(!is_file(APP_PATH.$module.'/config.php')) {
|
||||
file_put_contents(APP_PATH.$module.'/config.php',"<?php\nreturn [\n];");
|
||||
}
|
||||
if(!is_file(APP_PATH.$module.'/alias.php')) {
|
||||
file_put_contents(APP_PATH.$module.'/alias.php',"<?php\nreturn [\n];");
|
||||
}
|
||||
}
|
||||
}
|
||||
109
Library/Think/Db.php
Normal file
109
Library/Think/Db.php
Normal file
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | TOPThink [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2011 http://topthink.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace Think;
|
||||
/**
|
||||
* ThinkPHP 数据库中间层实现类
|
||||
*/
|
||||
class Db {
|
||||
|
||||
static private $instance = []; // 数据库连接实例
|
||||
static private $_instance = null; // 当前数据库连接实例
|
||||
|
||||
/**
|
||||
* 取得数据库类实例
|
||||
* @static
|
||||
* @access public
|
||||
* @param mixed $config 连接配置
|
||||
* @param boolean $lite 是否lite方式
|
||||
* @return Object 返回数据库驱动类
|
||||
*/
|
||||
static public function instance($config=[],$lite=false) {
|
||||
$md5 = md5(serialize($config));
|
||||
if(!isset(self::$instance[$md5])) {
|
||||
// 解析连接参数 支持数组和字符串
|
||||
$options = self::parseConfig($config);
|
||||
// 如果采用lite方式 仅支持原生SQL 包括query和execute方法
|
||||
$class = $lite? 'Think\Db\Lite' : 'Think\\Db\\Driver\\'.ucwords($options['dbms']);
|
||||
self::$instance[$md5] = new $class($options);
|
||||
}
|
||||
self::$_instance = self::$instance[$md5];
|
||||
return self::$_instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据库连接参数解析
|
||||
* @static
|
||||
* @access public
|
||||
* @param mixed $config
|
||||
* @return array
|
||||
*/
|
||||
static public function parseConfig($config){
|
||||
if(empty($config)) {
|
||||
$config = Config::get();
|
||||
}
|
||||
if(is_string($config)) {
|
||||
return self::parseDsn($config);
|
||||
}
|
||||
return [
|
||||
'dbms' => $config['db_type'],
|
||||
'dsn' => $config['db_dsn'],
|
||||
'username' => $config['db_user'],
|
||||
'password' => $config['db_pwd'],
|
||||
'hostname' => $config['db_host'],
|
||||
'hostport' => $config['db_port'],
|
||||
'database' => $config['db_name'],
|
||||
'params' => $config['db_params'],
|
||||
'charset' => $config['db_charset'],
|
||||
'deploy' => $config['db_deploy'],
|
||||
'socket' => $config['db_unix_socket'],
|
||||
'debug' => $config['db_debug'],
|
||||
'deploy' => $config['db_deploy'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* DSN解析
|
||||
* 格式: mysql://username:passwd@localhost:3306/DbName?param1=val1¶m2=val2#utf8
|
||||
* @static
|
||||
* @access public
|
||||
* @param string $dsnStr
|
||||
* @return array
|
||||
*/
|
||||
static public function parseDsn($dsnStr) {
|
||||
if( empty($dsnStr) ){return false;}
|
||||
$info = parse_url($dsnStr);
|
||||
if(!$info) {
|
||||
return false;
|
||||
}
|
||||
$dsn = [
|
||||
'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) : '',
|
||||
'charset' => isset($info['fragment'])?$info['fragment']:'',
|
||||
];
|
||||
$dsn['dsn'] = ''; // 兼容配置信息数组
|
||||
if(isset($info['query'])) {
|
||||
parse_str($info['query'],$dsn['params']);
|
||||
}else{
|
||||
$dsn['params'] = [];
|
||||
}
|
||||
return $dsn;
|
||||
}
|
||||
|
||||
// 调用驱动类的方法
|
||||
static public function __callStatic($method, $params){
|
||||
return call_user_func_array(array(self::$_instance, $method), $params);
|
||||
}
|
||||
}
|
||||
968
Library/Think/Db/Driver.php
Normal file
968
Library/Think/Db/Driver.php
Normal file
@@ -0,0 +1,968 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | TOPThink [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2011 http://topthink.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
// $Id$
|
||||
namespace Think\Db;
|
||||
use Think\Config;
|
||||
use Think\Debug;
|
||||
use Think\Log;
|
||||
use PDO;
|
||||
abstract class Driver {
|
||||
// PDO操作实例
|
||||
protected $PDOStatement = null;
|
||||
// 当前操作所属的模型名
|
||||
protected $model = '_think_';
|
||||
// 当前SQL指令
|
||||
protected $queryStr = '';
|
||||
protected $modelSql = [];
|
||||
// 最后插入ID
|
||||
protected $lastInsID = null;
|
||||
// 返回或者影响记录数
|
||||
protected $numRows = 0;
|
||||
// 事务指令数
|
||||
protected $transTimes = 0;
|
||||
// 错误信息
|
||||
protected $error = '';
|
||||
// 数据库连接ID 支持多个连接
|
||||
protected $linkID = [];
|
||||
// 当前连接ID
|
||||
protected $_linkID = null;
|
||||
// 数据库连接参数配置
|
||||
protected $config = [];
|
||||
// 数据库表达式
|
||||
protected $comparison = ['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 $queryTimes = 0;
|
||||
// 执行次数
|
||||
protected $executeTimes = 0;
|
||||
// PDO连接参数
|
||||
protected $options = [
|
||||
PDO::ATTR_CASE => PDO::CASE_LOWER,
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||
PDO::ATTR_ORACLE_NULLS => PDO::NULL_NATURAL,
|
||||
PDO::ATTR_STRINGIFY_FETCHES => false,
|
||||
];
|
||||
|
||||
/**
|
||||
* 架构函数 读取数据库配置信息
|
||||
* @access public
|
||||
* @param array $config 数据库配置数组
|
||||
*/
|
||||
public function __construct($config=''){
|
||||
if(!empty($config)) {
|
||||
$this->config = $config;
|
||||
if(empty($this->config['params'])) {
|
||||
$this->config['params'] = [];
|
||||
}
|
||||
$this->config['params'] = $this->options+$this->config['params'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 连接数据库方法
|
||||
* @access public
|
||||
*/
|
||||
public function connect($config='',$linkNum=0) {
|
||||
if ( !isset($this->linkID[$linkNum]) ) {
|
||||
if(empty($config)) $config = $this->config;
|
||||
try{
|
||||
if(empty($config['dsn'])) {
|
||||
$config['dsn'] = $config['dbms'].':dbname='.$config['database'].';host='.$config['hostname'];
|
||||
if(!empty($config['hostport'])) {
|
||||
$config['dsn'] .= ';port='.$config['hostport'];
|
||||
}elseif(!empty($config['socket'])){
|
||||
$config['dsn'] .= ';unix_socket='.$config['socket'];
|
||||
}
|
||||
}
|
||||
$this->linkID[$linkNum] = new PDO( $config['dsn'], $config['username'], $config['password'],$config['params']);
|
||||
}catch (\PDOException $e) {
|
||||
E($e->getMessage());
|
||||
}
|
||||
if(!empty($config['charset'])) {
|
||||
$this->linkID[$linkNum]->exec('SET NAMES '.$config['charset']);
|
||||
}
|
||||
// 注销数据库连接配置信息
|
||||
if(1 != $config['deploy']) $this->config = [];
|
||||
}
|
||||
return $this->linkID[$linkNum];
|
||||
}
|
||||
|
||||
/**
|
||||
* 释放查询结果
|
||||
* @access public
|
||||
*/
|
||||
public function free() {
|
||||
$this->PDOStatement = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行查询 返回数据集
|
||||
* @access public
|
||||
* @param string $str sql指令
|
||||
* @return mixed
|
||||
*/
|
||||
public function query($str,$bind=[]) {
|
||||
$this->initConnect(false);
|
||||
if ( !$this->_linkID ) return false;
|
||||
$this->queryStr = $str;
|
||||
//释放前次的查询结果
|
||||
if ( !empty($this->PDOStatement) ) $this->free();
|
||||
$this->queryTimes++;
|
||||
// 调试开始
|
||||
$this->debug(true);
|
||||
$this->PDOStatement = $this->_linkID->prepare($str);
|
||||
if(false === $this->PDOStatement)
|
||||
E($this->error());
|
||||
$result = $this->PDOStatement->execute($bind);
|
||||
// 调试结束
|
||||
$this->debug(false);
|
||||
if ( false === $result ) {
|
||||
$this->error();
|
||||
return false;
|
||||
} else {
|
||||
return $this->getResult();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行语句
|
||||
* @access public
|
||||
* @param string $str sql指令
|
||||
* @return integer
|
||||
*/
|
||||
public function execute($str,$bind=[]) {
|
||||
$this->initConnect(true);
|
||||
if ( !$this->_linkID ) return false;
|
||||
$this->queryStr = $str;
|
||||
//释放前次的查询结果
|
||||
if ( !empty($this->PDOStatement) ) $this->free();
|
||||
$this->executeTimes++;
|
||||
// 记录开始执行时间
|
||||
$this->debug(true);
|
||||
$this->PDOStatement = $this->_linkID->prepare($str);
|
||||
if(false === $this->PDOStatement) {
|
||||
E($this->error());
|
||||
}
|
||||
$result = $this->PDOStatement->execute($bind);
|
||||
$this->debug(false);
|
||||
if ( false === $result) {
|
||||
$this->error();
|
||||
return false;
|
||||
} else {
|
||||
$this->numRows = $this->PDOStatement->rowCount();
|
||||
if(preg_match("/^\s*(INSERT\s+INTO|REPLACE\s+INTO)\s+/i", $str)) {
|
||||
$this->lastInsID = $this->getLastInsertId();
|
||||
}
|
||||
return $this->numRows;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取最后插入id
|
||||
* @access public
|
||||
* @return integer
|
||||
*/
|
||||
public function getLastInsertId() {
|
||||
return $this->_linkID->lastInsertId();
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动事务
|
||||
* @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 getResult() {
|
||||
//返回数据集
|
||||
$result = $this->PDOStatement->fetchAll(PDO::FETCH_ASSOC);
|
||||
$this->numRows = count( $result );
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得查询次数
|
||||
* @access public
|
||||
* @param boolean $execute 是否包含所有查询
|
||||
* @return integer
|
||||
*/
|
||||
public function getQueryTimes($execute=false){
|
||||
return $execute?$this->queryTimes+$this->executeTimes:$this->queryTimes;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得执行次数
|
||||
* @access public
|
||||
* @return integer
|
||||
*/
|
||||
public function getExecuteTimes(){
|
||||
return $this->executeTimes;
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭数据库
|
||||
* @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;
|
||||
}
|
||||
Log::record($this->error,'ERR');
|
||||
return $this->error;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置锁机制
|
||||
* @access protected
|
||||
* @return string
|
||||
*/
|
||||
protected function parseLock($lock=false) {
|
||||
return $lock? ' 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([$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 = [];
|
||||
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 = [];
|
||||
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, [&$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,['AND','OR','XOR'])){
|
||||
// 定义逻辑运算规则 例如 OR XOR AND NOT
|
||||
$operate = ' '.$operate.' ';
|
||||
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))){
|
||||
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 = [];
|
||||
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 = [];
|
||||
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,['AND','OR','XOR'])){
|
||||
$likeStr = $this->comparison[strtolower($val[0])];
|
||||
$like = [];
|
||||
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,['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 .= '('.$key.' '.$op.' '.$this->parseValue($data).') '.$rule.' ';
|
||||
}
|
||||
}
|
||||
$whereStr = substr($whereStr,0,-4);
|
||||
}
|
||||
}else {
|
||||
//对字符串类型字段采用模糊匹配
|
||||
if($this->conf['db_like_fields'] && preg_match('/('.$this->conf['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 = [];
|
||||
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",Config::get('db_prefix').".strtolower('$1')",$joinStr);
|
||||
return $joinStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* order分析
|
||||
* @access protected
|
||||
* @param mixed $order
|
||||
* @return string
|
||||
*/
|
||||
protected function parseOrder($order) {
|
||||
if(is_array($order)) {
|
||||
$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=[],$replace=false) {
|
||||
$values = $fields = [];
|
||||
$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);
|
||||
$sql .= $this->parseComment(!empty($options['comment'])?$options['comment']:'');
|
||||
return $this->execute($sql,!empty($options['bind'])?$options['bind']:[]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过Select方式插入记录
|
||||
* @access public
|
||||
* @param string $fields 要插入的数据表字段名
|
||||
* @param string $table 要插入的数据表名
|
||||
* @param array $option 查询数据参数
|
||||
* @return false | integer
|
||||
*/
|
||||
public function selectInsert($fields,$table,$options=[]) {
|
||||
$this->model = $options['model'];
|
||||
if(is_string($fields)) $fields = explode(',',$fields);
|
||||
array_walk($fields, [$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(!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,!empty($options['bind'])?$options['bind']:[]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除记录
|
||||
* @access public
|
||||
* @param array $options 表达式
|
||||
* @return false | integer
|
||||
*/
|
||||
public function delete($options=[]) {
|
||||
$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,!empty($options['bind'])?$options['bind']:[]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找记录
|
||||
* @access public
|
||||
* @param array $options 表达式
|
||||
* @return mixed
|
||||
*/
|
||||
public function select($options=[]) {
|
||||
$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,!empty($options['bind'])?$options['bind']:[]);
|
||||
if($cache && false !== $result ) { // 查询缓存写入
|
||||
S($key,$result,$cache);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成查询SQL
|
||||
* @access public
|
||||
* @param array $options 表达式
|
||||
* @return string
|
||||
*/
|
||||
public function buildSelectSql($options=[]) {
|
||||
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;
|
||||
}
|
||||
$sql = $this->parseSql($this->selectSql,$options);
|
||||
$sql .= $this->parseLock(isset($options['lock'])?$options['lock']:false);
|
||||
return $sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* 替换SQL语句中表达式
|
||||
* @access public
|
||||
* @param array $options 表达式
|
||||
* @return string
|
||||
*/
|
||||
public function parseSql($sql,$options=[]){
|
||||
$sql = str_replace(
|
||||
['%TABLE%','%DISTINCT%','%FIELD%','%JOIN%','%WHERE%','%GROUP%','%HAVING%','%ORDER%','%LIMIT%','%UNION%','%COMMENT%'],
|
||||
[
|
||||
$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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据库调试 记录当前SQL
|
||||
* @access protected
|
||||
* @param boolean $start 调试开始标记 true 开始 false 结束
|
||||
*/
|
||||
protected function debug($start) {
|
||||
if($this->config['debug']) {// 开启数据库调试模式
|
||||
if($start) {
|
||||
Debug::remark('queryStartTime','time');
|
||||
}else{
|
||||
$this->modelSql[$this->model] = $this->queryStr;
|
||||
$this->model = '_think_';
|
||||
// 记录操作结束时间
|
||||
Debug::remark('queryEndTime','time');
|
||||
Log::record($this->queryStr.' [ RunTime:'.Debug::getUseTime('queryStartTime','queryEndTime').'s ]','SQL');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化数据库连接
|
||||
* @access protected
|
||||
* @param boolean $master 主服务器
|
||||
* @return void
|
||||
*/
|
||||
protected function initConnect($master=true) {
|
||||
if(1 == $this->config['deploy'])
|
||||
// 采用分布式数据库
|
||||
$this->_linkID = $this->multiConnect($master);
|
||||
else
|
||||
// 默认单数据库
|
||||
if ( !$this->_linkID ) $this->_linkID = $this->connect();
|
||||
}
|
||||
|
||||
/**
|
||||
* 连接分布式服务器
|
||||
* @access protected
|
||||
* @param boolean $master 主服务器
|
||||
* @return void
|
||||
*/
|
||||
protected function multiConnect($master=false) {
|
||||
static $_config = [];
|
||||
if(empty($_config)) {
|
||||
// 缓存分布式数据库配置解析
|
||||
foreach ($this->config as $key=>$val){
|
||||
$_config[$key] = explode(',',$val);
|
||||
}
|
||||
}
|
||||
// 数据库读写是否分离
|
||||
if(Config::get('db_rw_separate')){
|
||||
// 主从式采用读写分离
|
||||
if($master)
|
||||
// 主服务器写入
|
||||
$r = floor(mt_rand(0,Config::get('db_master_num')-1));
|
||||
else{
|
||||
if(is_numeric(Config::get('db_slave_no'))) {// 指定服务器读
|
||||
$r = Config::get('db_slave_no');
|
||||
}else{
|
||||
// 读操作连接从服务器
|
||||
$r = floor(mt_rand(Config::get('db_master_num'),count($_config['hostname'])-1)); // 每次随机连接的数据库
|
||||
}
|
||||
}
|
||||
}else{
|
||||
// 读写操作不区分服务器
|
||||
$r = floor(mt_rand(0,count($_config['hostname'])-1)); // 每次随机连接的数据库
|
||||
}
|
||||
$db_config = [
|
||||
'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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 析构方法
|
||||
* @access public
|
||||
*/
|
||||
public function __destruct() {
|
||||
// 释放查询
|
||||
if ($this->PDOStatement){
|
||||
$this->free();
|
||||
}
|
||||
// 关闭连接
|
||||
$this->close();
|
||||
}
|
||||
}
|
||||
73
Library/Think/Db/Driver/Mysql.php
Normal file
73
Library/Think/Db/Driver/Mysql.php
Normal file
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace Think\Db\Driver;
|
||||
use Think\Db\Driver;
|
||||
/**
|
||||
* PDO数据库驱动
|
||||
* @category Extend
|
||||
* @package Extend
|
||||
* @subpackage Driver.Db
|
||||
* @author liu21st <liu21st@gmail.com>
|
||||
*/
|
||||
class Mysql extends Driver{
|
||||
/**
|
||||
* 取得数据表的字段信息
|
||||
* @access public
|
||||
*/
|
||||
public function getFields($tableName) {
|
||||
$this->initConnect(true);
|
||||
$sql = 'SHOW COLUMNS FROM `'.$tableName.'`';
|
||||
$result = $this->query($sql);
|
||||
$info = [];
|
||||
if($result) {
|
||||
foreach ($result as $key => $val) {
|
||||
$info[$val['field']] = [
|
||||
'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='') {
|
||||
$sql = !empty($dbName)?'SHOW TABLES FROM '.$dbName:'SHOW TABLES ';
|
||||
$result = $this->query($sql);
|
||||
$info = [];
|
||||
foreach ($result as $key => $val) {
|
||||
$info[$key] = current($val);
|
||||
}
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* 字段和表名处理
|
||||
* @access protected
|
||||
* @param string $key
|
||||
* @return string
|
||||
*/
|
||||
protected function parseKey(&$key) {
|
||||
$key = trim($key);
|
||||
if(!preg_match('/[,\'\"\*\(\)`.\s]/',$key)) {
|
||||
$key = '`'.$key.'`';
|
||||
}
|
||||
return $key;
|
||||
}
|
||||
|
||||
}
|
||||
170
Library/Think/Db/Driver/Oracle.php
Normal file
170
Library/Think/Db/Driver/Oracle.php
Normal file
@@ -0,0 +1,170 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace Think\Db\Driver;
|
||||
use Think\Db\Driver;
|
||||
/**
|
||||
* Oracle数据库驱动
|
||||
* @category Extend
|
||||
* @package Extend
|
||||
* @subpackage Driver.Db
|
||||
* @author ZhangXuehun <zhangxuehun@sohu.com>
|
||||
*/
|
||||
class Oracle extends Driver{
|
||||
|
||||
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 string $str sql指令
|
||||
* @return integer
|
||||
*/
|
||||
public function execute($str,$bind=[]) {
|
||||
$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) . "'");
|
||||
}
|
||||
//释放前次的查询结果
|
||||
if ( !empty($this->PDOStatement) ) $this->free();
|
||||
$this->executeTimes++;
|
||||
// 记录开始执行时间
|
||||
$this->debug(true);
|
||||
$this->PDOStatement = $this->_linkID->prepare($str);
|
||||
if(false === $this->PDOStatement) {
|
||||
E($this->error());
|
||||
}
|
||||
$result = $this->PDOStatement->execute($bind);
|
||||
$this->debug(false);
|
||||
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
|
||||
*/
|
||||
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 = [];
|
||||
if($result) {
|
||||
foreach ($result as $key => $val) {
|
||||
$info[strtolower($val['column_name'])] = [
|
||||
'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 = [];
|
||||
foreach ($result as $key => $val) {
|
||||
$info[$key] = current($val);
|
||||
}
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 getLastInsertId() {
|
||||
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:'';
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置锁机制
|
||||
* @access protected
|
||||
* @return string
|
||||
*/
|
||||
protected function parseLock($lock=false) {
|
||||
if(!$lock) return '';
|
||||
return ' FOR UPDATE NOWAIT ';
|
||||
}
|
||||
}
|
||||
78
Library/Think/Db/Driver/Pgsql.php
Normal file
78
Library/Think/Db/Driver/Pgsql.php
Normal file
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace Think\Db\Driver;
|
||||
use Think\Db\Driver;
|
||||
/**
|
||||
* Pgsql数据库驱动
|
||||
* @category Extend
|
||||
* @package Extend
|
||||
* @subpackage Driver.Db
|
||||
* @author liu21st <liu21st@gmail.com>
|
||||
*/
|
||||
class Pgsql extends Driver{
|
||||
|
||||
/**
|
||||
* 取得数据表的字段信息
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getFields($tableName) {
|
||||
$result = $this->query('select fields_name as "field",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.');');
|
||||
$info = [];
|
||||
if($result){
|
||||
foreach ($result as $key => $val) {
|
||||
$info[$val['field']] = [
|
||||
'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 tablename as Tables_in_test from pg_tables where schemaname ='public'");
|
||||
$info = [];
|
||||
foreach ($result as $key => $val) {
|
||||
$info[$key] = current($val);
|
||||
}
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* limit分析
|
||||
* @access protected
|
||||
* @param mixed $lmit
|
||||
* @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;
|
||||
}
|
||||
|
||||
}
|
||||
88
Library/Think/Db/Driver/Sqlite.php
Normal file
88
Library/Think/Db/Driver/Sqlite.php
Normal file
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace Think\Db\Driver;
|
||||
use Think\Db\Driver;
|
||||
/**
|
||||
* Sqlite数据库驱动
|
||||
* @category Extend
|
||||
* @package Extend
|
||||
* @subpackage Driver.Db
|
||||
* @author liu21st <liu21st@gmail.com>
|
||||
*/
|
||||
class Sqlite extends Driver {
|
||||
|
||||
/**
|
||||
* 取得数据表的字段信息
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public function getFields($tableName) {
|
||||
$result = $this->query('PRAGMA table_info( '.$tableName.' )');
|
||||
$info = [];
|
||||
if($result){
|
||||
foreach ($result as $key => $val) {
|
||||
$info[$val['field']] = [
|
||||
'name' => $val['field'],
|
||||
'type' => $val['type'],
|
||||
'notnull' => (bool) ($val['null'] === ''), // not null is empty, null is yes
|
||||
'default' => $val['default'],
|
||||
'primary' => (strtolower($val['dey']) == '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 = [];
|
||||
foreach ($result as $key => $val) {
|
||||
$info[$key] = current($val);
|
||||
}
|
||||
return $info;
|
||||
}
|
||||
|
||||
/**
|
||||
* SQL指令安全过滤
|
||||
* @access public
|
||||
* @param string $str SQL指令
|
||||
* @return string
|
||||
*/
|
||||
public function escapeString($str) {
|
||||
return str_ireplace("'", "''", $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;
|
||||
}
|
||||
}
|
||||
130
Library/Think/Db/Driver/Sqlsrv.php
Normal file
130
Library/Think/Db/Driver/Sqlsrv.php
Normal file
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace Think\Db\Driver;
|
||||
use Think\Db\Driver;
|
||||
/**
|
||||
* Sqlsrv数据库驱动
|
||||
* @category Extend
|
||||
* @package Extend
|
||||
* @subpackage Driver.Db
|
||||
* @author liu21st <liu21st@gmail.com>
|
||||
*/
|
||||
class Sqlsrv extends Driver{
|
||||
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
|
||||
* @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 = [];
|
||||
if($result) {
|
||||
foreach ($result as $key => $val) {
|
||||
$info[$val['column_name']] = [
|
||||
'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 = [];
|
||||
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
|
||||
* @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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除记录
|
||||
* @access public
|
||||
* @param array $options 表达式
|
||||
* @return false | integer
|
||||
*/
|
||||
public function delete($options=[]) {
|
||||
$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);
|
||||
}
|
||||
|
||||
}
|
||||
410
Library/Think/Db/Lite.php
Normal file
410
Library/Think/Db/Lite.php
Normal file
@@ -0,0 +1,410 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | TOPThink [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2011 http://topthink.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
// $Id$
|
||||
namespace Think\Db;
|
||||
use Think\Config;
|
||||
use Think\Debug;
|
||||
use Think\Log;
|
||||
use PDO;
|
||||
class Lite {
|
||||
// PDO操作实例
|
||||
protected $PDOStatement = null;
|
||||
// 当前操作所属的模型名
|
||||
protected $model = '_think_';
|
||||
// 当前SQL指令
|
||||
protected $queryStr = '';
|
||||
protected $modelSql = [];
|
||||
// 最后插入ID
|
||||
protected $lastInsID = null;
|
||||
// 返回或者影响记录数
|
||||
protected $numRows = 0;
|
||||
// 事务指令数
|
||||
protected $transTimes = 0;
|
||||
// 错误信息
|
||||
protected $error = '';
|
||||
// 数据库连接ID 支持多个连接
|
||||
protected $linkID = [];
|
||||
// 当前连接ID
|
||||
protected $_linkID = null;
|
||||
// 当前查询ID
|
||||
protected $queryID = null;
|
||||
// 数据库连接参数配置
|
||||
protected $config = [];
|
||||
|
||||
protected $queryTimes = 0;
|
||||
protected $executeTimes = 0;
|
||||
// PDO连接参数
|
||||
protected $options = [
|
||||
PDO::ATTR_CASE => PDO::CASE_LOWER,
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
||||
PDO::ATTR_ORACLE_NULLS => PDO::NULL_NATURAL,
|
||||
PDO::ATTR_STRINGIFY_FETCHES => false,
|
||||
];
|
||||
|
||||
/**
|
||||
* 架构函数 读取数据库配置信息
|
||||
* @access public
|
||||
* @param array $config 数据库配置数组
|
||||
*/
|
||||
public function __construct($config=''){
|
||||
if(!empty($config)) {
|
||||
$this->config = $config;
|
||||
if(empty($this->config['params'])) {
|
||||
$this->config['params'] = [];
|
||||
}
|
||||
$this->config['params'] = $this->options+$this->config['params'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 连接数据库方法
|
||||
* @access public
|
||||
*/
|
||||
public function connect($config='',$linkNum=0) {
|
||||
if ( !isset($this->linkID[$linkNum]) ) {
|
||||
if(empty($config)) $config = $this->config;
|
||||
try{
|
||||
if(empty($config['dsn'])) {
|
||||
$config['dsn'] = $config['dbms'].':dbname='.$config['database'].';host='.$config['hostname'];
|
||||
if(!empty($config['hostport'])) {
|
||||
$config['dsn'] .= ';port='.$config['hostport'];
|
||||
}elseif(!empty($config['unix_socket'])){
|
||||
$config['dsn'] .= ';unix_socket='.$config['unix_socket'];
|
||||
}
|
||||
}
|
||||
$this->linkID[$linkNum] = new PDO( $config['dsn'], $config['username'], $config['password'],$config['params']);
|
||||
}catch (\PDOException $e) {
|
||||
E($e->getMessage());
|
||||
}
|
||||
if(!empty($config['charset'])) {
|
||||
$this->linkID[$linkNum]->exec('SET NAMES '.$config['charset']);
|
||||
}
|
||||
// 注销数据库连接配置信息
|
||||
if(1 != $config['deploy']) $this->config = [];
|
||||
}
|
||||
return $this->linkID[$linkNum];
|
||||
}
|
||||
|
||||
/**
|
||||
* 释放查询结果
|
||||
* @access public
|
||||
*/
|
||||
public function free() {
|
||||
$this->PDOStatement = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行查询 返回数据集
|
||||
* @access public
|
||||
* @param string $str sql指令
|
||||
* @return mixed
|
||||
*/
|
||||
public function query($str,$bind=[]) {
|
||||
$this->initConnect(false);
|
||||
if ( !$this->_linkID ) return false;
|
||||
$this->queryStr = $str;
|
||||
//释放前次的查询结果
|
||||
if ( !empty($this->PDOStatement) ) $this->free();
|
||||
$this->queryTimes++;
|
||||
$this->debug(true);
|
||||
$this->PDOStatement = $this->_linkID->prepare($str);
|
||||
if(false === $this->PDOStatement)
|
||||
E($this->error());
|
||||
$result = $this->PDOStatement->execute($bind);
|
||||
$this->debug(false);
|
||||
if ( false === $result ) {
|
||||
$this->error();
|
||||
return false;
|
||||
} else {
|
||||
return $this->getResult();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行语句
|
||||
* @access public
|
||||
* @param string $str sql指令
|
||||
* @return integer
|
||||
*/
|
||||
public function execute($str,$bind=[]) {
|
||||
$this->initConnect(true);
|
||||
if ( !$this->_linkID ) return false;
|
||||
$this->queryStr = $str;
|
||||
//释放前次的查询结果
|
||||
if ( !empty($this->PDOStatement) ) $this->free();
|
||||
$this->executeTimes++;
|
||||
// 记录开始执行时间
|
||||
$this->debug(true);
|
||||
$this->PDOStatement = $this->_linkID->prepare($str);
|
||||
if(false === $this->PDOStatement) {
|
||||
E($this->error());
|
||||
}
|
||||
$result = $this->PDOStatement->execute($bind);
|
||||
$this->debug(false);
|
||||
if ( false === $result) {
|
||||
$this->error();
|
||||
return false;
|
||||
} else {
|
||||
$this->numRows = $this->PDOStatement->rowCount();
|
||||
if(preg_match("/^\s*(INSERT\s+INTO|REPLACE\s+INTO)\s+/i", $str)) {
|
||||
$this->lastInsID = $this->getLastInsertId();
|
||||
}
|
||||
return $this->numRows;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取最后插入id
|
||||
* @access public
|
||||
* @return integer
|
||||
*/
|
||||
public function getLastInsertId() {
|
||||
return $this->_linkID->lastInsertId();
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动事务
|
||||
* @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 getResult() {
|
||||
//返回数据集
|
||||
$result = $this->PDOStatement->fetchAll(PDO::FETCH_ASSOC);
|
||||
$this->numRows = count( $result );
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得查询次数
|
||||
* @access public
|
||||
* @param boolean $execute 是否包含所有查询
|
||||
* @return integer
|
||||
*/
|
||||
public function getQueryTimes($execute=false){
|
||||
return $execute?$this->queryTimes+$this->executeTimes:$this->queryTimes;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得执行次数
|
||||
* @access public
|
||||
* @return integer
|
||||
*/
|
||||
public function getExecuteTimes(){
|
||||
return $this->executeTimes;
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭数据库
|
||||
* @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;
|
||||
}
|
||||
Log::record($this->error,'ERR');
|
||||
return $this->error;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取最近一次查询的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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置当前操作模型
|
||||
* @access public
|
||||
* @param string $model 模型名
|
||||
* @return void
|
||||
*/
|
||||
public function setModel($model){
|
||||
$this->model = $model;
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据库调试 记录当前SQL
|
||||
* @access protected
|
||||
* @param boolean $start 调试开始标记 true 开始 false 结束
|
||||
*/
|
||||
protected function debug($start) {
|
||||
if($this->config['debug']) {// 开启数据库调试模式
|
||||
if($start) {
|
||||
Debug::remark('queryStartTime','time');
|
||||
}else{
|
||||
$this->modelSql[$this->model] = $this->queryStr;
|
||||
$this->model = '_think_';
|
||||
// 记录操作结束时间
|
||||
Debug::remark('queryEndTime','time');
|
||||
Log::record($this->queryStr.' [ RunTime:'.Debug::getUseTime('queryStartTime','queryEndTime').'s ]','SQL');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化数据库连接
|
||||
* @access protected
|
||||
* @param boolean $master 主服务器
|
||||
* @return void
|
||||
*/
|
||||
protected function initConnect($master=true) {
|
||||
if(1 == $this->config['deploy'])
|
||||
// 采用分布式数据库
|
||||
$this->_linkID = $this->multiConnect($master);
|
||||
else
|
||||
// 默认单数据库
|
||||
if ( !$this->_linkID ) $this->_linkID = $this->connect();
|
||||
}
|
||||
|
||||
/**
|
||||
* 连接分布式服务器
|
||||
* @access protected
|
||||
* @param boolean $master 主服务器
|
||||
* @return void
|
||||
*/
|
||||
protected function multiConnect($master=false) {
|
||||
static $_config = [];
|
||||
if(empty($_config)) {
|
||||
// 缓存分布式数据库配置解析
|
||||
foreach ($this->config as $key=>$val){
|
||||
$_config[$key] = explode(',',$val);
|
||||
}
|
||||
}
|
||||
// 数据库读写是否分离
|
||||
if(Config::get('db_rw_separate')){
|
||||
// 主从式采用读写分离
|
||||
if($master)
|
||||
// 主服务器写入
|
||||
$r = floor(mt_rand(0,Config::get('db_master_num')-1));
|
||||
else{
|
||||
if(is_numeric(Config::get('db_slave_no'))) {// 指定服务器读
|
||||
$r = Config::get('db_slave_no');
|
||||
}else{
|
||||
// 读操作连接从服务器
|
||||
$r = floor(mt_rand(Config::get('db_master_num'),count($_config['hostname'])-1)); // 每次随机连接的数据库
|
||||
}
|
||||
}
|
||||
}else{
|
||||
// 读写操作不区分服务器
|
||||
$r = floor(mt_rand(0,count($_config['hostname'])-1)); // 每次随机连接的数据库
|
||||
}
|
||||
$db_config = [
|
||||
'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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 析构方法
|
||||
* @access public
|
||||
*/
|
||||
public function __destruct() {
|
||||
// 释放查询
|
||||
if ($this->queryID){
|
||||
$this->free();
|
||||
}
|
||||
// 关闭连接
|
||||
$this->close();
|
||||
}
|
||||
}
|
||||
111
Library/Think/Debug.php
Normal file
111
Library/Think/Debug.php
Normal file
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | TOPThink [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2011 http://topthink.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
// $Id$
|
||||
namespace Think;
|
||||
class Debug {
|
||||
|
||||
static protected $_info = [];
|
||||
static protected $_mem = [];
|
||||
|
||||
/**
|
||||
* 记录时间(微秒)和内存使用情况
|
||||
* @param string $name 标记位置
|
||||
* @param mixed $value 标记值 留空则取当前 time 表示仅记录时间 否则同时记录时间和内存
|
||||
* @return mixed
|
||||
*/
|
||||
static public function remark($name,$value='') {
|
||||
// 记录时间和内存使用
|
||||
self::$_info[$name] = is_float($value)?$value:microtime(TRUE);
|
||||
if('time' != $value && function_exists('memory_get_usage')) {
|
||||
self::$_mem['mem'][$name] = is_float($value)?$value:memory_get_usage();
|
||||
self::$_mem['peak'][$name] = function_exists('memory_get_peak_usage')?memory_get_peak_usage(): self::$_mem['mem'][$name];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计某个区间的时间(微秒)使用情况
|
||||
* @param string $start 开始标签
|
||||
* @param string $end 结束标签
|
||||
* @param integer|string $dec 小数位或者m
|
||||
* @return mixed
|
||||
*/
|
||||
static public function getUseTime($start,$end,$dec=6) {
|
||||
if(!isset(self::$_info[$end])) self::$_info[$end] = microtime(TRUE);
|
||||
return number_format((self::$_info[$end]-self::$_info[$start]),$dec);
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录内存使用情况
|
||||
* @param string $start 开始标签
|
||||
* @param string $end 结束标签
|
||||
* @param integer|string $dec 小数位或者m
|
||||
* @return mixed
|
||||
*/
|
||||
static public function getUseMem($start,$end,$dec=2) {
|
||||
if(!isset(self::$_mem['mem'][$end]))
|
||||
self::$_mem['mem'][$end] = memory_get_usage();
|
||||
$size = self::$_mem['mem'][$end]-self::$_mem['mem'][$start];
|
||||
$a = ['B', 'KB', 'MB', 'GB', 'TB'];
|
||||
$pos = 0;
|
||||
while ($size >= 1024) {
|
||||
$size /= 1024;
|
||||
$pos++;
|
||||
}
|
||||
return round($size,$dec)." ".$a[$pos];
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计内存峰值情况
|
||||
* @param string $start 开始标签
|
||||
* @param string $end 结束标签
|
||||
* @param integer|string $dec 小数位或者m
|
||||
* @return mixed
|
||||
*/
|
||||
static public function getMemPeak($start,$end,$dec=2) {
|
||||
if(!isset(self::$_mem['peak'][$end])) self::$_mem['peak'][$end] = function_exists('memory_get_peak_usage')?memory_get_peak_usage():memory_get_usage();
|
||||
$size = self::$_mem['peak'][$end]-self::$_mem['peak'][$start];
|
||||
$a = ['B', 'KB', 'MB', 'GB', 'TB'];
|
||||
$pos = 0;
|
||||
while ($size >= 1024) {
|
||||
$size /= 1024;
|
||||
$pos++;
|
||||
}
|
||||
return round($size,$dec)." ".$a[$pos];
|
||||
}
|
||||
|
||||
/**
|
||||
* 浏览器友好的变量输出
|
||||
* @param mixed $var 变量
|
||||
* @param boolean $echo 是否输出 默认为True 如果为false 则返回输出字符串
|
||||
* @param string $label 标签 默认为空
|
||||
* @return void|string
|
||||
*/
|
||||
static public function dump($var, $echo=true, $label=null) {
|
||||
$label = ($label === null) ? '' : rtrim($label) . ':';
|
||||
ob_start();
|
||||
var_dump($var);
|
||||
$output = ob_get_clean();
|
||||
$output = preg_replace('/\]\=\>\n(\s+)/m', '] => ', $output);
|
||||
if(IS_CLI) {
|
||||
$output = PHP_EOL . $label. $output . PHP_EOL;
|
||||
}else{
|
||||
if (!extension_loaded('xdebug')) {
|
||||
$output = htmlspecialchars($output, ENT_QUOTES);
|
||||
}
|
||||
$output = '<pre>' . $label . $output . '</pre>';
|
||||
}
|
||||
if ($echo) {
|
||||
echo($output);
|
||||
return null;
|
||||
}else
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
117
Library/Think/Error.php
Normal file
117
Library/Think/Error.php
Normal file
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | TOPThink [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2011 http://topthink.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
// $Id$
|
||||
namespace Think;
|
||||
class Error {
|
||||
|
||||
/**
|
||||
* 自定义异常处理
|
||||
* @access public
|
||||
* @param mixed $e 异常对象
|
||||
*/
|
||||
static public function appException($e) {
|
||||
$error = [];
|
||||
$error['message'] = $e->getMessage();
|
||||
$trace = $e->getTrace();
|
||||
if('E'==$trace[0]['function']) {
|
||||
$error['file'] = $trace[0]['file'];
|
||||
$error['line'] = $trace[0]['line'];
|
||||
}else{
|
||||
$error['file'] = $e->getFile();
|
||||
$error['line'] = $e->getLine();
|
||||
}
|
||||
$error['trace'] = $e->getTraceAsString();
|
||||
self::halt($error);
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义错误处理
|
||||
* @access public
|
||||
* @param int $errno 错误类型
|
||||
* @param string $errstr 错误信息
|
||||
* @param string $errfile 错误文件
|
||||
* @param int $errline 错误行数
|
||||
* @return void
|
||||
*/
|
||||
static public function appError($errno, $errstr, $errfile, $errline) {
|
||||
switch ($errno) {
|
||||
case E_ERROR:
|
||||
case E_PARSE:
|
||||
case E_CORE_ERROR:
|
||||
case E_COMPILE_ERROR:
|
||||
case E_USER_ERROR:
|
||||
$errorStr = "[$errno] $errstr ".$errfile." 第 $errline 行.";
|
||||
Log::record($errorStr,'ERROR');
|
||||
self::halt($errorStr);
|
||||
break;
|
||||
case E_STRICT:
|
||||
case E_USER_WARNING:
|
||||
case E_USER_NOTICE:
|
||||
default:
|
||||
$errorStr = "[$errno] $errstr ".$errfile." 第 $errline 行.";
|
||||
Log::record($errorStr,'NOTIC');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 应用关闭处理
|
||||
* @return void
|
||||
*/
|
||||
static public function appShutdown(){
|
||||
// 记录日志
|
||||
Log::save();
|
||||
if ($e = error_get_last()) {
|
||||
ob_end_clean();
|
||||
self::halt($e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 错误输出
|
||||
* @param mixed $error 错误
|
||||
* @return void
|
||||
*/
|
||||
static public function halt($error) {
|
||||
if(IS_CLI) {
|
||||
exit(is_array($error)?$error['message']:$error);
|
||||
}
|
||||
$e = [];
|
||||
if (Config::get('app_debug')) {
|
||||
//调试模式下输出错误信息
|
||||
if (!is_array($error)) {
|
||||
$trace = debug_backtrace();
|
||||
$e['message'] = $error;
|
||||
$e['file'] = $trace[0]['file'];
|
||||
$e['line'] = $trace[0]['line'];
|
||||
ob_start();
|
||||
debug_print_backtrace();
|
||||
$e['trace'] = ob_get_clean();
|
||||
} else {
|
||||
$e = $error;
|
||||
}
|
||||
} else {
|
||||
//否则定向到错误页面
|
||||
$error_page = Config::get('error_page');
|
||||
if (!empty($error_page)) {
|
||||
header('Location: ' . $error_page);
|
||||
} else {
|
||||
if (Config::get('show_error_msg'))
|
||||
$e['message'] = is_array($error) ? $error['message'] : $error;
|
||||
else
|
||||
$e['message'] = C('error_message');
|
||||
}
|
||||
}
|
||||
// 包含异常页面模板
|
||||
include Config::get('exception_tmpl');
|
||||
exit;
|
||||
}
|
||||
}
|
||||
14
Library/Think/Exception.php
Normal file
14
Library/Think/Exception.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | TOPThink [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2011 http://topthink.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
// $Id$
|
||||
namespace Think;
|
||||
class Exception extends \Exception {
|
||||
}
|
||||
221
Library/Think/Filter.php
Normal file
221
Library/Think/Filter.php
Normal file
@@ -0,0 +1,221 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | TOPThink [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2011 http://topthink.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
// $Id$
|
||||
namespace Think;
|
||||
class Filter {
|
||||
//html标签设置
|
||||
static public $htmlTags = [
|
||||
'allow' => 'table|td|th|tr|i|b|u|strong|img|p|br|div|strong|em|ul|ol|li|dl|dd|dt|a',
|
||||
'ban' => 'html|head|meta|link|base|basefont|body|bgsound|title|style|script|form|iframe|frame|frameset|applet|id|ilayer|layer|name|script|style|xml',
|
||||
];
|
||||
|
||||
static public function filter($data,$filter,$option=''){
|
||||
return filter_var($data,is_int($filter)?$filter:filter_id($filter),$option);
|
||||
}
|
||||
|
||||
static private function filter_input($type,$name,$filter,$options=''){
|
||||
return filter_input($type,$name,is_int($filter)?$filter:filter_id($filter),$option);
|
||||
}
|
||||
|
||||
static public function get($name,$filter,$option=''){
|
||||
return self::filter_input(INPUT_GET,$name,$filter,$option);
|
||||
}
|
||||
|
||||
static public function post($name,$filter,$option=''){
|
||||
return self::filter_input(INPUT_POST,$name,$filter,$option);
|
||||
}
|
||||
|
||||
static public function cookie($name,$filter,$option=''){
|
||||
return self::filter_input(INPUT_COOKIE,$name,$filter,$option);
|
||||
}
|
||||
|
||||
static public function server($name,$filter,$option=''){
|
||||
return self::filter_input(INPUT_SERVER,$name,$filter,$option);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理字符串,以便可以正常进行搜索
|
||||
* @access public
|
||||
* @param string $string 要处理的字符串
|
||||
* @return string
|
||||
*/
|
||||
static public function forSearch($string) {
|
||||
return str_replace( ['%','_'], ['\%','\_'], $string );
|
||||
}
|
||||
|
||||
/**
|
||||
* @access public
|
||||
* @param string $string 要处理的字符串
|
||||
* @return string
|
||||
*/
|
||||
static public function forShow($string) {
|
||||
return self::nl2Br( self::hsc($string) );
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理纯文本数据,以便在textarea标签中显示
|
||||
* @access public
|
||||
* @param string $string 要处理的字符串
|
||||
* @return string
|
||||
*/
|
||||
static public function forTarea($string) {
|
||||
return str_ireplace(['<textarea>','</textarea>'], ['<textarea>','</textarea>'], $string);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将数据中的单引号和双引号进行转义
|
||||
* @access public
|
||||
* @param string $text 要处理的字符串
|
||||
* @return string
|
||||
*/
|
||||
static public function forTag($string) {
|
||||
return str_replace(['"',"'"], ['"','''], $string);
|
||||
}
|
||||
|
||||
/**
|
||||
* 把换行转换为<br />标签
|
||||
* @access public
|
||||
* @param string $string 要处理的字符串
|
||||
* @return string
|
||||
*/
|
||||
static public function nl2Br($string) {
|
||||
return nl2Br($string);
|
||||
}
|
||||
|
||||
/**
|
||||
* 如果 magic_quotes_gpc 为关闭状态,这个函数可以转义字符串
|
||||
* @access public
|
||||
* @param string $string 要处理的字符串
|
||||
* @return string
|
||||
*/
|
||||
static public function addSlashes($string) {
|
||||
return addslashes($string);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于在textbox表单中显示html代码
|
||||
* @access public
|
||||
* @param string $string 要处理的字符串
|
||||
* @return string
|
||||
*/
|
||||
static function hsc($string) {
|
||||
return preg_replace(["/&/i", "/ /i"], ['&', '&nbsp;'], htmlspecialchars($string, ENT_QUOTES));
|
||||
}
|
||||
|
||||
/**
|
||||
* 是hsc()方法的逆操作
|
||||
* @access public
|
||||
* @param string $text 要处理的字符串
|
||||
* @return string
|
||||
*/
|
||||
static function undoHsc($text) {
|
||||
return preg_replace(["/>/i", "/</i", "/"/i", "/'/i", '/&nbsp;/i'], [">", "<", "\"", "'", " "], $text);
|
||||
}
|
||||
|
||||
/**
|
||||
* 输出安全的html,用于过滤危险代码
|
||||
* @access public
|
||||
* @param string $text 要处理的字符串
|
||||
* @param mixed $allowTags 允许的标签列表,如 table|td|th|td
|
||||
* @return string
|
||||
*/
|
||||
static public function safeHtml($text, $allowTags = null) {
|
||||
$text = trim($text);
|
||||
//完全过滤注释
|
||||
$text = preg_replace('/<!--?.*-->/','',$text);
|
||||
//完全过滤动态代码
|
||||
$text = preg_replace('/<\?|\?'.'>/','',$text);
|
||||
//完全过滤js
|
||||
$text = preg_replace('/<script?.*\/script>/','',$text);
|
||||
|
||||
$text = str_replace('[','[',$text);
|
||||
$text = str_replace(']',']',$text);
|
||||
$text = str_replace('|','|',$text);
|
||||
//过滤换行符
|
||||
$text = preg_replace('/\r?\n/','',$text);
|
||||
//br
|
||||
$text = preg_replace('/<br(\s\/)?'.'>/i','[br]',$text);
|
||||
$text = preg_replace('/(\[br\]\s*){10,}/i','[br]',$text);
|
||||
//过滤危险的属性,如:过滤on事件lang js
|
||||
while(preg_match('/(<[^><]+)(lang|on|action|background|codebase|dynsrc|lowsrc)[^><]+/i',$text,$mat)){
|
||||
$text=str_replace($mat[0],$mat[1],$text);
|
||||
}
|
||||
while(preg_match('/(<[^><]+)(window\.|javascript:|js:|about:|file:|document\.|vbs:|cookie)([^><]*)/i',$text,$mat)){
|
||||
$text=str_replace($mat[0],$mat[1].$mat[3],$text);
|
||||
}
|
||||
if( empty($allowTags) ) { $allowTags = self::$htmlTags['allow']; }
|
||||
//允许的HTML标签
|
||||
$text = preg_replace('/<('.$allowTags.')( [^><\[\]]*)>/i','[\1\2]',$text);
|
||||
//过滤多余html
|
||||
if ( empty($banTag) ) { $banTag = self::$htmlTags['ban']; }
|
||||
$text = preg_replace('/<\/?('.$banTag.')[^><]*>/i','',$text);
|
||||
//过滤合法的html标签
|
||||
while(preg_match('/<([a-z]+)[^><\[\]]*>[^><]*<\/\1>/i',$text,$mat)){
|
||||
$text=str_replace($mat[0],str_replace('>',']',str_replace('<','[',$mat[0])),$text);
|
||||
}
|
||||
//转换引号
|
||||
while(preg_match('/(\[[^\[\]]*=\s*)(\"|\')([^\2=\[\]]+)\2([^\[\]]*\])/i',$text,$mat)){
|
||||
$text=str_replace($mat[0],$mat[1].'|'.$mat[3].'|'.$mat[4],$text);
|
||||
}
|
||||
//空属性转换
|
||||
$text = str_replace('\'\'','||',$text);
|
||||
$text = str_replace('""','||',$text);
|
||||
//过滤错误的单个引号
|
||||
while(preg_match('/\[[^\[\]]*(\"|\')[^\[\]]*\]/i',$text,$mat)){
|
||||
$text=str_replace($mat[0],str_replace($mat[1],'',$mat[0]),$text);
|
||||
}
|
||||
//转换其它所有不合法的 < >
|
||||
$text = str_replace('<','<',$text);
|
||||
$text = str_replace('>','>',$text);
|
||||
$text = str_replace('"','"',$text);
|
||||
//反转换
|
||||
$text = str_replace('[','<',$text);
|
||||
$text = str_replace(']','>',$text);
|
||||
$text = str_replace('|','"',$text);
|
||||
//过滤多余空格
|
||||
$text = str_replace(' ',' ',$text);
|
||||
return $text;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除html标签,得到纯文本。可以处理嵌套的标签
|
||||
* @access public
|
||||
* @param string $string 要处理的html
|
||||
* @return string
|
||||
*/
|
||||
static public function deleteHtmlTags($string) {
|
||||
while(strstr($string, '>')) {
|
||||
$currentBeg = strpos($string, '<');
|
||||
$currentEnd = strpos($string, '>');
|
||||
$tmpStringBeg = @substr($string, 0, $currentBeg);
|
||||
$tmpStringEnd = @substr($string, $currentEnd + 1, strlen($string));
|
||||
$string = $tmpStringBeg.$tmpStringEnd;
|
||||
}
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理文本中的换行
|
||||
* @access public
|
||||
* @param string $string 要处理的字符串
|
||||
* @param mixed $br 对换行的处理,
|
||||
* false:去除换行;true:保留原样;string:替换成string
|
||||
* @return string
|
||||
*/
|
||||
static public function nl2($string, $br = '<br />') {
|
||||
if ($br == false) {
|
||||
$string = preg_replace("/(\015\012)|(\015)|(\012)/", '', $string);
|
||||
} elseif ($br != true){
|
||||
$string = preg_replace("/(\015\012)|(\015)|(\012)/", $br, $string);
|
||||
}
|
||||
return $string;
|
||||
}
|
||||
}
|
||||
89
Library/Think/Input.php
Normal file
89
Library/Think/Input.php
Normal file
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | TOPThink [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2011 http://topthink.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
// $Id$
|
||||
namespace Think;
|
||||
class Input {
|
||||
// 全局过滤规则
|
||||
static $filter = NULL;
|
||||
|
||||
/**
|
||||
* 获取系统变量 支持过滤和默认值
|
||||
* @access public
|
||||
* @param string $type 输入数据类型
|
||||
* @param array $args 参数 array(key,filter,default)
|
||||
* @return mixed
|
||||
*/
|
||||
static public function __callStatic($type,$args=[]) {
|
||||
switch(strtolower($type)) {
|
||||
case 'get': $input =& $_GET;break;
|
||||
case 'post': $input =& $_POST;break;
|
||||
case 'put' : parse_str(file_get_contents('php://input'), $input);break;
|
||||
case 'param' :
|
||||
switch($_SERVER['REQUEST_METHOD']) {
|
||||
case 'POST':
|
||||
$input = $_POST;
|
||||
break;
|
||||
case 'PUT':
|
||||
parse_str(file_get_contents('php://input'), $input);
|
||||
break;
|
||||
default:
|
||||
$input = $_GET;
|
||||
}
|
||||
break;
|
||||
case 'request': $input =& $_REQUEST;break;
|
||||
case 'server': $input =& $_SERVER;break;
|
||||
case 'cookie': $input =& $_COOKIE;break;
|
||||
case 'session': $input =& $_SESSION;break;
|
||||
case 'globals': $input =& $GLOBALS;break;
|
||||
default:return NULL;
|
||||
}
|
||||
// 变量全局过滤
|
||||
array_walk_recursive($input,'self::filter_exp');
|
||||
if(self::$filter) {
|
||||
$_filters = explode(',',self::$filter);
|
||||
foreach($_filters as $_filter){
|
||||
// 全局参数过滤
|
||||
array_walk_recursive($input,$_filter);
|
||||
}
|
||||
}
|
||||
if(''== $args[0]) {
|
||||
// 返回全部数据
|
||||
return $input;
|
||||
}elseif(isset($input[$args[0]])) {
|
||||
$data = $input[$args[0]];
|
||||
if(!empty($args[1])) {
|
||||
$filters = explode(',',$args[1]);
|
||||
foreach($filters as $filter){
|
||||
if(is_callable($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($args[2])?$args[2]:NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}else{
|
||||
// 不存在指定输入
|
||||
$data = isset($args[2])?$args[2]:NULL;
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
// 过滤表单中的表达式
|
||||
static private function filter_exp(&$value){
|
||||
if (in_array(strtolower($value),['exp','or'])){
|
||||
$value .= ' ';
|
||||
}
|
||||
}
|
||||
}
|
||||
53
Library/Think/Lang.php
Normal file
53
Library/Think/Lang.php
Normal file
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | TOPThink [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2011 http://topthink.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
// $Id$
|
||||
namespace Think;
|
||||
class Lang {
|
||||
static private $_lang = []; // 语言参数
|
||||
static private $_range = '_sys_'; // 作用域
|
||||
|
||||
// 设定语言参数的作用域
|
||||
static public function range($range){
|
||||
self::$_range = $range;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置语言定义(不区分大小写)
|
||||
* @param string|array $name 语言变量
|
||||
* @param string $value 语言值
|
||||
* @param string $range 作用域
|
||||
* @return mixed
|
||||
*/
|
||||
static public function set($name, $value=null,$range='') {
|
||||
$range = $range?$range:self::$_range;
|
||||
// 批量定义
|
||||
if (is_array($name)){
|
||||
return self::$_lang[$range] = array_merge(self::$_lang[$range], array_change_key_case($name));
|
||||
}else{
|
||||
return self::$_lang[$range][strtolower($name)] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取语言定义(不区分大小写)
|
||||
* @param string|null $name 语言变量
|
||||
* @param string $range 作用域
|
||||
* @return mixed
|
||||
*/
|
||||
static public function get($name=null, $range='') {
|
||||
$range = $range?$range:self::$_range;
|
||||
// 空参数返回所有定义
|
||||
if (empty($name))
|
||||
return self::$_lang[$range];
|
||||
$name = strtolower($name);
|
||||
return isset(self::$_lang[$range][$name]) ? self::$_lang[$range][$name] : $name;
|
||||
}
|
||||
}
|
||||
231
Library/Think/Loader.php
Normal file
231
Library/Think/Loader.php
Normal file
@@ -0,0 +1,231 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | TOPThink [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2011 http://topthink.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
namespace Think;
|
||||
use Think\Config;
|
||||
|
||||
class Loader {
|
||||
// 类名映射
|
||||
static protected $map = [];
|
||||
// 命名空间
|
||||
static protected $namespace = [
|
||||
'Think' => CORE_PATH,
|
||||
'Vendor' => VENDOR_PATH,
|
||||
'Library' => LIB_PATH,
|
||||
];
|
||||
|
||||
// 自动加载
|
||||
static public function autoload($class){
|
||||
// 检查是否定义classmap
|
||||
if(isset(self::$map[$class])) {
|
||||
include self::$map[$class];
|
||||
}else{ // 命名空间自动加载
|
||||
$name = strstr($class,'\\',true);
|
||||
$path = isset(self::$namespace[$name])?dirname(self::$namespace[$name]).'/':APP_PATH;
|
||||
$filename = $path.str_replace('\\','/',$class).EXT;
|
||||
if(is_file($filename)) {
|
||||
// Win环境下面严格区分大小写
|
||||
if (IS_WIN && !strstr(str_replace('/','\\',realpath($filename)),$class.EXT,true)){
|
||||
return ;
|
||||
}
|
||||
include $filename;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 注册classmap
|
||||
static public function addMap($class,$map=''){
|
||||
if(is_array($class)){
|
||||
self::$map = array_merge(self::$map,$class);
|
||||
}else{
|
||||
self::$map[$class] = $map;
|
||||
}
|
||||
}
|
||||
|
||||
// 注册命名空间
|
||||
static public function addNamespace($namespace,$path){
|
||||
self::$namespace[$namespace] = $path;
|
||||
}
|
||||
|
||||
// 注册自动加载机制
|
||||
static public function register($autoload=''){
|
||||
spl_autoload_register($autoload?$autoload:['Think\Loader','autoload']);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入所需的类库 同java的Import 本函数有缓存功能
|
||||
* @param string $class 类库命名空间字符串
|
||||
* @param string $baseUrl 起始路径
|
||||
* @param string $ext 导入的文件扩展名
|
||||
* @return boolean
|
||||
*/
|
||||
static public function import($class, $baseUrl = '', $ext= EXT ) {
|
||||
static $_file = [];
|
||||
$class = str_replace(['.', '#'], ['/', '.'], $class);
|
||||
if (isset($_file[$class . $baseUrl]))
|
||||
return true;
|
||||
else
|
||||
$_file[$class . $baseUrl] = true;
|
||||
$class_strut = explode('/', $class);
|
||||
if (empty($baseUrl)) {
|
||||
if ('@' == $class_strut[0] || MODULE_NAME == $class_strut[0]) {
|
||||
//加载当前项目应用类库
|
||||
$class = substr_replace($class, '', 0, strlen($class_strut[0]) + 1);
|
||||
$baseUrl = MODULE_PATH;
|
||||
}elseif (in_array($class_strut[0], ['Org','Com'])) {
|
||||
// org 第三方公共类库 com 企业公共类库
|
||||
$baseUrl = LIB_PATH;
|
||||
}elseif(in_array($class_strut[0], ['Think','Vendor','Library','Traits'])){
|
||||
$baseUrl = THINK_PATH;
|
||||
}else { // 加载其他项目应用类库
|
||||
$class = substr_replace($class, '', 0, strlen($class_strut[0]) + 1);
|
||||
$baseUrl = APP_PATH . $class_strut[0] .'/';
|
||||
}
|
||||
}
|
||||
if (substr($baseUrl, -1) != '/')
|
||||
$baseUrl .= '/';
|
||||
// 如果类不存在 则导入类库文件
|
||||
$filename = $baseUrl . $class . $ext;
|
||||
if(is_file($filename)) {
|
||||
include $filename;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 实例化一个没有模型文件的Model
|
||||
* @param string $name Model名称 支持指定基础模型 例如 MongoModel:User
|
||||
* @param string $tablePrefix 表前缀
|
||||
* @param mixed $connection 数据库连接信息
|
||||
* @return Model
|
||||
*/
|
||||
static public function table($name='', $tablePrefix='',$connection='') {
|
||||
static $_model = [];
|
||||
if(strpos($name,':')) {
|
||||
list($class,$name) = explode(':',$name);
|
||||
}else{
|
||||
$class = 'Think\Model';
|
||||
}
|
||||
$guid = $tablePrefix . $name . '_' . $class;
|
||||
if (!isset($_model[$guid]))
|
||||
$_model[$guid] = new $class($name,['table_prefix'=>$tablePrefix,'connection'=>$connection]);
|
||||
return $_model[$guid];
|
||||
}
|
||||
|
||||
/**
|
||||
* 实例化(分层)模型
|
||||
* @param string $name Model名称
|
||||
* @param string $layer 业务层名称
|
||||
* @return Object
|
||||
*/
|
||||
static public function model($name='',$layer='Model') {
|
||||
if(empty($name)) return new Model;
|
||||
static $_model = [];
|
||||
if(isset($_model[$name.$layer])) return $_model[$name.$layer];
|
||||
if(strpos($name,'/')) {
|
||||
list($module,$name) = explode('/',$name);
|
||||
}else{
|
||||
$module = MODULE_NAME;
|
||||
}
|
||||
$class = $module.'\\'.$layer.'\\'.parse_name($name,1).$layer;
|
||||
if(class_exists($class)) {
|
||||
$model = new $class($name);
|
||||
}else {
|
||||
Log::record('实例化不存在的类:'.$class,'NOTIC');
|
||||
$model = new Model($name);
|
||||
}
|
||||
$_model[$name.$layer] = $model;
|
||||
return $model;
|
||||
}
|
||||
|
||||
/**
|
||||
* 实例化(分层)控制器 格式:[模块名/]控制器名
|
||||
* @param string $name 资源地址
|
||||
* @param string $layer 控制层名称
|
||||
* @return Object|false
|
||||
*/
|
||||
static public function controller($name,$layer='Controller') {
|
||||
static $_instance = [];
|
||||
if(isset($_instance[$name.$layer])) return $_instance[$name.$layer];
|
||||
if(strpos($name,'/')) {
|
||||
list($module,$name) = explode('/',$name);
|
||||
}else{
|
||||
$module = MODULE_NAME;
|
||||
}
|
||||
$class = $module.'\\'.$layer.'\\'.parse_name($name,1).$layer;
|
||||
if(class_exists($class)) {
|
||||
$action = new $class;
|
||||
$_instance[$name.$layer] = $action;
|
||||
return $action;
|
||||
}elseif(class_exists($module.'\\'.$layer.'\\Empty'.$layer)){
|
||||
$class = $module.'\\'.$layer.'\\Empty'.$layer;
|
||||
return new $class;
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 实例化数据库
|
||||
* @param mixed $config 数据库配置
|
||||
* @param boolean $lite 是否采用lite方式连接
|
||||
* @return object
|
||||
*/
|
||||
static public function db($config,$lite=false) {
|
||||
return Db::instance($config,$lite);
|
||||
}
|
||||
|
||||
/**
|
||||
* 远程调用模块的操作方法 参数格式 [模块/控制器/]操作
|
||||
* @param string $url 调用地址
|
||||
* @param string|array $vars 调用参数 支持字符串和数组
|
||||
* @param string $layer 要调用的控制层名称
|
||||
* @return mixed
|
||||
*/
|
||||
static public function action($url,$vars=[],$layer='') {
|
||||
$info = pathinfo($url);
|
||||
$action = $info['basename'];
|
||||
$module = '.' != $info['dirname']?$info['dirname']:CONTROLLER_NAME;
|
||||
$class = self::controller($module,$layer);
|
||||
if($class){
|
||||
if(is_string($vars)) {
|
||||
parse_str($vars,$vars);
|
||||
}
|
||||
return call_user_func_array([&$class,$action.Config::get('action_suffix')],$vars);
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得对象实例 支持调用类的静态方法
|
||||
* @param string $class 对象类名
|
||||
* @param string $method 类的静态方法名
|
||||
* @return object
|
||||
*/
|
||||
static public function instance($class,$method='') {
|
||||
static $_instance = [];
|
||||
$identify = $class.$method;
|
||||
if(!isset($_instance[$identify])) {
|
||||
if(class_exists($class)){
|
||||
$o = new $class();
|
||||
if(!empty($method) && method_exists($o,$method))
|
||||
$_instance[$identify] = call_user_func_array([&$o, $method]);
|
||||
else
|
||||
$_instance[$identify] = $o;
|
||||
}
|
||||
else
|
||||
E('_CLASS_NOT_EXIST_:'.$class);
|
||||
}
|
||||
return $_instance[$identify];
|
||||
}
|
||||
|
||||
}
|
||||
89
Library/Think/Log.php
Normal file
89
Library/Think/Log.php
Normal file
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | TOPThink [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2011 http://topthink.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace Think;
|
||||
class Log {
|
||||
|
||||
// 日志信息
|
||||
static protected $log = [];
|
||||
static protected $level = ['ERR','NOTIC','DEBUG','SQL','INFO'];
|
||||
static protected $storage = null;
|
||||
|
||||
// 日志初始化
|
||||
static public function init($config=[]){
|
||||
$type = isset($config['type'])?$config['type']:'File';
|
||||
$class = 'Think\\Log\\Driver\\'. ucwords($type);
|
||||
if(class_exists($class)) {
|
||||
unset($config['type']);
|
||||
self::$storage = new $class($config);
|
||||
}else{
|
||||
throw new \Exception('Log type not exists:'.$type);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录日志 并且会过滤未经设置的级别
|
||||
* @access public
|
||||
* @param string $message 日志信息
|
||||
* @param string $level 日志级别
|
||||
* @param boolean $record 是否强制记录
|
||||
* @return void
|
||||
*/
|
||||
static public function record($message,$level='INFO') {
|
||||
self::$log[$level][] = "{$level}: {$message}";
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取内存中的日志信息
|
||||
* @access public
|
||||
* @param string $level 日志级别
|
||||
* @return array
|
||||
*/
|
||||
static public function getLog($level=''){
|
||||
return $level?self::$log[$level]:self::$log;
|
||||
}
|
||||
|
||||
/**
|
||||
* 日志保存
|
||||
* @access public
|
||||
* @param string $destination 写入目标
|
||||
* @param string $level 保存的日志级别
|
||||
* @return void
|
||||
*/
|
||||
static public function save($destination='',$level='') {
|
||||
$log = $level?self::$log[$level]:self::$log;
|
||||
if(empty($log)) return ;
|
||||
$message = '';
|
||||
if($level) {
|
||||
$message .= implode("\r\n",$log);
|
||||
self::$log[$level] = [];
|
||||
}else{
|
||||
foreach($log as $info){
|
||||
$message .= implode("\r\n",$info)."\r\n";
|
||||
}
|
||||
self::$log = [];
|
||||
}
|
||||
self::$storage && self::$storage->write($message,$destination);
|
||||
}
|
||||
|
||||
/**
|
||||
* 日志直接写入
|
||||
* @access public
|
||||
* @param string $log 日志信息
|
||||
* @param string $level 日志级别
|
||||
* @param string $destination 写入目标
|
||||
* @return void
|
||||
*/
|
||||
static public function write($log,$level,$destination='') {
|
||||
self::$storage && self::$storage->write("{$level}: {$log}",$destination);
|
||||
}
|
||||
|
||||
}
|
||||
43
Library/Think/Log/Driver/File.php
Normal file
43
Library/Think/Log/Driver/File.php
Normal file
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | TOPThink [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2011 http://topthink.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
// $Id$
|
||||
namespace Think\Log\Driver;
|
||||
|
||||
class File {
|
||||
|
||||
protected $config = [
|
||||
'log_time_format' => ' c ',
|
||||
'log_file_size' => 2097152,
|
||||
'log_path' => '',
|
||||
];
|
||||
|
||||
// 实例化并传入参数
|
||||
public function __construct($config=[]){
|
||||
$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);
|
||||
}
|
||||
}
|
||||
1179
Library/Think/Model.php
Normal file
1179
Library/Think/Model.php
Normal file
File diff suppressed because it is too large
Load Diff
235
Library/Think/Model/Lite.php
Normal file
235
Library/Think/Model/Lite.php
Normal file
@@ -0,0 +1,235 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | TOPThink [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2011 http://topthink.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
// $Id$
|
||||
|
||||
namespace Think\Model;
|
||||
class Lite {
|
||||
|
||||
// 当前数据库操作对象
|
||||
protected $db = null;
|
||||
// 数据库名称
|
||||
protected $dbName = '';
|
||||
//数据库配置
|
||||
protected $connection = '';
|
||||
// 数据表前缀
|
||||
protected $tablePrefix = '';
|
||||
// 数据表名(不包含表前缀)
|
||||
protected $tableName = '';
|
||||
// 实际数据表名(包含表前缀)
|
||||
protected $trueTableName = '';
|
||||
// 最近错误信息
|
||||
protected $error = '';
|
||||
// 配置参数
|
||||
protected $config = [];
|
||||
|
||||
/**
|
||||
* 架构函数
|
||||
* 取得DB类的实例对象 字段检查
|
||||
* @access public
|
||||
* @param string $name 模型名称
|
||||
* @param string $tablePrefix 表前缀
|
||||
* @param mixed $connection 数据库连接信息
|
||||
*/
|
||||
public function __construct($name='',$tablePrefix='',$connection='') {
|
||||
// 模型初始化
|
||||
$this->_initialize();
|
||||
// 读取配置参数
|
||||
$this->config = Config::get();
|
||||
|
||||
// 获取模型名称
|
||||
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:$this->config['db_prefix'];
|
||||
}
|
||||
|
||||
// 数据库初始化操作
|
||||
// 获取数据库操作对象
|
||||
// 当前模型有独立的数据库连接信息
|
||||
$this->db(0,empty($this->connection)?$connection:$this->connection);
|
||||
}
|
||||
|
||||
/**
|
||||
* 得到当前的数据对象名称
|
||||
* @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;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* SQL查询
|
||||
* @access public
|
||||
* @param string $sql SQL指令
|
||||
* @param array $binding 参数绑定
|
||||
* @return mixed
|
||||
*/
|
||||
public function query($sql,$binding=[]) {
|
||||
$sql = $this->parseSql($sql);
|
||||
return $this->db->query($sql,$binding);
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行SQL语句
|
||||
* @access public
|
||||
* @param string $sql SQL指令
|
||||
* @param array $binding 参数绑定
|
||||
* @return false | integer
|
||||
*/
|
||||
public function execute($sql,$binding=[]) {
|
||||
$sql = $this->parseSql($sql);
|
||||
return $this->db->execute($sql,$binding);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析SQL语句
|
||||
* @access public
|
||||
* @param string $sql SQL指令
|
||||
* @return string
|
||||
*/
|
||||
protected function parseSql($sql) {
|
||||
// 分析表达式
|
||||
$sql = strtr($sql,array('__TABLE__'=>$this->getTableName(),'__PREFIX__'=>$this->config['DB_PREFIX']));
|
||||
$this->db->setModel($this->name);
|
||||
return $sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换当前的数据库连接
|
||||
* @access public
|
||||
* @param integer $linkNum 连接序号
|
||||
* @param mixed $config 数据库连接信息
|
||||
* @return Model
|
||||
*/
|
||||
public function db($linkNum='',$config=''){
|
||||
if(''===$linkNum && $this->db) {
|
||||
return $this->db;
|
||||
}
|
||||
static $_linkNum = [];
|
||||
static $_db = [];
|
||||
if(!isset($_db[$linkNum]) || (isset($_db[$linkNum]) && $config && $_linkNum[$linkNum]!=$config) ) {
|
||||
// 创建一个新的实例
|
||||
if(!empty($config) && is_string($config) && false === strpos($config,'/')) { // 支持读取配置参数
|
||||
$config = Config::get($config);
|
||||
}
|
||||
$_db[$linkNum] = Db::Lite($config);
|
||||
}elseif(NULL === $config){
|
||||
$_db[$linkNum]->close(); // 关闭数据库连接
|
||||
unset($_db[$linkNum]);
|
||||
return ;
|
||||
}
|
||||
// 记录连接信息
|
||||
$_linkNum[$linkNum] = $config;
|
||||
// 切换数据库连接
|
||||
$this->db = $_db[$linkNum];
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动事务
|
||||
* @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);
|
||||
}
|
||||
|
||||
}
|
||||
425
Library/Think/Route.php
Normal file
425
Library/Think/Route.php
Normal file
@@ -0,0 +1,425 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | TOPThink [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2011 http://topthink.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
// $Id$
|
||||
namespace Think;
|
||||
class Route {
|
||||
// 路由规则
|
||||
static private $rules = [
|
||||
'GET' => [],
|
||||
'POST' => [],
|
||||
'PUT' => [],
|
||||
'DELETE' => [],
|
||||
'*' => [],
|
||||
];
|
||||
// URL映射规则
|
||||
static private $map = [];
|
||||
// 子域名部署规则
|
||||
static private $domain = [];
|
||||
|
||||
// 添加URL映射规则
|
||||
static public function map($map,$route=''){
|
||||
if(is_array($map)) {
|
||||
self::$map = array_merge(self::$map,$map);
|
||||
}else{
|
||||
self::$map[$map] = $route;
|
||||
}
|
||||
}
|
||||
|
||||
// 添加子域名部署规则
|
||||
static public function domain($domain,$rule=''){
|
||||
if(is_array($domain)) {
|
||||
self::$domain = array_merge(self::$domain,$domain);
|
||||
}else{
|
||||
self::$domain[$domain] = $rule;
|
||||
}
|
||||
}
|
||||
|
||||
// 注册路由规则
|
||||
static public function register($rule,$route='',$type='GET',$option=[]){
|
||||
if(strpos($type,'|')) {
|
||||
foreach (explode('|',$type) as $val){
|
||||
self::register($rule,$route,$val,$option);
|
||||
}
|
||||
}else{
|
||||
if(is_array($rule)) {
|
||||
foreach ($rule as $key=>$val){
|
||||
self::$rules[$type][$key] = ['route'=>$val,'option'=>$option];
|
||||
}
|
||||
}else{
|
||||
self::$rules[$type][$rule] = ['route'=>$route,'option'=>$option];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 注册任意请求的路由规则
|
||||
static public function any($rule,$route='',$option=[]){
|
||||
self::register($rule,$route,'*',$option);
|
||||
}
|
||||
|
||||
// 注册get请求的路由规则
|
||||
static public function get($rule,$route='',$option=[]){
|
||||
self::register($rule,$route,'GET',$option);
|
||||
}
|
||||
|
||||
// 注册post请求的路由规则
|
||||
static public function post($rule,$route='',$option=[]){
|
||||
self::register($rule,$route,'POST',$option);
|
||||
}
|
||||
|
||||
// 注册put请求的路由规则
|
||||
static public function put($rule,$route='',$option=[]){
|
||||
self::register($rule,$route,'PUT',$option);
|
||||
}
|
||||
|
||||
// 注册delete请求的路由规则
|
||||
static public function delete($rule,$route='',$option=[]){
|
||||
self::register($rule,$route,'DELETE',$option);
|
||||
}
|
||||
|
||||
// 检测子域名部署
|
||||
static public function checkDomain(){
|
||||
// 开启子域名部署 支持二级和三级域名
|
||||
if(!empty(self::$domain)) {
|
||||
$rules = self::$domain;
|
||||
if(isset($rules[$_SERVER['HTTP_HOST']])) { // 完整域名或者IP配置
|
||||
$rule = $rules[$_SERVER['HTTP_HOST']];
|
||||
}else{// 子域名配置
|
||||
$domain = array_slice(explode('.',$_SERVER['HTTP_HOST']),0,-2);
|
||||
if(!empty($domain)) {
|
||||
$subDomain = implode('.',$domain);
|
||||
$domain2 = array_pop($domain); // 二级域名
|
||||
if($domain) { // 存在三级域名
|
||||
$domain3 = array_pop($domain);
|
||||
}
|
||||
if($subDomain && isset($rules[$subDomain])) { // 子域名配置
|
||||
$rule = $rules[$subDomain];
|
||||
}elseif(isset($rules['*.'.$domain2]) && !empty($domain3)){ // 泛三级域名
|
||||
$rule = $rules['*.'.$domain2];
|
||||
$panDomain = $domain3;
|
||||
}elseif(isset($rules['*']) && !empty($domain2)){ // 泛二级域名
|
||||
if('www' != $domain2 ) {
|
||||
$rule = $rules['*'];
|
||||
$panDomain = $domain2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!empty($rule)) {
|
||||
// 子域名部署规则
|
||||
// '子域名'=>'模块名'
|
||||
// '子域名'=>['模块名','var1=a&var2=b&var3=*'];
|
||||
if($rule instanceof \Closure) {
|
||||
// 执行闭包并中止
|
||||
self::invokeRule($rule);
|
||||
exit;
|
||||
}
|
||||
if(is_array($rule)) {
|
||||
$_GET[Config::get('var_module')] = $rule[0];
|
||||
if(isset($rule[1])) { // 传入参数
|
||||
parse_str($rule[1],$parms);
|
||||
if(isset($panDomain)) {
|
||||
$pos = array_search('*',$parms);
|
||||
if(false !== $pos) {
|
||||
// 泛域名作为参数
|
||||
$parms[$pos] = $panDomain;
|
||||
}
|
||||
}
|
||||
$_GET = array_merge($_GET,$parms);
|
||||
}
|
||||
}else{
|
||||
$_GET[Config::get('var_module')] = $rule;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 检测URL路由
|
||||
static public function check($regx) {
|
||||
// 优先检测是否存在PATH_INFO
|
||||
if(empty($regx)) $regx = '/' ;
|
||||
// 分隔符替换 确保路由定义使用统一的分隔符
|
||||
$regx = str_replace(Config::get('pathinfo_depr'),'/',$regx);
|
||||
if(isset(self::$map[$regx])) { // URL映射
|
||||
return self::parseUrl(self::$map[$regx]);
|
||||
}
|
||||
// 获取当前请求类型的路由规则
|
||||
$rules = self::$rules[REQUEST_METHOD];
|
||||
if(!empty(self::$rules['*'])) { // 合并任意请求的路由规则
|
||||
$rules = array_merge(self::$rules['*'],$rules);
|
||||
}
|
||||
// 路由规则检测
|
||||
if(!empty($rules)) {
|
||||
foreach ($rules as $rule=>$val){
|
||||
$route = $val['route'];
|
||||
$option = $val['option'];
|
||||
|
||||
// 伪静态后缀检测
|
||||
if(isset($option['ext']) && __EXT__ != $option['ext']) {
|
||||
continue;
|
||||
}
|
||||
// https检测
|
||||
if(!empty($option['https']) && !self::isSsl()) {
|
||||
continue;
|
||||
}
|
||||
// 自定义检测
|
||||
if(!empty($option['callback']) && is_callable($option['callback'])) {
|
||||
if(false === call_user_func($option['callback'])) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if(0===strpos($rule,'/') && preg_match($rule,$regx,$matches)) { // 正则路由
|
||||
if($route instanceof \Closure) {
|
||||
// 执行闭包并中止
|
||||
self::invokeRegx($route,$matches);
|
||||
exit;
|
||||
}else{
|
||||
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);
|
||||
}
|
||||
}
|
||||
if(false !== $var = self::match($regx,$rule)){
|
||||
if($route instanceof \Closure) {
|
||||
// 执行闭包并中止
|
||||
self::invokeRule($route,$var);
|
||||
exit;
|
||||
}else{
|
||||
return self::parseRule($rule,$route,$regx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return self::parseUrl($regx);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否SSL协议
|
||||
* @return boolean
|
||||
*/
|
||||
static public function isSsl() {
|
||||
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;
|
||||
}
|
||||
|
||||
// 执行正则匹配下的闭包方法 支持参数调用
|
||||
static private function invokeRegx($closure,$var=[]) {
|
||||
$reflect = new \ReflectionFunction($closure);
|
||||
$params = $reflect->getParameters();
|
||||
$args = [];
|
||||
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=[]) {
|
||||
$reflect = new \ReflectionFunction($closure);
|
||||
$params = $reflect->getParameters();
|
||||
$args = [];
|
||||
foreach ($params as $param){
|
||||
$name = $param->getName();
|
||||
if(isset($var[$name])) {
|
||||
$args[] = $var[$name];
|
||||
}elseif($param->isDefaultValueAvailable()){
|
||||
$args[] = $param->getDefaultValue();
|
||||
}
|
||||
}
|
||||
$reflect->invokeArgs($args);
|
||||
}
|
||||
|
||||
// 解析模块的URL地址
|
||||
static private function parseUrl($url) {
|
||||
if('/'==$url) {
|
||||
return ;
|
||||
}
|
||||
$paths = explode('/',$url);
|
||||
$var_c = Config::get('var_controller');
|
||||
$var_a = Config::get('var_action');
|
||||
if(Config::get('require_controller') && !isset($_GET[$var_c])) {
|
||||
$_GET[$var_c] = array_shift($paths);
|
||||
}
|
||||
if(!isset($_GET[$var_a])) {
|
||||
$_GET[$var_a] = array_shift($paths);
|
||||
}
|
||||
// 解析剩余的URL参数
|
||||
$var = [];
|
||||
preg_replace('@(\w+)\/([^\/]+)@e', '$var[\'\\1\']=strip_tags(\'\\2\');', implode('/',$paths));
|
||||
$_GET = array_merge($var,$_GET);
|
||||
}
|
||||
|
||||
// 解析规范的路由地址
|
||||
// 地址格式 [控制器/操作?]参数1=值1&参数2=值2...
|
||||
static private function parseRoute($url) {
|
||||
$var = [];
|
||||
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)) {
|
||||
$_GET[Config::get('var_action')] = array_pop($path);
|
||||
if(!empty($path)) {
|
||||
$_GET[Config::get('var_controller')] = array_pop($path);
|
||||
}
|
||||
}
|
||||
return $var;
|
||||
}
|
||||
|
||||
// 检测URL和规则路由是否匹配
|
||||
static private function match($regx,$rule) {
|
||||
$m1 = explode('/',$regx);
|
||||
$m2 = explode('/',$rule);
|
||||
$var = [];
|
||||
foreach ($m2 as $key=>$val){
|
||||
if(0===strpos($val,':')) {// 动态变量
|
||||
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...'
|
||||
// '路由规则'=>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), 重定向
|
||||
static private function parseRule($rule,$route,$regx) {
|
||||
// 获取路由地址规则
|
||||
$url = is_array($route)?$route[0]:$route;
|
||||
// 获取URL地址中的参数
|
||||
$paths = explode('/',$regx);
|
||||
// 解析路由规则
|
||||
$matches = [];
|
||||
$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 = self::parseRoute($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);
|
||||
}
|
||||
}
|
||||
|
||||
// 解析正则路由
|
||||
// '路由正则'=>'[控制器/操作]?参数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'), 重定向
|
||||
static 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 = self::parseRoute($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);
|
||||
}
|
||||
}
|
||||
}
|
||||
21
Library/Think/Seesion/Driver.php
Normal file
21
Library/Think/Seesion/Driver.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | TOPThink [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2013 http://topthink.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
// $Id$
|
||||
namespace Think\Session\Driver;
|
||||
use SessionHandler;
|
||||
class Driver extends SessionHandler {
|
||||
protected $config = [];
|
||||
|
||||
public function __construct($config=[]){
|
||||
$this->config = array_merge($this->config,$config);
|
||||
}
|
||||
|
||||
}
|
||||
160
Library/Think/Session.php
Normal file
160
Library/Think/Session.php
Normal file
@@ -0,0 +1,160 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | TOPThink [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2011 http://topthink.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
// $Id$
|
||||
namespace Think;
|
||||
|
||||
class Session {
|
||||
static protected $prefix = '';
|
||||
|
||||
/**
|
||||
* 设置或者获取session作用域(前缀)
|
||||
* @param string $prefix
|
||||
* @return string|void
|
||||
*/
|
||||
static public function prefix($prefix=''){
|
||||
if(empty($prefix)) {
|
||||
return self::$config['prefix'];
|
||||
}else{
|
||||
self::$config['prefix'] = $prefix;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* session初始化
|
||||
* @param array $config
|
||||
* @return void
|
||||
*/
|
||||
static public function init($config=[]) {
|
||||
if(isset($config['prefix'])) self::$prefix = $config['prefix'];
|
||||
if(isset($config['var_session_id']) && isset($_REQUEST[$config['var_session_id']])){
|
||||
session_id($_REQUEST[$config['var_session_id']]);
|
||||
}elseif(isset($config['id'])) {
|
||||
session_id($config['id']);
|
||||
}
|
||||
ini_set('session.auto_start', 0);
|
||||
if(isset($config['name'])) session_name($config['name']);
|
||||
if(isset($config['path'])) session_save_path($config['path']);
|
||||
if(isset($config['domain'])) ini_set('session.cookie_domain', $config['domain']);
|
||||
if(isset($config['expire'])) ini_set('session.gc_maxlifetime', $config['expire']);
|
||||
if(isset($config['use_trans_sid'])) ini_set('session.use_trans_sid', $config['use_trans_sid']?1:0);
|
||||
if(isset($config['use_cookies'])) ini_set('session.use_cookies', $config['use_cookies']?1:0);
|
||||
if(isset($config['cache_limiter'])) session_cache_limiter($config['cache_limiter']);
|
||||
if(isset($config['cache_expire'])) session_cache_expire($config['cache_expire']);
|
||||
if(!empty($config['type'])) { // 读取session驱动
|
||||
$class = 'Think\\Session\\Driver\\'. ucwords(strtolower($config['type']));
|
||||
// 检查驱动类
|
||||
session_set_save_handler(new $class());
|
||||
}
|
||||
// 启动session
|
||||
if($config['auto_start']) session_start();
|
||||
}
|
||||
|
||||
/**
|
||||
* session设置
|
||||
* @param string $name session名称
|
||||
* @param mixed $value session值
|
||||
* @param string $prefix 作用域(前缀)
|
||||
* @return void
|
||||
*/
|
||||
static public function set($name,$value='',$prefix='') {
|
||||
$prefix = $prefix?$prefix:self::$prefix;
|
||||
if($prefix){
|
||||
if (!is_array($_SESSION[$prefix])) {
|
||||
$_SESSION[$prefix] = [];
|
||||
}
|
||||
$_SESSION[$prefix][$name] = $value;
|
||||
}else{
|
||||
$_SESSION[$name] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* session获取
|
||||
* @param string $name session名称
|
||||
* @param string $prefix 作用域(前缀)
|
||||
* @return mixed
|
||||
*/
|
||||
static public function get($name,$prefix='') {
|
||||
$prefix = $prefix?$prefix:self::$prefix;
|
||||
if($prefix){ // 获取session
|
||||
return isset($_SESSION[$prefix][$name])?$_SESSION[$prefix][$name]:null;
|
||||
}else{
|
||||
return isset($_SESSION[$name])?$_SESSION[$name]:null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除session数据
|
||||
* @param string $name session名称
|
||||
* @param string $prefix 作用域(前缀)
|
||||
* @return void
|
||||
*/
|
||||
static public function delete($name,$prefix='') {
|
||||
$prefix = $prefix?$prefix:$this->prefix;
|
||||
if($prefix){
|
||||
unset($_SESSION[$prefix][$name]);
|
||||
}else{
|
||||
unset($_SESSION[$name]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空session数据
|
||||
* @param string $prefix 作用域(前缀)
|
||||
* @return void
|
||||
*/
|
||||
static public function clear($prefix='') {
|
||||
$prefix = $prefix?$prefix:self::$prefix;
|
||||
if($prefix) {
|
||||
unset($_SESSION[$prefix]);
|
||||
}else{
|
||||
$_SESSION = [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断session数据
|
||||
* @param string $name session名称
|
||||
* @param mixed $value session值
|
||||
* @return boolean
|
||||
*/
|
||||
static public function has($name,$prefix='') {
|
||||
$prefix = $prefix?$prefix:self::$prefix;
|
||||
if($prefix){
|
||||
return isset($_SESSION[$prefix][$name]);
|
||||
}else{
|
||||
return isset($_SESSION[$name]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* session管理
|
||||
* @param string $name session操作名称
|
||||
* @return void
|
||||
*/
|
||||
static public function operate($name) {
|
||||
if('pause'==$name){ // 暂停session
|
||||
session_write_close();
|
||||
}elseif('start'==$name){ // 启动session
|
||||
session_start();
|
||||
}elseif('destroy'==$name){ // 销毁session
|
||||
$_SESSION = [];
|
||||
session_unset();
|
||||
session_destroy();
|
||||
}elseif('regenerate'==$name){ // 重新生成id
|
||||
session_regenerate_id();
|
||||
}
|
||||
}
|
||||
|
||||
static public function __callStatic($name,$args) {
|
||||
self::operate($name);
|
||||
}
|
||||
}
|
||||
84
Library/Think/Tag.php
Normal file
84
Library/Think/Tag.php
Normal file
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | TOPThink [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2011 http://topthink.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
// $Id$
|
||||
namespace Think;
|
||||
class Tag {
|
||||
|
||||
static private $tags = [];
|
||||
|
||||
/**
|
||||
* 动态添加行为扩展到某个标签
|
||||
* @param string $tag 标签名称
|
||||
* @param mixed $behavior 行为名称
|
||||
* @return void
|
||||
*/
|
||||
static public function add($tag,$behavior) {
|
||||
if(is_array($hehavior)) {
|
||||
self::$tags[$tag] = array_merge(self::$tags[$tag],$hehavior);
|
||||
}else{
|
||||
self::$tags[$tag][] = $behavior;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量导入行为
|
||||
* @param array $tags 标签行为
|
||||
* @return void
|
||||
*/
|
||||
static public function import($tags) {
|
||||
self::$tags = array_merge(self::$tags,$tags);
|
||||
}
|
||||
|
||||
/**
|
||||
* 监听标签的行为
|
||||
* @param string $tag 标签名称
|
||||
* @param mixed $params 传入参数
|
||||
* @return void
|
||||
*/
|
||||
static public function listen($tag, &$params=NULL) {
|
||||
if(isset(self::$tags[$tag])) {
|
||||
foreach (self::$tags[$tag] as $val) {
|
||||
Debug::remark('behavior_start','time');
|
||||
$result = self::exec($val, $params);
|
||||
Debug::remark('behavior_end','time');
|
||||
Log::record('Run '.$val.' Behavior [ RunTime:'.Debug::getUseTime('behavior_start','behavior_end').'s ]','INFO');
|
||||
if(false === $result) {
|
||||
// 如果返回false 则中断行为执行
|
||||
return ;
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行某个行为
|
||||
* @param string $name 行为名称
|
||||
* @param Mixed $params 传人的参数
|
||||
* @return void
|
||||
*/
|
||||
static public function exec($name, &$params=NULL) {
|
||||
if($name instanceof \Closure) {
|
||||
return $name($params);
|
||||
}
|
||||
if(false === strpos($name,'\\')) {
|
||||
$class = '\\'.ucwords(MODULE_NAME).'\\Behavior\\'.$name;
|
||||
}else{
|
||||
$class = $name;
|
||||
}
|
||||
if(class_exists($class)) {
|
||||
$behavior = new $class();
|
||||
return $behavior->run($params);
|
||||
}
|
||||
return ;
|
||||
}
|
||||
|
||||
}
|
||||
720
Library/Think/Template.php
Normal file
720
Library/Think/Template.php
Normal file
@@ -0,0 +1,720 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkTemplate -- ThinkPHP Template
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2013 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace Think;
|
||||
|
||||
/**
|
||||
* ThinkPHP分离出来的模板引擎
|
||||
* 支持XML标签和普通标签的模板解析
|
||||
* 编译型模板引擎 支持动态缓存
|
||||
*/
|
||||
class Template {
|
||||
protected $tVar = []; // 模板变量
|
||||
protected $config = [ // 引擎配置
|
||||
'tpl_path' => '',
|
||||
'tpl_suffix' => '.html', // 默认模板文件后缀
|
||||
'cache_suffix' => '.php', // 默认模板缓存后缀
|
||||
'tpl_deny_func_list' => 'echo,exit', // 模板引擎禁用函数
|
||||
'tpl_deny_php' => false, // 默认模板引擎是否禁用PHP原生代码
|
||||
'tpl_begin' => '{', // 模板引擎普通标签开始标记
|
||||
'tpl_end' => '}', // 模板引擎普通标签结束标记
|
||||
'strip_space' => false, // 是否去除模板文件里面的html空格与换行
|
||||
'tpl_cache' => true, // 是否开启模板编译缓存,设为false则每次都会重新编译
|
||||
'compile_type' => 'file',
|
||||
'cache_path' => '',
|
||||
'cache_prefix' => '', // 模板缓存前缀标识,可以动态改变
|
||||
'cache_time' => 0, // 模板缓存有效期 0 为永久,(以数字为值,单位:秒)
|
||||
'layout_item' => '{__CONTENT__}', // 布局模板的内容替换标识
|
||||
'taglib_begin' => '<', // 标签库标签开始标记
|
||||
'taglib_end' => '>', // 标签库标签结束标记
|
||||
'taglib_load' => true, // 是否使用内置标签库之外的其它标签库,默认自动检测
|
||||
'taglib_build_in' => 'cx', // 内置标签库名称(标签使用不必指定标签库名称),以逗号分隔 注意解析顺序
|
||||
'taglib_pre_load' => '', // 需要额外加载的标签库(须指定标签库名称),多个以逗号分隔
|
||||
'display_cache' => false,
|
||||
];
|
||||
|
||||
private $literal = [];
|
||||
private $block = [];
|
||||
protected $storage = null;
|
||||
|
||||
/**
|
||||
* 架构函数
|
||||
* @access public
|
||||
*/
|
||||
public function __construct($config=[]){
|
||||
if(!empty($config)) {
|
||||
$this->config = array_merge($this->config,$config);
|
||||
}
|
||||
$this->config['taglib_begin'] = $this->stripPreg($this->config['taglib_begin']);
|
||||
$this->config['taglib_end'] = $this->stripPreg($this->config['taglib_end']);
|
||||
$this->config['tpl_begin'] = $this->stripPreg($this->config['tpl_begin']);
|
||||
$this->config['tpl_end'] = $this->stripPreg($this->config['tpl_end']);
|
||||
|
||||
// 初始化模板编译存储器
|
||||
$type = $this->config['compile_type']?$this->config['compile_type']:'File';
|
||||
$class = '\Think\Template\Driver\\'.ucwords($type);
|
||||
$this->storage = new $class();
|
||||
}
|
||||
|
||||
/**
|
||||
* 字符串替换 避免正则混淆
|
||||
* @access private
|
||||
* @param string $str
|
||||
*/
|
||||
private function stripPreg($str) {
|
||||
return str_replace(
|
||||
['{','}','(',')','|','[',']','-','+','*','.','^','?'],
|
||||
['\{','\}','\(','\)','\|','\[','\]','\-','\+','\*','\.','\^','\?'],
|
||||
$str);
|
||||
}
|
||||
|
||||
/**
|
||||
* 模板变量赋值
|
||||
* @access public
|
||||
* @param mixed $name
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function assign($name,$value=''){
|
||||
if(is_array($name)) {
|
||||
$this->tVar = array_merge($this->tVar,$name);
|
||||
}else {
|
||||
$this->tVar[$name] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 模板引擎参数赋值
|
||||
* @access public
|
||||
* @param mixed $name
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function __set($name,$value){
|
||||
$this->config[$name] = $value;
|
||||
}
|
||||
|
||||
public function get($name){
|
||||
return $this->tVar[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* 渲染模板文件
|
||||
* @access public
|
||||
* @param string $template 模板文件
|
||||
* @param array $vars 模板变量
|
||||
* @param string $cacheId 模板缓存标识
|
||||
* @return void
|
||||
*/
|
||||
public function display($template,$vars=[],$cacheId='') {
|
||||
$template = $this->parseTemplateFile($template);
|
||||
$cacheFile = $this->config['cache_path'].$this->config['cache_prefix'].md5($template).$this->config['cache_suffix'];
|
||||
if(!$this->checkCache($template,$cacheFile)) { // 缓存无效
|
||||
// 模板编译
|
||||
$this->compiler(file_get_contents($template),$cacheFile);
|
||||
}
|
||||
// 页面缓存
|
||||
ob_start();
|
||||
ob_implicit_flush(0);
|
||||
// 读取编译存储
|
||||
$this->storage->read($cacheFile,$vars?$vars:$this->tVar);
|
||||
// 获取并清空缓存
|
||||
$content = ob_get_clean();
|
||||
if($cacheId && $this->config['display_cache']) {
|
||||
// 缓存页面输出
|
||||
Cache::set($cacheId,$content,$this->config['cache_time']);
|
||||
}
|
||||
echo $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* 渲染模板内容
|
||||
* @access public
|
||||
* @param string $content 模板内容
|
||||
* @param array $vars 模板变量
|
||||
* @return void
|
||||
*/
|
||||
public function fetch($content,$vars=[]) {
|
||||
$cacheFile = $this->config['cache_path'].$this->config['cache_prefix'].md5($content).$this->config['cache_suffix'];
|
||||
if(!$this->checkCache($content,$cacheFile)) { // 缓存无效
|
||||
// 模板编译
|
||||
$this->compiler($content,$cacheFile);
|
||||
}
|
||||
// 读取编译存储
|
||||
$this->storage->read($cacheFile,$vars?$vars:$this->tVar);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查编译缓存是否有效
|
||||
* 如果无效则需要重新编译
|
||||
* @access private
|
||||
* @param string $template 模板文件名
|
||||
* @param string $cacheFile 缓存文件名
|
||||
* @return boolen
|
||||
*/
|
||||
private function checkCache($template,$cacheFile) {
|
||||
if (!$this->config['tpl_cache']) // 优先对配置设定检测
|
||||
return false;
|
||||
// 检查编译存储是否有效
|
||||
return $this->storage->check($template,$cacheFile,$this->config['cache_time']);
|
||||
}
|
||||
|
||||
public function isCache($cacheId){
|
||||
if($cacheId && $this->config['display_cache']) {
|
||||
// 缓存页面输出
|
||||
return Cache::get($cacheId)?true:false;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 编译模板文件内容
|
||||
* @access private
|
||||
* @param string $content 模板内容
|
||||
* @param string $cacheFile 缓存文件名
|
||||
* @return void
|
||||
*/
|
||||
private function compiler($content,$cacheFile) {
|
||||
// 模板解析
|
||||
$content = $this->parse($content);
|
||||
// 还原被替换的Literal标签
|
||||
$content = preg_replace('/<!--###literal(\d+)###-->/eis',"\$this->restoreLiteral('\\1')",$content);
|
||||
// 添加安全代码
|
||||
$content = '<?php if (!defined(\'THINK_PATH\')) exit();?>'.$content;
|
||||
if($this->config['strip_space']) {
|
||||
/* 去除html空格与换行 */
|
||||
$find = ['~>\s+<~','~>(\s+\n|\r)~'];
|
||||
$replace = ['><','>'];
|
||||
$content = preg_replace($find, $replace, $content);
|
||||
}
|
||||
// 优化生成的php代码
|
||||
$content = str_replace('?><?php','',$content);
|
||||
// 编译存储
|
||||
$this->storage->write($cacheFile,$content);
|
||||
return ;
|
||||
}
|
||||
|
||||
/**
|
||||
* 模板解析入口
|
||||
* 支持普通标签和TagLib解析 支持自定义标签库
|
||||
* @access public
|
||||
* @param string $content 要解析的模板内容
|
||||
* @return string
|
||||
*/
|
||||
public function parse($content) {
|
||||
// 内容为空不解析
|
||||
if(empty($content)) return '';
|
||||
$begin = $this->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 name="html,mytag..." />
|
||||
// 当TAGLIB_LOAD配置为true时才会进行检测
|
||||
if($this->config['taglib_load']) {
|
||||
$tagLibs = $this->getIncludeTagLib($content);
|
||||
if(!empty($tagLibs)) {
|
||||
// 对导入的TagLib进行解析
|
||||
foreach($tagLibs as $tagLibName) {
|
||||
$this->parseTagLib($tagLibName,$content);
|
||||
}
|
||||
}
|
||||
}
|
||||
// 预先加载的标签库 无需在每个模板中使用taglib标签加载 但必须使用标签库XML前缀
|
||||
if($this->config['taglib_pre_load']) {
|
||||
$tagLibs = explode(',',$this->config['taglib_pre_load']);
|
||||
foreach ($tagLibs as $tag){
|
||||
$this->parseTagLib($tag,$content);
|
||||
}
|
||||
}
|
||||
// 内置标签库 无需使用taglib标签导入就可以使用 并且不需使用标签库XML前缀
|
||||
$tagLibs = explode(',',$this->config['taglib_build_in']);
|
||||
foreach ($tagLibs as $tag){
|
||||
$this->parseTagLib($tag,$content,true);
|
||||
}
|
||||
// 解析普通模板标签 {tagName}
|
||||
$content = preg_replace('/('.$this->config['tpl_begin'].')([^\d\s'.$this->config['tpl_begin'].$this->config['tpl_end'].'].+?)('.$this->config['tpl_end'].')/eis',"\$this->parseTag('\\2','\\0')",$content);
|
||||
return $content;
|
||||
}
|
||||
|
||||
// 检查PHP语法
|
||||
private function parsePhp($content) {
|
||||
if(ini_get('short_open_tag')){
|
||||
// 开启短标签的情况要将<?标签用echo方式输出 否则无法正常输出xml标识
|
||||
$content = preg_replace('/(<\?(?!php|=|$))/i', '<?php echo \'\\1\'; ?>'."\n", $content );
|
||||
}
|
||||
// PHP语法检查
|
||||
if($this->config['tpl_deny_php'] && false !== strpos($content,'<?php')) {
|
||||
exit('_NOT_ALLOW_PHP_');
|
||||
}
|
||||
return $content;
|
||||
}
|
||||
|
||||
// 解析模板中的include标签
|
||||
private function parseInclude($content) {
|
||||
// 解析继承
|
||||
$content = $this->parseExtend($content);
|
||||
// 解析布局
|
||||
$content = $this->parseLayout($content);
|
||||
// 读取模板中的include标签
|
||||
$find = preg_match_all('/'.$this->config['taglib_begin'].'include\s(.+?)\s*?\/'.$this->config['taglib_end'].'/is',$content,$matches);
|
||||
if($find) {
|
||||
for($i=0;$i<$find;$i++) {
|
||||
$include = $matches[1][$i];
|
||||
$array = $this->parseXmlAttrs($include);
|
||||
$file = $array['file'];
|
||||
unset($array['file']);
|
||||
$content = str_replace($matches[0][$i],$this->parseIncludeItem($file,$array),$content);
|
||||
}
|
||||
}
|
||||
return $content;
|
||||
}
|
||||
|
||||
// 解析模板中的布局标签
|
||||
private function parseLayout($content) {
|
||||
// 读取模板中的布局标签
|
||||
$find = preg_match('/'.$this->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]);
|
||||
// 读取布局模板
|
||||
$layoutFile = $this->config['tpl_path'].$array['name'].$this->config['tpl_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;
|
||||
}
|
||||
|
||||
// 解析模板中的extend标签
|
||||
private function parseExtend($content) {
|
||||
$begin = $this->config['taglib_begin'];
|
||||
$end = $this->config['taglib_end'];
|
||||
// 读取模板中的继承标签
|
||||
$find = preg_match('/'.$begin.'extend\s(.+?)\s*?\/'.$end.'/is',$content,$matches);
|
||||
if($find) {
|
||||
//替换extend标签
|
||||
$content = str_replace($matches[0],'',$content);
|
||||
// 记录页面中的block标签
|
||||
preg_replace('/'.$begin.'block\sname=(.+?)\s*?'.$end.'(.*?)'.$begin.'\/block'.$end.'/eis',"\$this->parseBlock('\\1','\\2')",$content);
|
||||
// 读取继承模板
|
||||
$array = $this->parseXmlAttrs($matches[1]);
|
||||
$content = $this->parseTemplateName($array['name']);
|
||||
// 替换block标签
|
||||
$content = preg_replace('/'.$begin.'block\sname=(.+?)\s*?'.$end.'(.*?)'.$begin.'\/block'.$end.'/eis',"\$this->replaceBlock('\\1','\\2')",$content);
|
||||
}else{
|
||||
$content = preg_replace('/'.$begin.'block\sname=(.+?)\s*?'.$end.'(.*?)'.$begin.'\/block'.$end.'/eis',"stripslashes('\\2')",$content);
|
||||
}
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* 分析XML属性
|
||||
* @access private
|
||||
* @param string $attrs XML属性字符串
|
||||
* @return array
|
||||
*/
|
||||
private function parseXmlAttrs($attrs) {
|
||||
$xml = '<tpl><tag '.$attrs.' /></tpl>';
|
||||
$xml = simplexml_load_string($xml);
|
||||
if(!$xml)
|
||||
exit('_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
|
||||
*/
|
||||
private function parseLiteral($content) {
|
||||
if(trim($content)=='') return '';
|
||||
$content = stripslashes($content);
|
||||
$i = count($this->literal);
|
||||
$parseStr = "<!--###literal{$i}###-->";
|
||||
$this->literal[$i] = $content;
|
||||
return $parseStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* 还原被替换的literal标签
|
||||
* @access private
|
||||
* @param string $tag literal标签序号
|
||||
* @return string
|
||||
*/
|
||||
private function restoreLiteral($tag) {
|
||||
// 还原literal标签
|
||||
$parseStr = $this->literal[$tag];
|
||||
// 销毁literal记录
|
||||
unset($this->literal[$tag]);
|
||||
return $parseStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录当前页面中的block标签
|
||||
* @access private
|
||||
* @param string $name block名称
|
||||
* @param string $content 模板内容
|
||||
* @return string
|
||||
*/
|
||||
private function parseBlock($name,$content) {
|
||||
$this->block[$name] = $content;
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* 替换继承模板中的block标签
|
||||
* @access private
|
||||
* @param string $name block名称
|
||||
* @param string $content 模板内容
|
||||
* @return string
|
||||
*/
|
||||
private function replaceBlock($name,$content) {
|
||||
// 替换block标签 没有重新定义则使用原来的
|
||||
$replace = isset($this->block[$name])? $this->block[$name] : $content;
|
||||
return stripslashes($replace);
|
||||
}
|
||||
|
||||
/**
|
||||
* 搜索模板页面中包含的TagLib库
|
||||
* 并返回列表
|
||||
* @access private
|
||||
* @param string $content 模板内容
|
||||
* @return array
|
||||
*/
|
||||
private 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]);
|
||||
return explode(',',$array['name']);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* TagLib库解析
|
||||
* @access private
|
||||
* @param string $tagLib 要解析的标签库
|
||||
* @param string $content 要解析的模板内容
|
||||
* @param boolen $hide 是否隐藏标签库前缀
|
||||
* @return void
|
||||
*/
|
||||
protected function parseTagLib($tagLib,&$content,$hide=false) {
|
||||
$begin = $this->config['taglib_begin'];
|
||||
$end = $this->config['taglib_end'];
|
||||
$className = '\\Think\\Template\\TagLib\\'.ucwords($tagLib);
|
||||
$tLib = new $className;
|
||||
foreach ($tLib->getTags() as $name=>$val){
|
||||
$tags = [$name];
|
||||
if(isset($val['alias'])) {// 别名设置
|
||||
$tags = explode(',',$val['alias']);
|
||||
$tags[] = $name;
|
||||
}
|
||||
$level = isset($val['level'])?$val['level']:1;
|
||||
$closeTag = isset($val['close'])?$val['close']:true;
|
||||
foreach ($tags as $tag){
|
||||
$parseTag = !$hide? $tagLib.':'.$tag: $tag;// 实际要解析的标签名称
|
||||
if(!method_exists($tLib,'_'.$tag)) {
|
||||
// 别名可以无需定义解析方法
|
||||
$tag = $name;
|
||||
}
|
||||
$n1 = empty($val['attr'])?'(\s*?)':'\s([^'.$end.']*)';
|
||||
if (!$closeTag){
|
||||
$patterns = '/'.$begin.$parseTag.$n1.'\/(\s*?)'.$end.'/eis';
|
||||
$replacement = "\$this->parseXmlTag(\$tLib,'$tagLib','$tag','$1','')";
|
||||
$content = preg_replace($patterns, $replacement,$content);
|
||||
}else{
|
||||
$patterns = '/'.$begin.$parseTag.$n1.$end.'(.*?)'.$begin.'\/'.$parseTag.'(\s*?)'.$end.'/eis';
|
||||
$replacement = "\$this->parseXmlTag(\$tLib,'$tagLib','$tag','$1','$2')";
|
||||
for($i=0;$i<$level;$i++)
|
||||
$content=preg_replace($patterns,$replacement,$content);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析标签库的标签
|
||||
* 需要调用对应的标签库文件解析类
|
||||
* @access private
|
||||
* @param object $tLib 模板引擎实例
|
||||
* @param string $tagLib 标签库名称
|
||||
* @param string $tag 标签名
|
||||
* @param string $attr 标签属性
|
||||
* @param string $content 标签内容
|
||||
* @return string
|
||||
*/
|
||||
private function parseXmlTag($tLib,$tagLib,$tag,$attr,$content) {
|
||||
$attr = stripslashes($attr);
|
||||
$content= stripslashes($content);
|
||||
if(ini_get('magic_quotes_sybase'))
|
||||
$attr = str_replace('\"','\'',$attr);
|
||||
$parse = '_'.$tag;
|
||||
$content = trim($content);
|
||||
$tags = $tLib->parseXmlAttr($attr,$tag);
|
||||
$tLib->tpl = $this;
|
||||
return $tLib->$parse($tags,$content);
|
||||
}
|
||||
|
||||
/**
|
||||
* 模板标签解析
|
||||
* 格式: {TagName:args [|content] }
|
||||
* @access private
|
||||
* @param string $tagStr 标签内容
|
||||
* @param string $content 原始内容
|
||||
* @return string
|
||||
*/
|
||||
private function parseTag($tagStr,$content){
|
||||
$tagStr = stripslashes($tagStr);
|
||||
|
||||
//还原非模板标签
|
||||
if(!preg_match('/^[\s|\d]/is',$tagStr)){
|
||||
$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 '<?php echo '.$flag.$name.';?>';
|
||||
}elseif(':' == $flag){ // 输出某个函数的结果
|
||||
return '<?php echo '.$name.';?>';
|
||||
}elseif('~' == $flag){ // 执行某个函数
|
||||
return '<?php '.$name.';?>';
|
||||
}elseif(substr($tagStr,0,2)=='//' || (substr($tagStr,0,2)=='/*' && substr($tagStr,-2)=='*/')){
|
||||
//注释标签
|
||||
return '';
|
||||
}
|
||||
}
|
||||
// 非法标签直接返回
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* 模板变量解析,支持使用函数
|
||||
* 格式: {$varname|function1|function2=arg1,arg2}
|
||||
* @access private
|
||||
* @param string $varStr 变量数据
|
||||
* @return string
|
||||
*/
|
||||
private function parseVar($varStr){
|
||||
$varStr = trim($varStr);
|
||||
static $_varParseList = [];
|
||||
//如果已经解析过该变量字串,则直接返回变量值
|
||||
if(isset($_varParseList[$varStr])) return $_varParseList[$varStr];
|
||||
$parseStr = '';
|
||||
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);
|
||||
$name = '$'.$var;
|
||||
foreach ($vars as $key=>$val)
|
||||
$name .= '["'.$val.'"]';
|
||||
}elseif(false !== strpos($var,'[')) {
|
||||
//支持 {$var['key']} 方式输出数组
|
||||
$name = "$".$var;
|
||||
}elseif(false !==strpos($var,':') && false ===strpos($var,'::') && false ===strpos($var,'?')){
|
||||
//支持 {$var:property} 方式输出对象的属性
|
||||
$vars = explode(':',$var);
|
||||
$var = str_replace(':','->',$var);
|
||||
$name = "$".$var;
|
||||
}else {
|
||||
$name = "$$var";
|
||||
}
|
||||
//对变量使用函数
|
||||
if(count($varArray)>0)
|
||||
$name = $this->parseVarFunction($name,$varArray);
|
||||
$parseStr = '<?php echo ('.$name.'); ?>';
|
||||
}
|
||||
$_varParseList[$varStr] = $parseStr;
|
||||
return $parseStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* 对模板变量使用函数
|
||||
* 格式 {$varname|function1|function2=arg1,arg2}
|
||||
* @access private
|
||||
* @param string $name 变量名
|
||||
* @param array $varArray 函数列表
|
||||
* @return string
|
||||
*/
|
||||
private function parseVarFunction($name,$varArray){
|
||||
//对变量使用函数
|
||||
$length = count($varArray);
|
||||
//取得模板禁止使用函数列表
|
||||
$template_deny_funs = explode(',',$this->config['tpl_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 private
|
||||
* @param string $varStr 变量字符串
|
||||
* @return string
|
||||
*/
|
||||
private 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_TEMPLATE_VERSION';
|
||||
break;
|
||||
case 'LDELIM':
|
||||
$parseStr = $this->config['tpl_begin'];
|
||||
break;
|
||||
case 'RDELIM':
|
||||
$parseStr = $this->config['tpl_end'];
|
||||
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=[]){
|
||||
// 分析模板文件名并读取内容
|
||||
$parseStr = $this->parseTemplateName($tmplPublicName);
|
||||
// 替换变量
|
||||
foreach ($vars as $key=>$val) {
|
||||
if(strpos($val,'['.$key.']')) {
|
||||
$parseStr = str_replace('['.$key.']',$val,$parseStr);
|
||||
}
|
||||
}
|
||||
// 再次对包含文件进行模板分析
|
||||
return $this->parseInclude($parseStr);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分析加载的模板文件并读取内容 支持多个模板文件读取
|
||||
* @access private
|
||||
* @param string $tmplPublicName 模板文件名
|
||||
* @return string
|
||||
*/
|
||||
private function parseTemplateName($templateName){
|
||||
if(substr($templateName,0,1)=='$')
|
||||
//支持加载变量文件名
|
||||
$templateName = $this->get(substr($templateName,1));
|
||||
$array = explode(',',$templateName);
|
||||
$parseStr = '';
|
||||
foreach ($array as $templateName){
|
||||
$template = $this->parseTemplateFile($templateName);
|
||||
// 获取模板文件内容
|
||||
$parseStr .= file_get_contents($template);
|
||||
}
|
||||
return $parseStr;
|
||||
}
|
||||
|
||||
private function parseTemplateFile($template) {
|
||||
if(false === strpos($template,'.')) {
|
||||
return $this->config['tpl_path'].$template.$this->config['tpl_suffix'];
|
||||
}else{
|
||||
return $template;
|
||||
}
|
||||
}
|
||||
}
|
||||
45
Library/Think/Template/Driver/File.php
Normal file
45
Library/Think/Template/Driver/File.php
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | TOPThink [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2011 http://topthink.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
// $Id$
|
||||
|
||||
namespace Think\Template\Driver;
|
||||
class File {
|
||||
// 写入编译缓存
|
||||
public function write($cacheFile,$content){
|
||||
// 检测模板目录
|
||||
$dir = dirname($cacheFile);
|
||||
if(!is_dir($dir))
|
||||
mkdir($dir,0755,true);
|
||||
// 生成模板缓存文件
|
||||
if( false === file_put_contents($cacheFile,$content))
|
||||
E('_CACHE_WRITE_ERROR_:'.$cacheFile);
|
||||
}
|
||||
|
||||
// 读取编译编译
|
||||
public function read($cacheFile,$vars){
|
||||
// 模板阵列变量分解成为独立变量
|
||||
extract($vars, EXTR_OVERWRITE);
|
||||
//载入模版缓存文件
|
||||
include $cacheFile;
|
||||
}
|
||||
|
||||
// 检查编译缓存是否有效
|
||||
public function check($template,$cacheFile,$cacheTime){
|
||||
if(!is_file($cacheFile)|| (is_file($template) && filemtime($template) > filemtime($cacheFile))) {
|
||||
// 模板文件如果有更新则缓存需要更新
|
||||
return false;
|
||||
}elseif ($cacheTime != 0 && time() > filemtime($cacheFile)+$cacheTime) {
|
||||
// 缓存是否在有效期
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
243
Library/Think/Template/TagLib.php
Normal file
243
Library/Think/Template/TagLib.php
Normal file
@@ -0,0 +1,243 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | TOPThink [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2013 http://topthink.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
// $Id$
|
||||
namespace Think\Template;
|
||||
/**
|
||||
* ThinkPHP标签库TagLib解析基类
|
||||
* @category Think
|
||||
* @package Think
|
||||
* @subpackage Template
|
||||
* @author liu21st <liu21st@gmail.com>
|
||||
*/
|
||||
class TagLib {
|
||||
|
||||
/**
|
||||
* 标签库定义XML文件
|
||||
* @var string
|
||||
* @access protected
|
||||
*/
|
||||
protected $xml = '';
|
||||
protected $tags = [];// 标签定义
|
||||
/**
|
||||
* 标签库名称
|
||||
* @var string
|
||||
* @access protected
|
||||
*/
|
||||
protected $tagLib ='';
|
||||
|
||||
/**
|
||||
* 标签库标签列表
|
||||
* @var string
|
||||
* @access protected
|
||||
*/
|
||||
protected $tagList = [];
|
||||
|
||||
/**
|
||||
* 标签库分析数组
|
||||
* @var string
|
||||
* @access protected
|
||||
*/
|
||||
protected $parse = [];
|
||||
|
||||
/**
|
||||
* 标签库是否有效
|
||||
* @var string
|
||||
* @access protected
|
||||
*/
|
||||
protected $valid = false;
|
||||
|
||||
/**
|
||||
* 当前模板对象
|
||||
* @var object
|
||||
* @access protected
|
||||
*/
|
||||
public $tpl;
|
||||
|
||||
protected $comparison = [' nheq '=>' !== ',' heq '=>' === ',' neq '=>' != ',' eq '=>' == ',' egt '=>' >= ',' gt '=>' > ',' elt '=>' <= ',' lt '=>' < '];
|
||||
|
||||
/**
|
||||
* TagLib标签属性分析 返回标签属性数组
|
||||
* @access public
|
||||
* @param string $tagStr 标签内容
|
||||
* @return array
|
||||
*/
|
||||
public function parseXmlAttr($attr,$tag) {
|
||||
if(''== trim($attr)) {
|
||||
return [];
|
||||
}
|
||||
//XML解析安全过滤
|
||||
$attr = str_replace('&','___', $attr);
|
||||
$xml = '<tpl><tag '.$attr.' /></tpl>';
|
||||
$xml = simplexml_load_string($xml);
|
||||
if(!$xml) {
|
||||
exit('_XML_TAG_ERROR_ : '.$attr);
|
||||
}
|
||||
$xml = (array)($xml->tag->attributes());
|
||||
$array = array_change_key_case($xml['@attributes']);
|
||||
if($array) {
|
||||
$tag = strtolower($tag);
|
||||
if(isset($this->tags[$tag]['attr'])) {
|
||||
$attrs = explode(',',$this->tags[$tag]['attr']);
|
||||
if(isset($this->tags[strtolower($tag)]['must'])){
|
||||
$must = explode(',',$this->tags[$tag]['must']);
|
||||
}else{
|
||||
$must = [];
|
||||
}
|
||||
foreach($attrs as $name) {
|
||||
if( isset($array[$name])) {
|
||||
$array[$name] = str_replace('___','&',$array[$name]);
|
||||
}elseif(false !== array_search($name,$must)){
|
||||
exit('_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);
|
||||
$condition = preg_replace('/\$(\w+)\.(\w+)\s/is','$\\1["\\2"] ',$condition);
|
||||
|
||||
if(false !== strpos($condition, '$Think'))
|
||||
$condition = preg_replace('/(\$Think.*?)\s/ies',"\$this->parseThinkVar('\\1');" , $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);
|
||||
$name = '$'.$var;
|
||||
foreach ($vars as $key=>$val){
|
||||
if(0===strpos($val,'$')) {
|
||||
$name .= '["{'.$val.'}"]';
|
||||
}else{
|
||||
$name .= '["'.$val.'"]';
|
||||
}
|
||||
}
|
||||
}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].'\']';
|
||||
}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[\''.$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;
|
||||
}
|
||||
}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;
|
||||
default: if(defined($vars[1])) $parseStr = $vars[1];
|
||||
}
|
||||
}
|
||||
return $parseStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* 对模板变量使用函数
|
||||
* 格式 {$varname|function1|function2=arg1,arg2}
|
||||
* @access protected
|
||||
* @param string $name 变量名
|
||||
* @param array $varArray 函数列表
|
||||
* @return string
|
||||
*/
|
||||
protected function parseVarFunction($name,$varArray){
|
||||
//对变量使用函数
|
||||
$length = count($varArray);
|
||||
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(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;
|
||||
}
|
||||
|
||||
// 获取标签定义
|
||||
public function getTags(){
|
||||
return $this->tags;
|
||||
}
|
||||
}
|
||||
614
Library/Think/Template/TagLib/Cx.php
Normal file
614
Library/Think/Template/TagLib/Cx.php
Normal file
@@ -0,0 +1,614 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2006-2012 http://thinkphp.cn All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace Think\Template\TagLib;
|
||||
use Think\Template\TagLib;
|
||||
/**
|
||||
* CX标签库解析类
|
||||
* @category Think
|
||||
* @package Think
|
||||
* @subpackage Driver.Taglib
|
||||
* @author liu21st <liu21st@gmail.com>
|
||||
*/
|
||||
class Cx extends TagLib {
|
||||
|
||||
// 标签定义
|
||||
protected $tags = [
|
||||
// 标签定义: attr 属性列表 close 是否闭合(0 或者1 默认1) alias 标签别名 level 嵌套层次
|
||||
'php' => [],
|
||||
'volist' => ['attr'=>'name,id,offset,length,key,mod','level'=>3,'alias'=>'iterate'],
|
||||
'foreach' => ['attr'=>'name,item,key','level'=>3],
|
||||
'if' => ['attr'=>'condition','level'=>2],
|
||||
'elseif' => ['attr'=>'condition','close'=>0],
|
||||
'else' => ['attr'=>'','close'=>0],
|
||||
'switch' => ['attr'=>'name','level'=>2],
|
||||
'case' => ['attr'=>'value,break'],
|
||||
'default' => ['attr'=>'','close'=>0],
|
||||
'compare' => ['attr'=>'name,value,type','level'=>3,'alias'=>'eq,equal,notequal,neq,gt,lt,egt,elt,heq,nheq'],
|
||||
'range' => ['attr'=>'name,value,type','level'=>3,'alias'=>'in,notin,between,notbetween'],
|
||||
'empty' => ['attr'=>'name','level'=>3],
|
||||
'notempty' => ['attr'=>'name','level'=>3],
|
||||
'present' => ['attr'=>'name','level'=>3],
|
||||
'notpresent'=> ['attr'=>'name','level'=>3],
|
||||
'defined' => ['attr'=>'name','level'=>3],
|
||||
'notdefined'=> ['attr'=>'name','level'=>3],
|
||||
'import' => ['attr'=>'file,href,type,value,basepath','close'=>0,'alias'=>'load,css,js'],
|
||||
'assign' => ['attr'=>'name,value','close'=>0],
|
||||
'define' => ['attr'=>'name,value','close'=>0],
|
||||
'for' => ['attr'=>'start,end,name,comparison,step', 'level'=>3],
|
||||
];
|
||||
|
||||
/**
|
||||
* php标签解析
|
||||
* @access public
|
||||
* @param array $tag 标签属性
|
||||
* @param string $content 标签内容
|
||||
* @return string
|
||||
*/
|
||||
public function _php($tag,$content) {
|
||||
$parseStr = '<?php '.$content.' ?>';
|
||||
return $parseStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* volist标签解析 循环输出数据集
|
||||
* 格式:
|
||||
* <volist name="userList" id="user" empty="" >
|
||||
* {user.username}
|
||||
* {user.email}
|
||||
* </volist>
|
||||
* @access public
|
||||
* @param array $tag 标签属性
|
||||
* @param string $content 标签内容
|
||||
* @return string|void
|
||||
*/
|
||||
public function _volist($tag,$content) {
|
||||
$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';
|
||||
// 允许使用函数设定数据集 <volist name=":fun('arg')" id="vo">{$vo.name}</volist>
|
||||
$parseStr = '<?php ';
|
||||
if(0===strpos($name,':')) {
|
||||
$parseStr .= '$_result='.substr($name,1).';';
|
||||
$name = '$_result';
|
||||
}else{
|
||||
$name = $this->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 .= ($content);
|
||||
$parseStr .= '<?php endforeach; endif; else: echo "'.$empty.'" ;endif; ?>';
|
||||
|
||||
if(!empty($parseStr)) {
|
||||
return $parseStr;
|
||||
}
|
||||
return ;
|
||||
}
|
||||
|
||||
/**
|
||||
* foreach标签解析 循环输出数据集
|
||||
* @access public
|
||||
* @param array $tag 标签属性
|
||||
* @param string $content 标签内容
|
||||
* @return string|void
|
||||
*/
|
||||
public function _foreach($tag,$content) {
|
||||
$name = $tag['name'];
|
||||
$item = $tag['item'];
|
||||
$key = !empty($tag['key'])?$tag['key']:'key';
|
||||
$name = $this->autoBuildVar($name);
|
||||
$parseStr = '<?php if(is_array('.$name.')): foreach('.$name.' as $'.$key.'=>$'.$item.'): ?>';
|
||||
$parseStr .= ($content);
|
||||
$parseStr .= '<?php endforeach; endif; ?>';
|
||||
if(!empty($parseStr)) {
|
||||
return $parseStr;
|
||||
}
|
||||
return ;
|
||||
}
|
||||
|
||||
/**
|
||||
* if标签解析
|
||||
* 格式:
|
||||
* <if condition=" $a eq 1" >
|
||||
* <elseif condition="$a eq 2" />
|
||||
* <else />
|
||||
* </if>
|
||||
* 表达式支持 eq neq gt egt lt elt == > >= < <= or and || &&
|
||||
* @access public
|
||||
* @param array $tag 标签属性
|
||||
* @param string $content 标签内容
|
||||
* @return string
|
||||
*/
|
||||
public function _if($tag,$content) {
|
||||
$condition = $this->parseCondition($tag['condition']);
|
||||
$parseStr = '<?php if('.$condition.'): ?>'.$content.'<?php endif; ?>';
|
||||
return $parseStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* else标签解析
|
||||
* 格式:见if标签
|
||||
* @access public
|
||||
* @param array $tag 标签属性
|
||||
* @param string $content 标签内容
|
||||
* @return string
|
||||
*/
|
||||
public function _elseif($tag,$content) {
|
||||
$condition = $this->parseCondition($tag['condition']);
|
||||
$parseStr = '<?php elseif('.$condition.'): ?>';
|
||||
return $parseStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* else标签解析
|
||||
* @access public
|
||||
* @param array $tag 标签属性
|
||||
* @return string
|
||||
*/
|
||||
public function _else($tag) {
|
||||
$parseStr = '<?php else: ?>';
|
||||
return $parseStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* switch标签解析
|
||||
* 格式:
|
||||
* <switch name="a.name" >
|
||||
* <case value="1" break="false">1</case>
|
||||
* <case value="2" >2</case>
|
||||
* <default />other
|
||||
* </switch>
|
||||
* @access public
|
||||
* @param array $tag 标签属性
|
||||
* @param string $content 标签内容
|
||||
* @return string
|
||||
*/
|
||||
public function _switch($tag,$content) {
|
||||
$name = $tag['name'];
|
||||
$varArray = explode('|',$name);
|
||||
$name = array_shift($varArray);
|
||||
$name = $this->autoBuildVar($name);
|
||||
if(count($varArray)>0)
|
||||
$name = $this->parseVarFunction($name,$varArray);
|
||||
$parseStr = '<?php switch('.$name.'): ?>'.$content.'<?php endswitch;?>';
|
||||
return $parseStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* case标签解析 需要配合switch才有效
|
||||
* @access public
|
||||
* @param array $tag 标签属性
|
||||
* @param string $content 标签内容
|
||||
* @return string
|
||||
*/
|
||||
public function _case($tag,$content) {
|
||||
$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->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 = '<?php '.$value.' ?>'.$content;
|
||||
$isBreak = isset($tag['break']) ? $tag['break'] : '';
|
||||
if('' ==$isBreak || $isBreak) {
|
||||
$parseStr .= '<?php break;?>';
|
||||
}
|
||||
return $parseStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* default标签解析 需要配合switch才有效
|
||||
* 使用: <default />ddfdf
|
||||
* @access public
|
||||
* @param array $tag 标签属性
|
||||
* @param string $content 标签内容
|
||||
* @return string
|
||||
*/
|
||||
public function _default($tag) {
|
||||
$parseStr = '<?php default: ?>';
|
||||
return $parseStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* compare标签解析
|
||||
* 用于值的比较 支持 eq neq gt lt egt elt heq nheq 默认是eq
|
||||
* 格式: <compare name="" type="eq" value="" >content</compare>
|
||||
* @access public
|
||||
* @param array $tag 标签属性
|
||||
* @param string $content 标签内容
|
||||
* @return string
|
||||
*/
|
||||
public function _compare($tag,$content,$type='eq') {
|
||||
$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->parseVarFunction($name,$varArray);
|
||||
if('$' == substr($value,0,1)) {
|
||||
$value = $this->autoBuildVar(substr($value,1));
|
||||
}else {
|
||||
$value = '"'.$value.'"';
|
||||
}
|
||||
$parseStr = '<?php if(('.$name.') '.$type.' '.$value.'): ?>'.$content.'<?php endif; ?>';
|
||||
return $parseStr;
|
||||
}
|
||||
|
||||
public function _eq($tag,$content) {
|
||||
return $this->_compare($tag,$content,'eq');
|
||||
}
|
||||
|
||||
public function _equal($tag,$content) {
|
||||
return $this->_compare($tag,$content,'eq');
|
||||
}
|
||||
|
||||
public function _neq($tag,$content) {
|
||||
return $this->_compare($tag,$content,'neq');
|
||||
}
|
||||
|
||||
public function _notequal($tag,$content) {
|
||||
return $this->_compare($tag,$content,'neq');
|
||||
}
|
||||
|
||||
public function _gt($tag,$content) {
|
||||
return $this->_compare($tag,$content,'gt');
|
||||
}
|
||||
|
||||
public function _lt($tag,$content) {
|
||||
return $this->_compare($tag,$content,'lt');
|
||||
}
|
||||
|
||||
public function _egt($tag,$content) {
|
||||
return $this->_compare($tag,$content,'egt');
|
||||
}
|
||||
|
||||
public function _elt($tag,$content) {
|
||||
return $this->_compare($tag,$content,'elt');
|
||||
}
|
||||
|
||||
public function _heq($tag,$content) {
|
||||
return $this->_compare($tag,$content,'heq');
|
||||
}
|
||||
|
||||
public function _nheq($tag,$content) {
|
||||
return $this->_compare($tag,$content,'nheq');
|
||||
}
|
||||
|
||||
/**
|
||||
* range标签解析
|
||||
* 如果某个变量存在于某个范围 则输出内容 type= in 表示在范围内 否则表示在范围外
|
||||
* 格式: <range name="var|function" value="val" type='in|notin' >content</range>
|
||||
* example: <range name="a" value="1,2,3" type='in' >content</range>
|
||||
* @access public
|
||||
* @param array $tag 标签属性
|
||||
* @param string $content 标签内容
|
||||
* @param string $type 比较类型
|
||||
* @return string
|
||||
*/
|
||||
public function _range($tag,$content,$type='in') {
|
||||
$name = $tag['name'];
|
||||
$value = $tag['value'];
|
||||
$varArray = explode('|',$name);
|
||||
$name = array_shift($varArray);
|
||||
$name = $this->autoBuildVar($name);
|
||||
if(count($varArray)>0)
|
||||
$name = $this->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 = '<?php $_RANGE_VAR_='.$str.';if('.$name.'>= $_RANGE_VAR_[0] && '.$name.'<= $_RANGE_VAR_[1]):?>'.$content.'<?php endif; ?>';
|
||||
}elseif($type=='notbetween'){
|
||||
$parseStr = '<?php $_RANGE_VAR_='.$str.';if('.$name.'<$_RANGE_VAR_[0] || '.$name.'>$_RANGE_VAR_[1]):?>'.$content.'<?php endif; ?>';
|
||||
}else{
|
||||
$fun = ($type == 'in')? 'in_array' : '!in_array';
|
||||
$parseStr = '<?php if('.$fun.'(('.$name.'), '.$str.')): ?>'.$content.'<?php endif; ?>';
|
||||
}
|
||||
return $parseStr;
|
||||
}
|
||||
|
||||
// range标签的别名 用于in判断
|
||||
public function _in($tag,$content) {
|
||||
return $this->_range($tag,$content,'in');
|
||||
}
|
||||
|
||||
// range标签的别名 用于notin判断
|
||||
public function _notin($tag,$content) {
|
||||
return $this->_range($tag,$content,'notin');
|
||||
}
|
||||
|
||||
public function _between($tag,$content){
|
||||
return $this->_range($tag,$content,'between');
|
||||
}
|
||||
|
||||
public function _notbetween($tag,$content){
|
||||
return $this->_range($tag,$content,'notbetween');
|
||||
}
|
||||
|
||||
/**
|
||||
* present标签解析
|
||||
* 如果某个变量已经设置 则输出内容
|
||||
* 格式: <present name="" >content</present>
|
||||
* @access public
|
||||
* @param array $tag 标签属性
|
||||
* @param string $content 标签内容
|
||||
* @return string
|
||||
*/
|
||||
public function _present($tag,$content) {
|
||||
$name = $tag['name'];
|
||||
$name = $this->autoBuildVar($name);
|
||||
$parseStr = '<?php if(isset('.$name.')): ?>'.$content.'<?php endif; ?>';
|
||||
return $parseStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* notpresent标签解析
|
||||
* 如果某个变量没有设置,则输出内容
|
||||
* 格式: <notpresent name="" >content</notpresent>
|
||||
* @access public
|
||||
* @param array $tag 标签属性
|
||||
* @param string $content 标签内容
|
||||
* @return string
|
||||
*/
|
||||
public function _notpresent($tag,$content) {
|
||||
$name = $tag['name'];
|
||||
$name = $this->autoBuildVar($name);
|
||||
$parseStr = '<?php if(!isset('.$name.')): ?>'.$content.'<?php endif; ?>';
|
||||
return $parseStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* empty标签解析
|
||||
* 如果某个变量为empty 则输出内容
|
||||
* 格式: <empty name="" >content</empty>
|
||||
* @access public
|
||||
* @param array $tag 标签属性
|
||||
* @param string $content 标签内容
|
||||
* @return string
|
||||
*/
|
||||
public function _empty($tag,$content) {
|
||||
$name = $tag['name'];
|
||||
$name = $this->autoBuildVar($name);
|
||||
$parseStr = '<?php if(empty('.$name.')): ?>'.$content.'<?php endif; ?>';
|
||||
return $parseStr;
|
||||
}
|
||||
|
||||
public function _notempty($tag,$content) {
|
||||
$name = $tag['name'];
|
||||
$name = $this->autoBuildVar($name);
|
||||
$parseStr = '<?php if(!empty('.$name.')): ?>'.$content.'<?php endif; ?>';
|
||||
return $parseStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否已经定义了该常量
|
||||
* <defined name='TXT'>已定义</defined>
|
||||
* @param <type> $tag
|
||||
* @param <type> $content
|
||||
* @return string
|
||||
*/
|
||||
public function _defined($tag,$content) {
|
||||
$name = $tag['name'];
|
||||
$parseStr = '<?php if(defined("'.$name.'")): ?>'.$content.'<?php endif; ?>';
|
||||
return $parseStr;
|
||||
}
|
||||
|
||||
public function _notdefined($tag,$content) {
|
||||
$name = $tag['name'];
|
||||
$parseStr = '<?php if(!defined("'.$name.'")): ?>'.$content.'<?php endif; ?>';
|
||||
return $parseStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* import 标签解析 <import file="Js.Base" />
|
||||
* <import file="Css.Base" type="css" />
|
||||
* @access public
|
||||
* @param array $tag 标签属性
|
||||
* @param string $content 标签内容
|
||||
* @param boolean $isFile 是否文件方式
|
||||
* @param string $type 类型
|
||||
* @return string
|
||||
*/
|
||||
public function _import($tag,$content,$isFile=false,$type='') {
|
||||
$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->parseVarFunction($name,$varArray);
|
||||
else
|
||||
$name = 'isset('.$name.')';
|
||||
$parseStr .= '<?php if('.$name.'): ?>';
|
||||
$endStr = '<?php endif; ?>';
|
||||
}
|
||||
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 .= '<script type="text/javascript" src="'.$val.'"></script>';
|
||||
break;
|
||||
case 'css':
|
||||
$parseStr .= '<link rel="stylesheet" type="text/css" href="'.$val.'" />';
|
||||
break;
|
||||
case 'php':
|
||||
$parseStr .= '<?php require_cache("'.$val.'"); ?>';
|
||||
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 .= '<script type="text/javascript" src="'.$basepath.'/'.str_replace(['.','#'], ['/','.'],$val).'.js'.($version?'?'.$version:'').'"></script>';
|
||||
break;
|
||||
case 'css':
|
||||
$parseStr .= '<link rel="stylesheet" type="text/css" href="'.$basepath.'/'.str_replace(['.','#'], ['/','.'],$val).'.css'.($version?'?'.$version:'').'" />';
|
||||
break;
|
||||
case 'php':
|
||||
$parseStr .= '<?php import("'.$val.'"); ?>';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $parseStr.$endStr;
|
||||
}
|
||||
|
||||
// import别名 采用文件方式加载(要使用命名空间必须用import) 例如 <load file="__PUBLIC__/Js/Base.js" />
|
||||
public function _load($tag,$content) {
|
||||
return $this->_import($tag,$content,true);
|
||||
}
|
||||
|
||||
// import别名使用 导入css文件 <css file="__PUBLIC__/Css/Base.css" />
|
||||
public function _css($tag,$content) {
|
||||
return $this->_import($tag,$content,true,'css');
|
||||
}
|
||||
|
||||
// import别名使用 导入js文件 <js file="__PUBLIC__/Js/Base.js" />
|
||||
public function _js($tag,$content) {
|
||||
return $this->_import($tag,$content,true,'js');
|
||||
}
|
||||
|
||||
/**
|
||||
* assign标签解析
|
||||
* 在模板中给某个变量赋值 支持变量赋值
|
||||
* 格式: <assign name="" value="" />
|
||||
* @access public
|
||||
* @param array $tag 标签属性
|
||||
* @param string $content 标签内容
|
||||
* @return string
|
||||
*/
|
||||
public function _assign($tag,$content) {
|
||||
$name = $this->autoBuildVar($tag['name']);
|
||||
if('$'==substr($tag['value'],0,1)) {
|
||||
$value = $this->autoBuildVar(substr($tag['value'],1));
|
||||
}else{
|
||||
$value = '\''.$tag['value']. '\'';
|
||||
}
|
||||
$parseStr = '<?php '.$name.' = '.$value.'; ?>';
|
||||
return $parseStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* define标签解析
|
||||
* 在模板中定义常量 支持变量赋值
|
||||
* 格式: <define name="" value="" />
|
||||
* @access public
|
||||
* @param array $tag 标签属性
|
||||
* @param string $content 标签内容
|
||||
* @return string
|
||||
*/
|
||||
public function _define($tag,$content) {
|
||||
$name = '\''.$tag['name']. '\'';
|
||||
if('$'==substr($tag['value'],0,1)) {
|
||||
$value = $this->autoBuildVar(substr($tag['value'],1));
|
||||
}else{
|
||||
$value = '\''.$tag['value']. '\'';
|
||||
}
|
||||
$parseStr = '<?php define('.$name.', '.$value.'); ?>';
|
||||
return $parseStr;
|
||||
}
|
||||
|
||||
/**
|
||||
* for标签解析
|
||||
* 格式: <for start="" end="" comparison="" step="" name="" />
|
||||
* @access public
|
||||
* @param array $tag 标签属性
|
||||
* @param string $content 标签内容
|
||||
* @return string
|
||||
*/
|
||||
public function _for($tag, $content){
|
||||
//设置默认值
|
||||
$start = 0;
|
||||
$end = 0;
|
||||
$step = 1;
|
||||
$comparison = 'lt';
|
||||
$name = 'i';
|
||||
$rand = rand(); //添加随机数,防止嵌套变量冲突
|
||||
//获取属性
|
||||
foreach ($tag 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 = '<?php $__FOR_START_'.$rand.'__='.$start.';$__FOR_END_'.$rand.'__='.$end.';';
|
||||
$parseStr .= 'for($'.$name.'=$__FOR_START_'.$rand.'__;'.$this->parseCondition('$'.$name.' '.$comparison.' $__FOR_END_'.$rand.'__').';$'.$name.'+='.$step.'){ ?>';
|
||||
$parseStr .= $content;
|
||||
$parseStr .= '<?php } ?>';
|
||||
return $parseStr;
|
||||
}
|
||||
|
||||
}
|
||||
151
Library/Think/Url.php
Normal file
151
Library/Think/Url.php
Normal file
@@ -0,0 +1,151 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | TOPThink [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2011 http://topthink.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
// $Id$
|
||||
|
||||
namespace Think;
|
||||
class Url {
|
||||
|
||||
static public function param($num,$default=''){
|
||||
$paths = explode(Config::get('url_pathinfo_depr'),trim($_SERVER['PATH_INFO'],'/'));
|
||||
return isset($paths[$num])?$paths[$num]:$default;
|
||||
}
|
||||
|
||||
static public function route($route){
|
||||
}
|
||||
|
||||
/**
|
||||
* URL组装 支持不同URL模式
|
||||
* @param string $url URL表达式,格式:'[分组/模块/操作#锚点@域名]?参数1=值1&参数2=值2...'
|
||||
* @param string|array $vars 传入的参数,支持数组和字符串
|
||||
* @param string $suffix 伪静态后缀,默认为true表示获取配置值
|
||||
* @param boolean $domain 是否显示域名
|
||||
* @return string
|
||||
*/
|
||||
static public function build($url='',$vars='',$suffix=true,$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(Config::get('app_sub_domain_deplay') ) { // 开启子域名部署
|
||||
$domain = $domain=='localhost'?'localhost':'www'.strstr($_SERVER['HTTP_HOST'],'.');
|
||||
// '子域名'=>array('项目[/分组]');
|
||||
foreach (Config::get('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 = [];
|
||||
}
|
||||
if(isset($info['query'])) { // 解析地址里面参数 合并到vars
|
||||
parse_str($info['query'],$params);
|
||||
$vars = array_merge($params,$vars);
|
||||
}
|
||||
|
||||
// URL组装
|
||||
$depr = Config::get('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 = [];
|
||||
$var[Config::get('var_action')] = !empty($path)?array_pop($path):ACTION_NAME;
|
||||
if(Config::get('require_controller')) {
|
||||
$var[Config::get('var_controller')] = !empty($path)?array_pop($path):CONTROLLER_NAME;
|
||||
}
|
||||
if(Config::get('require_module')) {
|
||||
$var[Config::get('var_module')] = !empty($path)?array_pop($path):MODULE_NAME;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(Config::get('url_model') == 0) { // 普通模式URL转换
|
||||
$url = Config::get('base_url').'?'.http_build_query(array_reverse($var));
|
||||
if(!empty($vars)) {
|
||||
$vars = urldecode(http_build_query($vars));
|
||||
$url .= '&'.$vars;
|
||||
}
|
||||
}else{ // PATHINFO模式或者兼容URL模式
|
||||
if(isset($route)) {
|
||||
$url = Config::get('base_url').'/'.rtrim($url,$depr);
|
||||
}else{
|
||||
$url = Config::get('base_url').'/'.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?Config::get('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 = (self::is_ssl()?'https://':'http://').$domain.$url;
|
||||
}
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否SSL协议
|
||||
* @return boolean
|
||||
*/
|
||||
static public 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;
|
||||
}
|
||||
}
|
||||
188
Library/Think/Validate.php
Normal file
188
Library/Think/Validate.php
Normal file
@@ -0,0 +1,188 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | TOPThink [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2011 http://topthink.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
// $Id$
|
||||
namespace Think;
|
||||
class Validate {
|
||||
|
||||
protected $validate = []; // 自动验证定义
|
||||
// 是否批处理验证
|
||||
protected $patchValidate = false;
|
||||
protected $error = '';
|
||||
|
||||
public function rule($rule){
|
||||
$this->validate = $rule;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getError(){
|
||||
return $this->error;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动表单验证
|
||||
* @access protected
|
||||
* @param array $data 创建数据
|
||||
* @param string $type 创建类型
|
||||
* @return boolean
|
||||
*/
|
||||
public function valid($data,$rule=[]) {
|
||||
$validate = $rule?$rule:$this->validate;
|
||||
// 属性验证
|
||||
if($validate) { // 如果设置了数据自动验证则进行数据验证
|
||||
if($this->patchValidate) { // 重置验证错误信息
|
||||
$this->error = [];
|
||||
}
|
||||
foreach($validate as $key=>$val) {
|
||||
// 验证因子定义格式
|
||||
// array(field,rule,message,condition,type,params)
|
||||
// 判断是否需要执行验证
|
||||
if(0==strpos($val[2],'{%') && strpos($val[2],'}'))
|
||||
// 支持提示信息的多语言 使用 {%语言定义} 方式
|
||||
$val[2] = L(substr($val[2],2,-1));
|
||||
$val[3] = isset($val[3])?$val[3]:0;
|
||||
$val[4] = isset($val[4])?$val[4]:'regex';
|
||||
// 判断验证条件
|
||||
if( 1 == $val[3] || (2 == $val[3] && '' != trim($data[$val[0]])) || (0 == $val[3] && 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 'callback':// 调用方法进行验证
|
||||
$args = isset($val[5])?(array)$val[5]:[];
|
||||
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]]);
|
||||
}
|
||||
return call_user_func_array($val[1], $args);
|
||||
case 'confirm': // 验证两个字段是否相同
|
||||
return $data[$val[0]] == $data[$val[1]];
|
||||
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($_SERVER['REMOTE_ADDR'],explode(',',$rule));
|
||||
case 'ip_deny': // IP 操作禁止验证
|
||||
return !in_array($_SERVER['REMOTE_ADDR'],explode(',',$rule));
|
||||
case 'regex':
|
||||
default: // 默认使用正则验证 可以使用验证类中定义的验证名称
|
||||
// 检查附加规则
|
||||
return $this->regex($value,$rule);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用正则验证数据
|
||||
* @access public
|
||||
* @param string $value 要验证的数据
|
||||
* @param string $rule 验证规则
|
||||
* @return boolean
|
||||
*/
|
||||
public function regex($value,$rule) {
|
||||
$validate = [
|
||||
'require' => '/.+/',
|
||||
'email' => '/^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/',
|
||||
'url' => '/^http(s?):\/\/(?:[A-za-z0-9-]+\.)+[A-za-z]{2,4}(?:[\/\?#][\/=\?%\-&~`@[\]\':+!\.#\w]*)?$/',
|
||||
'currency' => '/^\d+(\.\d+)?$/',
|
||||
'number' => '/^\d+$/',
|
||||
'zip' => '/^\d{6}$/',
|
||||
'integer' => '/^[-\+]?\d+$/',
|
||||
'double' => '/^[-\+]?\d+(\.\d+)?$/',
|
||||
'english' => '/^[A-Za-z]+$/',
|
||||
];
|
||||
// 检查是否有内置的正则表达式
|
||||
if(isset($validate[strtolower($rule)]))
|
||||
$rule = $validate[strtolower($rule)];
|
||||
return preg_match($rule,$value)===1;
|
||||
}
|
||||
}
|
||||
229
Library/Think/View.php
Normal file
229
Library/Think/View.php
Normal file
@@ -0,0 +1,229 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | TOPThink [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2011 http://topthink.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
// $Id$
|
||||
namespace Think;
|
||||
class View {
|
||||
|
||||
protected $engine = null; // 模板引擎实例
|
||||
protected $theme = ''; // 模板主题名称
|
||||
protected $data = []; // 模板变量
|
||||
protected $config = [ // 视图参数
|
||||
'http_output_content' => true,
|
||||
'http_content_type' => 'text/html',
|
||||
'http_charset' => 'utf-8',
|
||||
'http_cache_control' => 'private',
|
||||
'http_render_content' => false,
|
||||
'theme_on' => false,
|
||||
'auto_detect_theme' => false,
|
||||
'var_theme' => 't',
|
||||
'default_theme' => 'default',
|
||||
'http_cache_id' => null,
|
||||
'view_path' => '',
|
||||
'view_suffix' => '.html',
|
||||
|
||||
];
|
||||
|
||||
/**
|
||||
* 模板变量赋值
|
||||
* @access public
|
||||
* @param mixed $name
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function assign($name,$value=''){
|
||||
if(is_array($name)) {
|
||||
$this->data = array_merge($this->data,$name);
|
||||
return $this;
|
||||
}else {
|
||||
$this->data[$name] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 视图参数设置
|
||||
* @access public
|
||||
* @param mixed $name
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function __set($name,$value=''){
|
||||
$this->config[$name] = $value;
|
||||
}
|
||||
|
||||
public function __construct(array $config=[]){
|
||||
$this->config = array_merge($this->config,$config);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置当前模板解析的引擎
|
||||
* @access public
|
||||
* @param string $engine 引擎名称
|
||||
* @param array $config 引擎参数
|
||||
* @return View
|
||||
*/
|
||||
public function engine($engine,$config=[]){
|
||||
$class = '\\Think\\View\\Driver\\'.ucwords($engine);
|
||||
$this->engine = new $class($config);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置当前输出的模板主题
|
||||
* @access public
|
||||
* @param mixed $theme 主题名称
|
||||
* @return View
|
||||
*/
|
||||
public function theme($theme){
|
||||
if(true === $theme) { // 自动侦测
|
||||
$this->config['theme_on'] = true;
|
||||
$this->config['auto_detect_theme'] = true;
|
||||
}elseif(false === $theme){ // 关闭主题
|
||||
$this->config['theme_on'] = false;
|
||||
}else{ // 指定模板主题
|
||||
$this->config['theme_on'] = true;
|
||||
$this->theme = $theme;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载模板和页面输出 可以返回输出内容
|
||||
* @access public
|
||||
* @param string $template 模板文件名
|
||||
* @param array $vars 模板输出变量
|
||||
* @param string $cacheId 模板缓存标识
|
||||
* @return mixed
|
||||
*/
|
||||
public function display($template='',$vars=[],$cacheId='') {
|
||||
Tag::listen('view_begin',$template);
|
||||
// 解析并获取模板内容
|
||||
$content = $this->fetch($template,$vars,$cacheId);
|
||||
// 输出内容过滤
|
||||
Tag::listen('view_filter',$content);
|
||||
// 输出模板内容
|
||||
if($this->config['http_output_content']) {
|
||||
$this->render($content);
|
||||
}else{ // 返回解析后的内容
|
||||
return $content;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析和获取模板内容 用于输出
|
||||
* @access protected
|
||||
* @param string $template 模板文件名或者内容
|
||||
* @param array $vars 模板输出变量
|
||||
* @param string $cacheId 模板缓存标识
|
||||
* @return string
|
||||
*/
|
||||
protected function fetch($template,$vars=[],$cacheId='') {
|
||||
if(!$this->config['http_render_content']) {
|
||||
$template = $this->parseTemplate($template);
|
||||
// 模板不存在 抛出异常
|
||||
if(!is_file($template))
|
||||
E('template file not exists:'.$template);
|
||||
}
|
||||
$vars = $vars?$vars:$this->data;
|
||||
// 页面缓存
|
||||
ob_start();
|
||||
ob_implicit_flush(0);
|
||||
if($this->engine) { // 指定模板引擎
|
||||
$this->engine->fetch($template,$vars,$cacheId);
|
||||
}else{ // 原生PHP解析
|
||||
extract($vars, EXTR_OVERWRITE);
|
||||
is_file($template)?include $template:eval('?>'.$template);
|
||||
}
|
||||
// 获取并清空缓存
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动定位模板文件
|
||||
* @access private
|
||||
* @param string $template 模板文件规则
|
||||
* @return string
|
||||
*/
|
||||
private function parseTemplate($template) {
|
||||
if(is_file($template)) {
|
||||
return $template;
|
||||
}
|
||||
$template = str_replace(':','/',$template);
|
||||
// 获取当前主题名称
|
||||
$theme = $this->getTemplateTheme();
|
||||
// 分析模板文件规则
|
||||
if(''==$template) {
|
||||
// 如果模板文件名为空 按照默认规则定位
|
||||
$template = CONTROLLER_NAME.'/'.ACTION_NAME;
|
||||
}elseif(false === strpos($template,'/')){
|
||||
$template = CONTROLLER_NAME.'/'.$template;
|
||||
}
|
||||
return ($this->config['view_path']?$this->config['view_path']:MODULE_PATH.'View/').$theme.$template.$this->config['view_suffix'];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前的模板主题
|
||||
* @access private
|
||||
* @return string
|
||||
*/
|
||||
private function getTemplateTheme() {
|
||||
if($this->config['theme_on']) {
|
||||
if($this->theme) { // 指定模板主题
|
||||
$theme = $this->theme;
|
||||
}elseif($this->config['auto_detect_theme']){
|
||||
// 自动侦测模板主题
|
||||
$t = $this->config['var_theme'];
|
||||
if (isset($_GET[$t])){
|
||||
$theme = $_GET[$t];
|
||||
}elseif(Cookie::get('think_theme')){
|
||||
$theme = Cookie::get('think_theme');
|
||||
}
|
||||
if(!is_dir(MODULE_PATH.'View/'.$theme)) {
|
||||
$theme = $this->config['default_theme'];
|
||||
}
|
||||
Cookie::set('think_theme',$theme,864000);
|
||||
}else{
|
||||
$theme = $this->config['default_theme'];
|
||||
}
|
||||
return $theme.'/';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* 视图输出参数设置
|
||||
* @access public
|
||||
* @param mixed $config
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function http($config=[],$value=''){
|
||||
if(is_array($config)) {
|
||||
$this->config = array_merge($this->config,$config);
|
||||
}else{
|
||||
$this->config[$config] = $value;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 输出内容文本可以包括Html
|
||||
* @access private
|
||||
* @param string $content 输出内容
|
||||
* @param string $charset 模板输出字符集
|
||||
* @param string $contentType 输出类型
|
||||
* @return mixed
|
||||
*/
|
||||
private function render($content){
|
||||
// 网页字符编码
|
||||
header('Content-Type:'.$this->config['http_content_type'].'; charset='.$this->config['http_charset']);
|
||||
header('Cache-control: '.$this->config['http_cache_control']); // 页面缓存控制
|
||||
header('X-Powered-By:ThinkPHP');
|
||||
// 输出模板文件
|
||||
echo $content;
|
||||
}
|
||||
}
|
||||
27
Library/Think/View/Driver/Think.php
Normal file
27
Library/Think/View/Driver/Think.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
// +----------------------------------------------------------------------
|
||||
// | TOPThink [ WE CAN DO IT JUST THINK ]
|
||||
// +----------------------------------------------------------------------
|
||||
// | Copyright (c) 2011 http://topthink.com All rights reserved.
|
||||
// +----------------------------------------------------------------------
|
||||
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
|
||||
// +----------------------------------------------------------------------
|
||||
// | Author: liu21st <liu21st@gmail.com>
|
||||
// +----------------------------------------------------------------------
|
||||
// $Id$
|
||||
namespace Think\View\Driver;
|
||||
use Think\Template;
|
||||
class Think {
|
||||
private $template = null;
|
||||
public function __construct($config=[]){
|
||||
$this->template = new Template($config);
|
||||
}
|
||||
|
||||
public function fetch($template,$data=[],$cacheId=''){
|
||||
if(is_file($template)) {
|
||||
$this->template->display($template,$data,$cacheId);
|
||||
}else{
|
||||
$this->template->fetch($template,$data);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user