部分类库从Think命名空间移到Org

Think目录移入Library目录
This commit is contained in:
ThinkPHP
2013-04-14 19:28:21 +08:00
parent 095308ae51
commit 732a694846
87 changed files with 52 additions and 57 deletions

228
Library/Think/App.php Normal file
View 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
View 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;
}
}

View 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;
}
}

View 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;
}
}

View 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);
}
}

View 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();
}
}

View 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
View 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);
}
}

View 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();
}
}

View 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'].'`');
}
}

View 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 ;
}
}

View 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;
}
}
}

View 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();
}
}

View 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();
}
}

View 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);
}
}

View 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));
}
}

View 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 ;
}
}

View 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 ;
}
}

View 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
View 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; // 避免非法参数
}
}

View 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);
}
}
}

View 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;
}
}

View 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 ;
}
}
}

View 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 ;
}
}

View 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();
}
}

View 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
View 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
View 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
View 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&param2=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
View 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();
}
}

View 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;
}
}

View 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 ';
}
}

View 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;
}
}

View 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;
}
}

View 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
View 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
View 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
View 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;
}
}

View 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
View 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>'], ['&lt;textarea>','&lt;/textarea>'], $string);
}
/**
* 将数据中的单引号和双引号进行转义
* @access public
* @param string $text 要处理的字符串
* @return string
*/
static public function forTag($string) {
return str_replace(['"',"'"], ['&quot;','&#039;'], $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(["/&amp;/i", "/&nbsp;/i"], ['&', '&amp;nbsp;'], htmlspecialchars($string, ENT_QUOTES));
}
/**
* 是hsc()方法的逆操作
* @access public
* @param string $text 要处理的字符串
* @return string
*/
static function undoHsc($text) {
return preg_replace(["/&gt;/i", "/&lt;/i", "/&quot;/i", "/&#039;/i", '/&amp;nbsp;/i'], [">", "<", "\"", "'", "&nbsp;"], $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('[','&#091;',$text);
$text = str_replace(']','&#093;',$text);
$text = str_replace('|','&#124;',$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('<','&lt;',$text);
$text = str_replace('>','&gt;',$text);
$text = str_replace('"','&quot;',$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
View 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
View 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
View 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
View 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);
}
}

View 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

File diff suppressed because it is too large Load Diff

View 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
View 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);
}
}
}

View 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
View 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
View 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
View 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;
}
}
}

View 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;
}
}

View 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;
}
}

View 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
View 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
View 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
View 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;
}
}

View 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);
}
}
}