1
0
mirror of https://e.coding.net/circlecloud/MinecraftAccount.git synced 2025-11-26 21:46:09 +00:00

首次提交...

Signed-off-by: j502647092 <jtb1@163.com>
This commit is contained in:
j502647092
2015-11-01 22:25:03 +08:00
commit 2003fda7cb
409 changed files with 77938 additions and 0 deletions

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,231 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2011 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: luofei614 <weibo.com/luofei614> 
// +----------------------------------------------------------------------
namespace Think;
/**
* 权限认证类
* 功能特性:
* 1是对规则进行认证不是对节点进行认证。用户可以把节点当作规则名称实现对节点进行认证。
* $auth=new Auth(); $auth->check('规则名称','用户id')
* 2可以同时对多条规则进行认证并设置多条规则的关系or或者and
* $auth=new Auth(); $auth->check('规则1,规则2','用户id','and')
* 第三个参数为and时表示用户需要同时具有规则1和规则2的权限。 当第三个参数为or时表示用户值需要具备其中一个条件即可。默认为or
* 3一个用户可以属于多个用户组(think_auth_group_access表 定义了用户所属用户组)。我们需要设置每个用户组拥有哪些规则(think_auth_group 定义了用户组权限)
*
* 4支持规则表达式。
* 在think_auth_rule 表中定义一条规则时如果type为1 condition字段就可以定义规则表达式。 如定义{score}>5 and {score}<100 表示用户的分数在5-100之间时这条规则才会通过。
*/
//数据库
/*
-- ----------------------------
-- think_auth_rule规则表
-- id:主键name规则唯一标识, title规则中文名称 status 状态为1正常为0禁用condition规则表达式为空表示存在就验证不为空表示按照条件验证
-- ----------------------------
DROP TABLE IF EXISTS `think_auth_rule`;
CREATE TABLE `think_auth_rule` (
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
`name` char(80) NOT NULL DEFAULT '',
`title` char(20) NOT NULL DEFAULT '',
`type` tinyint(1) NOT NULL DEFAULT '1',
`status` tinyint(1) NOT NULL DEFAULT '1',
`condition` char(100) NOT NULL DEFAULT '', # 规则附件条件,满足附加条件的规则,才认为是有效的规则
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- ----------------------------
-- think_auth_group 用户组表,
-- id主键 title:用户组中文名称, rules用户组拥有的规则id 多个规则","隔开status 状态为1正常为0禁用
-- ----------------------------
DROP TABLE IF EXISTS `think_auth_group`;
CREATE TABLE `think_auth_group` (
`id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
`title` char(100) NOT NULL DEFAULT '',
`status` tinyint(1) NOT NULL DEFAULT '1',
`rules` char(80) NOT NULL DEFAULT '',
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
-- ----------------------------
-- think_auth_group_access 用户组明细表
-- uid:用户idgroup_id用户组id
-- ----------------------------
DROP TABLE IF EXISTS `think_auth_group_access`;
CREATE TABLE `think_auth_group_access` (
`uid` mediumint(8) unsigned NOT NULL,
`group_id` mediumint(8) unsigned NOT NULL,
UNIQUE KEY `uid_group_id` (`uid`,`group_id`),
KEY `uid` (`uid`),
KEY `group_id` (`group_id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
*/
class Auth{
//默认配置
protected $_config = array(
'AUTH_ON' => true, // 认证开关
'AUTH_TYPE' => 1, // 认证方式1为实时认证2为登录认证。
'AUTH_GROUP' => 'auth_group', // 用户组数据表名
'AUTH_GROUP_ACCESS' => 'auth_group_access', // 用户-用户组关系表
'AUTH_RULE' => 'auth_rule', // 权限规则表
'AUTH_USER' => 'member' // 用户信息表
);
public function __construct() {
$prefix = C('DB_PREFIX');
$this->_config['AUTH_GROUP'] = $prefix.$this->_config['AUTH_GROUP'];
$this->_config['AUTH_RULE'] = $prefix.$this->_config['AUTH_RULE'];
$this->_config['AUTH_USER'] = $prefix.$this->_config['AUTH_USER'];
$this->_config['AUTH_GROUP_ACCESS'] = $prefix.$this->_config['AUTH_GROUP_ACCESS'];
if (C('AUTH_CONFIG')) {
//可设置配置项 AUTH_CONFIG, 此配置项为数组。
$this->_config = array_merge($this->_config, C('AUTH_CONFIG'));
}
}
/**
* 检查权限
* @param name string|array 需要验证的规则列表,支持逗号分隔的权限规则或索引数组
* @param uid int 认证用户的id
* @param string mode 执行check的模式
* @param relation string 如果为 'or' 表示满足任一条规则即通过验证;如果为 'and'则表示需满足所有规则才能通过验证
* @return boolean 通过验证返回true;失败返回false
*/
public function check($name, $uid, $type=1, $mode='url', $relation='or') {
if (!$this->_config['AUTH_ON'])
return true;
$authList = $this->getAuthList($uid,$type); //获取用户需要验证的所有有效规则列表
if (is_string($name)) {
$name = strtolower($name);
if (strpos($name, ',') !== false) {
$name = explode(',', $name);
} else {
$name = array($name);
}
}
$list = array(); //保存验证通过的规则名
if ($mode=='url') {
$REQUEST = unserialize( strtolower(serialize($_REQUEST)) );
}
foreach ( $authList as $auth ) {
$query = preg_replace('/^.+\?/U','',$auth);
if ($mode=='url' && $query!=$auth ) {
parse_str($query,$param); //解析规则中的param
$intersect = array_intersect_assoc($REQUEST,$param);
$auth = preg_replace('/\?.*$/U','',$auth);
if ( in_array($auth,$name) && $intersect==$param ) { //如果节点相符且url参数满足
$list[] = $auth ;
}
}else if (in_array($auth , $name)){
$list[] = $auth ;
}
}
if ($relation == 'or' and !empty($list)) {
return true;
}
$diff = array_diff($name, $list);
if ($relation == 'and' and empty($diff)) {
return true;
}
return false;
}
/**
* 根据用户id获取用户组,返回值为数组
* @param uid int 用户id
* @return array 用户所属的用户组 array(
* array('uid'=>'用户id','group_id'=>'用户组id','title'=>'用户组名称','rules'=>'用户组拥有的规则id,多个,号隔开'),
* ...)
*/
public function getGroups($uid) {
static $groups = array();
if (isset($groups[$uid]))
return $groups[$uid];
$user_groups = M()
->table($this->_config['AUTH_GROUP_ACCESS'] . ' a')
->where("a.uid='$uid' and g.status='1'")
->join($this->_config['AUTH_GROUP']." g on a.group_id=g.id")
->field('uid,group_id,title,rules')->select();
$groups[$uid]=$user_groups?:array();
return $groups[$uid];
}
/**
* 获得权限列表
* @param integer $uid 用户id
* @param integer $type
*/
protected function getAuthList($uid,$type) {
static $_authList = array(); //保存用户验证通过的权限列表
$t = implode(',',(array)$type);
if (isset($_authList[$uid.$t])) {
return $_authList[$uid.$t];
}
if( $this->_config['AUTH_TYPE']==2 && isset($_SESSION['_AUTH_LIST_'.$uid.$t])){
return $_SESSION['_AUTH_LIST_'.$uid.$t];
}
//读取用户所属用户组
$groups = $this->getGroups($uid);
$ids = array();//保存用户所属用户组设置的所有权限规则id
foreach ($groups as $g) {
$ids = array_merge($ids, explode(',', trim($g['rules'], ',')));
}
$ids = array_unique($ids);
if (empty($ids)) {
$_authList[$uid.$t] = array();
return array();
}
$map=array(
'id'=>array('in',$ids),
'type'=>$type,
'status'=>1,
);
//读取用户组所有权限规则
$rules = M()->table($this->_config['AUTH_RULE'])->where($map)->field('condition,name')->select();
//循环规则,判断结果。
$authList = array(); //
foreach ($rules as $rule) {
if (!empty($rule['condition'])) { //根据condition进行验证
$user = $this->getUserInfo($uid);//获取用户信息,一维数组
$command = preg_replace('/\{(\w*?)\}/', '$user[\'\\1\']', $rule['condition']);
//dump($command);//debug
@(eval('$condition=(' . $command . ');'));
if ($condition) {
$authList[] = strtolower($rule['name']);
}
} else {
//只要存在就记录
$authList[] = strtolower($rule['name']);
}
}
$_authList[$uid.$t] = $authList;
if($this->_config['AUTH_TYPE']==2){
//规则列表结果保存到session
$_SESSION['_AUTH_LIST_'.$uid.$t]=$authList;
}
return array_unique($authList);
}
/**
* 获得用户资料,根据自己的情况读取数据库
*/
protected function getUserInfo($uid) {
static $userinfo=array();
if(!isset($userinfo[$uid])){
$userinfo[$uid]=M()->where(array('uid'=>$uid))->table($this->_config['AUTH_USER'])->find();
}
return $userinfo[$uid];
}
}

View File

@@ -0,0 +1,24 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
namespace Think;
/**
* ThinkPHP Behavior基础类
*/
abstract class Behavior {
/**
* 执行行为 run方法是Behavior唯一的接口
* @access public
* @param mixed $params 行为参数
* @return void
*/
abstract public function run(&$params);
}

View File

@@ -0,0 +1,165 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
namespace Think;
/**
* 用于ThinkPHP的自动生成
*/
class Build {
static protected $controller = '<?php
namespace [MODULE]\Controller;
use Think\Controller;
class [CONTROLLER]Controller extends Controller {
public function index(){
$this->show(\'<style type="text/css">*{ padding: 0; margin: 0; } div{ padding: 4px 48px;} body{ background: #fff; font-family: "微软雅黑"; color: #333;font-size:24px} h1{ font-size: 100px; font-weight: normal; margin-bottom: 12px; } p{ line-height: 1.8em; font-size: 36px } a,a:hover{color:blue;}</style><div style="padding: 24px 48px;"> <h1>:)</h1><p>欢迎使用 <b>ThinkPHP</b></p><br/>版本 V{$Think.version}</div><script type="text/javascript" src="http://ad.topthink.com/Public/static/client.js"></script><thinkad id="ad_55e75dfae343f5a1"></thinkad><script type="text/javascript" src="http://tajs.qq.com/stats?sId=9347272" charset="UTF-8"></script>\',\'utf-8\');
}
}';
static protected $model = '<?php
namespace [MODULE]\Model;
use Think\Model;
class [MODEL]Model extends Model {
}';
// 检测应用目录是否需要自动创建
static public function checkDir($module){
if(!is_dir(APP_PATH.$module)) {
// 创建模块的目录结构
self::buildAppDir($module);
}elseif(!is_dir(LOG_PATH)){
// 检查缓存目录
self::buildRuntime();
}
}
// 创建应用和模块的目录结构
static public function buildAppDir($module) {
// 没有创建的话自动创建
if(!is_dir(APP_PATH)) mkdir(APP_PATH,0755,true);
if(is_writeable(APP_PATH)) {
$dirs = array(
COMMON_PATH,
COMMON_PATH.'Common/',
CONF_PATH,
APP_PATH.$module.'/',
APP_PATH.$module.'/Common/',
APP_PATH.$module.'/Controller/',
APP_PATH.$module.'/Model/',
APP_PATH.$module.'/Conf/',
APP_PATH.$module.'/View/',
RUNTIME_PATH,
CACHE_PATH,
CACHE_PATH.$module.'/',
LOG_PATH,
LOG_PATH.$module.'/',
TEMP_PATH,
DATA_PATH,
);
foreach ($dirs as $dir){
if(!is_dir($dir)) mkdir($dir,0755,true);
}
// 写入目录安全文件
self::buildDirSecure($dirs);
// 写入应用配置文件
if(!is_file(CONF_PATH.'config'.CONF_EXT))
file_put_contents(CONF_PATH.'config'.CONF_EXT,'.php' == CONF_EXT ? "<?php\nreturn array(\n\t//'配置项'=>'配置值'\n);":'');
// 写入模块配置文件
if(!is_file(APP_PATH.$module.'/Conf/config'.CONF_EXT))
file_put_contents(APP_PATH.$module.'/Conf/config'.CONF_EXT,'.php' == CONF_EXT ? "<?php\nreturn array(\n\t//'配置项'=>'配置值'\n);":'');
// 生成模块的测试控制器
if(defined('BUILD_CONTROLLER_LIST')){
// 自动生成的控制器列表(注意大小写)
$list = explode(',',BUILD_CONTROLLER_LIST);
foreach($list as $controller){
self::buildController($module,$controller);
}
}else{
// 生成默认的控制器
self::buildController($module);
}
// 生成模块的模型
if(defined('BUILD_MODEL_LIST')){
// 自动生成的控制器列表(注意大小写)
$list = explode(',',BUILD_MODEL_LIST);
foreach($list as $model){
self::buildModel($module,$model);
}
}
}else{
header('Content-Type:text/html; charset=utf-8');
exit('应用目录['.APP_PATH.']不可写,目录无法自动生成!<BR>请手动生成项目目录~');
}
}
// 检查缓存目录(Runtime) 如果不存在则自动创建
static public function buildRuntime() {
if(!is_dir(RUNTIME_PATH)) {
mkdir(RUNTIME_PATH);
}elseif(!is_writeable(RUNTIME_PATH)) {
header('Content-Type:text/html; charset=utf-8');
exit('目录 [ '.RUNTIME_PATH.' ] 不可写!');
}
mkdir(CACHE_PATH); // 模板缓存目录
if(!is_dir(LOG_PATH)) mkdir(LOG_PATH); // 日志目录
if(!is_dir(TEMP_PATH)) mkdir(TEMP_PATH); // 数据缓存目录
if(!is_dir(DATA_PATH)) mkdir(DATA_PATH); // 数据文件目录
return true;
}
// 创建控制器类
static public function buildController($module,$controller='Index') {
$file = APP_PATH.$module.'/Controller/'.$controller.'Controller'.EXT;
if(!is_file($file)){
$content = str_replace(array('[MODULE]','[CONTROLLER]'),array($module,$controller),self::$controller);
if(!C('APP_USE_NAMESPACE')){
$content = preg_replace('/namespace\s(.*?);/','',$content,1);
}
$dir = dirname($file);
if(!is_dir($dir)){
mkdir($dir, 0755, true);
}
file_put_contents($file,$content);
}
}
// 创建模型类
static public function buildModel($module,$model) {
$file = APP_PATH.$module.'/Model/'.$model.'Model'.EXT;
if(!is_file($file)){
$content = str_replace(array('[MODULE]','[MODEL]'),array($module,$model),self::$model);
if(!C('APP_USE_NAMESPACE')){
$content = preg_replace('/namespace\s(.*?);/','',$content,1);
}
$dir = dirname($file);
if(!is_dir($dir)){
mkdir($dir, 0755, true);
}
file_put_contents($file,$content);
}
}
// 生成目录安全文件
static public function buildDirSecure($dirs=array()) {
// 目录安全写入(默认开启)
defined('BUILD_DIR_SECURE') or define('BUILD_DIR_SECURE', true);
if(BUILD_DIR_SECURE) {
defined('DIR_SECURE_FILENAME') or define('DIR_SECURE_FILENAME', 'index.html');
defined('DIR_SECURE_CONTENT') or define('DIR_SECURE_CONTENT', ' ');
// 自动写入目录安全文件
$content = DIR_SECURE_CONTENT;
$files = explode(',', DIR_SECURE_FILENAME);
foreach ($files as $filename){
foreach ($dirs as $dir)
file_put_contents($dir.$filename,$content);
}
}
}
}

View File

@@ -0,0 +1,127 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 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 string
* @access protected
*/
protected $handler ;
/**
* 缓存连接参数
* @var integer
* @access protected
*/
protected $options = array();
/**
* 连接缓存
* @access public
* @param string $type 缓存类型
* @param array $options 配置数组
* @return object
*/
public function connect($type='',$options=array()) {
if(empty($type)) $type = C('DATA_CACHE_TYPE');
$class = strpos($type,'\\')? $type : 'Think\\Cache\\Driver\\'.ucwords(strtolower($type));
if(class_exists($class))
$cache = new $class($options);
else
E(L('_CACHE_TYPE_INVALID_').':'.$type);
return $cache;
}
/**
* 取得缓存类实例
* @static
* @access public
* @return mixed
*/
static function getInstance($type='',$options=array()) {
static $_instance = array();
$guid = $type.to_guid_string($options);
if(!isset($_instance[$guid])){
$obj = new Cache();
$_instance[$guid] = $obj->connect($type,$options);
}
return $_instance[$guid];
}
public function __get($name) {
return $this->get($name);
}
public function __set($name,$value) {
return $this->set($name,$value);
}
public function __unset($name) {
$this->rm($name);
}
public function setOptions($name,$value) {
$this->options[$name] = $value;
}
public function getOptions($name) {
return $this->options[$name];
}
/**
* 队列缓存
* @access protected
* @param string $key 队列名
* @return mixed
*/
//
protected function queue($key) {
static $_handler = array(
'file' => array('F','F'),
'xcache'=> array('xcache_get','xcache_set'),
'apc' => array('apc_fetch','apc_store'),
);
$queue = isset($this->options['queue'])?$this->options['queue']:'file';
$fun = isset($_handler[$queue])?$_handler[$queue]:$_handler['file'];
$queue_name = isset($this->options['queue_name'])?$this->options['queue_name']:'think_queue';
$value = $fun[0]($queue_name);
if(!$value) {
$value = array();
}
// 进列
if(false===array_search($key, $value)) array_push($value,$key);
if(count($value) > $this->options['length']) {
// 出列
$key = array_shift($value);
// 删除缓存
$this->rm($key);
if(APP_DEBUG){
//调试模式下,记录出列次数
N($queue_name.'_out_times',1);
}
}
return $fun[1]($queue_name,$value);
}
public function __call($method,$args){
//调用缓存类型自己的方法
if(method_exists($this->handler, $method)){
return call_user_func_array(array($this->handler,$method), $args);
}else{
E(__CLASS__.':'.$method.L('_METHOD_NOT_EXIST_'));
return;
}
}
}

View File

@@ -0,0 +1,124 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
namespace Think\Cache\Driver;
use Think\Cache;
defined('THINK_PATH') or exit();
/**
* Apachenote缓存驱动
*/
class Apachenote extends Cache {
/**
* 架构函数
* @param array $options 缓存参数
* @access public
*/
public function __construct($options=array()) {
if(!empty($options)) {
$this->options = $options;
}
if(empty($options)) {
$options = array (
'host' => '127.0.0.1',
'port' => 1042,
'timeout' => 10,
);
}
$this->options = $options;
$this->options['prefix'] = isset($options['prefix'])? $options['prefix'] : C('DATA_CACHE_PREFIX');
$this->options['length'] = isset($options['length'])? $options['length'] : 0;
$this->handler = null;
$this->open();
}
/**
* 读取缓存
* @access public
* @param string $name 缓存变量名
* @return mixed
*/
public function get($name) {
$this->open();
$name = $this->options['prefix'].$name;
$s = 'F' . pack('N', strlen($name)) . $name;
fwrite($this->handler, $s);
for ($data = ''; !feof($this->handler);) {
$data .= fread($this->handler, 4096);
}
N('cache_read',1);
$this->close();
return $data === '' ? '' : unserialize($data);
}
/**
* 写入缓存
* @access public
* @param string $name 缓存变量名
* @param mixed $value 存储数据
* @return boolean
*/
public function set($name, $value) {
N('cache_write',1);
$this->open();
$value = serialize($value);
$name = $this->options['prefix'].$name;
$s = 'S' . pack('NN', strlen($name), strlen($value)) . $name . $value;
fwrite($this->handler, $s);
$ret = fgets($this->handler);
$this->close();
if($ret === "OK\n") {
if($this->options['length']>0) {
// 记录缓存队列
$this->queue($name);
}
return true;
}
return false;
}
/**
* 删除缓存
* @access public
* @param string $name 缓存变量名
* @return boolean
*/
public function rm($name) {
$this->open();
$name = $this->options['prefix'].$name;
$s = 'D' . pack('N', strlen($name)) . $name;
fwrite($this->handler, $s);
$ret = fgets($this->handler);
$this->close();
return $ret === "OK\n";
}
/**
* 关闭缓存
* @access private
*/
private function close() {
fclose($this->handler);
$this->handler = false;
}
/**
* 打开缓存
* @access private
*/
private function open() {
if (!is_resource($this->handler)) {
$this->handler = fsockopen($this->options['host'], $this->options['port'], $_, $_, $this->options['timeout']);
}
}
}

View File

@@ -0,0 +1,86 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
namespace Think\Cache\Driver;
use Think\Cache;
defined('THINK_PATH') or exit();
/**
* Apc缓存驱动
*/
class Apc extends Cache {
/**
* 架构函数
* @param array $options 缓存参数
* @access public
*/
public function __construct($options=array()) {
if(!function_exists('apc_cache_info')) {
E(L('_NOT_SUPPORT_').':Apc');
}
$this->options['prefix'] = isset($options['prefix'])? $options['prefix'] : C('DATA_CACHE_PREFIX');
$this->options['length'] = isset($options['length'])? $options['length'] : 0;
$this->options['expire'] = isset($options['expire'])? $options['expire'] : C('DATA_CACHE_TIME');
}
/**
* 读取缓存
* @access public
* @param string $name 缓存变量名
* @return mixed
*/
public function get($name) {
N('cache_read',1);
return apc_fetch($this->options['prefix'].$name);
}
/**
* 写入缓存
* @access public
* @param string $name 缓存变量名
* @param mixed $value 存储数据
* @param integer $expire 有效时间(秒)
* @return boolean
*/
public function set($name, $value, $expire = null) {
N('cache_write',1);
if(is_null($expire)) {
$expire = $this->options['expire'];
}
$name = $this->options['prefix'].$name;
if($result = apc_store($name, $value, $expire)) {
if($this->options['length']>0) {
// 记录缓存队列
$this->queue($name);
}
}
return $result;
}
/**
* 删除缓存
* @access public
* @param string $name 缓存变量名
* @return boolean
*/
public function rm($name) {
return apc_delete($this->options['prefix'].$name);
}
/**
* 清除缓存
* @access public
* @return boolean
*/
public function clear() {
return apc_clear_cache();
}
}

View File

@@ -0,0 +1,138 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
namespace Think\Cache\Driver;
use Think\Cache;
defined('THINK_PATH') or exit();
/**
* 数据库方式缓存驱动
* CREATE TABLE think_cache (
* cachekey varchar(255) NOT NULL,
* expire int(11) NOT NULL,
* data blob,
* datacrc int(32),
* UNIQUE KEY `cachekey` (`cachekey`)
* );
*/
class Db extends Cache {
/**
* 架构函数
* @param array $options 缓存参数
* @access public
*/
public function __construct($options=array()) {
if(empty($options)) {
$options = array (
'table' => C('DATA_CACHE_TABLE'),
);
}
$this->options = $options;
$this->options['prefix'] = isset($options['prefix'])? $options['prefix'] : C('DATA_CACHE_PREFIX');
$this->options['length'] = isset($options['length'])? $options['length'] : 0;
$this->options['expire'] = isset($options['expire'])? $options['expire'] : C('DATA_CACHE_TIME');
$this->handler = \Think\Db::getInstance();
}
/**
* 读取缓存
* @access public
* @param string $name 缓存变量名
* @return mixed
*/
public function get($name) {
$name = $this->options['prefix'].addslashes($name);
N('cache_read',1);
$result = $this->handler->query('SELECT `data`,`datacrc` FROM `'.$this->options['table'].'` WHERE `cachekey`=\''.$name.'\' AND (`expire` =0 OR `expire`>'.time().') LIMIT 0,1');
if(false !== $result ) {
$result = $result[0];
if(C('DATA_CACHE_CHECK')) {//开启数据校验
if($result['datacrc'] != md5($result['data'])) {//校验错误
return false;
}
}
$content = $result['data'];
if(C('DATA_CACHE_COMPRESS') && function_exists('gzcompress')) {
//启用数据压缩
$content = gzuncompress($content);
}
$content = unserialize($content);
return $content;
}
else {
return false;
}
}
/**
* 写入缓存
* @access public
* @param string $name 缓存变量名
* @param mixed $value 存储数据
* @param integer $expire 有效时间(秒)
* @return boolean
*/
public function set($name, $value,$expire=null) {
$data = serialize($value);
$name = $this->options['prefix'].addslashes($name);
N('cache_write',1);
if( C('DATA_CACHE_COMPRESS') && function_exists('gzcompress')) {
//数据压缩
$data = gzcompress($data,3);
}
if(C('DATA_CACHE_CHECK')) {//开启数据校验
$crc = md5($data);
}else {
$crc = '';
}
if(is_null($expire)) {
$expire = $this->options['expire'];
}
$expire = ($expire==0)?0: (time()+$expire) ;//缓存有效期为0表示永久缓存
$result = $this->handler->query('select `cachekey` from `'.$this->options['table'].'` where `cachekey`=\''.$name.'\' limit 0,1');
if(!empty($result) ) {
//更新记录
$result = $this->handler->execute('UPDATE '.$this->options['table'].' SET data=\''.$data.'\' ,datacrc=\''.$crc.'\',expire='.$expire.' WHERE `cachekey`=\''.$name.'\'');
}else {
//新增记录
$result = $this->handler->execute('INSERT INTO '.$this->options['table'].' (`cachekey`,`data`,`datacrc`,`expire`) VALUES (\''.$name.'\',\''.$data.'\',\''.$crc.'\','.$expire.')');
}
if($result) {
if($this->options['length']>0) {
// 记录缓存队列
$this->queue($name);
}
return true;
}else {
return false;
}
}
/**
* 删除缓存
* @access public
* @param string $name 缓存变量名
* @return boolean
*/
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 boolean
*/
public function clear() {
return $this->handler->execute('TRUNCATE TABLE `'.$this->options['table'].'`');
}
}

View File

@@ -0,0 +1,77 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
namespace Think\Cache\Driver;
use Think\Cache;
defined('THINK_PATH') or exit();
/**
* Eaccelerator缓存驱动
*/
class Eaccelerator extends Cache {
/**
* 架构函数
* @param array $options 缓存参数
* @access public
*/
public function __construct($options=array()) {
$this->options['expire'] = isset($options['expire'])? $options['expire'] : C('DATA_CACHE_TIME');
$this->options['prefix'] = isset($options['prefix'])? $options['prefix'] : C('DATA_CACHE_PREFIX');
$this->options['length'] = isset($options['length'])? $options['length'] : 0;
}
/**
* 读取缓存
* @access public
* @param string $name 缓存变量名
* @return mixed
*/
public function get($name) {
N('cache_read',1);
return eaccelerator_get($this->options['prefix'].$name);
}
/**
* 写入缓存
* @access public
* @param string $name 缓存变量名
* @param mixed $value 存储数据
* @param integer $expire 有效时间(秒)
* @return boolean
*/
public function set($name, $value, $expire = null) {
N('cache_write',1);
if(is_null($expire)) {
$expire = $this->options['expire'];
}
$name = $this->options['prefix'].$name;
eaccelerator_lock($name);
if(eaccelerator_put($name, $value, $expire)) {
if($this->options['length']>0) {
// 记录缓存队列
$this->queue($name);
}
return true;
}
return false;
}
/**
* 删除缓存
* @access public
* @param string $name 缓存变量名
* @return boolean
*/
public function rm($name) {
return eaccelerator_rm($this->options['prefix'].$name);
}
}

View File

@@ -0,0 +1,181 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
namespace Think\Cache\Driver;
use Think\Cache;
defined('THINK_PATH') or exit();
/**
* 文件类型缓存类
*/
class File extends Cache {
/**
* 架构函数
* @access public
*/
public function __construct($options=array()) {
if(!empty($options)) {
$this->options = $options;
}
$this->options['temp'] = !empty($options['temp'])? $options['temp'] : C('DATA_CACHE_PATH');
$this->options['prefix'] = isset($options['prefix'])? $options['prefix'] : C('DATA_CACHE_PREFIX');
$this->options['expire'] = isset($options['expire'])? $options['expire'] : C('DATA_CACHE_TIME');
$this->options['length'] = isset($options['length'])? $options['length'] : 0;
if(substr($this->options['temp'], -1) != '/') $this->options['temp'] .= '/';
$this->init();
}
/**
* 初始化检查
* @access private
* @return boolean
*/
private function init() {
// 创建应用缓存目录
if (!is_dir($this->options['temp'])) {
mkdir($this->options['temp']);
}
}
/**
* 取得变量的存储文件名
* @access private
* @param string $name 缓存变量名
* @return string
*/
private function filename($name) {
$name = md5(C('DATA_CACHE_KEY').$name);
if(C('DATA_CACHE_SUBDIR')) {
// 使用子目录
$dir ='';
for($i=0;$i<C('DATA_PATH_LEVEL');$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;
}
N('cache_read',1);
$content = file_get_contents($filename);
if( false !== $content) {
$expire = (int)substr($content,8, 12);
if($expire != 0 && time() > filemtime($filename) + $expire) {
//缓存过期删除缓存文件
unlink($filename);
return false;
}
if(C('DATA_CACHE_CHECK')) {//开启数据校验
$check = substr($content,20, 32);
$content = substr($content,52, -3);
if($check != md5($content)) {//校验错误
return false;
}
}else {
$content = substr($content,20, -3);
}
if(C('DATA_CACHE_COMPRESS') && function_exists('gzcompress')) {
//启用数据压缩
$content = gzuncompress($content);
}
$content = unserialize($content);
return $content;
}
else {
return false;
}
}
/**
* 写入缓存
* @access public
* @param string $name 缓存变量名
* @param mixed $value 存储数据
* @param int $expire 有效时间 0为永久
* @return boolean
*/
public function set($name,$value,$expire=null) {
N('cache_write',1);
if(is_null($expire)) {
$expire = $this->options['expire'];
}
$filename = $this->filename($name);
$data = serialize($value);
if( C('DATA_CACHE_COMPRESS') && function_exists('gzcompress')) {
//数据压缩
$data = gzcompress($data,3);
}
if(C('DATA_CACHE_CHECK')) {//开启数据校验
$check = md5($data);
}else {
$check = '';
}
$data = "<?php\n//".sprintf('%012d',$expire).$check.$data."\n?>";
$result = file_put_contents($filename,$data);
if($result) {
if($this->options['length']>0) {
// 记录缓存队列
$this->queue($name);
}
clearstatcache();
return true;
}else {
return false;
}
}
/**
* 删除缓存
* @access public
* @param string $name 缓存变量名
* @return boolean
*/
public function rm($name) {
return unlink($this->filename($name));
}
/**
* 清除缓存
* @access public
* @param string $name 缓存变量名
* @return boolean
*/
public function clear() {
$path = $this->options['temp'];
$files = scandir($path);
if($files){
foreach($files as $file){
if ($file != '.' && $file != '..' && is_dir($path.$file) ){
array_map( 'unlink', glob( $path.$file.'/*.*' ) );
}elseif(is_file($path.$file)){
unlink( $path . $file );
}
}
return true;
}
return false;
}
}

View File

@@ -0,0 +1,103 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
namespace Think\Cache\Driver;
use Think\Cache;
defined('THINK_PATH') or exit();
/**
* Memcache缓存驱动
*/
class Memcache extends Cache {
/**
* 架构函数
* @param array $options 缓存参数
* @access public
*/
function __construct($options=array()) {
if ( !extension_loaded('memcache') ) {
E(L('_NOT_SUPPORT_').':memcache');
}
$options = array_merge(array (
'host' => C('MEMCACHE_HOST') ? : '127.0.0.1',
'port' => C('MEMCACHE_PORT') ? : 11211,
'timeout' => C('DATA_CACHE_TIMEOUT') ? : false,
'persistent' => false,
),$options);
$this->options = $options;
$this->options['expire'] = isset($options['expire'])? $options['expire'] : C('DATA_CACHE_TIME');
$this->options['prefix'] = isset($options['prefix'])? $options['prefix'] : C('DATA_CACHE_PREFIX');
$this->options['length'] = isset($options['length'])? $options['length'] : 0;
$func = $options['persistent'] ? 'pconnect' : 'connect';
$this->handler = new \Memcache;
$options['timeout'] === false ?
$this->handler->$func($options['host'], $options['port']) :
$this->handler->$func($options['host'], $options['port'], $options['timeout']);
}
/**
* 读取缓存
* @access public
* @param string $name 缓存变量名
* @return mixed
*/
public function get($name) {
N('cache_read',1);
return $this->handler->get($this->options['prefix'].$name);
}
/**
* 写入缓存
* @access public
* @param string $name 缓存变量名
* @param mixed $value 存储数据
* @param integer $expire 有效时间(秒)
* @return boolean
*/
public function set($name, $value, $expire = null) {
N('cache_write',1);
if(is_null($expire)) {
$expire = $this->options['expire'];
}
$name = $this->options['prefix'].$name;
if($this->handler->set($name, $value, 0, $expire)) {
if($this->options['length']>0) {
// 记录缓存队列
$this->queue($name);
}
return true;
}
return false;
}
/**
* 删除缓存
* @access public
* @param string $name 缓存变量名
* @return boolean
*/
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 boolean
*/
public function clear() {
return $this->handler->flush();
}
}

View File

@@ -0,0 +1,102 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2013 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: 何辉 <runphp@qq.com>
// +----------------------------------------------------------------------
namespace Think\Cache\Driver;
use Memcached as MemcachedResource;
use Think\Cache;
/**
* Memcached缓存驱动
*/
class Memcached extends Cache {
/**
*
* @param array $options
*/
public function __construct($options = array()) {
if ( !extension_loaded('memcached') ) {
E(L('_NOT_SUPPORT_').':memcached');
}
$options = array_merge(array(
'servers' => C('MEMCACHED_SERVER') ? : null,
'lib_options' => C('MEMCACHED_LIB') ? : null
), $options);
$this->options = $options;
$this->options['expire'] = isset($options['expire'])? $options['expire'] : C('DATA_CACHE_TIME');
$this->options['prefix'] = isset($options['prefix'])? $options['prefix'] : C('DATA_CACHE_PREFIX');
$this->options['length'] = isset($options['length'])? $options['length'] : 0;
$this->handler = new MemcachedResource;
$options['servers'] && $this->handler->addServers($options['servers']);
$options['lib_options'] && $this->handler->setOptions($options['lib_options']);
}
/**
* 读取缓存
* @access public
* @param string $name 缓存变量名
* @return mixed
*/
public function get($name) {
N('cache_read',1);
return $this->handler->get($this->options['prefix'].$name);
}
/**
* 写入缓存
* @access public
* @param string $name 缓存变量名
* @param mixed $value 存储数据
* @param integer $expire 有效时间(秒)
* @return boolean
*/
public function set($name, $value, $expire = null) {
N('cache_write',1);
if(is_null($expire)) {
$expire = $this->options['expire'];
}
$name = $this->options['prefix'].$name;
if($this->handler->set($name, $value, time() + $expire)) {
if($this->options['length']>0) {
// 记录缓存队列
$this->queue($name);
}
return true;
}
return false;
}
/**
* 删除缓存
* @access public
* @param string $name 缓存变量名
* @return boolean
*/
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 boolean
*/
public function clear() {
return $this->handler->flush();
}
}

View File

@@ -0,0 +1,144 @@
<?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\Cache\Driver;
use Think\Cache;
defined('THINK_PATH') or exit();
/**
* Memcache缓存驱动
* @category Extend
* @package Extend
* @subpackage Driver.Cache
* @author liu21st <liu21st@gmail.com>
*/
class Memcachesae extends Cache {
/**
* 架构函数
* @param array $options 缓存参数
* @access public
*/
function __construct($options=array()) {
$options = array_merge(array (
'host' => C('MEMCACHE_HOST') ? : '127.0.0.1',
'port' => C('MEMCACHE_PORT') ? : 11211,
'timeout' => C('DATA_CACHE_TIMEOUT') ? : false,
'persistent' => false,
),$options);
$this->options = $options;
$this->options['expire'] = isset($options['expire'])? $options['expire'] : C('DATA_CACHE_TIME');
$this->options['prefix'] = isset($options['prefix'])? $options['prefix'] : C('DATA_CACHE_PREFIX');
$this->options['length'] = isset($options['length'])? $options['length'] : 0;
$this->handler = memcache_init();//[sae] 下实例化
//[sae] 下不用链接
$this->connected=true;
}
/**
* 是否连接
* @access private
* @return boolean
*/
private function isConnected() {
return $this->connected;
}
/**
* 读取缓存
* @access public
* @param string $name 缓存变量名
* @return mixed
*/
public function get($name) {
N('cache_read',1);
return $this->handler->get($_SERVER['HTTP_APPVERSION'].'/'.$this->options['prefix'].$name);
}
/**
* 写入缓存
* @access public
* @param string $name 缓存变量名
* @param mixed $value 存储数据
* @param integer $expire 有效时间(秒)
* @return boolean
*/
public function set($name, $value, $expire = null) {
N('cache_write',1);
if(is_null($expire)) {
$expire = $this->options['expire'];
}
$name = $this->options['prefix'].$name;
if($this->handler->set($_SERVER['HTTP_APPVERSION'].'/'.$name, $value, 0, $expire)) {
if($this->options['length']>0) {
// 记录缓存队列
$this->queue($name);
}
return true;
}
return false;
}
/**
* 删除缓存
* @access public
* @param string $name 缓存变量名
* @return boolean
*/
public function rm($name, $ttl = false) {
$name = $_SERVER['HTTP_APPVERSION'].'/'.$this->options['prefix'].$name;
return $ttl === false ?
$this->handler->delete($name) :
$this->handler->delete($name, $ttl);
}
/**
* 清除缓存
* @access public
* @return boolean
*/
public function clear() {
return $this->handler->flush();
}
/**
* 队列缓存
* @access protected
* @param string $key 队列名
* @return mixed
*/
//[sae] 下重写queque队列缓存方法
protected function queue($key) {
$queue_name=isset($this->options['queue_name'])?$this->options['queue_name']:'think_queue';
$value = F($queue_name);
if(!$value) {
$value = array();
}
// 进列
if(false===array_search($key, $value)) array_push($value,$key);
if(count($value) > $this->options['length']) {
// 出列
$key = array_shift($value);
// 删除缓存
$this->rm($key);
if (APP_DEBUG) {
//调试模式下记录出队次数
$counter = Think::instance('SaeCounter');
if ($counter->exists($queue_name.'_out_times'))
$counter->incr($queue_name.'_out_times');
else
$counter->create($queue_name.'_out_times', 1);
}
}
return F($queue_name,$value);
}
}

View File

@@ -0,0 +1,107 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
namespace Think\Cache\Driver;
use Think\Cache;
defined('THINK_PATH') or exit();
/**
* Redis缓存驱动
* 要求安装phpredis扩展https://github.com/nicolasff/phpredis
*/
class Redis extends Cache {
/**
* 架构函数
* @param array $options 缓存参数
* @access public
*/
public function __construct($options=array()) {
if ( !extension_loaded('redis') ) {
E(L('_NOT_SUPPORT_').':redis');
}
$options = array_merge(array (
'host' => C('REDIS_HOST') ? : '127.0.0.1',
'port' => C('REDIS_PORT') ? : 6379,
'timeout' => C('DATA_CACHE_TIMEOUT') ? : false,
'persistent' => false,
),$options);
$this->options = $options;
$this->options['expire'] = isset($options['expire'])? $options['expire'] : C('DATA_CACHE_TIME');
$this->options['prefix'] = isset($options['prefix'])? $options['prefix'] : C('DATA_CACHE_PREFIX');
$this->options['length'] = isset($options['length'])? $options['length'] : 0;
$func = $options['persistent'] ? 'pconnect' : 'connect';
$this->handler = new \Redis;
$options['timeout'] === false ?
$this->handler->$func($options['host'], $options['port']) :
$this->handler->$func($options['host'], $options['port'], $options['timeout']);
}
/**
* 读取缓存
* @access public
* @param string $name 缓存变量名
* @return mixed
*/
public function get($name) {
N('cache_read',1);
$value = $this->handler->get($this->options['prefix'].$name);
$jsonData = json_decode( $value, true );
return ($jsonData === NULL) ? $value : $jsonData; //检测是否为JSON数据 true 返回JSON解析数组, false返回源数据
}
/**
* 写入缓存
* @access public
* @param string $name 缓存变量名
* @param mixed $value 存储数据
* @param integer $expire 有效时间(秒)
* @return boolean
*/
public function set($name, $value, $expire = null) {
N('cache_write',1);
if(is_null($expire)) {
$expire = $this->options['expire'];
}
$name = $this->options['prefix'].$name;
//对数组/对象数据进行缓存处理,保证数据完整性
$value = (is_object($value) || is_array($value)) ? json_encode($value) : $value;
if(is_int($expire) && $expire) {
$result = $this->handler->setex($name, $expire, $value);
}else{
$result = $this->handler->set($name, $value);
}
if($result && $this->options['length']>0) {
// 记录缓存队列
$this->queue($name);
}
return $result;
}
/**
* 删除缓存
* @access public
* @param string $name 缓存变量名
* @return boolean
*/
public function rm($name) {
return $this->handler->delete($this->options['prefix'].$name);
}
/**
* 清除缓存
* @access public
* @return boolean
*/
public function clear() {
return $this->handler->flushDB();
}
}

View File

@@ -0,0 +1,186 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
namespace Think\Cache\Driver;
use Think\Cache;
defined('THINK_PATH') or exit();
/**
* Shmop缓存驱动
*/
class Shmop extends Cache {
/**
* 架构函数
* @param array $options 缓存参数
* @access public
*/
public function __construct($options=array()) {
if ( !extension_loaded('shmop') ) {
E(L('_NOT_SUPPORT_').':shmop');
}
if(!empty($options)){
$options = array(
'size' => C('SHARE_MEM_SIZE'),
'temp' => TEMP_PATH,
'project' => 's',
'length' => 0,
);
}
$this->options = $options;
$this->options['prefix'] = isset($options['prefix'])? $options['prefix'] : C('DATA_CACHE_PREFIX');
$this->options['length'] = isset($options['length'])? $options['length'] : 0;
$this->handler = $this->_ftok($this->options['project']);
}
/**
* 读取缓存
* @access public
* @param string $name 缓存变量名
* @return mixed
*/
public function get($name = false) {
N('cache_read',1);
$id = shmop_open($this->handler, 'c', 0600, 0);
if ($id !== false) {
$ret = unserialize(shmop_read($id, 0, shmop_size($id)));
shmop_close($id);
if ($name === false) {
return $ret;
}
$name = $this->options['prefix'].$name;
if(isset($ret[$name])) {
$content = $ret[$name];
if(C('DATA_CACHE_COMPRESS') && function_exists('gzcompress')) {
//启用数据压缩
$content = gzuncompress($content);
}
return $content;
}else {
return null;
}
}else {
return false;
}
}
/**
* 写入缓存
* @access public
* @param string $name 缓存变量名
* @param mixed $value 存储数据
* @return boolean
*/
public function set($name, $value) {
N('cache_write',1);
$lh = $this->_lock();
$val = $this->get();
if (!is_array($val)) $val = array();
if( C('DATA_CACHE_COMPRESS') && function_exists('gzcompress')) {
//数据压缩
$value = gzcompress($value,3);
}
$name = $this->options['prefix'].$name;
$val[$name] = $value;
$val = serialize($val);
if($this->_write($val, $lh)) {
if($this->options['length']>0) {
// 记录缓存队列
$this->queue($name);
}
return true;
}
return false;
}
/**
* 删除缓存
* @access public
* @param string $name 缓存变量名
* @return boolean
*/
public function rm($name) {
$lh = $this->_lock();
$val = $this->get();
if (!is_array($val)) $val = array();
$name = $this->options['prefix'].$name;
unset($val[$name]);
$val = serialize($val);
return $this->_write($val, $lh);
}
/**
* 生成IPC key
* @access private
* @param string $project 项目标识名
* @return integer
*/
private function _ftok($project) {
if (function_exists('ftok')) return ftok(__FILE__, $project);
if(strtoupper(PHP_OS) == 'WINNT'){
$s = stat(__FILE__);
return sprintf("%u", (($s['ino'] & 0xffff) | (($s['dev'] & 0xff) << 16) |
(($project & 0xff) << 24)));
}else {
$filename = __FILE__ . (string) $project;
for($key = array(); sizeof($key) < strlen($filename); $key[] = ord(substr($filename, sizeof($key), 1)));
return dechex(array_sum($key));
}
}
/**
* 写入操作
* @access private
* @param string $name 缓存变量名
* @return integer|boolean
*/
private function _write(&$val, &$lh) {
$id = shmop_open($this->handler, 'c', 0600, $this->options['size']);
if ($id) {
$ret = shmop_write($id, $val, 0) == strlen($val);
shmop_close($id);
$this->_unlock($lh);
return $ret;
}
$this->_unlock($lh);
return false;
}
/**
* 共享锁定
* @access private
* @param string $name 缓存变量名
* @return boolean
*/
private function _lock() {
if (function_exists('sem_get')) {
$fp = sem_get($this->handler, 1, 0600, 1);
sem_acquire ($fp);
} else {
$fp = fopen($this->options['temp'].$this->options['prefix'].md5($this->handler), 'w');
flock($fp, LOCK_EX);
}
return $fp;
}
/**
* 解除共享锁定
* @access private
* @param string $name 缓存变量名
* @return boolean
*/
private function _unlock(&$fp) {
if (function_exists('sem_release')) {
sem_release($fp);
} else {
fclose($fp);
}
}
}

View File

@@ -0,0 +1,119 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
namespace Think\Cache\Driver;
use Think\Cache;
defined('THINK_PATH') or exit();
/**
* Sqlite缓存驱动
*/
class Sqlite extends Cache {
/**
* 架构函数
* @param array $options 缓存参数
* @access public
*/
public function __construct($options=array()) {
if ( !extension_loaded('sqlite') ) {
E(L('_NOT_SUPPORT_').':sqlite');
}
if(empty($options)) {
$options = array (
'db' => ':memory:',
'table' => 'sharedmemory',
);
}
$this->options = $options;
$this->options['prefix'] = isset($options['prefix'])? $options['prefix'] : C('DATA_CACHE_PREFIX');
$this->options['length'] = isset($options['length'])? $options['length'] : 0;
$this->options['expire'] = isset($options['expire'])? $options['expire'] : C('DATA_CACHE_TIME');
$func = $this->options['persistent'] ? 'sqlite_popen' : 'sqlite_open';
$this->handler = $func($this->options['db']);
}
/**
* 读取缓存
* @access public
* @param string $name 缓存变量名
* @return mixed
*/
public function get($name) {
N('cache_read',1);
$name = $this->options['prefix'].sqlite_escape_string($name);
$sql = 'SELECT value FROM '.$this->options['table'].' WHERE var=\''.$name.'\' AND (expire=0 OR expire >'.time().') LIMIT 1';
$result = sqlite_query($this->handler, $sql);
if (sqlite_num_rows($result)) {
$content = sqlite_fetch_single($result);
if(C('DATA_CACHE_COMPRESS') && function_exists('gzcompress')) {
//启用数据压缩
$content = gzuncompress($content);
}
return unserialize($content);
}
return false;
}
/**
* 写入缓存
* @access public
* @param string $name 缓存变量名
* @param mixed $value 存储数据
* @param integer $expire 有效时间(秒)
* @return boolean
*/
public function set($name, $value,$expire=null) {
N('cache_write',1);
$name = $this->options['prefix'].sqlite_escape_string($name);
$value = sqlite_escape_string(serialize($value));
if(is_null($expire)) {
$expire = $this->options['expire'];
}
$expire = ($expire==0)?0: (time()+$expire) ;//缓存有效期为0表示永久缓存
if( C('DATA_CACHE_COMPRESS') && function_exists('gzcompress')) {
//数据压缩
$value = gzcompress($value,3);
}
$sql = 'REPLACE INTO '.$this->options['table'].' (var, value,expire) VALUES (\''.$name.'\', \''.$value.'\', \''.$expire.'\')';
if(sqlite_query($this->handler, $sql)){
if($this->options['length']>0) {
// 记录缓存队列
$this->queue($name);
}
return true;
}
return false;
}
/**
* 删除缓存
* @access public
* @param string $name 缓存变量名
* @return boolean
*/
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 boolean
*/
public function clear() {
$sql = 'DELETE FROM '.$this->options['table'];
sqlite_query($this->handler, $sql);
return ;
}
}

View File

@@ -0,0 +1,88 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
namespace Think\Cache\Driver;
use Think\Cache;
defined('THINK_PATH') or exit();
/**
* Wincache缓存驱动
*/
class Wincache extends Cache {
/**
* 架构函数
* @param array $options 缓存参数
* @access public
*/
public function __construct($options=array()) {
if ( !function_exists('wincache_ucache_info') ) {
E(L('_NOT_SUPPORT_').':WinCache');
}
$this->options['expire'] = isset($options['expire'])? $options['expire'] : C('DATA_CACHE_TIME');
$this->options['prefix'] = isset($options['prefix'])? $options['prefix'] : C('DATA_CACHE_PREFIX');
$this->options['length'] = isset($options['length'])? $options['length'] : 0;
}
/**
* 读取缓存
* @access public
* @param string $name 缓存变量名
* @return mixed
*/
public function get($name) {
N('cache_read',1);
$name = $this->options['prefix'].$name;
return wincache_ucache_exists($name)? wincache_ucache_get($name) : false;
}
/**
* 写入缓存
* @access public
* @param string $name 缓存变量名
* @param mixed $value 存储数据
* @param integer $expire 有效时间(秒)
* @return boolean
*/
public function set($name, $value,$expire=null) {
N('cache_write',1);
if(is_null($expire)) {
$expire = $this->options['expire'];
}
$name = $this->options['prefix'].$name;
if(wincache_ucache_set($name, $value, $expire)) {
if($this->options['length']>0) {
// 记录缓存队列
$this->queue($name);
}
return true;
}
return false;
}
/**
* 删除缓存
* @access public
* @param string $name 缓存变量名
* @return boolean
*/
public function rm($name) {
return wincache_ucache_delete($this->options['prefix'].$name);
}
/**
* 清除缓存
* @access public
* @return boolean
*/
public function clear() {
return wincache_ucache_clear();
}
}

View File

@@ -0,0 +1,90 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
namespace Think\Cache\Driver;
use Think\Cache;
defined('THINK_PATH') or exit();
/**
* Xcache缓存驱动
*/
class Xcache extends Cache {
/**
* 架构函数
* @param array $options 缓存参数
* @access public
*/
public function __construct($options=array()) {
if ( !function_exists('xcache_info') ) {
E(L('_NOT_SUPPORT_').':Xcache');
}
$this->options['expire'] = isset($options['expire'])?$options['expire']:C('DATA_CACHE_TIME');
$this->options['prefix'] = isset($options['prefix'])?$options['prefix']:C('DATA_CACHE_PREFIX');
$this->options['length'] = isset($options['length'])?$options['length']:0;
}
/**
* 读取缓存
* @access public
* @param string $name 缓存变量名
* @return mixed
*/
public function get($name) {
N('cache_read',1);
$name = $this->options['prefix'].$name;
if (xcache_isset($name)) {
return xcache_get($name);
}
return false;
}
/**
* 写入缓存
* @access public
* @param string $name 缓存变量名
* @param mixed $value 存储数据
* @param integer $expire 有效时间(秒)
* @return boolean
*/
public function set($name, $value,$expire=null) {
N('cache_write',1);
if(is_null($expire)) {
$expire = $this->options['expire'] ;
}
$name = $this->options['prefix'].$name;
if(xcache_set($name, $value, $expire)) {
if($this->options['length']>0) {
// 记录缓存队列
$this->queue($name);
}
return true;
}
return false;
}
/**
* 删除缓存
* @access public
* @param string $name 缓存变量名
* @return boolean
*/
public function rm($name) {
return xcache_unset($this->options['prefix'].$name);
}
/**
* 清除缓存
* @access public
* @return boolean
*/
public function clear() {
return xcache_clear_cache(1, -1);
}
}

View File

@@ -0,0 +1,307 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
namespace Think;
/**
* ThinkPHP 控制器基类 抽象类
*/
abstract class Controller {
/**
* 视图实例对象
* @var view
* @access protected
*/
protected $view = null;
/**
* 控制器参数
* @var config
* @access protected
*/
protected $config = array();
/**
* 架构函数 取得模板对象实例
* @access public
*/
public function __construct() {
Hook::listen('action_begin',$this->config);
//实例化视图类
$this->view = Think::instance('Think\View');
//控制器初始化
if(method_exists($this,'_initialize'))
$this->_initialize();
}
/**
* 模板显示 调用内置的模板引擎显示方法,
* @access protected
* @param string $templateFile 指定要调用的模板文件
* 默认为空 由系统自动定位模板文件
* @param string $charset 输出编码
* @param string $contentType 输出类型
* @param string $content 输出内容
* @param string $prefix 模板缓存前缀
* @return void
*/
protected function display($templateFile='',$charset='',$contentType='',$content='',$prefix='') {
$this->view->display($templateFile,$charset,$contentType,$content,$prefix);
}
/**
* 输出内容文本可以包括Html 并支持内容解析
* @access protected
* @param string $content 输出内容
* @param string $charset 模板输出字符集
* @param string $contentType 输出类型
* @param string $prefix 模板缓存前缀
* @return mixed
*/
protected function show($content,$charset='',$contentType='',$prefix='') {
$this->view->display('',$charset,$contentType,$content,$prefix);
}
/**
* 获取输出页面内容
* 调用内置的模板引擎fetch方法
* @access protected
* @param string $templateFile 指定要调用的模板文件
* 默认为空 由系统自动定位模板文件
* @param string $content 模板输出内容
* @param string $prefix 模板缓存前缀*
* @return string
*/
protected function fetch($templateFile='',$content='',$prefix='') {
return $this->view->fetch($templateFile,$content,$prefix);
}
/**
* 创建静态页面
* @access protected
* @htmlfile 生成的静态文件名称
* @htmlpath 生成的静态文件路径
* @param string $templateFile 指定要调用的模板文件
* 默认为空 由系统自动定位模板文件
* @return string
*/
protected function buildHtml($htmlfile='',$htmlpath='',$templateFile='') {
$content = $this->fetch($templateFile);
$htmlpath = !empty($htmlpath)?$htmlpath:HTML_PATH;
$htmlfile = $htmlpath.$htmlfile.C('HTML_FILE_SUFFIX');
Storage::put($htmlfile,$content,'html');
return $content;
}
/**
* 模板主题设置
* @access protected
* @param string $theme 模版主题
* @return Action
*/
protected function theme($theme){
$this->view->theme($theme);
return $this;
}
/**
* 模板变量赋值
* @access protected
* @param mixed $name 要显示的模板变量
* @param mixed $value 变量的值
* @return Action
*/
protected function assign($name,$value='') {
$this->view->assign($name,$value);
return $this;
}
public function __set($name,$value) {
$this->assign($name,$value);
}
/**
* 取得模板显示变量的值
* @access protected
* @param string $name 模板显示变量
* @return mixed
*/
public function get($name='') {
return $this->view->get($name);
}
public function __get($name) {
return $this->get($name);
}
/**
* 检测模板变量的值
* @access public
* @param string $name 名称
* @return boolean
*/
public function __isset($name) {
return $this->get($name);
}
/**
* 魔术方法 有不存在的操作的时候执行
* @access public
* @param string $method 方法名
* @param array $args 参数
* @return mixed
*/
public function __call($method,$args) {
if( 0 === strcasecmp($method,ACTION_NAME.C('ACTION_SUFFIX'))) {
if(method_exists($this,'_empty')) {
// 如果定义了_empty操作 则调用
$this->_empty($method,$args);
}elseif(file_exists_case($this->view->parseTemplate())){
// 检查是否存在默认模版 如果有直接输出模版
$this->display();
}else{
E(L('_ERROR_ACTION_').':'.ACTION_NAME);
}
}else{
E(__CLASS__.':'.$method.L('_METHOD_NOT_EXIST_'));
return;
}
}
/**
* 操作错误跳转的快捷方法
* @access protected
* @param string $message 错误信息
* @param string $jumpUrl 页面跳转地址
* @param mixed $ajax 是否为Ajax方式 当数字时指定跳转时间
* @return void
*/
protected function error($message='',$jumpUrl='',$ajax=false) {
$this->dispatchJump($message,0,$jumpUrl,$ajax);
}
/**
* 操作成功跳转的快捷方法
* @access protected
* @param string $message 提示信息
* @param string $jumpUrl 页面跳转地址
* @param mixed $ajax 是否为Ajax方式 当数字时指定跳转时间
* @return void
*/
protected function success($message='',$jumpUrl='',$ajax=false) {
$this->dispatchJump($message,1,$jumpUrl,$ajax);
}
/**
* Ajax方式返回数据到客户端
* @access protected
* @param mixed $data 要返回的数据
* @param String $type AJAX返回数据格式
* @param int $json_option 传递给json_encode的option参数
* @return void
*/
protected function ajaxReturn($data,$type='',$json_option=0) {
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,$json_option));
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,$json_option).');');
case 'EVAL' :
// 返回可执行的js脚本
header('Content-Type:text/html; charset=utf-8');
exit($data);
default :
// 用于扩展其他返回格式数据
Hook::listen('ajax_return',$data);
}
}
/**
* Action跳转(URL重定向 支持指定模块和延时跳转
* @access protected
* @param string $url 跳转的URL表达式
* @param array $params 其它URL参数
* @param integer $delay 延时跳转的时间 单位为秒
* @param string $msg 跳转提示信息
* @return void
*/
protected function redirect($url,$params=array(),$delay=0,$msg='') {
$url = U($url,$params);
redirect($url,$delay,$msg);
}
/**
* 默认跳转操作 支持错误导向和正确跳转
* 调用模板显示 默认为public目录下面的success页面
* 提示页面为可配置 支持模板标签
* @param string $message 提示信息
* @param Boolean $status 状态
* @param string $jumpUrl 页面跳转地址
* @param mixed $ajax 是否为Ajax方式 当数字时指定跳转时间
* @access private
* @return void
*/
private function dispatchJump($message,$status=1,$jumpUrl='',$ajax=false) {
if(true === $ajax || IS_AJAX) {// AJAX提交
$data = is_array($ajax)?$ajax:array();
$data['info'] = $message;
$data['status'] = $status;
$data['url'] = $jumpUrl;
$this->ajaxReturn($data);
}
if(is_int($ajax)) $this->assign('waitSecond',$ajax);
if(!empty($jumpUrl)) $this->assign('jumpUrl',$jumpUrl);
// 提示标题
$this->assign('msgTitle',$status? L('_OPERATION_SUCCESS_') : L('_OPERATION_FAIL_'));
//如果设置了关闭窗口,则提示完毕后自动关闭窗口
if($this->get('closeWin')) $this->assign('jumpUrl','javascript:window.close();');
$this->assign('status',$status); // 状态
//保证输出不受静态缓存影响
C('HTML_CACHE_ON',false);
if($status) { //发送成功信息
$this->assign('message',$message);// 提示信息
// 成功操作后默认停留1秒
if(!isset($this->waitSecond)) $this->assign('waitSecond','1');
// 默认操作成功自动返回操作前页面
if(!isset($this->jumpUrl)) $this->assign("jumpUrl",$_SERVER["HTTP_REFERER"]);
$this->display(C('TMPL_ACTION_SUCCESS'));
}else{
$this->assign('error',$message);// 提示信息
//发生错误时候默认停留3秒
if(!isset($this->waitSecond)) $this->assign('waitSecond','3');
// 默认发生错误的话自动返回上页
if(!isset($this->jumpUrl)) $this->assign('jumpUrl',"javascript:history.back(-1);");
$this->display(C('TMPL_ACTION_ERROR'));
// 中止执行 避免出错后继续执行
exit ;
}
}
/**
* 析构方法
* @access public
*/
public function __destruct() {
// 执行后续操作
Hook::listen('action_end');
}
}
// 设置控制器别名 便于升级
class_alias('Think\Controller','Think\Action');

View File

@@ -0,0 +1,61 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
namespace Think\Controller;
/**
* ThinkPHP Hprose控制器类
*/
class HproseController {
protected $allowMethodList = '';
protected $crossDomain = false;
protected $P3P = false;
protected $get = true;
protected $debug = false;
/**
* 架构函数
* @access public
*/
public function __construct() {
//控制器初始化
if(method_exists($this,'_initialize'))
$this->_initialize();
//导入类库
Vendor('Hprose.HproseHttpServer');
//实例化HproseHttpServer
$server = new \HproseHttpServer();
if($this->allowMethodList){
$methods = $this->allowMethodList;
}else{
$methods = get_class_methods($this);
$methods = array_diff($methods,array('__construct','__call','_initialize'));
}
$server->addMethods($methods,$this);
if(APP_DEBUG || $this->debug ) {
$server->setDebugEnabled(true);
}
// Hprose设置
$server->setCrossDomainEnabled($this->crossDomain);
$server->setP3PEnabled($this->P3P);
$server->setGetEnabled($this->get);
// 启动server
$server->start();
}
/**
* 魔术方法 有不存在的操作的时候执行
* @access public
* @param string $method 方法名
* @param array $args 参数
* @return mixed
*/
public function __call($method,$args){}
}

View File

@@ -0,0 +1,39 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
namespace Think\Controller;
/**
* ThinkPHP JsonRPC控制器类
*/
class JsonRpcController {
/**
* 架构函数
* @access public
*/
public function __construct() {
//控制器初始化
if(method_exists($this,'_initialize'))
$this->_initialize();
//导入类库
Vendor('jsonRPC.jsonRPCServer');
// 启动server
\jsonRPCServer::handle($this);
}
/**
* 魔术方法 有不存在的操作的时候执行
* @access public
* @param string $method 方法名
* @param array $args 参数
* @return mixed
*/
public function __call($method,$args){}
}

View File

@@ -0,0 +1,234 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
namespace Think\Controller;
use Think\Controller;
use Think\App;
/**
* ThinkPHP REST控制器类
*/
class RestController extends Controller {
// 当前请求类型
protected $_method = '';
// 当前请求的资源类型
protected $_type = '';
// REST允许的请求类型列表
protected $allowMethod = array('get','post','put','delete');
// REST默认请求类型
protected $defaultMethod = 'get';
// REST允许请求的资源类型列表
protected $allowType = array('html','xml','json','rss');
// 默认的资源类型
protected $defaultType = 'html';
// REST允许输出的资源类型列表
protected $allowOutputType= array(
'xml' => 'application/xml',
'json' => 'application/json',
'html' => 'text/html',
);
/**
* 架构函数
* @access public
*/
public function __construct() {
// 资源类型检测
if(''==__EXT__) { // 自动检测资源类型
$this->_type = $this->getAcceptType();
}elseif(!in_array(__EXT__,$this->allowType)) {
// 资源类型非法 则用默认资源类型访问
$this->_type = $this->defaultType;
}else{
$this->_type = __EXT__ ;
}
// 请求方式检测
$method = strtolower(REQUEST_METHOD);
if(!in_array($method,$this->allowMethod)) {
// 请求方式非法 则用默认请求方法
$method = $this->defaultMethod;
}
$this->_method = $method;
parent::__construct();
}
/**
* 魔术方法 有不存在的操作的时候执行
* @access public
* @param string $method 方法名
* @param array $args 参数
* @return mixed
*/
public function __call($method,$args) {
if( 0 === strcasecmp($method,ACTION_NAME.C('ACTION_SUFFIX'))) {
if(method_exists($this,$method.'_'.$this->_method.'_'.$this->_type)) { // RESTFul方法支持
$fun = $method.'_'.$this->_method.'_'.$this->_type;
App::invokeAction($this,$fun);
}elseif($this->_method == $this->defaultMethod && method_exists($this,$method.'_'.$this->_type) ){
$fun = $method.'_'.$this->_type;
App::invokeAction($this,$fun);
}elseif($this->_type == $this->defaultType && method_exists($this,$method.'_'.$this->_method) ){
$fun = $method.'_'.$this->_method;
App::invokeAction($this,$fun);
}elseif(method_exists($this,'_empty')) {
// 如果定义了_empty操作 则调用
$this->_empty($method,$args);
}elseif(file_exists_case($this->view->parseTemplate())){
// 检查是否存在默认模版 如果有直接输出模版
$this->display();
}else{
E(L('_ERROR_ACTION_').':'.ACTION_NAME);
}
}
}
/**
* 获取当前请求的Accept头信息
* @return string
*/
protected function getAcceptType(){
$type = array(
'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',
'html' => 'text/html,application/xhtml+xml,*/*'
);
foreach($type as $key=>$val){
$array = explode(',',$val);
foreach($array as $k=>$v){
if(stristr($_SERVER['HTTP_ACCEPT'], $v)) {
return $key;
}
}
}
return false;
}
// 发送Http状态信息
protected function sendHttpStatus($code) {
static $_status = array(
// 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]);
}
}
/**
* 编码数据
* @access protected
* @param mixed $data 要返回的数据
* @param String $type 返回类型 JSON XML
* @return string
*/
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;
}
/**
* 设置页面输出的CONTENT_TYPE和编码
* @access public
* @param string $type content_type 类型对应的扩展名
* @param string $charset 页面输出编码
* @return void
*/
public function setContentType($type, $charset=''){
if(headers_sent()) return;
if(empty($charset)) $charset = C('DEFAULT_CHARSET');
$type = strtolower($type);
if(isset($this->allowOutputType[$type])) //过滤content_type
header('Content-Type: '.$this->allowOutputType[$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)));
}
}

View File

@@ -0,0 +1,56 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
namespace Think\Controller;
/**
* ThinkPHP RPC控制器类
*/
class RpcController {
protected $allowMethodList = '';
protected $debug = false;
/**
* 架构函数
* @access public
*/
public function __construct() {
//控制器初始化
if(method_exists($this,'_initialize'))
$this->_initialize();
//导入类库
Vendor('phpRPC.phprpc_server');
//实例化phprpc
$server = new \PHPRPC_Server();
if($this->allowMethodList){
$methods = $this->allowMethodList;
}else{
$methods = get_class_methods($this);
$methods = array_diff($methods,array('__construct','__call','_initialize'));
}
$server->add($methods,$this);
if(APP_DEBUG || $this->debug ) {
$server->setDebugMode(true);
}
$server->setEnableGZIP(true);
$server->start();
echo $server->comment();
}
/**
* 魔术方法 有不存在的操作的时候执行
* @access public
* @param string $method 方法名
* @param array $args 参数
* @return mixed
*/
public function __call($method,$args){}
}

View File

@@ -0,0 +1,42 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
namespace Think\Controller;
/**
* ThinkPHP Yar控制器类
*/
class YarController {
/**
* 架构函数
* @access public
*/
public function __construct() {
//控制器初始化
if(method_exists($this,'_initialize'))
$this->_initialize();
//判断扩展是否存在
if(!extension_loaded('yar'))
E(L('_NOT_SUPPORT_').':yar');
//实例化Yar_Server
$server = new \Yar_Server($this);
// 启动server
$server->handle();
}
/**
* 魔术方法 有不存在的操作的时候执行
* @access public
* @param string $method 方法名
* @param array $args 参数
* @return mixed
*/
public function __call($method,$args){}
}

View File

@@ -0,0 +1,53 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
namespace Think;
/**
* 加密解密类
*/
class Crypt {
private static $handler = '';
public static function init($type=''){
$type = $type?:C('DATA_CRYPT_TYPE');
$class = strpos($type,'\\')? $type: 'Think\\Crypt\\Driver\\'. ucwords(strtolower($type));
self::$handler = $class;
}
/**
* 加密字符串
* @param string $str 字符串
* @param string $key 加密key
* @param integer $expire 有效期(秒) 0 为永久有效
* @return string
*/
public static function encrypt($data,$key,$expire=0){
if(empty(self::$handler)){
self::init();
}
$class = self::$handler;
return $class::encrypt($data,$key,$expire);
}
/**
* 解密字符串
* @param string $str 字符串
* @param string $key 加密key
* @return string
*/
public static function decrypt($data,$key){
if(empty(self::$handler)){
self::init();
}
$class = self::$handler;
return $class::decrypt($data,$key);
}
}

View File

@@ -0,0 +1,74 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2009 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
namespace Think\Crypt\Driver;
/**
* Base64 加密实现类
*/
class Base64 {
/**
* 加密字符串
* @param string $str 字符串
* @param string $key 加密key
* @param integer $expire 有效期(秒)
* @return string
*/
public static function encrypt($data,$key,$expire=0) {
$expire = sprintf('%010d', $expire ? $expire + time():0);
$key = md5($key);
$data = base64_encode($expire.$data);
$x=0;
$len = strlen($data);
$l = strlen($key);
for ($i=0;$i< $len;$i++) {
if ($x== $l) $x=0;
$char .=substr($key,$x,1);
$x++;
}
for ($i=0;$i< $len;$i++) {
$str .=chr(ord(substr($data,$i,1))+(ord(substr($char,$i,1)))%256);
}
return $str;
}
/**
* 解密字符串
* @param string $str 字符串
* @param string $key 加密key
* @return string
*/
public static function decrypt($data,$key) {
$key = md5($key);
$x=0;
$len = strlen($data);
$l = strlen($key);
for ($i=0;$i< $len;$i++) {
if ($x== $l) $x=0;
$char .=substr($key,$x,1);
$x++;
}
for ($i=0;$i< $len;$i++) {
if (ord(substr($data,$i,1))<ord(substr($char,$i,1))) {
$str .=chr((ord(substr($data,$i,1))+256)-ord(substr($char,$i,1)));
}else{
$str .=chr(ord(substr($data,$i,1))-ord(substr($char,$i,1)));
}
}
$data = base64_decode($str);
$expire = substr($data,0,10);
if($expire > 0 && $expire < time()) {
return '';
}
$data = substr($data,10);
return $data;
}
}

View File

@@ -0,0 +1,83 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2009 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
namespace Think\Crypt\Driver;
/**
* Crypt 加密实现类
* @category ORG
* @package ORG
* @subpackage Crypt
* @author liu21st <liu21st@gmail.com>
*/
class Crypt {
/**
* 加密字符串
* @param string $str 字符串
* @param string $key 加密key
* @param integer $expire 有效期(秒)
* @return string
*/
public static function encrypt($str,$key,$expire=0){
$expire = sprintf('%010d', $expire ? $expire + time():0);
$r = md5($key);
$c = 0;
$v = "";
$str = $expire.$str;
$len = strlen($str);
$l = strlen($r);
for ($i=0;$i<$len;$i++){
if ($c== $l) $c=0;
$v .= substr($r,$c,1) .
(substr($str,$i,1) ^ substr($r,$c,1));
$c++;
}
return self::ed($v,$key);
}
/**
* 解密字符串
* @param string $str 字符串
* @param string $key 加密key
* @return string
*/
public static function decrypt($str,$key) {
$str = self::ed($str,$key);
$v = "";
$len = strlen($str);
for ($i=0;$i<$len;$i++){
$md5 = substr($str,$i,1);
$i++;
$v .= (substr($str,$i,1) ^ $md5);
}
$data = $v;
$expire = substr($data,0,10);
if($expire > 0 && $expire < time()) {
return '';
}
$data = substr($data,10);
return $data;
}
static private function ed($str,$key) {
$r = md5($key);
$c = 0;
$v = '';
$len = strlen($str);
$l = strlen($r);
for ($i=0;$i<$len;$i++) {
if ($c==$l) $c=0;
$v .= substr($str,$i,1) ^ substr($r,$c,1);
$c++;
}
return $v;
}
}

View File

@@ -0,0 +1,241 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2009 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
namespace Think\Crypt\Driver;
/**
* Des 加密实现类
* Converted from JavaScript to PHP by Jim Gibbs, June 2004 Paul Tero, July 2001
* Optimised for performance with large blocks by Michael Hayworth, November 2001
* http://www.netdealing.com
*/
class Des {
/**
* 加密字符串
* @param string $str 字符串
* @param string $key 加密key
* @param integer $expire 有效期(秒)
* @return string
*/
public static function encrypt($str, $key,$expire=0) {
if ($str == "") {
return "";
}
$expire = sprintf('%010d', $expire ? $expire + time():0);
$str = $expire.$str;
return self::_des($key,$str,1);
}
/**
* 解密字符串
* @param string $str 字符串
* @param string $key 加密key
* @return string
*/
public static function decrypt($str, $key) {
if ($str == "") {
return "";
}
$data = self::_des($key,$str,0);
$expire = substr($data,0,10);
if($expire > 0 && $expire < time()) {
return '';
}
$data = substr($data,10);
return $data;
}
/**
* Des算法
* @param string $str 字符串
* @param string $key 加密key
* @return string
*/
private static function _des($key, $message, $encrypt, $mode=0, $iv=null) {
//declaring this locally speeds things up a bit
$spfunction1 = array (0x1010400,0,0x10000,0x1010404,0x1010004,0x10404,0x4,0x10000,0x400,0x1010400,0x1010404,0x400,0x1000404,0x1010004,0x1000000,0x4,0x404,0x1000400,0x1000400,0x10400,0x10400,0x1010000,0x1010000,0x1000404,0x10004,0x1000004,0x1000004,0x10004,0,0x404,0x10404,0x1000000,0x10000,0x1010404,0x4,0x1010000,0x1010400,0x1000000,0x1000000,0x400,0x1010004,0x10000,0x10400,0x1000004,0x400,0x4,0x1000404,0x10404,0x1010404,0x10004,0x1010000,0x1000404,0x1000004,0x404,0x10404,0x1010400,0x404,0x1000400,0x1000400,0,0x10004,0x10400,0,0x1010004);
$spfunction2 = array (-0x7fef7fe0,-0x7fff8000,0x8000,0x108020,0x100000,0x20,-0x7fefffe0,-0x7fff7fe0,-0x7fffffe0,-0x7fef7fe0,-0x7fef8000,-0x80000000,-0x7fff8000,0x100000,0x20,-0x7fefffe0,0x108000,0x100020,-0x7fff7fe0,0,-0x80000000,0x8000,0x108020,-0x7ff00000,0x100020,-0x7fffffe0,0,0x108000,0x8020,-0x7fef8000,-0x7ff00000,0x8020,0,0x108020,-0x7fefffe0,0x100000,-0x7fff7fe0,-0x7ff00000,-0x7fef8000,0x8000,-0x7ff00000,-0x7fff8000,0x20,-0x7fef7fe0,0x108020,0x20,0x8000,-0x80000000,0x8020,-0x7fef8000,0x100000,-0x7fffffe0,0x100020,-0x7fff7fe0,-0x7fffffe0,0x100020,0x108000,0,-0x7fff8000,0x8020,-0x80000000,-0x7fefffe0,-0x7fef7fe0,0x108000);
$spfunction3 = array (0x208,0x8020200,0,0x8020008,0x8000200,0,0x20208,0x8000200,0x20008,0x8000008,0x8000008,0x20000,0x8020208,0x20008,0x8020000,0x208,0x8000000,0x8,0x8020200,0x200,0x20200,0x8020000,0x8020008,0x20208,0x8000208,0x20200,0x20000,0x8000208,0x8,0x8020208,0x200,0x8000000,0x8020200,0x8000000,0x20008,0x208,0x20000,0x8020200,0x8000200,0,0x200,0x20008,0x8020208,0x8000200,0x8000008,0x200,0,0x8020008,0x8000208,0x20000,0x8000000,0x8020208,0x8,0x20208,0x20200,0x8000008,0x8020000,0x8000208,0x208,0x8020000,0x20208,0x8,0x8020008,0x20200);
$spfunction4 = array (0x802001,0x2081,0x2081,0x80,0x802080,0x800081,0x800001,0x2001,0,0x802000,0x802000,0x802081,0x81,0,0x800080,0x800001,0x1,0x2000,0x800000,0x802001,0x80,0x800000,0x2001,0x2080,0x800081,0x1,0x2080,0x800080,0x2000,0x802080,0x802081,0x81,0x800080,0x800001,0x802000,0x802081,0x81,0,0,0x802000,0x2080,0x800080,0x800081,0x1,0x802001,0x2081,0x2081,0x80,0x802081,0x81,0x1,0x2000,0x800001,0x2001,0x802080,0x800081,0x2001,0x2080,0x800000,0x802001,0x80,0x800000,0x2000,0x802080);
$spfunction5 = array (0x100,0x2080100,0x2080000,0x42000100,0x80000,0x100,0x40000000,0x2080000,0x40080100,0x80000,0x2000100,0x40080100,0x42000100,0x42080000,0x80100,0x40000000,0x2000000,0x40080000,0x40080000,0,0x40000100,0x42080100,0x42080100,0x2000100,0x42080000,0x40000100,0,0x42000000,0x2080100,0x2000000,0x42000000,0x80100,0x80000,0x42000100,0x100,0x2000000,0x40000000,0x2080000,0x42000100,0x40080100,0x2000100,0x40000000,0x42080000,0x2080100,0x40080100,0x100,0x2000000,0x42080000,0x42080100,0x80100,0x42000000,0x42080100,0x2080000,0,0x40080000,0x42000000,0x80100,0x2000100,0x40000100,0x80000,0,0x40080000,0x2080100,0x40000100);
$spfunction6 = array (0x20000010,0x20400000,0x4000,0x20404010,0x20400000,0x10,0x20404010,0x400000,0x20004000,0x404010,0x400000,0x20000010,0x400010,0x20004000,0x20000000,0x4010,0,0x400010,0x20004010,0x4000,0x404000,0x20004010,0x10,0x20400010,0x20400010,0,0x404010,0x20404000,0x4010,0x404000,0x20404000,0x20000000,0x20004000,0x10,0x20400010,0x404000,0x20404010,0x400000,0x4010,0x20000010,0x400000,0x20004000,0x20000000,0x4010,0x20000010,0x20404010,0x404000,0x20400000,0x404010,0x20404000,0,0x20400010,0x10,0x4000,0x20400000,0x404010,0x4000,0x400010,0x20004010,0,0x20404000,0x20000000,0x400010,0x20004010);
$spfunction7 = array (0x200000,0x4200002,0x4000802,0,0x800,0x4000802,0x200802,0x4200800,0x4200802,0x200000,0,0x4000002,0x2,0x4000000,0x4200002,0x802,0x4000800,0x200802,0x200002,0x4000800,0x4000002,0x4200000,0x4200800,0x200002,0x4200000,0x800,0x802,0x4200802,0x200800,0x2,0x4000000,0x200800,0x4000000,0x200800,0x200000,0x4000802,0x4000802,0x4200002,0x4200002,0x2,0x200002,0x4000000,0x4000800,0x200000,0x4200800,0x802,0x200802,0x4200800,0x802,0x4000002,0x4200802,0x4200000,0x200800,0,0x2,0x4200802,0,0x200802,0x4200000,0x800,0x4000002,0x4000800,0x800,0x200002);
$spfunction8 = array (0x10001040,0x1000,0x40000,0x10041040,0x10000000,0x10001040,0x40,0x10000000,0x40040,0x10040000,0x10041040,0x41000,0x10041000,0x41040,0x1000,0x40,0x10040000,0x10000040,0x10001000,0x1040,0x41000,0x40040,0x10040040,0x10041000,0x1040,0,0,0x10040040,0x10000040,0x10001000,0x41040,0x40000,0x41040,0x40000,0x10041000,0x1000,0x40,0x10040040,0x1000,0x41040,0x10001000,0x40,0x10000040,0x10040000,0x10040040,0x10000000,0x40000,0x10001040,0,0x10041040,0x40040,0x10000040,0x10040000,0x10001000,0x10001040,0,0x10041040,0x41000,0x41000,0x1040,0x1040,0x40040,0x10000000,0x10041000);
$masks = array (4294967295,2147483647,1073741823,536870911,268435455,134217727,67108863,33554431,16777215,8388607,4194303,2097151,1048575,524287,262143,131071,65535,32767,16383,8191,4095,2047,1023,511,255,127,63,31,15,7,3,1,0);
//create the 16 or 48 subkeys we will need
$keys = self::_createKeys ($key);
$m=0;
$len = strlen($message);
$chunk = 0;
//set up the loops for single and triple des
$iterations = ((count($keys) == 32) ? 3 : 9); //single or triple des
if ($iterations == 3) {$looping = (($encrypt) ? array (0, 32, 2) : array (30, -2, -2));}
else {$looping = (($encrypt) ? array (0, 32, 2, 62, 30, -2, 64, 96, 2) : array (94, 62, -2, 32, 64, 2, 30, -2, -2));}
$message .= (chr(0) . chr(0) . chr(0) . chr(0) . chr(0) . chr(0) . chr(0) . chr(0)); //pad the message out with null bytes
//store the result here
$result = "";
$tempresult = "";
if ($mode == 1) { //CBC mode
$cbcleft = (ord($iv{$m++}) << 24) | (ord($iv{$m++}) << 16) | (ord($iv{$m++}) << 8) | ord($iv{$m++});
$cbcright = (ord($iv{$m++}) << 24) | (ord($iv{$m++}) << 16) | (ord($iv{$m++}) << 8) | ord($iv{$m++});
$m=0;
}
//loop through each 64 bit chunk of the message
while ($m < $len) {
$left = (ord($message{$m++}) << 24) | (ord($message{$m++}) << 16) | (ord($message{$m++}) << 8) | ord($message{$m++});
$right = (ord($message{$m++}) << 24) | (ord($message{$m++}) << 16) | (ord($message{$m++}) << 8) | ord($message{$m++});
//for Cipher Block Chaining mode, xor the message with the previous result
if ($mode == 1) {if ($encrypt) {$left ^= $cbcleft; $right ^= $cbcright;} else {$cbcleft2 = $cbcleft; $cbcright2 = $cbcright; $cbcleft = $left; $cbcright = $right;}}
//first each 64 but chunk of the message must be permuted according to IP
$temp = (($left >> 4 & $masks[4]) ^ $right) & 0x0f0f0f0f; $right ^= $temp; $left ^= ($temp << 4);
$temp = (($left >> 16 & $masks[16]) ^ $right) & 0x0000ffff; $right ^= $temp; $left ^= ($temp << 16);
$temp = (($right >> 2 & $masks[2]) ^ $left) & 0x33333333; $left ^= $temp; $right ^= ($temp << 2);
$temp = (($right >> 8 & $masks[8]) ^ $left) & 0x00ff00ff; $left ^= $temp; $right ^= ($temp << 8);
$temp = (($left >> 1 & $masks[1]) ^ $right) & 0x55555555; $right ^= $temp; $left ^= ($temp << 1);
$left = (($left << 1) | ($left >> 31 & $masks[31]));
$right = (($right << 1) | ($right >> 31 & $masks[31]));
//do this either 1 or 3 times for each chunk of the message
for ($j=0; $j<$iterations; $j+=3) {
$endloop = $looping[$j+1];
$loopinc = $looping[$j+2];
//now go through and perform the encryption or decryption
for ($i=$looping[$j]; $i!=$endloop; $i+=$loopinc) { //for efficiency
$right1 = $right ^ $keys[$i];
$right2 = (($right >> 4 & $masks[4]) | ($right << 28)) ^ $keys[$i+1];
//the result is attained by passing these bytes through the S selection functions
$temp = $left;
$left = $right;
$right = $temp ^ ($spfunction2[($right1 >> 24 & $masks[24]) & 0x3f] | $spfunction4[($right1 >> 16 & $masks[16]) & 0x3f]
| $spfunction6[($right1 >> 8 & $masks[8]) & 0x3f] | $spfunction8[$right1 & 0x3f]
| $spfunction1[($right2 >> 24 & $masks[24]) & 0x3f] | $spfunction3[($right2 >> 16 & $masks[16]) & 0x3f]
| $spfunction5[($right2 >> 8 & $masks[8]) & 0x3f] | $spfunction7[$right2 & 0x3f]);
}
$temp = $left; $left = $right; $right = $temp; //unreverse left and right
} //for either 1 or 3 iterations
//move then each one bit to the right
$left = (($left >> 1 & $masks[1]) | ($left << 31));
$right = (($right >> 1 & $masks[1]) | ($right << 31));
//now perform IP-1, which is IP in the opposite direction
$temp = (($left >> 1 & $masks[1]) ^ $right) & 0x55555555; $right ^= $temp; $left ^= ($temp << 1);
$temp = (($right >> 8 & $masks[8]) ^ $left) & 0x00ff00ff; $left ^= $temp; $right ^= ($temp << 8);
$temp = (($right >> 2 & $masks[2]) ^ $left) & 0x33333333; $left ^= $temp; $right ^= ($temp << 2);
$temp = (($left >> 16 & $masks[16]) ^ $right) & 0x0000ffff; $right ^= $temp; $left ^= ($temp << 16);
$temp = (($left >> 4 & $masks[4]) ^ $right) & 0x0f0f0f0f; $right ^= $temp; $left ^= ($temp << 4);
//for Cipher Block Chaining mode, xor the message with the previous result
if ($mode == 1) {if ($encrypt) {$cbcleft = $left; $cbcright = $right;} else {$left ^= $cbcleft2; $right ^= $cbcright2;}}
$tempresult .= (chr($left>>24 & $masks[24]) . chr(($left>>16 & $masks[16]) & 0xff) . chr(($left>>8 & $masks[8]) & 0xff) . chr($left & 0xff) . chr($right>>24 & $masks[24]) . chr(($right>>16 & $masks[16]) & 0xff) . chr(($right>>8 & $masks[8]) & 0xff) . chr($right & 0xff));
$chunk += 8;
if ($chunk == 512) {$result .= $tempresult; $tempresult = ""; $chunk = 0;}
} //for every 8 characters, or 64 bits in the message
//return the result as an array
return ($result . $tempresult);
} //end of des
/**
* createKeys
* this takes as input a 64 bit key (even though only 56 bits are used)
* as an array of 2 integers, and returns 16 48 bit keys
* @param string $key 加密key
* @return string
*/
private static function _createKeys ($key) {
//declaring this locally speeds things up a bit
$pc2bytes0 = array (0,0x4,0x20000000,0x20000004,0x10000,0x10004,0x20010000,0x20010004,0x200,0x204,0x20000200,0x20000204,0x10200,0x10204,0x20010200,0x20010204);
$pc2bytes1 = array (0,0x1,0x100000,0x100001,0x4000000,0x4000001,0x4100000,0x4100001,0x100,0x101,0x100100,0x100101,0x4000100,0x4000101,0x4100100,0x4100101);
$pc2bytes2 = array (0,0x8,0x800,0x808,0x1000000,0x1000008,0x1000800,0x1000808,0,0x8,0x800,0x808,0x1000000,0x1000008,0x1000800,0x1000808);
$pc2bytes3 = array (0,0x200000,0x8000000,0x8200000,0x2000,0x202000,0x8002000,0x8202000,0x20000,0x220000,0x8020000,0x8220000,0x22000,0x222000,0x8022000,0x8222000);
$pc2bytes4 = array (0,0x40000,0x10,0x40010,0,0x40000,0x10,0x40010,0x1000,0x41000,0x1010,0x41010,0x1000,0x41000,0x1010,0x41010);
$pc2bytes5 = array (0,0x400,0x20,0x420,0,0x400,0x20,0x420,0x2000000,0x2000400,0x2000020,0x2000420,0x2000000,0x2000400,0x2000020,0x2000420);
$pc2bytes6 = array (0,0x10000000,0x80000,0x10080000,0x2,0x10000002,0x80002,0x10080002,0,0x10000000,0x80000,0x10080000,0x2,0x10000002,0x80002,0x10080002);
$pc2bytes7 = array (0,0x10000,0x800,0x10800,0x20000000,0x20010000,0x20000800,0x20010800,0x20000,0x30000,0x20800,0x30800,0x20020000,0x20030000,0x20020800,0x20030800);
$pc2bytes8 = array (0,0x40000,0,0x40000,0x2,0x40002,0x2,0x40002,0x2000000,0x2040000,0x2000000,0x2040000,0x2000002,0x2040002,0x2000002,0x2040002);
$pc2bytes9 = array (0,0x10000000,0x8,0x10000008,0,0x10000000,0x8,0x10000008,0x400,0x10000400,0x408,0x10000408,0x400,0x10000400,0x408,0x10000408);
$pc2bytes10 = array (0,0x20,0,0x20,0x100000,0x100020,0x100000,0x100020,0x2000,0x2020,0x2000,0x2020,0x102000,0x102020,0x102000,0x102020);
$pc2bytes11 = array (0,0x1000000,0x200,0x1000200,0x200000,0x1200000,0x200200,0x1200200,0x4000000,0x5000000,0x4000200,0x5000200,0x4200000,0x5200000,0x4200200,0x5200200);
$pc2bytes12 = array (0,0x1000,0x8000000,0x8001000,0x80000,0x81000,0x8080000,0x8081000,0x10,0x1010,0x8000010,0x8001010,0x80010,0x81010,0x8080010,0x8081010);
$pc2bytes13 = array (0,0x4,0x100,0x104,0,0x4,0x100,0x104,0x1,0x5,0x101,0x105,0x1,0x5,0x101,0x105);
$masks = array (4294967295,2147483647,1073741823,536870911,268435455,134217727,67108863,33554431,16777215,8388607,4194303,2097151,1048575,524287,262143,131071,65535,32767,16383,8191,4095,2047,1023,511,255,127,63,31,15,7,3,1,0);
//how many iterations (1 for des, 3 for triple des)
$iterations = ((strlen($key) >= 24) ? 3 : 1);
//stores the return keys
$keys = array (); // size = 32 * iterations but you don't specify this in php
//now define the left shifts which need to be done
$shifts = array (0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0);
//other variables
$m=0;
$n=0;
for ($j=0; $j<$iterations; $j++) { //either 1 or 3 iterations
$left = (ord($key{$m++}) << 24) | (ord($key{$m++}) << 16) | (ord($key{$m++}) << 8) | ord($key{$m++});
$right = (ord($key{$m++}) << 24) | (ord($key{$m++}) << 16) | (ord($key{$m++}) << 8) | ord($key{$m++});
$temp = (($left >> 4 & $masks[4]) ^ $right) & 0x0f0f0f0f; $right ^= $temp; $left ^= ($temp << 4);
$temp = (($right >> 16 & $masks[16]) ^ $left) & 0x0000ffff; $left ^= $temp; $right ^= ($temp << -16);
$temp = (($left >> 2 & $masks[2]) ^ $right) & 0x33333333; $right ^= $temp; $left ^= ($temp << 2);
$temp = (($right >> 16 & $masks[16]) ^ $left) & 0x0000ffff; $left ^= $temp; $right ^= ($temp << -16);
$temp = (($left >> 1 & $masks[1]) ^ $right) & 0x55555555; $right ^= $temp; $left ^= ($temp << 1);
$temp = (($right >> 8 & $masks[8]) ^ $left) & 0x00ff00ff; $left ^= $temp; $right ^= ($temp << 8);
$temp = (($left >> 1 & $masks[1]) ^ $right) & 0x55555555; $right ^= $temp; $left ^= ($temp << 1);
//the right side needs to be shifted and to get the last four bits of the left side
$temp = ($left << 8) | (($right >> 20 & $masks[20]) & 0x000000f0);
//left needs to be put upside down
$left = ($right << 24) | (($right << 8) & 0xff0000) | (($right >> 8 & $masks[8]) & 0xff00) | (($right >> 24 & $masks[24]) & 0xf0);
$right = $temp;
//now go through and perform these shifts on the left and right keys
for ($i=0; $i < count($shifts); $i++) {
//shift the keys either one or two bits to the left
if ($shifts[$i] > 0) {
$left = (($left << 2) | ($left >> 26 & $masks[26]));
$right = (($right << 2) | ($right >> 26 & $masks[26]));
} else {
$left = (($left << 1) | ($left >> 27 & $masks[27]));
$right = (($right << 1) | ($right >> 27 & $masks[27]));
}
$left = $left & -0xf;
$right = $right & -0xf;
//now apply PC-2, in such a way that E is easier when encrypting or decrypting
//this conversion will look like PC-2 except only the last 6 bits of each byte are used
//rather than 48 consecutive bits and the order of lines will be according to
//how the S selection functions will be applied: S2, S4, S6, S8, S1, S3, S5, S7
$lefttemp = $pc2bytes0[$left >> 28 & $masks[28]] | $pc2bytes1[($left >> 24 & $masks[24]) & 0xf]
| $pc2bytes2[($left >> 20 & $masks[20]) & 0xf] | $pc2bytes3[($left >> 16 & $masks[16]) & 0xf]
| $pc2bytes4[($left >> 12 & $masks[12]) & 0xf] | $pc2bytes5[($left >> 8 & $masks[8]) & 0xf]
| $pc2bytes6[($left >> 4 & $masks[4]) & 0xf];
$righttemp = $pc2bytes7[$right >> 28 & $masks[28]] | $pc2bytes8[($right >> 24 & $masks[24]) & 0xf]
| $pc2bytes9[($right >> 20 & $masks[20]) & 0xf] | $pc2bytes10[($right >> 16 & $masks[16]) & 0xf]
| $pc2bytes11[($right >> 12 & $masks[12]) & 0xf] | $pc2bytes12[($right >> 8 & $masks[8]) & 0xf]
| $pc2bytes13[($right >> 4 & $masks[4]) & 0xf];
$temp = (($righttemp >> 16 & $masks[16]) ^ $lefttemp) & 0x0000ffff;
$keys[$n++] = $lefttemp ^ $temp; $keys[$n++] = $righttemp ^ ($temp << 16);
}
} //for each iterations
//return the keys we've created
return $keys;
} //end of des_createKeys
}

View File

@@ -0,0 +1,86 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2009 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
namespace Think\Crypt\Driver;
/**
* Base64 加密实现类
*/
class Think {
/**
* 加密字符串
* @param string $str 字符串
* @param string $key 加密key
* @param integer $expire 有效期(秒)
* @return string
*/
public static function encrypt($data,$key,$expire=0) {
$expire = sprintf('%010d', $expire ? $expire + time():0);
$key = md5($key);
$data = base64_encode($expire.$data);
$x = 0;
$len = strlen($data);
$l = strlen($key);
$char = $str = '';
for ($i = 0; $i < $len; $i++) {
if ($x == $l) $x = 0;
$char .= substr($key, $x, 1);
$x++;
}
for ($i = 0; $i < $len; $i++) {
$str .= chr(ord(substr($data, $i, 1)) + (ord(substr($char, $i, 1)))%256);
}
return str_replace(array('+','/','='),array('-','_',''),base64_encode($str));
}
/**
* 解密字符串
* @param string $str 字符串
* @param string $key 加密key
* @return string
*/
public static function decrypt($data,$key) {
$key = md5($key);
$data = str_replace(array('-','_'),array('+','/'),$data);
$mod4 = strlen($data) % 4;
if ($mod4) {
$data .= substr('====', $mod4);
}
$data = base64_decode($data);
$x = 0;
$len = strlen($data);
$l = strlen($key);
$char = $str = '';
for ($i = 0; $i < $len; $i++) {
if ($x == $l) $x = 0;
$char .= substr($key, $x, 1);
$x++;
}
for ($i = 0; $i < $len; $i++) {
if (ord(substr($data, $i, 1))<ord(substr($char, $i, 1))) {
$str .= chr((ord(substr($data, $i, 1)) + 256) - ord(substr($char, $i, 1)));
}else{
$str .= chr(ord(substr($data, $i, 1)) - ord(substr($char, $i, 1)));
}
}
$data = base64_decode($str);
$expire = substr($data,0,10);
if($expire > 0 && $expire < time()) {
return '';
}
$data = substr($data,10);
return $data;
}
}

View File

@@ -0,0 +1,116 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2009 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
namespace Think\Crypt\Driver;
/**
* Xxtea 加密实现类
*/
class Xxtea {
/**
* 加密字符串
* @param string $str 字符串
* @param string $key 加密key
* @param integer $expire 有效期(秒)
* @return string
*/
public static function encrypt($str, $key,$expire=0) {
$expire = sprintf('%010d', $expire ? $expire + time():0);
$str = $expire.$str;
$v = self::str2long($str, true);
$k = self::str2long($key, false);
$n = count($v) - 1;
$z = $v[$n];
$y = $v[0];
$delta = 0x9E3779B9;
$q = floor(6 + 52 / ($n + 1));
$sum = 0;
while (0 < $q--) {
$sum = self::int32($sum + $delta);
$e = $sum >> 2 & 3;
for ($p = 0; $p < $n; $p++) {
$y = $v[$p + 1];
$mx = self::int32((($z >> 5 & 0x07ffffff) ^ $y << 2) + (($y >> 3 & 0x1fffffff) ^ $z << 4)) ^ self::int32(($sum ^ $y) + ($k[$p & 3 ^ $e] ^ $z));
$z = $v[$p] = self::int32($v[$p] + $mx);
}
$y = $v[0];
$mx = self::int32((($z >> 5 & 0x07ffffff) ^ $y << 2) + (($y >> 3 & 0x1fffffff) ^ $z << 4)) ^ self::int32(($sum ^ $y) + ($k[$p & 3 ^ $e] ^ $z));
$z = $v[$n] = self::int32($v[$n] + $mx);
}
return self::long2str($v, false);
}
/**
* 解密字符串
* @param string $str 字符串
* @param string $key 加密key
* @return string
*/
public static function decrypt($str, $key) {
$v = self::str2long($str, false);
$k = self::str2long($key, false);
$n = count($v) - 1;
$z = $v[$n];
$y = $v[0];
$delta = 0x9E3779B9;
$q = floor(6 + 52 / ($n + 1));
$sum = self::int32($q * $delta);
while ($sum != 0) {
$e = $sum >> 2 & 3;
for ($p = $n; $p > 0; $p--) {
$z = $v[$p - 1];
$mx = self::int32((($z >> 5 & 0x07ffffff) ^ $y << 2) + (($y >> 3 & 0x1fffffff) ^ $z << 4)) ^ self::int32(($sum ^ $y) + ($k[$p & 3 ^ $e] ^ $z));
$y = $v[$p] = self::int32($v[$p] - $mx);
}
$z = $v[$n];
$mx = self::int32((($z >> 5 & 0x07ffffff) ^ $y << 2) + (($y >> 3 & 0x1fffffff) ^ $z << 4)) ^ self::int32(($sum ^ $y) + ($k[$p & 3 ^ $e] ^ $z));
$y = $v[0] = self::int32($v[0] - $mx);
$sum = self::int32($sum - $delta);
}
$data = self::long2str($v, true);
$expire = substr($data,0,10);
if($expire > 0 && $expire < time()) {
return '';
}
$data = substr($data,10);
return $data;
}
private static function long2str($v, $w) {
$len = count($v);
$s = array();
for ($i = 0; $i < $len; $i++) {
$s[$i] = pack("V", $v[$i]);
}
if ($w) {
return substr(join('', $s), 0, $v[$len - 1]);
}else{
return join('', $s);
}
}
private static function str2long($s, $w) {
$v = unpack("V*", $s. str_repeat("\0", (4 - strlen($s) % 4) & 3));
$v = array_values($v);
if ($w) {
$v[count($v)] = strlen($s);
}
return $v;
}
private static function int32($n) {
while ($n >= 2147483648) $n -= 4294967296;
while ($n <= -2147483649) $n += 4294967296;
return (int)$n;
}
}

View File

@@ -0,0 +1,137 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn 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 = array(); // 数据库连接实例
static private $_instance = null; // 当前数据库连接实例
/**
* 取得数据库类实例
* @static
* @access public
* @param mixed $config 连接配置
* @return Object 返回数据库驱动类
*/
static public function getInstance($config=array()) {
$md5 = md5(serialize($config));
if(!isset(self::$instance[$md5])) {
// 解析连接参数 支持数组和字符串
$options = self::parseConfig($config);
// 兼容mysqli
if('mysqli' == $options['type']) $options['type'] = 'mysql';
// 如果采用lite方式 仅支持原生SQL 包括query和execute方法
$class = !empty($options['lite'])? 'Think\Db\Lite' : 'Think\\Db\\Driver\\'.ucwords(strtolower($options['type']));
if(class_exists($class)){
self::$instance[$md5] = new $class($options);
}else{
// 类没有定义
E(L('_NO_DB_DRIVER_').': ' . $class);
}
}
self::$_instance = self::$instance[$md5];
return self::$_instance;
}
/**
* 数据库连接参数解析
* @static
* @access private
* @param mixed $config
* @return array
*/
static private function parseConfig($config){
if(!empty($config)){
if(is_string($config)) {
return self::parseDsn($config);
}
$config = array_change_key_case($config);
$config = array (
'type' => $config['db_type'],
'username' => $config['db_user'],
'password' => $config['db_pwd'],
'hostname' => $config['db_host'],
'hostport' => $config['db_port'],
'database' => $config['db_name'],
'dsn' => isset($config['db_dsn'])?$config['db_dsn']:null,
'params' => isset($config['db_params'])?$config['db_params']:null,
'charset' => isset($config['db_charset'])?$config['db_charset']:'utf8',
'deploy' => isset($config['db_deploy_type'])?$config['db_deploy_type']:0,
'rw_separate' => isset($config['db_rw_separate'])?$config['db_rw_separate']:false,
'master_num' => isset($config['db_master_num'])?$config['db_master_num']:1,
'slave_no' => isset($config['db_slave_no'])?$config['db_slave_no']:'',
'debug' => isset($config['db_debug'])?$config['db_debug']:APP_DEBUG,
'lite' => isset($config['db_lite'])?$config['db_lite']:false,
);
}else {
$config = array (
'type' => C('DB_TYPE'),
'username' => C('DB_USER'),
'password' => C('DB_PWD'),
'hostname' => C('DB_HOST'),
'hostport' => C('DB_PORT'),
'database' => C('DB_NAME'),
'dsn' => C('DB_DSN'),
'params' => C('DB_PARAMS'),
'charset' => C('DB_CHARSET'),
'deploy' => C('DB_DEPLOY_TYPE'),
'rw_separate' => C('DB_RW_SEPARATE'),
'master_num' => C('DB_MASTER_NUM'),
'slave_no' => C('DB_SLAVE_NO'),
'debug' => C('DB_DEBUG',null,APP_DEBUG),
'lite' => C('DB_LITE'),
);
}
return $config;
}
/**
* DSN解析
* 格式: mysql://username:passwd@localhost:3306/DbName?param1=val1&param2=val2#utf8
* @static
* @access private
* @param string $dsnStr
* @return array
*/
static private function parseDsn($dsnStr) {
if( empty($dsnStr) ){return false;}
$info = parse_url($dsnStr);
if(!$info) {
return false;
}
$dsn = array(
'type' => $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']:'utf8',
);
if(isset($info['query'])) {
parse_str($info['query'],$dsn['params']);
}else{
$dsn['params'] = array();
}
return $dsn;
}
// 调用驱动类的方法
static public function __callStatic($method, $params){
return call_user_func_array(array(self::$_instance, $method), $params);
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,151 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 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;
/**
* Firebird数据库驱动
*/
class Firebird extends Driver{
protected $selectSql = 'SELECT %LIMIT% %DISTINCT% %FIELD% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%%ORDER%';
/**
* 解析pdo连接的dsn信息
* @access public
* @param array $config 连接信息
* @return string
*/
protected function parseDsn($config){
$dsn = 'firebird:dbname='.$config['hostname'].'/'.($config['hostport']?:3050).':'.$config['database'];
return $dsn;
}
/**
* 执行语句
* @access public
* @param string $str sql指令
* @param boolean $fetchSql 不执行只是获取SQL
* @return mixed
*/
public function execute($str,$fetchSql=false) {
$this->initConnect(true);
if ( !$this->_linkID ) return false;
$this->queryStr = $str;
if(!empty($this->bind)){
$that = $this;
$this->queryStr = strtr($this->queryStr,array_map(function($val) use($that){ return '\''.$that->escapeString($val).'\''; },$this->bind));
}
if($fetchSql){
return $this->queryStr;
}
//释放前次的查询结果
if ( !empty($this->PDOStatement) ) $this->free();
$this->executeTimes++;
N('db_write',1); // 兼容代码
// 记录开始执行时间
$this->debug(true);
$this->PDOStatement = $this->_linkID->prepare($str);
if(false === $this->PDOStatement) {
E($this->error());
}
foreach ($this->bind as $key => $val) {
if(is_array($val)){
$this->PDOStatement->bindValue($key, $val[0], $val[1]);
}else{
$this->PDOStatement->bindValue($key, $val);
}
}
$this->bind = array();
$result = $this->PDOStatement->execute();
$this->debug(false);
if ( false === $result) {
$this->error();
return false;
} else {
$this->numRows = $this->PDOStatement->rowCount();
return $this->numRows;
}
}
/**
* 取得数据表的字段信息
* @access public
*/
public function getFields($tableName) {
$this->initConnect(true);
list($tableName) = explode(' ', $tableName);
$sql='SELECT RF.RDB$FIELD_NAME AS FIELD,RF.RDB$DEFAULT_VALUE AS DEFAULT1,RF.RDB$NULL_FLAG AS NULL1,TRIM(T.RDB$TYPE_NAME) || \'(\' || F.RDB$FIELD_LENGTH || \')\' as TYPE FROM RDB$RELATION_FIELDS RF LEFT JOIN RDB$FIELDS F ON (F.RDB$FIELD_NAME = RF.RDB$FIELD_SOURCE) LEFT JOIN RDB$TYPES T ON (T.RDB$TYPE = F.RDB$FIELD_TYPE) WHERE RDB$RELATION_NAME=UPPER(\''.$tableName.'\') AND T.RDB$FIELD_NAME = \'RDB$FIELD_TYPE\' ORDER By RDB$FIELD_POSITION';
$result = $this->query($sql);
$info = array();
if($result){
foreach($result as $key => $val){
$info[trim($val['field'])] = array(
'name' => trim($val['field']),
'type' => $val['type'],
'notnull' => (bool) ($val['null1'] ==1), // 1表示不为Null
'default' => $val['default1'],
'primary' => false,
'autoinc' => false,
);
}
}
//获取主键
$sql='select b.rdb$field_name as field_name from rdb$relation_constraints a join rdb$index_segments b on a.rdb$index_name=b.rdb$index_name where a.rdb$constraint_type=\'PRIMARY KEY\' and a.rdb$relation_name=UPPER(\''.$tableName.'\')';
$rs_temp = $this->query($sql);
foreach($rs_temp as $row) {
$info[trim($row['field_name'])]['primary']= true;
}
return $info;
}
/**
* 取得数据库的表信息
* @access public
*/
public function getTables($dbName='') {
$sql='SELECT DISTINCT RDB$RELATION_NAME FROM RDB$RELATION_FIELDS WHERE RDB$SYSTEM_FLAG=0';
$result = $this->query($sql);
$info = array();
foreach ($result as $key => $val) {
$info[$key] = trim(current($val));
}
return $info;
}
/**
* SQL指令安全过滤
* @access public
* @param string $str SQL指令
* @return string
*/
public function escapeString($str) {
return str_replace("'", "''", $str);
}
/**
* limit
* @access public
* @param $limit limit表达式
* @return string
*/
public function parseLimit($limit) {
$limitStr = '';
if(!empty($limit)) {
$limit = explode(',',$limit);
if(count($limit)>1) {
$limitStr = ' FIRST '.$limit[1].' SKIP '.$limit[0].' ';
}else{
$limitStr = ' FIRST '.$limit[0].' ';
}
}
return $limitStr;
}
}

View File

@@ -0,0 +1,821 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 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;
/**
* Mongo数据库驱动
*/
class Mongo extends Driver {
protected $_mongo = null; // MongoDb Object
protected $_collection = null; // MongoCollection Object
protected $_dbName = ''; // dbName
protected $_collectionName = ''; // collectionName
protected $_cursor = null; // MongoCursor Object
protected $comparison = array('neq'=>'ne','ne'=>'ne','gt'=>'gt','egt'=>'gte','gte'=>'gte','lt'=>'lt','elt'=>'lte','lte'=>'lte','in'=>'in','not in'=>'nin','nin'=>'nin');
/**
* 架构函数 读取数据库配置信息
* @access public
* @param array $config 数据库配置数组
*/
public function __construct($config=''){
if ( !class_exists('mongoClient') ) {
E(L('_NOT_SUPPORT_').':Mongo');
}
if(!empty($config)) {
$this->config = array_merge($this->config,$config);
if(empty($this->config['params'])){
$this->config['params'] = array();
}
}
}
/**
* 连接数据库方法
* @access public
*/
public function connect($config='',$linkNum=0) {
if ( !isset($this->linkID[$linkNum]) ) {
if(empty($config)) $config = $this->config;
$host = 'mongodb://'.($config['username']?"{$config['username']}":'').($config['password']?":{$config['password']}@":'').$config['hostname'].($config['hostport']?":{$config['hostport']}":'').'/'.($config['database']?"{$config['database']}":'');
try{
$this->linkID[$linkNum] = new \mongoClient( $host,$this->config['params']);
}catch (\MongoConnectionException $e){
E($e->getmessage());
}
}
return $this->linkID[$linkNum];
}
/**
* 切换当前操作的Db和Collection
* @access public
* @param string $collection collection
* @param string $db db
* @param boolean $master 是否主服务器
* @return void
*/
public function switchCollection($collection,$db='',$master=true){
// 当前没有连接 则首先进行数据库连接
if ( !$this->_linkID ) $this->initConnect($master);
try{
if(!empty($db)) { // 传人Db则切换数据库
// 当前MongoDb对象
$this->_dbName = $db;
$this->_mongo = $this->_linkID->selectDb($db);
}
// 当前MongoCollection对象
if($this->config['debug']) {
$this->queryStr = $this->_dbName.'.getCollection('.$collection.')';
}
if($this->_collectionName != $collection) {
$this->queryTimes++;
N('db_query',1); // 兼容代码
$this->debug(true);
$this->_collection = $this->_mongo->selectCollection($collection);
$this->debug(false);
$this->_collectionName = $collection; // 记录当前Collection名称
}
}catch (MongoException $e){
E($e->getMessage());
}
}
/**
* 释放查询结果
* @access public
*/
public function free() {
$this->_cursor = null;
}
/**
* 执行命令
* @access public
* @param array $command 指令
* @return array
*/
public function command($command=array(), $options=array()) {
$cache = isset($options['cache'])?$options['cache']:false;
if($cache) { // 查询缓存检测
$key = is_string($cache['key'])?$cache['key']:md5(serialize($command));
$value = S($key,'','',$cache['type']);
if(false !== $value) {
return $value;
}
}
N('db_write',1); // 兼容代码
$this->executeTimes++;
try{
if($this->config['debug']) {
$this->queryStr = $this->_dbName.'.'.$this->_collectionName.'.runCommand(';
$this->queryStr .= json_encode($command);
$this->queryStr .= ')';
}
$this->debug(true);
$result = $this->_mongo->command($command);
$this->debug(false);
if($cache && $result['ok']) { // 查询缓存写入
S($key,$result,$cache['expire'],$cache['type']);
}
return $result;
} catch (\MongoCursorException $e) {
E($e->getMessage());
}
}
/**
* 执行语句
* @access public
* @param string $code sql指令
* @param array $args 参数
* @return mixed
*/
public function execute($code,$args=array()) {
$this->executeTimes++;
N('db_write',1); // 兼容代码
$this->debug(true);
$this->queryStr = 'execute:'.$code;
$result = $this->_mongo->execute($code,$args);
$this->debug(false);
if($result['ok']) {
return $result['retval'];
}else{
E($result['errmsg']);
}
}
/**
* 关闭数据库
* @access public
*/
public function close() {
if($this->_linkID) {
$this->_linkID->close();
$this->_linkID = null;
$this->_mongo = null;
$this->_collection = null;
$this->_cursor = null;
}
}
/**
* 数据库错误信息
* @access public
* @return string
*/
public function error() {
$this->error = $this->_mongo->lastError();
trace($this->error,'','ERR');
return $this->error;
}
/**
* 插入记录
* @access public
* @param mixed $data 数据
* @param array $options 参数表达式
* @param boolean $replace 是否replace
* @return false | integer
*/
public function insert($data,$options=array(),$replace=false) {
if(isset($options['table'])) {
$this->switchCollection($options['table']);
}
$this->model = $options['model'];
$this->executeTimes++;
N('db_write',1); // 兼容代码
if($this->config['debug']) {
$this->queryStr = $this->_dbName.'.'.$this->_collectionName.'.insert(';
$this->queryStr .= $data?json_encode($data):'{}';
$this->queryStr .= ')';
}
try{
$this->debug(true);
$result = $replace? $this->_collection->save($data): $this->_collection->insert($data);
$this->debug(false);
if($result) {
$_id = $data['_id'];
if(is_object($_id)) {
$_id = $_id->__toString();
}
$this->lastInsID = $_id;
}
return $result;
} catch (\MongoCursorException $e) {
E($e->getMessage());
}
}
/**
* 插入多条记录
* @access public
* @param array $dataList 数据
* @param array $options 参数表达式
* @return bool
*/
public function insertAll($dataList,$options=array()) {
if(isset($options['table'])) {
$this->switchCollection($options['table']);
}
$this->model = $options['model'];
$this->executeTimes++;
N('db_write',1); // 兼容代码
try{
$this->debug(true);
$result = $this->_collection->batchInsert($dataList);
$this->debug(false);
return $result;
} catch (\MongoCursorException $e) {
E($e->getMessage());
}
}
/**
* 生成下一条记录ID 用于自增非MongoId主键
* @access public
* @param string $pk 主键名
* @return integer
*/
public function getMongoNextId($pk) {
if($this->config['debug']) {
$this->queryStr = $this->_dbName.'.'.$this->_collectionName.'.find({},{'.$pk.':1}).sort({'.$pk.':-1}).limit(1)';
}
try{
$this->debug(true);
$result = $this->_collection->find(array(),array($pk=>1))->sort(array($pk=>-1))->limit(1);
$this->debug(false);
} catch (\MongoCursorException $e) {
E($e->getMessage());
}
$data = $result->getNext();
return isset($data[$pk])?$data[$pk]+1:1;
}
/**
* 更新记录
* @access public
* @param mixed $data 数据
* @param array $options 表达式
* @return bool
*/
public function update($data,$options) {
if(isset($options['table'])) {
$this->switchCollection($options['table']);
}
$this->executeTimes++;
N('db_write',1); // 兼容代码
$this->model = $options['model'];
$query = $this->parseWhere(isset($options['where'])?$options['where']:array());
$set = $this->parseSet($data);
if($this->config['debug']) {
$this->queryStr = $this->_dbName.'.'.$this->_collectionName.'.update(';
$this->queryStr .= $query?json_encode($query):'{}';
$this->queryStr .= ','.json_encode($set).')';
}
try{
$this->debug(true);
if(isset($options['limit']) && $options['limit'] == 1) {
$multiple = array("multiple" => false);
}else{
$multiple = array("multiple" => true);
}
$result = $this->_collection->update($query,$set,$multiple);
$this->debug(false);
return $result;
} catch (\MongoCursorException $e) {
E($e->getMessage());
}
}
/**
* 删除记录
* @access public
* @param array $options 表达式
* @return false | integer
*/
public function delete($options=array()) {
if(isset($options['table'])) {
$this->switchCollection($options['table']);
}
$query = $this->parseWhere(isset($options['where'])?$options['where']:array());
$this->model = $options['model'];
$this->executeTimes++;
N('db_write',1); // 兼容代码
if($this->config['debug']) {
$this->queryStr = $this->_dbName.'.'.$this->_collectionName.'.remove('.json_encode($query).')';
}
try{
$this->debug(true);
$result = $this->_collection->remove($query);
$this->debug(false);
return $result;
} catch (\MongoCursorException $e) {
E($e->getMessage());
}
}
/**
* 清空记录
* @access public
* @param array $options 表达式
* @return false | integer
*/
public function clear($options=array()){
if(isset($options['table'])) {
$this->switchCollection($options['table']);
}
$this->model = $options['model'];
$this->executeTimes++;
N('db_write',1); // 兼容代码
if($this->config['debug']) {
$this->queryStr = $this->_dbName.'.'.$this->_collectionName.'.remove({})';
}
try{
$this->debug(true);
$result = $this->_collection->drop();
$this->debug(false);
return $result;
} catch (\MongoCursorException $e) {
E($e->getMessage());
}
}
/**
* 查找记录
* @access public
* @param array $options 表达式
* @return iterator
*/
public function select($options=array()) {
if(isset($options['table'])) {
$this->switchCollection($options['table'],'',false);
}
$this->model = $options['model'];
$this->queryTimes++;
N('db_query',1); // 兼容代码
$query = $this->parseWhere(isset($options['where'])?$options['where']:array());
$field = $this->parseField(isset($options['field'])?$options['field']:array());
try{
if($this->config['debug']) {
$this->queryStr = $this->_dbName.'.'.$this->_collectionName.'.find(';
$this->queryStr .= $query? json_encode($query):'{}';
if(is_array($field) && count($field)) {
foreach ($field as $f=>$v)
$_field_array[$f] = $v ? 1 : 0;
$this->queryStr .= $field? ', '.json_encode($_field_array):', {}';
}
$this->queryStr .= ')';
}
$this->debug(true);
$_cursor = $this->_collection->find($query,$field);
if(!empty($options['order'])) {
$order = $this->parseOrder($options['order']);
if($this->config['debug']) {
$this->queryStr .= '.sort('.json_encode($order).')';
}
$_cursor = $_cursor->sort($order);
}
if(isset($options['page'])) { // 根据页数计算limit
list($page,$length) = $options['page'];
$page = $page>0 ? $page : 1;
$length = $length>0 ? $length : (is_numeric($options['limit'])?$options['limit']:20);
$offset = $length*((int)$page-1);
$options['limit'] = $offset.','.$length;
}
if(isset($options['limit'])) {
list($offset,$length) = $this->parseLimit($options['limit']);
if(!empty($offset)) {
if($this->config['debug']) {
$this->queryStr .= '.skip('.intval($offset).')';
}
$_cursor = $_cursor->skip(intval($offset));
}
if($this->config['debug']) {
$this->queryStr .= '.limit('.intval($length).')';
}
$_cursor = $_cursor->limit(intval($length));
}
$this->debug(false);
$this->_cursor = $_cursor;
$resultSet = iterator_to_array($_cursor);
return $resultSet;
} catch (\MongoCursorException $e) {
E($e->getMessage());
}
}
/**
* 查找某个记录
* @access public
* @param array $options 表达式
* @return array
*/
public function find($options=array()){
$options['limit'] = 1;
$find = $this->select($options);
return array_shift($find);
}
/**
* 统计记录数
* @access public
* @param array $options 表达式
* @return iterator
*/
public function count($options=array()){
if(isset($options['table'])) {
$this->switchCollection($options['table'],'',false);
}
$this->model = $options['model'];
$this->queryTimes++;
N('db_query',1); // 兼容代码
$query = $this->parseWhere(isset($options['where'])?$options['where']:array());
if($this->config['debug']) {
$this->queryStr = $this->_dbName.'.'.$this->_collectionName;
$this->queryStr .= $query?'.find('.json_encode($query).')':'';
$this->queryStr .= '.count()';
}
try{
$this->debug(true);
$count = $this->_collection->count($query);
$this->debug(false);
return $count;
} catch (\MongoCursorException $e) {
E($e->getMessage());
}
}
public function group($keys,$initial,$reduce,$options=array()){
if(isset($options['table']) && $this->_collectionName != $options['table']) {
$this->switchCollection($options['table'],'',false);
}
$cache = isset($options['cache'])?$options['cache']:false;
if($cache) {
$key = is_string($cache['key'])?$cache['key']:md5(serialize($options));
$value = S($key,'','',$cache['type']);
if(false !== $value) {
return $value;
}
}
$this->model = $options['model'];
$this->queryTimes++;
N('db_query',1); // 兼容代码
$query = $this->parseWhere(isset($options['where'])?$options['where']:array());
if($this->config['debug']) {
$this->queryStr = $this->_dbName.'.'.$this->_collectionName.'.group({key:'.json_encode($keys).',cond:'.
json_encode($options['condition']) . ',reduce:' .
json_encode($reduce).',initial:'.
json_encode($initial).'})';
}
try{
$this->debug(true);
$option = array('condition'=>$options['condition'], 'finalize'=>$options['finalize'], 'maxTimeMS'=>$options['maxTimeMS']);
$group = $this->_collection->group($keys,$initial,$reduce,$options);
$this->debug(false);
if($cache && $group['ok'])
S($key,$group,$cache['expire'],$cache['type']);
return $group;
} catch (\MongoCursorException $e) {
E($e->getMessage());
}
}
/**
* 取得数据表的字段信息
* @access public
* @return array
*/
public function getFields($collection=''){
if(!empty($collection) && $collection != $this->_collectionName) {
$this->switchCollection($collection,'',false);
}
$this->queryTimes++;
N('db_query',1); // 兼容代码
if($this->config['debug']) {
$this->queryStr = $this->_dbName.'.'.$this->_collectionName.'.findOne()';
}
try{
$this->debug(true);
$result = $this->_collection->findOne();
$this->debug(false);
} catch (\MongoCursorException $e) {
E($e->getMessage());
}
if($result) { // 存在数据则分析字段
$info = array();
foreach ($result as $key=>$val){
$info[$key] = array(
'name' => $key,
'type' => getType($val),
);
}
return $info;
}
// 暂时没有数据 返回false
return false;
}
/**
* 取得当前数据库的collection信息
* @access public
*/
public function getTables(){
if($this->config['debug']) {
$this->queryStr = $this->_dbName.'.getCollenctionNames()';
}
$this->queryTimes++;
N('db_query',1); // 兼容代码
$this->debug(true);
$list = $this->_mongo->listCollections();
$this->debug(false);
$info = array();
foreach ($list as $collection){
$info[] = $collection->getName();
}
return $info;
}
/**
* 取得当前数据库的对象
* @access public
* @return object mongoClient
*/
public function getDB(){
return $this->_mongo;
}
/**
* 取得当前集合的对象
* @access public
* @return object MongoCollection
*/
public function getCollection(){
return $this->_collection;
}
/**
* set分析
* @access protected
* @param array $data
* @return string
*/
protected function parseSet($data) {
$result = array();
foreach ($data as $key=>$val){
if(is_array($val)) {
switch($val[0]) {
case 'inc':
$result['$inc'][$key] = (int)$val[1];
break;
case 'set':
case 'unset':
case 'push':
case 'pushall':
case 'addtoset':
case 'pop':
case 'pull':
case 'pullall':
$result['$'.$val[0]][$key] = $val[1];
break;
default:
$result['$set'][$key] = $val;
}
}else{
$result['$set'][$key] = $val;
}
}
return $result;
}
/**
* order分析
* @access protected
* @param mixed $order
* @return array
*/
protected function parseOrder($order) {
if(is_string($order)) {
$array = explode(',',$order);
$order = array();
foreach ($array as $key=>$val){
$arr = explode(' ',trim($val));
if(isset($arr[1])) {
$arr[1] = $arr[1]=='asc'?1:-1;
}else{
$arr[1] = 1;
}
$order[$arr[0]] = $arr[1];
}
}
return $order;
}
/**
* limit分析
* @access protected
* @param mixed $limit
* @return array
*/
protected function parseLimit($limit) {
if(strpos($limit,',')) {
$array = explode(',',$limit);
}else{
$array = array(0,$limit);
}
return $array;
}
/**
* field分析
* @access protected
* @param mixed $fields
* @return array
*/
public function parseField($fields){
if(empty($fields)) {
$fields = array();
}
if(is_string($fields)) {
$_fields = explode(',',$fields);
$fields = array();
foreach ($_fields as $f)
$fields[$f] = true;
}elseif(is_array($fields)) {
$_fields = $fields;
$fields = array();
foreach ($_fields as $f=>$v) {
if(is_numeric($f))
$fields[$v] = true;
else
$fields[$f] = $v ? true : false;
}
}
return $fields;
}
/**
* where分析
* @access protected
* @param mixed $where
* @return array
*/
public function parseWhere($where){
$query = array();
$return = array();
$_logic = '$and';
if(isset($where['_logic'])){
$where['_logic'] = strtolower($where['_logic']);
$_logic = in_array($where['_logic'], array('or','xor','nor', 'and'))?'$'.$where['_logic']:$_logic;
unset($where['_logic']);
}
foreach ($where as $key=>$val){
if('_id' != $key && 0===strpos($key,'_')) {
// 解析特殊条件表达式
$parse = $this->parseThinkWhere($key,$val);
$query = array_merge($query,$parse);
}else{
// 查询字段的安全过滤
if(!preg_match('/^[A-Z_\|\&\-.a-z0-9]+$/',trim($key))){
E(L('_ERROR_QUERY_').':'.$key);
}
$key = trim($key);
if(strpos($key,'|')) {
$array = explode('|',$key);
$str = array();
foreach ($array as $k){
$str[] = $this->parseWhereItem($k,$val);
}
$query['$or'] = $str;
}elseif(strpos($key,'&')){
$array = explode('&',$key);
$str = array();
foreach ($array as $k){
$str[] = $this->parseWhereItem($k,$val);
}
$query = array_merge($query,$str);
}else{
$str = $this->parseWhereItem($key,$val);
$query = array_merge($query,$str);
}
}
}
if($_logic == '$and')
return $query;
foreach($query as $key=>$val)
$return[$_logic][] = array($key=>$val);
return $return;
}
/**
* 特殊条件分析
* @access protected
* @param string $key
* @param mixed $val
* @return string
*/
protected function parseThinkWhere($key,$val) {
$query = array();
$_logic = array('or','xor','nor', 'and');
switch($key) {
case '_query': // 字符串模式查询条件
parse_str($val,$query);
if(isset($query['_logic']) && strtolower($query['_logic']) == 'or' ) {
unset($query['_logic']);
$query['$or'] = $query;
}
break;
case '_complex': // 子查询模式查询条件
$__logic = strtolower($val['_logic']);
if(isset($val['_logic']) && in_array($__logic, $_logic) ) {
unset($val['_logic']);
$query['$'.$__logic] = $val;
}
break;
case '_string':// MongoCode查询
$query['$where'] = new \MongoCode($val);
break;
}
//兼容 MongoClient OR条件查询方法
if(isset($query['$or']) && !is_array(current($query['$or']))) {
$val = array();
foreach ($query['$or'] as $k=>$v)
$val[] = array($k=>$v);
$query['$or'] = $val;
}
return $query;
}
/**
* where子单元分析
* @access protected
* @param string $key
* @param mixed $val
* @return array
*/
protected function parseWhereItem($key,$val) {
$query = array();
if(is_array($val)) {
if(is_string($val[0])) {
$con = strtolower($val[0]);
if(in_array($con,array('neq','ne','gt','egt','gte','lt','lte','elt'))) { // 比较运算
$k = '$'.$this->comparison[$con];
$query[$key] = array($k=>$val[1]);
}elseif('like'== $con){ // 模糊查询 采用正则方式
$query[$key] = new \MongoRegex("/".$val[1]."/");
}elseif('mod'==$con){ // mod 查询
$query[$key] = array('$mod'=>$val[1]);
}elseif('regex'==$con){ // 正则查询
$query[$key] = new \MongoRegex($val[1]);
}elseif(in_array($con,array('in','nin','not in'))){ // IN NIN 运算
$data = is_string($val[1])? explode(',',$val[1]):$val[1];
$k = '$'.$this->comparison[$con];
$query[$key] = array($k=>$data);
}elseif('all'==$con){ // 满足所有指定条件
$data = is_string($val[1])? explode(',',$val[1]):$val[1];
$query[$key] = array('$all'=>$data);
}elseif('between'==$con){ // BETWEEN运算
$data = is_string($val[1])? explode(',',$val[1]):$val[1];
$query[$key] = array('$gte'=>$data[0],'$lte'=>$data[1]);
}elseif('not between'==$con){
$data = is_string($val[1])? explode(',',$val[1]):$val[1];
$query[$key] = array('$lt'=>$data[0],'$gt'=>$data[1]);
}elseif('exp'==$con){ // 表达式查询
$query['$where'] = new \MongoCode($val[1]);
}elseif('exists'==$con){ // 字段是否存在
$query[$key] = array('$exists'=>(bool)$val[1]);
}elseif('size'==$con){ // 限制属性大小
$query[$key] = array('$size'=>intval($val[1]));
}elseif('type'==$con){ // 限制字段类型 1 浮点型 2 字符型 3 对象或者MongoDBRef 5 MongoBinData 7 MongoId 8 布尔型 9 MongoDate 10 NULL 15 MongoCode 16 32位整型 17 MongoTimestamp 18 MongoInt64 如果是数组的话判断元素的类型
$query[$key] = array('$type'=>intval($val[1]));
}else{
$query[$key] = $val;
}
return $query;
}
}
$query[$key] = $val;
return $query;
}
}

View File

@@ -0,0 +1,235 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 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;
/**
* mysql数据库驱动
*/
class Mysql extends Driver{
/**
* 解析pdo连接的dsn信息
* @access public
* @param array $config 连接信息
* @return string
*/
protected function parseDsn($config){
$dsn = 'mysql:dbname='.$config['database'].';host='.$config['hostname'];
if(!empty($config['hostport'])) {
$dsn .= ';port='.$config['hostport'];
}elseif(!empty($config['socket'])){
$dsn .= ';unix_socket='.$config['socket'];
}
if(!empty($config['charset'])){
//为兼容各版本PHP,用两种方式设置编码
$this->options[\PDO::MYSQL_ATTR_INIT_COMMAND] = 'SET NAMES '.$config['charset'];
$dsn .= ';charset='.$config['charset'];
}
return $dsn;
}
/**
* 取得数据表的字段信息
* @access public
*/
public function getFields($tableName) {
$this->initConnect(true);
list($tableName) = explode(' ', $tableName);
if(strpos($tableName,'.')){
list($dbName,$tableName) = explode('.',$tableName);
$sql = 'SHOW COLUMNS FROM `'.$dbName.'`.`'.$tableName.'`';
}else{
$sql = 'SHOW COLUMNS FROM `'.$tableName.'`';
}
$result = $this->query($sql);
$info = array();
if($result) {
foreach ($result as $key => $val) {
if(\PDO::CASE_LOWER != $this->_linkID->getAttribute(\PDO::ATTR_CASE)){
$val = array_change_key_case ( $val , CASE_LOWER );
}
$info[$val['field']] = array(
'name' => $val['field'],
'type' => $val['type'],
'notnull' => (bool) ($val['null'] === ''), // not null is empty, null is yes
'default' => $val['default'],
'primary' => (strtolower($val['key']) == 'pri'),
'autoinc' => (strtolower($val['extra']) == 'auto_increment'),
);
}
}
return $info;
}
/**
* 取得数据库的表信息
* @access public
*/
public function getTables($dbName='') {
$sql = !empty($dbName)?'SHOW TABLES FROM '.$dbName:'SHOW TABLES ';
$result = $this->query($sql);
$info = array();
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(!is_numeric($key) && !preg_match('/[,\'\"\*\(\)`.\s]/',$key)) {
$key = '`'.$key.'`';
}
return $key;
}
/**
* 批量插入记录
* @access public
* @param mixed $dataSet 数据集
* @param array $options 参数表达式
* @param boolean $replace 是否replace
* @return false | integer
*/
public function insertAll($dataSet,$options=array(),$replace=false) {
$values = array();
$this->model = $options['model'];
if(!is_array($dataSet[0])) return false;
$this->parseBind(!empty($options['bind'])?$options['bind']:array());
$fields = array_map(array($this,'parseKey'),array_keys($dataSet[0]));
foreach ($dataSet as $data){
$value = array();
foreach ($data as $key=>$val){
if(is_array($val) && 'exp' == $val[0]){
$value[] = $val[1];
}elseif(is_null($val)){
$value[] = 'NULL';
}elseif(is_scalar($val)){
if(0===strpos($val,':') && in_array($val,array_keys($this->bind))){
$value[] = $this->parseValue($val);
}else{
$name = count($this->bind);
$value[] = ':'.$name;
$this->bindParam($name,$val);
}
}
}
$values[] = '('.implode(',', $value).')';
}
// 兼容数字传入方式
$replace= (is_numeric($replace) && $replace>0)?true:$replace;
$sql = (true===$replace?'REPLACE':'INSERT').' INTO '.$this->parseTable($options['table']).' ('.implode(',', $fields).') VALUES '.implode(',',$values).$this->parseDuplicate($replace);
$sql .= $this->parseComment(!empty($options['comment'])?$options['comment']:'');
return $this->execute($sql,!empty($options['fetch_sql']) ? true : false);
}
/**
* ON DUPLICATE KEY UPDATE 分析
* @access protected
* @param mixed $duplicate
* @return string
*/
protected function parseDuplicate($duplicate){
// 布尔值或空则返回空字符串
if(is_bool($duplicate) || empty($duplicate)) return '';
if(is_string($duplicate)){
// field1,field2 转数组
$duplicate = explode(',', $duplicate);
}elseif(is_object($duplicate)){
// 对象转数组
$duplicate = get_class_vars($duplicate);
}
$updates = array();
foreach((array) $duplicate as $key=>$val){
if(is_numeric($key)){ // array('field1', 'field2', 'field3') 解析为 ON DUPLICATE KEY UPDATE field1=VALUES(field1), field2=VALUES(field2), field3=VALUES(field3)
$updates[] = $this->parseKey($val)."=VALUES(".$this->parseKey($val).")";
}else{
if(is_scalar($val)) // 兼容标量传值方式
$val = array('value', $val);
if(!isset($val[1])) continue;
switch($val[0]){
case 'exp': // 表达式
$updates[] = $this->parseKey($key)."=($val[1])";
break;
case 'value': // 值
default:
$name = count($this->bind);
$updates[] = $this->parseKey($key)."=:".$name;
$this->bindParam($name, $val[1]);
break;
}
}
}
if(empty($updates)) return '';
return " ON DUPLICATE KEY UPDATE ".join(', ', $updates);
}
/**
* 执行存储过程查询 返回多个数据集
* @access public
* @param string $str sql指令
* @param boolean $fetchSql 不执行只是获取SQL
* @return mixed
*/
public function procedure($str,$fetchSql=false) {
$this->initConnect(false);
$this->_linkID->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_WARNING);
if ( !$this->_linkID ) return false;
$this->queryStr = $str;
if($fetchSql){
return $this->queryStr;
}
//释放前次的查询结果
if ( !empty($this->PDOStatement) ) $this->free();
$this->queryTimes++;
N('db_query',1); // 兼容代码
// 调试开始
$this->debug(true);
$this->PDOStatement = $this->_linkID->prepare($str);
if(false === $this->PDOStatement){
$this->error();
return false;
}
try{
$result = $this->PDOStatement->execute();
// 调试结束
$this->debug(false);
do
{
$result = $this->PDOStatement->fetchAll(\PDO::FETCH_ASSOC);
if ($result)
{
$resultArr[] = $result;
}
}
while ($this->PDOStatement->nextRowset());
$this->_linkID->setAttribute(\PDO::ATTR_ERRMODE, $this->options[\PDO::ATTR_ERRMODE]);
return $resultArr;
}catch (\PDOException $e) {
$this->error();
$this->_linkID->setAttribute(\PDO::ATTR_ERRMODE, $this->options[\PDO::ATTR_ERRMODE]);
return false;
}
}
}

View File

@@ -0,0 +1,168 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 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数据库驱动
*/
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%';
/**
* 解析pdo连接的dsn信息
* @access public
* @param array $config 连接信息
* @return string
*/
protected function parseDsn($config){
$dsn = 'oci:dbname=//'.$config['hostname'].($config['hostport']?':'.$config['hostport']:'').'/'.$config['database'];
if(!empty($config['charset'])) {
$dsn .= ';charset='.$config['charset'];
}
return $dsn;
}
/**
* 执行语句
* @access public
* @param string $str sql指令
* @param boolean $fetchSql 不执行只是获取SQL
* @return integer
*/
public function execute($str,$fetchSql=false) {
$this->initConnect(true);
if ( !$this->_linkID ) return false;
$this->queryStr = $str;
if(!empty($this->bind)){
$that = $this;
$this->queryStr = strtr($this->queryStr,array_map(function($val) use($that){ return '\''.$that->escapeString($val).'\''; },$this->bind));
}
if($fetchSql){
return $this->queryStr;
}
$flag = false;
if(preg_match("/^\s*(INSERT\s+INTO)\s+(\w+)\s+/i", $str, $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++;
N('db_write',1); // 兼容代码
// 记录开始执行时间
$this->debug(true);
$this->PDOStatement = $this->_linkID->prepare($str);
if(false === $this->PDOStatement) {
$this->error();
return false;
}
foreach ($this->bind as $key => $val) {
if(is_array($val)){
$this->PDOStatement->bindValue($key, $val[0], $val[1]);
}else{
$this->PDOStatement->bindValue($key, $val);
}
}
$this->bind = array();
$result = $this->PDOStatement->execute();
$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->_linkID->lastInsertId();
}
return $this->numRows;
}
}
/**
* 取得数据表的字段信息
* @access public
*/
public function getFields($tableName) {
list($tableName) = explode(' ', $tableName);
$result = $this->query("select a.column_name,data_type,decode(nullable,'Y',0,1) notnull,data_default,decode(a.column_name,b.column_name,1,0) pk "
."from user_tab_columns a,(select column_name from user_constraints c,user_cons_columns col "
."where c.constraint_name=col.constraint_name and c.constraint_type='P'and c.table_name='".strtoupper($tableName)
."') b where table_name='".strtoupper($tableName)."' and a.column_name=b.column_name(+)");
$info = array();
if($result) {
foreach ($result as $key => $val) {
$info[strtolower($val['column_name'])] = array(
'name' => strtolower($val['column_name']),
'type' => strtolower($val['data_type']),
'notnull' => $val['notnull'],
'default' => $val['data_default'],
'primary' => $val['pk'],
'autoinc' => $val['pk'],
);
}
}
return $info;
}
/**
* 取得数据库的表信息(暂时实现取得用户表信息)
* @access public
*/
public function getTables($dbName='') {
$result = $this->query("select table_name from user_tables");
$info = array();
foreach ($result as $key => $val) {
$info[$key] = current($val);
}
return $info;
}
/**
* 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 = "(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,91 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 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数据库驱动
*/
class Pgsql extends Driver{
/**
* 解析pdo连接的dsn信息
* @access public
* @param array $config 连接信息
* @return string
*/
protected function parseDsn($config){
$dsn = 'pgsql:dbname='.$config['database'].';host='.$config['hostname'];
if(!empty($config['hostport'])) {
$dsn .= ';port='.$config['hostport'];
}
return $dsn;
}
/**
* 取得数据表的字段信息
* @access public
* @return array
*/
public function getFields($tableName) {
list($tableName) = explode(' ', $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 = array();
if($result){
foreach ($result as $key => $val) {
$info[$val['field']] = array(
'name' => $val['field'],
'type' => $val['type'],
'notnull' => (bool) ($val['null'] === ''), // not null is empty, null is yes
'default' => $val['default'],
'primary' => (strtolower($val['key']) == 'pri'),
'autoinc' => (strtolower($val['extra']) == 'auto_increment'),
);
}
}
return $info;
}
/**
* 取得数据库的表信息
* @access public
* @return array
*/
public function getTables($dbName='') {
$result = $this->query("select tablename as Tables_in_test from pg_tables where schemaname ='public'");
$info = array();
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,98 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 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数据库驱动
*/
class Sqlite extends Driver {
/**
* 解析pdo连接的dsn信息
* @access public
* @param array $config 连接信息
* @return string
*/
protected function parseDsn($config){
$dsn = 'sqlite:'.$config['database'];
return $dsn;
}
/**
* 取得数据表的字段信息
* @access public
* @return array
*/
public function getFields($tableName) {
list($tableName) = explode(' ', $tableName);
$result = $this->query('PRAGMA table_info( '.$tableName.' )');
$info = array();
if($result){
foreach ($result as $key => $val) {
$info[$val['field']] = array(
'name' => $val['field'],
'type' => $val['type'],
'notnull' => (bool) ($val['null'] === ''), // not null is empty, null is yes
'default' => $val['default'],
'primary' => (strtolower($val['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 = array();
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,166 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 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;
use PDO;
/**
* Sqlsrv数据库驱动
*/
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% %UNION%) AS thinkphp) AS T1 %LIMIT%%COMMENT%';
// PDO连接参数
protected $options = array(
PDO::ATTR_CASE => PDO::CASE_LOWER,
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_STRINGIFY_FETCHES => false,
PDO::SQLSRV_ATTR_ENCODING => PDO::SQLSRV_ENCODING_UTF8,
);
/**
* 解析pdo连接的dsn信息
* @access public
* @param array $config 连接信息
* @return string
*/
protected function parseDsn($config){
$dsn = 'sqlsrv:Database='.$config['database'].';Server='.$config['hostname'];
if(!empty($config['hostport'])) {
$dsn .= ','.$config['hostport'];
}
return $dsn;
}
/**
* 取得数据表的字段信息
* @access public
* @return array
*/
public function getFields($tableName) {
list($tableName) = explode(' ', $tableName);
$result = $this->query("SELECT column_name, data_type, column_default, is_nullable
FROM information_schema.tables AS t
JOIN information_schema.columns AS c
ON t.table_catalog = c.table_catalog
AND t.table_schema = c.table_schema
AND t.table_name = c.table_name
WHERE t.table_name = '$tableName'");
$info = array();
if($result) {
foreach ($result as $key => $val) {
$info[$val['column_name']] = array(
'name' => $val['column_name'],
'type' => $val['data_type'],
'notnull' => (bool) ($val['is_nullable'] === ''), // not null is empty, null is yes
'default' => $val['column_default'],
'primary' => false,
'autoinc' => false,
);
}
}
return $info;
}
/**
* 取得数据表的字段信息
* @access public
* @return array
*/
public function getTables($dbName='') {
$result = $this->query("SELECT TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_TYPE = 'BASE TABLE'
");
$info = array();
foreach ($result as $key => $val) {
$info[$key] = current($val);
}
return $info;
}
/**
* order分析
* @access protected
* @param mixed $order
* @return string
*/
protected function parseOrder($order) {
return !empty($order)? ' ORDER BY '.$order:' ORDER BY rand()';
}
/**
* 字段名分析
* @access protected
* @param string $key
* @return string
*/
protected function parseKey(&$key) {
$key = trim($key);
if(!is_numeric($key) && !preg_match('/[,\'\"\*\(\)\[.\s]/',$key)) {
$key = '['.$key.']';
}
return $key;
}
/**
* limit
* @access public
* @param mixed $limit
* @return string
*/
public function parseLimit($limit) {
if(empty($limit)) return '';
$limit = explode(',',$limit);
if(count($limit)>1)
$limitStr = '(T1.ROW_NUMBER BETWEEN '.$limit[0].' + 1 AND '.$limit[0].' + '.$limit[1].')';
else
$limitStr = '(T1.ROW_NUMBER BETWEEN 1 AND '.$limit[0].")";
return 'WHERE '.$limitStr;
}
/**
* 更新记录
* @access public
* @param mixed $data 数据
* @param array $options 表达式
* @return false | integer
*/
public function update($data,$options) {
$this->model = $options['model'];
$this->parseBind(!empty($options['bind'])?$options['bind']:array());
$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,!empty($options['fetch_sql']) ? true : false);
}
/**
* 删除记录
* @access public
* @param array $options 表达式
* @return false | integer
*/
public function delete($options=array()) {
$this->model = $options['model'];
$this->parseBind(!empty($options['bind'])?$options['bind']:array());
$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,!empty($options['fetch_sql']) ? true : false);
}
}

View File

@@ -0,0 +1,466 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
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 = array();
// 最后插入ID
protected $lastInsID = null;
// 返回或者影响记录数
protected $numRows = 0;
// 事务指令数
protected $transTimes = 0;
// 错误信息
protected $error = '';
// 数据库连接ID 支持多个连接
protected $linkID = array();
// 当前连接ID
protected $_linkID = null;
// 数据库连接参数配置
protected $config = array(
'type' => '', // 数据库类型
'hostname' => '127.0.0.1', // 服务器地址
'database' => '', // 数据库名
'username' => '', // 用户名
'password' => '', // 密码
'hostport' => '', // 端口
'dsn' => '', //
'params' => array(), // 数据库连接参数
'charset' => 'utf8', // 数据库编码默认采用utf8
'prefix' => '', // 数据库表前缀
'debug' => false, // 数据库调试模式
'deploy' => 0, // 数据库部署方式:0 集中式(单一服务器),1 分布式(主从服务器)
'rw_separate' => false, // 数据库读写是否分离 主从式有效
'master_num' => 1, // 读写分离后 主服务器数量
'slave_no' => '', // 指定从服务器序号
);
// 数据库表达式
protected $comparison = array('eq'=>'=','neq'=>'<>','gt'=>'>','egt'=>'>=','lt'=>'<','elt'=>'<=','notlike'=>'NOT LIKE','like'=>'LIKE','in'=>'IN','notin'=>'NOT IN');
// 查询表达式
protected $selectSql = 'SELECT%DISTINCT% %FIELD% FROM %TABLE%%JOIN%%WHERE%%GROUP%%HAVING%%ORDER%%LIMIT% %UNION%%COMMENT%';
// 查询次数
protected $queryTimes = 0;
// 执行次数
protected $executeTimes = 0;
// PDO连接参数
protected $options = array(
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 = array_merge($this->config,$config);
if(is_array($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'] = $this->parseDsn($config);
}
if(version_compare(PHP_VERSION,'5.3.6','<=')){ //禁用模拟预处理语句
$this->options[PDO::ATTR_EMULATE_PREPARES] = false;
}
$this->linkID[$linkNum] = new PDO( $config['dsn'], $config['username'], $config['password'],$this->options);
}catch (\PDOException $e) {
E($e->getMessage());
}
}
return $this->linkID[$linkNum];
}
/**
* 解析pdo连接的dsn信息
* @access public
* @param array $config 连接信息
* @return string
*/
protected function parseDsn($config){}
/**
* 释放查询结果
* @access public
*/
public function free() {
$this->PDOStatement = null;
}
/**
* 执行查询 返回数据集
* @access public
* @param string $str sql指令
* @param array $bind 参数绑定
* @return mixed
*/
public function query($str,$bind=array()) {
$this->initConnect(false);
if ( !$this->_linkID ) return false;
$this->queryStr = $str;
if(!empty($bind)){
$that = $this;
$this->queryStr = strtr($this->queryStr,array_map(function($val) use($that){ return '\''.$that->escapeString($val).'\''; },$bind));
}
//释放前次的查询结果
if ( !empty($this->PDOStatement) ) $this->free();
$this->queryTimes++;
N('db_query',1); // 兼容代码
// 调试开始
$this->debug(true);
$this->PDOStatement = $this->_linkID->prepare($str);
if(false === $this->PDOStatement)
E($this->error());
foreach ($bind as $key => $val) {
if(is_array($val)){
$this->PDOStatement->bindValue($key, $val[0], $val[1]);
}else{
$this->PDOStatement->bindValue($key, $val);
}
}
$result = $this->PDOStatement->execute();
// 调试结束
$this->debug(false);
if ( false === $result ) {
$this->error();
return false;
} else {
return $this->getResult();
}
}
/**
* 执行语句
* @access public
* @param string $str sql指令
* @param array $bind 参数绑定
* @return integer
*/
public function execute($str,$bind=array()) {
$this->initConnect(true);
if ( !$this->_linkID ) return false;
$this->queryStr = $str;
if(!empty($bind)){
$that = $this;
$this->queryStr = strtr($this->queryStr,array_map(function($val) use($that){ return '\''.$that->escapeString($val).'\''; },$bind));
}
//释放前次的查询结果
if ( !empty($this->PDOStatement) ) $this->free();
$this->executeTimes++;
N('db_write',1); // 兼容代码
// 记录开始执行时间
$this->debug(true);
$this->PDOStatement = $this->_linkID->prepare($str);
if(false === $this->PDOStatement) {
E($this->error());
}
foreach ($bind as $key => $val) {
if(is_array($val)){
$this->PDOStatement->bindValue($key, $val[0], $val[1]);
}else{
$this->PDOStatement->bindValue($key, $val);
}
}
$result = $this->PDOStatement->execute();
$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->_linkID->lastInsertId();
}
return $this->numRows;
}
}
/**
* 启动事务
* @access public
* @return void
*/
public function startTrans() {
$this->initConnect(true);
if ( !$this->_linkID ) return false;
//数据rollback 支持
if ($this->transTimes == 0) {
$this->_linkID->beginTransaction();
}
$this->transTimes++;
return ;
}
/**
* 用于非自动提交状态下面的查询提交
* @access public
* @return boolean
*/
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 boolean
*/
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;
}
// 记录错误日志
trace($this->error,'','ERR');
if($this->config['debug']) {// 开启数据库调试模式
E($this->error);
}else{
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;
}
/**
* 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) {
G('queryStartTime');
}else{
$this->modelSql[$this->model] = $this->queryStr;
//$this->model = '_think_';
// 记录操作结束时间
G('queryEndTime');
trace($this->queryStr.' [ RunTime:'.G('queryStartTime','queryEndTime').'s ]','','SQL');
}
}
}
/**
* 初始化数据库连接
* @access protected
* @param boolean $master 主服务器
* @return void
*/
protected function initConnect($master=true) {
if(!empty($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) {
// 分布式数据库配置解析
$_config['username'] = explode(',',$this->config['username']);
$_config['password'] = explode(',',$this->config['password']);
$_config['hostname'] = explode(',',$this->config['hostname']);
$_config['hostport'] = explode(',',$this->config['hostport']);
$_config['database'] = explode(',',$this->config['database']);
$_config['dsn'] = explode(',',$this->config['dsn']);
$_config['charset'] = explode(',',$this->config['charset']);
// 数据库读写是否分离
if($this->config['rw_separate']){
// 主从式采用读写分离
if($master)
// 主服务器写入
$r = floor(mt_rand(0,$this->config['master_num']-1));
else{
if(is_numeric($this->config['slave_no'])) {// 指定服务器读
$r = $this->config['slave_no'];
}else{
// 读操作连接从服务器
$r = floor(mt_rand($this->config['master_num'],count($_config['hostname'])-1)); // 每次随机连接的数据库
}
}
}else{
// 读写操作不区分服务器
$r = floor(mt_rand(0,count($_config['hostname'])-1)); // 每次随机连接的数据库
}
$db_config = array(
'username' => isset($_config['username'][$r])?$_config['username'][$r]:$_config['username'][0],
'password' => isset($_config['password'][$r])?$_config['password'][$r]:$_config['password'][0],
'hostname' => isset($_config['hostname'][$r])?$_config['hostname'][$r]:$_config['hostname'][0],
'hostport' => isset($_config['hostport'][$r])?$_config['hostport'][$r]:$_config['hostport'][0],
'database' => isset($_config['database'][$r])?$_config['database'][$r]:$_config['database'][0],
'dsn' => isset($_config['dsn'][$r])?$_config['dsn'][$r]:$_config['dsn'][0],
'charset' => isset($_config['charset'][$r])?$_config['charset'][$r]:$_config['charset'][0],
);
return $this->connect($db_config,$r);
}
/**
* 析构方法
* @access public
*/
public function __destruct() {
// 释放查询
if ($this->PDOStatement){
$this->free();
}
// 关闭连接
$this->close();
}
}

View File

@@ -0,0 +1,339 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
namespace Think;
/**
* ThinkPHP内置的Dispatcher类
* 完成URL解析、路由和调度
*/
class Dispatcher {
/**
* URL映射到控制器
* @access public
* @return void
*/
static public function dispatch() {
$varPath = C('VAR_PATHINFO');
$varAddon = C('VAR_ADDON');
$varModule = C('VAR_MODULE');
$varController = C('VAR_CONTROLLER');
$varAction = C('VAR_ACTION');
$urlCase = C('URL_CASE_INSENSITIVE');
if(isset($_GET[$varPath])) { // 判断URL里面是否有兼容模式参数
$_SERVER['PATH_INFO'] = $_GET[$varPath];
unset($_GET[$varPath]);
}elseif(IS_CLI){ // CLI模式下 index.php module/controller/action/params/...
$_SERVER['PATH_INFO'] = isset($_SERVER['argv'][1]) ? $_SERVER['argv'][1] : '';
}
// 开启子域名部署
if(C('APP_SUB_DOMAIN_DEPLOY')) {
$rules = C('APP_SUB_DOMAIN_RULES');
if(isset($rules[$_SERVER['HTTP_HOST']])) { // 完整域名或者IP配置
define('APP_DOMAIN',$_SERVER['HTTP_HOST']); // 当前完整域名
$rule = $rules[APP_DOMAIN];
}else{
if(strpos(C('APP_DOMAIN_SUFFIX'),'.')){ // com.cn net.cn
$domain = array_slice(explode('.', $_SERVER['HTTP_HOST']), 0, -3);
}else{
$domain = array_slice(explode('.', $_SERVER['HTTP_HOST']), 0, -2);
}
if(!empty($domain)) {
$subDomain = implode('.', $domain);
define('SUB_DOMAIN',$subDomain); // 当前完整子域名
$domain2 = array_pop($domain); // 二级域名
if($domain) { // 存在三级域名
$domain3 = array_pop($domain);
}
if(isset($rules[$subDomain])) { // 子域名
$rule = $rules[$subDomain];
}elseif(isset($rules['*.' . $domain2]) && !empty($domain3)){ // 泛三级域名
$rule = $rules['*.' . $domain2];
$panDomain = $domain3;
}elseif(isset($rules['*']) && !empty($domain2) && 'www' != $domain2 ){ // 泛二级域名
$rule = $rules['*'];
$panDomain = $domain2;
}
}
}
if(!empty($rule)) {
// 子域名部署规则 '子域名'=>array('模块名[/控制器名]','var1=a&var2=b');
if(is_array($rule)){
list($rule,$vars) = $rule;
}
$array = explode('/',$rule);
// 模块绑定
define('BIND_MODULE',array_shift($array));
// 控制器绑定
if(!empty($array)) {
$controller = array_shift($array);
if($controller){
define('BIND_CONTROLLER',$controller);
}
}
if(isset($vars)) { // 传入参数
parse_str($vars,$parms);
if(isset($panDomain)){
$pos = array_search('*', $parms);
if(false !== $pos) {
// 泛域名作为参数
$parms[$pos] = $panDomain;
}
}
$_GET = array_merge($_GET,$parms);
}
}
}
// 分析PATHINFO信息
if(!isset($_SERVER['PATH_INFO'])) {
$types = explode(',',C('URL_PATHINFO_FETCH'));
foreach ($types as $type){
if(0===strpos($type,':')) {// 支持函数判断
$_SERVER['PATH_INFO'] = call_user_func(substr($type,1));
break;
}elseif(!empty($_SERVER[$type])) {
$_SERVER['PATH_INFO'] = (0 === strpos($_SERVER[$type],$_SERVER['SCRIPT_NAME']))?
substr($_SERVER[$type], strlen($_SERVER['SCRIPT_NAME'])) : $_SERVER[$type];
break;
}
}
}
$depr = C('URL_PATHINFO_DEPR');
define('MODULE_PATHINFO_DEPR', $depr);
if(empty($_SERVER['PATH_INFO'])) {
$_SERVER['PATH_INFO'] = '';
define('__INFO__','');
define('__EXT__','');
}else{
define('__INFO__',trim($_SERVER['PATH_INFO'],'/'));
// URL后缀
define('__EXT__', strtolower(pathinfo($_SERVER['PATH_INFO'],PATHINFO_EXTENSION)));
$_SERVER['PATH_INFO'] = __INFO__;
if(!defined('BIND_MODULE') && (!C('URL_ROUTER_ON') || !Route::check())){
if (__INFO__ && C('MULTI_MODULE')){ // 获取模块名
$paths = explode($depr,__INFO__,2);
$allowList = C('MODULE_ALLOW_LIST'); // 允许的模块列表
$module = preg_replace('/\.' . __EXT__ . '$/i', '',$paths[0]);
if( empty($allowList) || (is_array($allowList) && in_array_case($module, $allowList))){
$_GET[$varModule] = $module;
$_SERVER['PATH_INFO'] = isset($paths[1])?$paths[1]:'';
}
}
}
}
// URL常量
define('__SELF__',strip_tags($_SERVER[C('URL_REQUEST_URI')]));
// 获取模块名称
define('MODULE_NAME', defined('BIND_MODULE')? BIND_MODULE : self::getModule($varModule));
// 检测模块是否存在
if( MODULE_NAME && (defined('BIND_MODULE') || !in_array_case(MODULE_NAME,C('MODULE_DENY_LIST')) ) && is_dir(APP_PATH.MODULE_NAME)){
// 定义当前模块路径
define('MODULE_PATH', APP_PATH.MODULE_NAME.'/');
// 定义当前模块的模版缓存路径
C('CACHE_PATH',CACHE_PATH.MODULE_NAME.'/');
// 定义当前模块的日志目录
C('LOG_PATH', realpath(LOG_PATH).'/'.MODULE_NAME.'/');
// 模块检测
Hook::listen('module_check');
// 加载模块配置文件
if(is_file(MODULE_PATH.'Conf/config'.CONF_EXT))
C(load_config(MODULE_PATH.'Conf/config'.CONF_EXT));
// 加载应用模式对应的配置文件
if('common' != APP_MODE && is_file(MODULE_PATH.'Conf/config_'.APP_MODE.CONF_EXT))
C(load_config(MODULE_PATH.'Conf/config_'.APP_MODE.CONF_EXT));
// 当前应用状态对应的配置文件
if(APP_STATUS && is_file(MODULE_PATH.'Conf/'.APP_STATUS.CONF_EXT))
C(load_config(MODULE_PATH.'Conf/'.APP_STATUS.CONF_EXT));
// 加载模块别名定义
if(is_file(MODULE_PATH.'Conf/alias.php'))
Think::addMap(include MODULE_PATH.'Conf/alias.php');
// 加载模块tags文件定义
if(is_file(MODULE_PATH.'Conf/tags.php'))
Hook::import(include MODULE_PATH.'Conf/tags.php');
// 加载模块函数文件
if(is_file(MODULE_PATH.'Common/function.php'))
include MODULE_PATH.'Common/function.php';
$urlCase = C('URL_CASE_INSENSITIVE');
// 加载模块的扩展配置文件
load_ext_file(MODULE_PATH);
}else{
E(L('_MODULE_NOT_EXIST_').':'.MODULE_NAME);
}
if(!defined('__APP__')){
$urlMode = C('URL_MODEL');
if($urlMode == URL_COMPAT ){// 兼容模式判断
define('PHP_FILE',_PHP_FILE_.'?'.$varPath.'=');
}elseif($urlMode == URL_REWRITE ) {
$url = dirname(_PHP_FILE_);
if($url == '/' || $url == '\\')
$url = '';
define('PHP_FILE',$url);
}else {
define('PHP_FILE',_PHP_FILE_);
}
// 当前应用地址
define('__APP__',strip_tags(PHP_FILE));
}
// 模块URL地址
$moduleName = defined('MODULE_ALIAS')? MODULE_ALIAS : MODULE_NAME;
define('__MODULE__',(defined('BIND_MODULE') || !C('MULTI_MODULE'))? __APP__ : __APP__.'/'.($urlCase ? strtolower($moduleName) : $moduleName));
if('' != $_SERVER['PATH_INFO'] && (!C('URL_ROUTER_ON') || !Route::check()) ){ // 检测路由规则 如果没有则按默认规则调度URL
Hook::listen('path_info');
// 检查禁止访问的URL后缀
if(C('URL_DENY_SUFFIX') && preg_match('/\.('.trim(C('URL_DENY_SUFFIX'),'.').')$/i', $_SERVER['PATH_INFO'])){
send_http_status(404);
exit;
}
// 去除URL后缀
$_SERVER['PATH_INFO'] = preg_replace(C('URL_HTML_SUFFIX')? '/\.('.trim(C('URL_HTML_SUFFIX'),'.').')$/i' : '/\.'.__EXT__.'$/i', '', $_SERVER['PATH_INFO']);
$depr = C('URL_PATHINFO_DEPR');
$paths = explode($depr,trim($_SERVER['PATH_INFO'],$depr));
if(!defined('BIND_CONTROLLER')) {// 获取控制器
if(C('CONTROLLER_LEVEL')>1){// 控制器层次
$_GET[$varController] = implode('/',array_slice($paths,0,C('CONTROLLER_LEVEL')));
$paths = array_slice($paths, C('CONTROLLER_LEVEL'));
}else{
$_GET[$varController] = array_shift($paths);
}
}
// 获取操作
if(!defined('BIND_ACTION')){
$_GET[$varAction] = array_shift($paths);
}
// 解析剩余的URL参数
$var = array();
if(C('URL_PARAMS_BIND') && 1 == C('URL_PARAMS_BIND_TYPE')){
// URL参数按顺序绑定变量
$var = $paths;
}else{
preg_replace_callback('/(\w+)\/([^\/]+)/', function($match) use(&$var){$var[$match[1]]=strip_tags($match[2]);}, implode('/',$paths));
}
$_GET = array_merge($var,$_GET);
}
// 获取控制器的命名空间(路径)
define('CONTROLLER_PATH', self::getSpace($varAddon,$urlCase));
// 获取控制器和操作名
define('CONTROLLER_NAME', defined('BIND_CONTROLLER')? BIND_CONTROLLER : self::getController($varController,$urlCase));
define('ACTION_NAME', defined('BIND_ACTION')? BIND_ACTION : self::getAction($varAction,$urlCase));
// 当前控制器的UR地址
$controllerName = defined('CONTROLLER_ALIAS')? CONTROLLER_ALIAS : CONTROLLER_NAME;
define('__CONTROLLER__',__MODULE__.$depr.(defined('BIND_CONTROLLER')? '': ( $urlCase ? parse_name($controllerName) : $controllerName )) );
// 当前操作的URL地址
define('__ACTION__',__CONTROLLER__.$depr.(defined('ACTION_ALIAS')?ACTION_ALIAS:ACTION_NAME));
//保证$_REQUEST正常取值
$_REQUEST = array_merge($_POST,$_GET,$_COOKIE); // -- 加了$_COOKIE. 保证哦..
}
/**
* 获得控制器的命名空间路径 便于插件机制访问
*/
static private function getSpace($var,$urlCase) {
$space = !empty($_GET[$var])?strip_tags($_GET[$var]):'';
unset($_GET[$var]);
return $space;
}
/**
* 获得实际的控制器名称
*/
static private function getController($var,$urlCase) {
$controller = (!empty($_GET[$var])? $_GET[$var]:C('DEFAULT_CONTROLLER'));
unset($_GET[$var]);
if($maps = C('URL_CONTROLLER_MAP')) {
if(isset($maps[strtolower($controller)])) {
// 记录当前别名
define('CONTROLLER_ALIAS',strtolower($controller));
// 获取实际的控制器名
return ucfirst($maps[CONTROLLER_ALIAS]);
}elseif(array_search(strtolower($controller),$maps)){
// 禁止访问原始控制器
return '';
}
}
if($urlCase) {
// URL地址不区分大小写
// 智能识别方式 user_type 识别到 UserTypeController 控制器
$controller = parse_name($controller,1);
}
return strip_tags(ucfirst($controller));
}
/**
* 获得实际的操作名称
*/
static private function getAction($var,$urlCase) {
$action = !empty($_POST[$var]) ?
$_POST[$var] :
(!empty($_GET[$var])?$_GET[$var]:C('DEFAULT_ACTION'));
unset($_POST[$var],$_GET[$var]);
if($maps = C('URL_ACTION_MAP')) {
if(isset($maps[strtolower(CONTROLLER_NAME)])) {
$maps = $maps[strtolower(CONTROLLER_NAME)];
if(isset($maps[strtolower($action)])) {
// 记录当前别名
define('ACTION_ALIAS',strtolower($action));
// 获取实际的操作名
if(is_array($maps[ACTION_ALIAS])){
parse_str($maps[ACTION_ALIAS][1],$vars);
$_GET = array_merge($_GET,$vars);
return $maps[ACTION_ALIAS][0];
}else{
return $maps[ACTION_ALIAS];
}
}elseif(array_search(strtolower($action),$maps)){
// 禁止访问原始操作
return '';
}
}
}
return strip_tags( $urlCase? strtolower($action) : $action );
}
/**
* 获得实际的模块名称
*/
static private function getModule($var) {
$module = (!empty($_GET[$var])?$_GET[$var]:C('DEFAULT_MODULE'));
unset($_GET[$var]);
if($maps = C('URL_MODULE_MAP')) {
if(isset($maps[strtolower($module)])) {
// 记录当前别名
define('MODULE_ALIAS',strtolower($module));
// 获取实际的模块名
return ucfirst($maps[MODULE_ALIAS]);
}elseif(array_search(strtolower($module),$maps)){
// 禁止访问原始模块
return '';
}
}
return strip_tags(ucfirst($module));
}
}

View File

@@ -0,0 +1,16 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
namespace Think;
/**
* ThinkPHP系统异常基类
*/
class Exception extends \Exception {
}

View File

@@ -0,0 +1,121 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006~2013 http://topthink.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
namespace Think;
/**
* ThinkPHP系统钩子实现
*/
class Hook {
static private $tags = array();
/**
* 动态添加插件到某个标签
* @param string $tag 标签名称
* @param mixed $name 插件名称
* @return void
*/
static public function add($tag,$name) {
if(!isset(self::$tags[$tag])){
self::$tags[$tag] = array();
}
if(is_array($name)){
self::$tags[$tag] = array_merge(self::$tags[$tag],$name);
}else{
self::$tags[$tag][] = $name;
}
}
/**
* 批量导入插件
* @param array $data 插件信息
* @param boolean $recursive 是否递归合并
* @return void
*/
static public function import($data,$recursive=true) {
if(!$recursive){ // 覆盖导入
self::$tags = array_merge(self::$tags,$data);
}else{ // 合并导入
foreach ($data as $tag=>$val){
if(!isset(self::$tags[$tag]))
self::$tags[$tag] = array();
if(!empty($val['_overlay'])){
// 可以针对某个标签指定覆盖模式
unset($val['_overlay']);
self::$tags[$tag] = $val;
}else{
// 合并模式
self::$tags[$tag] = array_merge(self::$tags[$tag],$val);
}
}
}
}
/**
* 获取插件信息
* @param string $tag 插件位置 留空获取全部
* @return array
*/
static public function get($tag='') {
if(empty($tag)){
// 获取全部的插件信息
return self::$tags;
}else{
return self::$tags[$tag];
}
}
/**
* 监听标签的插件
* @param string $tag 标签名称
* @param mixed $params 传入参数
* @return void
*/
static public function listen($tag, &$params=NULL) {
if(isset(self::$tags[$tag])) {
if(APP_DEBUG) {
G($tag.'Start');
trace('[ '.$tag.' ] --START--','','INFO');
}
foreach (self::$tags[$tag] as $name) {
APP_DEBUG && G($name.'_start');
$result = self::exec($name, $tag,$params);
if(APP_DEBUG){
G($name.'_end');
trace('Run '.$name.' [ RunTime:'.G($name.'_start',$name.'_end',6).'s ]','','INFO');
}
if(false === $result) {
// 如果返回false 则中断插件执行
return ;
}
}
if(APP_DEBUG) { // 记录行为的执行日志
trace('[ '.$tag.' ] --END-- [ RunTime:'.G($tag.'Start',$tag.'End',6).'s ]','','INFO');
}
}
return;
}
/**
* 执行某个插件
* @param string $name 插件名称
* @param string $tag 方法名(标签名)
* @param Mixed $params 传入的参数
* @return void
*/
static public function exec($name, $tag,&$params=NULL) {
if('Behavior' == substr($name,-8) ){
// 行为扩展必须用run入口方法
$tag = 'run';
}
$addon = new $name();
return $addon->$tag($params);
}
}

View File

@@ -0,0 +1,191 @@
<?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: 麦当苗儿 <zuojiazi@vip.qq.com> <http://www.zjzit.cn>
// +----------------------------------------------------------------------
// | ThinkImage.class.php 2013-03-05
// +----------------------------------------------------------------------
namespace Think;
/**
* 图片处理驱动类,可配置图片处理库
* 目前支持GD库和imagick
* @author 麦当苗儿 <zuojiazi@vip.qq.com>
*/
class Image{
/* 驱动相关常量定义 */
const IMAGE_GD = 1; //常量标识GD库类型
const IMAGE_IMAGICK = 2; //常量标识imagick库类型
/* 缩略图相关常量定义 */
const IMAGE_THUMB_SCALE = 1 ; //常量,标识缩略图等比例缩放类型
const IMAGE_THUMB_FILLED = 2 ; //常量,标识缩略图缩放后填充类型
const IMAGE_THUMB_CENTER = 3 ; //常量,标识缩略图居中裁剪类型
const IMAGE_THUMB_NORTHWEST = 4 ; //常量,标识缩略图左上角裁剪类型
const IMAGE_THUMB_SOUTHEAST = 5 ; //常量,标识缩略图右下角裁剪类型
const IMAGE_THUMB_FIXED = 6 ; //常量,标识缩略图固定尺寸缩放类型
/* 水印相关常量定义 */
const IMAGE_WATER_NORTHWEST = 1 ; //常量,标识左上角水印
const IMAGE_WATER_NORTH = 2 ; //常量,标识上居中水印
const IMAGE_WATER_NORTHEAST = 3 ; //常量,标识右上角水印
const IMAGE_WATER_WEST = 4 ; //常量,标识左居中水印
const IMAGE_WATER_CENTER = 5 ; //常量,标识居中水印
const IMAGE_WATER_EAST = 6 ; //常量,标识右居中水印
const IMAGE_WATER_SOUTHWEST = 7 ; //常量,标识左下角水印
const IMAGE_WATER_SOUTH = 8 ; //常量,标识下居中水印
const IMAGE_WATER_SOUTHEAST = 9 ; //常量,标识右下角水印
/**
* 图片资源
* @var resource
*/
private $img;
/**
* 构造方法,用于实例化一个图片处理对象
* @param string $type 要使用的类库默认使用GD库
*/
public function __construct($type = self::IMAGE_GD, $imgname = null){
/* 判断调用库的类型 */
switch ($type) {
case self::IMAGE_GD:
$class = 'Gd';
break;
case self::IMAGE_IMAGICK:
$class = 'Imagick';
break;
default:
E('不支持的图片处理库类型');
}
/* 引入处理库,实例化图片处理对象 */
$class = "Think\\Image\\Driver\\{$class}";
$this->img = new $class($imgname);
}
/**
* 打开一幅图像
* @param string $imgname 图片路径
* @return Object 当前图片处理库对象
*/
public function open($imgname){
$this->img->open($imgname);
return $this;
}
/**
* 保存图片
* @param string $imgname 图片保存名称
* @param string $type 图片类型
* @param integer $quality 图像质量
* @param boolean $interlace 是否对JPEG类型图片设置隔行扫描
* @return Object 当前图片处理库对象
*/
public function save($imgname, $type = null, $quality=80,$interlace = true){
$this->img->save($imgname, $type, $quality,$interlace);
return $this;
}
/**
* 返回图片宽度
* @return integer 图片宽度
*/
public function width(){
return $this->img->width();
}
/**
* 返回图片高度
* @return integer 图片高度
*/
public function height(){
return $this->img->height();
}
/**
* 返回图像类型
* @return string 图片类型
*/
public function type(){
return $this->img->type();
}
/**
* 返回图像MIME类型
* @return string 图像MIME类型
*/
public function mime(){
return $this->img->mime();
}
/**
* 返回图像尺寸数组 0 - 图片宽度1 - 图片高度
* @return array 图片尺寸
*/
public function size(){
return $this->img->size();
}
/**
* 裁剪图片
* @param integer $w 裁剪区域宽度
* @param integer $h 裁剪区域高度
* @param integer $x 裁剪区域x坐标
* @param integer $y 裁剪区域y坐标
* @param integer $width 图片保存宽度
* @param integer $height 图片保存高度
* @return Object 当前图片处理库对象
*/
public function crop($w, $h, $x = 0, $y = 0, $width = null, $height = null){
$this->img->crop($w, $h, $x, $y, $width, $height);
return $this;
}
/**
* 生成缩略图
* @param integer $width 缩略图最大宽度
* @param integer $height 缩略图最大高度
* @param integer $type 缩略图裁剪类型
* @return Object 当前图片处理库对象
*/
public function thumb($width, $height, $type = self::IMAGE_THUMB_SCALE){
$this->img->thumb($width, $height, $type);
return $this;
}
/**
* 添加水印
* @param string $source 水印图片路径
* @param integer $locate 水印位置
* @param integer $alpha 水印透明度
* @return Object 当前图片处理库对象
*/
public function water($source, $locate = self::IMAGE_WATER_SOUTHEAST,$alpha=80){
$this->img->water($source, $locate,$alpha);
return $this;
}
/**
* 图像添加文字
* @param string $text 添加的文字
* @param string $font 字体路径
* @param integer $size 字号
* @param string $color 文字颜色
* @param integer $locate 文字写入位置
* @param integer $offset 文字相对当前位置的偏移量
* @param integer $angle 文字倾斜角度
* @return Object 当前图片处理库对象
*/
public function text($text, $font, $size, $color = '#00000000',
$locate = self::IMAGE_WATER_SOUTHEAST, $offset = 0, $angle = 0){
$this->img->text($text, $font, $size, $color, $locate, $offset, $angle);
return $this;
}
}

View File

@@ -0,0 +1,567 @@
<?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: 麦当苗儿 <zuojiazi@vip.qq.com> <http://www.zjzit.cn>
// +----------------------------------------------------------------------
// | GIF.class.php 2013-03-09
// +----------------------------------------------------------------------
namespace Think\Image\Driver;
class GIF{
/**
* GIF帧列表
* @var array
*/
private $frames = array();
/**
* 每帧等待时间列表
* @var array
*/
private $delays = array();
/**
* 构造方法用于解码GIF图片
* @param string $src GIF图片数据
* @param string $mod 图片数据类型
*/
public function __construct($src = null, $mod = 'url') {
if(!is_null($src)){
if('url' == $mod && is_file($src)){
$src = file_get_contents($src);
}
/* 解码GIF图片 */
try{
$de = new GIFDecoder($src);
$this->frames = $de->GIFGetFrames();
$this->delays = $de->GIFGetDelays();
} catch(\Exception $e){
E("解码GIF图片出错");
}
}
}
/**
* 设置或获取当前帧的数据
* @param string $stream 二进制数据流
* @return boolean 获取到的数据
*/
public function image($stream = null){
if(is_null($stream)){
$current = current($this->frames);
return false === $current ? reset($this->frames) : $current;
} else {
$this->frames[key($this->frames)] = $stream;
}
}
/**
* 将当前帧移动到下一帧
* @return string 当前帧数据
*/
public function nextImage(){
return next($this->frames);
}
/**
* 编码并保存当前GIF图片
* @param string $gifname 图片名称
*/
public function save($gifname){
$gif = new GIFEncoder($this->frames, $this->delays, 0, 2, 0, 0, 0, 'bin');
file_put_contents($gifname, $gif->GetAnimation());
}
}
/*
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::
:: GIFEncoder Version 2.0 by László Zsidi, http://gifs.hu
::
:: This class is a rewritten 'GifMerge.class.php' version.
::
:: Modification:
:: - Simplified and easy code,
:: - Ultra fast encoding,
:: - Built-in errors,
:: - Stable working
::
::
:: Updated at 2007. 02. 13. '00.05.AM'
::
::
::
:: Try on-line GIFBuilder Form demo based on GIFEncoder.
::
:: http://gifs.hu/phpclasses/demos/GifBuilder/
::
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
*/
Class GIFEncoder {
private $GIF = "GIF89a"; /* GIF header 6 bytes */
private $VER = "GIFEncoder V2.05"; /* Encoder version */
private $BUF = Array ( );
private $LOP = 0;
private $DIS = 2;
private $COL = -1;
private $IMG = -1;
private $ERR = Array (
'ERR00' => "Does not supported function for only one image!",
'ERR01' => "Source is not a GIF image!",
'ERR02' => "Unintelligible flag ",
'ERR03' => "Does not make animation from animated GIF source",
);
/*
:::::::::::::::::::::::::::::::::::::::::::::::::::
::
:: GIFEncoder...
::
*/
public function __construct($GIF_src, $GIF_dly, $GIF_lop, $GIF_dis,$GIF_red, $GIF_grn, $GIF_blu, $GIF_mod) {
if ( ! is_array ( $GIF_src ) && ! is_array ( $GIF_dly ) ) {
printf ( "%s: %s", $this->VER, $this->ERR [ 'ERR00' ] );
exit ( 0 );
}
$this->LOP = ( $GIF_lop > -1 ) ? $GIF_lop : 0;
$this->DIS = ( $GIF_dis > -1 ) ? ( ( $GIF_dis < 3 ) ? $GIF_dis : 3 ) : 2;
$this->COL = ( $GIF_red > -1 && $GIF_grn > -1 && $GIF_blu > -1 ) ?
( $GIF_red | ( $GIF_grn << 8 ) | ( $GIF_blu << 16 ) ) : -1;
for ( $i = 0; $i < count ( $GIF_src ); $i++ ) {
if ( strToLower ( $GIF_mod ) == "url" ) {
$this->BUF [ ] = fread ( fopen ( $GIF_src [ $i ], "rb" ), filesize ( $GIF_src [ $i ] ) );
}
else if ( strToLower ( $GIF_mod ) == "bin" ) {
$this->BUF [ ] = $GIF_src [ $i ];
}
else {
printf ( "%s: %s ( %s )!", $this->VER, $this->ERR [ 'ERR02' ], $GIF_mod );
exit ( 0 );
}
if ( substr ( $this->BUF [ $i ], 0, 6 ) != "GIF87a" && substr ( $this->BUF [ $i ], 0, 6 ) != "GIF89a" ) {
printf ( "%s: %d %s", $this->VER, $i, $this->ERR [ 'ERR01' ] );
exit ( 0 );
}
for ( $j = ( 13 + 3 * ( 2 << ( ord ( $this->BUF [ $i ] { 10 } ) & 0x07 ) ) ), $k = TRUE; $k; $j++ ) {
switch ( $this->BUF [ $i ] { $j } ) {
case "!":
if ( ( substr ( $this->BUF [ $i ], ( $j + 3 ), 8 ) ) == "NETSCAPE" ) {
printf ( "%s: %s ( %s source )!", $this->VER, $this->ERR [ 'ERR03' ], ( $i + 1 ) );
exit ( 0 );
}
break;
case ";":
$k = FALSE;
break;
}
}
}
$this->GIFAddHeader ( );
for ( $i = 0; $i < count ( $this->BUF ); $i++ ) {
$this->GIFAddFrames ( $i, $GIF_dly [ $i ] );
}
$this->GIFAddFooter ( );
}
/*
:::::::::::::::::::::::::::::::::::::::::::::::::::
::
:: GIFAddHeader...
::
*/
private function GIFAddHeader ( ) {
$cmap = 0;
if ( ord ( $this->BUF [ 0 ] { 10 } ) & 0x80 ) {
$cmap = 3 * ( 2 << ( ord ( $this->BUF [ 0 ] { 10 } ) & 0x07 ) );
$this->GIF .= substr ( $this->BUF [ 0 ], 6, 7 );
$this->GIF .= substr ( $this->BUF [ 0 ], 13, $cmap );
$this->GIF .= "!\377\13NETSCAPE2.0\3\1" . $this->GIFWord ( $this->LOP ) . "\0";
}
}
/*
:::::::::::::::::::::::::::::::::::::::::::::::::::
::
:: GIFAddFrames...
::
*/
private function GIFAddFrames ( $i, $d ) {
$Locals_str = 13 + 3 * ( 2 << ( ord ( $this->BUF [ $i ] { 10 } ) & 0x07 ) );
$Locals_end = strlen ( $this->BUF [ $i ] ) - $Locals_str - 1;
$Locals_tmp = substr ( $this->BUF [ $i ], $Locals_str, $Locals_end );
$Global_len = 2 << ( ord ( $this->BUF [ 0 ] { 10 } ) & 0x07 );
$Locals_len = 2 << ( ord ( $this->BUF [ $i ] { 10 } ) & 0x07 );
$Global_rgb = substr ( $this->BUF [ 0 ], 13,
3 * ( 2 << ( ord ( $this->BUF [ 0 ] { 10 } ) & 0x07 ) ) );
$Locals_rgb = substr ( $this->BUF [ $i ], 13,
3 * ( 2 << ( ord ( $this->BUF [ $i ] { 10 } ) & 0x07 ) ) );
$Locals_ext = "!\xF9\x04" . chr ( ( $this->DIS << 2 ) + 0 ) .
chr ( ( $d >> 0 ) & 0xFF ) . chr ( ( $d >> 8 ) & 0xFF ) . "\x0\x0";
if ( $this->COL > -1 && ord ( $this->BUF [ $i ] { 10 } ) & 0x80 ) {
for ( $j = 0; $j < ( 2 << ( ord ( $this->BUF [ $i ] { 10 } ) & 0x07 ) ); $j++ ) {
if (
ord ( $Locals_rgb { 3 * $j + 0 } ) == ( ( $this->COL >> 16 ) & 0xFF ) &&
ord ( $Locals_rgb { 3 * $j + 1 } ) == ( ( $this->COL >> 8 ) & 0xFF ) &&
ord ( $Locals_rgb { 3 * $j + 2 } ) == ( ( $this->COL >> 0 ) & 0xFF )
) {
$Locals_ext = "!\xF9\x04" . chr ( ( $this->DIS << 2 ) + 1 ) .
chr ( ( $d >> 0 ) & 0xFF ) . chr ( ( $d >> 8 ) & 0xFF ) . chr ( $j ) . "\x0";
break;
}
}
}
switch ( $Locals_tmp { 0 } ) {
case "!":
$Locals_img = substr ( $Locals_tmp, 8, 10 );
$Locals_tmp = substr ( $Locals_tmp, 18, strlen ( $Locals_tmp ) - 18 );
break;
case ",":
$Locals_img = substr ( $Locals_tmp, 0, 10 );
$Locals_tmp = substr ( $Locals_tmp, 10, strlen ( $Locals_tmp ) - 10 );
break;
}
if ( ord ( $this->BUF [ $i ] { 10 } ) & 0x80 && $this->IMG > -1 ) {
if ( $Global_len == $Locals_len ) {
if ( $this->GIFBlockCompare ( $Global_rgb, $Locals_rgb, $Global_len ) ) {
$this->GIF .= ( $Locals_ext . $Locals_img . $Locals_tmp );
}
else {
$byte = ord ( $Locals_img { 9 } );
$byte |= 0x80;
$byte &= 0xF8;
$byte |= ( ord ( $this->BUF [ 0 ] { 10 } ) & 0x07 );
$Locals_img { 9 } = chr ( $byte );
$this->GIF .= ( $Locals_ext . $Locals_img . $Locals_rgb . $Locals_tmp );
}
}
else {
$byte = ord ( $Locals_img { 9 } );
$byte |= 0x80;
$byte &= 0xF8;
$byte |= ( ord ( $this->BUF [ $i ] { 10 } ) & 0x07 );
$Locals_img { 9 } = chr ( $byte );
$this->GIF .= ( $Locals_ext . $Locals_img . $Locals_rgb . $Locals_tmp );
}
}
else {
$this->GIF .= ( $Locals_ext . $Locals_img . $Locals_tmp );
}
$this->IMG = 1;
}
/*
:::::::::::::::::::::::::::::::::::::::::::::::::::
::
:: GIFAddFooter...
::
*/
private function GIFAddFooter ( ) {
$this->GIF .= ";";
}
/*
:::::::::::::::::::::::::::::::::::::::::::::::::::
::
:: GIFBlockCompare...
::
*/
private function GIFBlockCompare ( $GlobalBlock, $LocalBlock, $Len ) {
for ( $i = 0; $i < $Len; $i++ ) {
if (
$GlobalBlock { 3 * $i + 0 } != $LocalBlock { 3 * $i + 0 } ||
$GlobalBlock { 3 * $i + 1 } != $LocalBlock { 3 * $i + 1 } ||
$GlobalBlock { 3 * $i + 2 } != $LocalBlock { 3 * $i + 2 }
) {
return ( 0 );
}
}
return ( 1 );
}
/*
:::::::::::::::::::::::::::::::::::::::::::::::::::
::
:: GIFWord...
::
*/
private function GIFWord ( $int ) {
return ( chr ( $int & 0xFF ) . chr ( ( $int >> 8 ) & 0xFF ) );
}
/*
:::::::::::::::::::::::::::::::::::::::::::::::::::
::
:: GetAnimation...
::
*/
public function GetAnimation ( ) {
return ( $this->GIF );
}
}
/*
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
::
:: GIFDecoder Version 2.0 by László Zsidi, http://gifs.hu
::
:: Created at 2007. 02. 01. '07.47.AM'
::
::
::
::
:: Try on-line GIFBuilder Form demo based on GIFDecoder.
::
:: http://gifs.hu/phpclasses/demos/GifBuilder/
::
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
*/
Class GIFDecoder {
private $GIF_buffer = Array ( );
private $GIF_arrays = Array ( );
private $GIF_delays = Array ( );
private $GIF_stream = "";
private $GIF_string = "";
private $GIF_bfseek = 0;
private $GIF_screen = Array ( );
private $GIF_global = Array ( );
private $GIF_sorted;
private $GIF_colorS;
private $GIF_colorC;
private $GIF_colorF;
/*
:::::::::::::::::::::::::::::::::::::::::::::::::::
::
:: GIFDecoder ( $GIF_pointer )
::
*/
public function __construct ( $GIF_pointer ) {
$this->GIF_stream = $GIF_pointer;
$this->GIFGetByte ( 6 ); // GIF89a
$this->GIFGetByte ( 7 ); // Logical Screen Descriptor
$this->GIF_screen = $this->GIF_buffer;
$this->GIF_colorF = $this->GIF_buffer [ 4 ] & 0x80 ? 1 : 0;
$this->GIF_sorted = $this->GIF_buffer [ 4 ] & 0x08 ? 1 : 0;
$this->GIF_colorC = $this->GIF_buffer [ 4 ] & 0x07;
$this->GIF_colorS = 2 << $this->GIF_colorC;
if ( $this->GIF_colorF == 1 ) {
$this->GIFGetByte ( 3 * $this->GIF_colorS );
$this->GIF_global = $this->GIF_buffer;
}
/*
*
* 05.06.2007.
* Made a little modification
*
*
- for ( $cycle = 1; $cycle; ) {
+ if ( GIFDecoder::GIFGetByte ( 1 ) ) {
- switch ( $this->GIF_buffer [ 0 ] ) {
- case 0x21:
- GIFDecoder::GIFReadExtensions ( );
- break;
- case 0x2C:
- GIFDecoder::GIFReadDescriptor ( );
- break;
- case 0x3B:
- $cycle = 0;
- break;
- }
- }
+ else {
+ $cycle = 0;
+ }
- }
*/
for ( $cycle = 1; $cycle; ) {
if ( $this->GIFGetByte ( 1 ) ) {
switch ( $this->GIF_buffer [ 0 ] ) {
case 0x21:
$this->GIFReadExtensions ( );
break;
case 0x2C:
$this->GIFReadDescriptor ( );
break;
case 0x3B:
$cycle = 0;
break;
}
}
else {
$cycle = 0;
}
}
}
/*
:::::::::::::::::::::::::::::::::::::::::::::::::::
::
:: GIFReadExtension ( )
::
*/
private function GIFReadExtensions ( ) {
$this->GIFGetByte ( 1 );
for ( ; ; ) {
$this->GIFGetByte ( 1 );
if ( ( $u = $this->GIF_buffer [ 0 ] ) == 0x00 ) {
break;
}
$this->GIFGetByte ( $u );
/*
* 07.05.2007.
* Implemented a new line for a new function
* to determine the originaly delays between
* frames.
*
*/
if ( $u == 4 ) {
$this->GIF_delays [ ] = ( $this->GIF_buffer [ 1 ] | $this->GIF_buffer [ 2 ] << 8 );
}
}
}
/*
:::::::::::::::::::::::::::::::::::::::::::::::::::
::
:: GIFReadExtension ( )
::
*/
private function GIFReadDescriptor ( ) {
$GIF_screen = Array ( );
$this->GIFGetByte ( 9 );
$GIF_screen = $this->GIF_buffer;
$GIF_colorF = $this->GIF_buffer [ 8 ] & 0x80 ? 1 : 0;
if ( $GIF_colorF ) {
$GIF_code = $this->GIF_buffer [ 8 ] & 0x07;
$GIF_sort = $this->GIF_buffer [ 8 ] & 0x20 ? 1 : 0;
}
else {
$GIF_code = $this->GIF_colorC;
$GIF_sort = $this->GIF_sorted;
}
$GIF_size = 2 << $GIF_code;
$this->GIF_screen [ 4 ] &= 0x70;
$this->GIF_screen [ 4 ] |= 0x80;
$this->GIF_screen [ 4 ] |= $GIF_code;
if ( $GIF_sort ) {
$this->GIF_screen [ 4 ] |= 0x08;
}
$this->GIF_string = "GIF87a";
$this->GIFPutByte ( $this->GIF_screen );
if ( $GIF_colorF == 1 ) {
$this->GIFGetByte ( 3 * $GIF_size );
$this->GIFPutByte ( $this->GIF_buffer );
}
else {
$this->GIFPutByte ( $this->GIF_global );
}
$this->GIF_string .= chr ( 0x2C );
$GIF_screen [ 8 ] &= 0x40;
$this->GIFPutByte ( $GIF_screen );
$this->GIFGetByte ( 1 );
$this->GIFPutByte ( $this->GIF_buffer );
for ( ; ; ) {
$this->GIFGetByte ( 1 );
$this->GIFPutByte ( $this->GIF_buffer );
if ( ( $u = $this->GIF_buffer [ 0 ] ) == 0x00 ) {
break;
}
$this->GIFGetByte ( $u );
$this->GIFPutByte ( $this->GIF_buffer );
}
$this->GIF_string .= chr ( 0x3B );
/*
Add frames into $GIF_stream array...
*/
$this->GIF_arrays [ ] = $this->GIF_string;
}
/*
:::::::::::::::::::::::::::::::::::::::::::::::::::
::
:: GIFGetByte ( $len )
::
*/
/*
*
* 05.06.2007.
* Made a little modification
*
*
- function GIFGetByte ( $len ) {
- $this->GIF_buffer = Array ( );
-
- for ( $i = 0; $i < $len; $i++ ) {
+ if ( $this->GIF_bfseek > strlen ( $this->GIF_stream ) ) {
+ return 0;
+ }
- $this->GIF_buffer [ ] = ord ( $this->GIF_stream { $this->GIF_bfseek++ } );
- }
+ return 1;
- }
*/
private function GIFGetByte ( $len ) {
$this->GIF_buffer = Array ( );
for ( $i = 0; $i < $len; $i++ ) {
if ( $this->GIF_bfseek > strlen ( $this->GIF_stream ) ) {
return 0;
}
$this->GIF_buffer [ ] = ord ( $this->GIF_stream { $this->GIF_bfseek++ } );
}
return 1;
}
/*
:::::::::::::::::::::::::::::::::::::::::::::::::::
::
:: GIFPutByte ( $bytes )
::
*/
private function GIFPutByte ( $bytes ) {
for ( $i = 0; $i < count ( $bytes ); $i++ ) {
$this->GIF_string .= chr ( $bytes [ $i ] );
}
}
/*
:::::::::::::::::::::::::::::::::::::::::::::::::::
::
:: PUBLIC FUNCTIONS
::
::
:: GIFGetFrames ( )
::
*/
public function GIFGetFrames ( ) {
return ( $this->GIF_arrays );
}
/*
:::::::::::::::::::::::::::::::::::::::::::::::::::
::
:: GIFGetDelays ( )
::
*/
public function GIFGetDelays ( ) {
return ( $this->GIF_delays );
}
}

View File

@@ -0,0 +1,542 @@
<?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: 麦当苗儿 <zuojiazi@vip.qq.com> <http://www.zjzit.cn>
// +----------------------------------------------------------------------
// | ImageGd.class.php 2013-03-05
// +----------------------------------------------------------------------
namespace Think\Image\Driver;
use Think\Image;
class Gd{
/**
* 图像资源对象
* @var resource
*/
private $img;
/**
* 图像信息包括width,height,type,mime,size
* @var array
*/
private $info;
/**
* 构造方法,可用于打开一张图像
* @param string $imgname 图像路径
*/
public function __construct($imgname = null) {
$imgname && $this->open($imgname);
}
/**
* 打开一张图像
* @param string $imgname 图像路径
*/
public function open($imgname){
//检测图像文件
if(!is_file($imgname)) E('不存在的图像文件');
//获取图像信息
$info = getimagesize($imgname);
//检测图像合法性
if(false === $info || (IMAGETYPE_GIF === $info[2] && empty($info['bits']))){
E('非法图像文件');
}
//设置图像信息
$this->info = array(
'width' => $info[0],
'height' => $info[1],
'type' => image_type_to_extension($info[2], false),
'mime' => $info['mime'],
);
//销毁已存在的图像
empty($this->img) || imagedestroy($this->img);
//打开图像
if('gif' == $this->info['type']){
$class = 'Think\\Image\\Driver\\GIF';
$this->gif = new $class($imgname);
$this->img = imagecreatefromstring($this->gif->image());
} else {
$fun = "imagecreatefrom{$this->info['type']}";
$this->img = $fun($imgname);
}
}
/**
* 保存图像
* @param string $imgname 图像保存名称
* @param string $type 图像类型
* @param integer $quality 图像质量
* @param boolean $interlace 是否对JPEG类型图像设置隔行扫描
*/
public function save($imgname, $type = null, $quality=80,$interlace = true){
if(empty($this->img)) E('没有可以被保存的图像资源');
//自动获取图像类型
if(is_null($type)){
$type = $this->info['type'];
} else {
$type = strtolower($type);
}
//保存图像
if('jpeg' == $type || 'jpg' == $type){
//JPEG图像设置隔行扫描
imageinterlace($this->img, $interlace);
imagejpeg($this->img, $imgname,$quality);
}elseif('gif' == $type && !empty($this->gif)){
$this->gif->save($imgname);
}else{
$fun = 'image'.$type;
$fun($this->img, $imgname);
}
}
/**
* 返回图像宽度
* @return integer 图像宽度
*/
public function width(){
if(empty($this->img)) E('没有指定图像资源');
return $this->info['width'];
}
/**
* 返回图像高度
* @return integer 图像高度
*/
public function height(){
if(empty($this->img)) E('没有指定图像资源');
return $this->info['height'];
}
/**
* 返回图像类型
* @return string 图像类型
*/
public function type(){
if(empty($this->img)) E('没有指定图像资源');
return $this->info['type'];
}
/**
* 返回图像MIME类型
* @return string 图像MIME类型
*/
public function mime(){
if(empty($this->img)) E('没有指定图像资源');
return $this->info['mime'];
}
/**
* 返回图像尺寸数组 0 - 图像宽度1 - 图像高度
* @return array 图像尺寸
*/
public function size(){
if(empty($this->img)) E('没有指定图像资源');
return array($this->info['width'], $this->info['height']);
}
/**
* 裁剪图像
* @param integer $w 裁剪区域宽度
* @param integer $h 裁剪区域高度
* @param integer $x 裁剪区域x坐标
* @param integer $y 裁剪区域y坐标
* @param integer $width 图像保存宽度
* @param integer $height 图像保存高度
*/
public function crop($w, $h, $x = 0, $y = 0, $width = null, $height = null){
if(empty($this->img)) E('没有可以被裁剪的图像资源');
//设置保存尺寸
empty($width) && $width = $w;
empty($height) && $height = $h;
do {
//创建新图像
$img = imagecreatetruecolor($width, $height);
// 调整默认颜色
$color = imagecolorallocate($img, 255, 255, 255);
imagefill($img, 0, 0, $color);
//裁剪
imagecopyresampled($img, $this->img, 0, 0, $x, $y, $width, $height, $w, $h);
imagedestroy($this->img); //销毁原图
//设置新图像
$this->img = $img;
} while(!empty($this->gif) && $this->gifNext());
$this->info['width'] = $width;
$this->info['height'] = $height;
}
/**
* 生成缩略图
* @param integer $width 缩略图最大宽度
* @param integer $height 缩略图最大高度
* @param integer $type 缩略图裁剪类型
*/
public function thumb($width, $height, $type = Image::IMAGE_THUMB_SCALE){
if(empty($this->img)) E('没有可以被缩略的图像资源');
//原图宽度和高度
$w = $this->info['width'];
$h = $this->info['height'];
/* 计算缩略图生成的必要参数 */
switch ($type) {
/* 等比例缩放 */
case Image::IMAGE_THUMB_SCALE:
//原图尺寸小于缩略图尺寸则不进行缩略
if($w < $width && $h < $height) return;
//计算缩放比例
$scale = min($width/$w, $height/$h);
//设置缩略图的坐标及宽度和高度
$x = $y = 0;
$width = $w * $scale;
$height = $h * $scale;
break;
/* 居中裁剪 */
case Image::IMAGE_THUMB_CENTER:
//计算缩放比例
$scale = max($width/$w, $height/$h);
//设置缩略图的坐标及宽度和高度
$w = $width/$scale;
$h = $height/$scale;
$x = ($this->info['width'] - $w)/2;
$y = ($this->info['height'] - $h)/2;
break;
/* 左上角裁剪 */
case Image::IMAGE_THUMB_NORTHWEST:
//计算缩放比例
$scale = max($width/$w, $height/$h);
//设置缩略图的坐标及宽度和高度
$x = $y = 0;
$w = $width/$scale;
$h = $height/$scale;
break;
/* 右下角裁剪 */
case Image::IMAGE_THUMB_SOUTHEAST:
//计算缩放比例
$scale = max($width/$w, $height/$h);
//设置缩略图的坐标及宽度和高度
$w = $width/$scale;
$h = $height/$scale;
$x = $this->info['width'] - $w;
$y = $this->info['height'] - $h;
break;
/* 填充 */
case Image::IMAGE_THUMB_FILLED:
//计算缩放比例
if($w < $width && $h < $height){
$scale = 1;
} else {
$scale = min($width/$w, $height/$h);
}
//设置缩略图的坐标及宽度和高度
$neww = $w * $scale;
$newh = $h * $scale;
$posx = ($width - $w * $scale)/2;
$posy = ($height - $h * $scale)/2;
do{
//创建新图像
$img = imagecreatetruecolor($width, $height);
// 调整默认颜色
$color = imagecolorallocate($img, 255, 255, 255);
imagefill($img, 0, 0, $color);
//裁剪
imagecopyresampled($img, $this->img, $posx, $posy, $x, $y, $neww, $newh, $w, $h);
imagedestroy($this->img); //销毁原图
$this->img = $img;
} while(!empty($this->gif) && $this->gifNext());
$this->info['width'] = $width;
$this->info['height'] = $height;
return;
/* 固定 */
case Image::IMAGE_THUMB_FIXED:
$x = $y = 0;
break;
default:
E('不支持的缩略图裁剪类型');
}
/* 裁剪图像 */
$this->crop($w, $h, $x, $y, $width, $height);
}
/**
* 添加水印
* @param string $source 水印图片路径
* @param integer $locate 水印位置
* @param integer $alpha 水印透明度
*/
public function water($source, $locate = Image::IMAGE_WATER_SOUTHEAST,$alpha=80){
//资源检测
if(empty($this->img)) E('没有可以被添加水印的图像资源');
if(!is_file($source)) E('水印图像不存在');
//获取水印图像信息
$info = getimagesize($source);
if(false === $info || (IMAGETYPE_GIF === $info[2] && empty($info['bits']))){
E('非法水印文件');
}
//创建水印图像资源
$fun = 'imagecreatefrom' . image_type_to_extension($info[2], false);
$water = $fun($source);
//设定水印图像的混色模式
imagealphablending($water, true);
/* 设定水印位置 */
switch ($locate) {
/* 右下角水印 */
case Image::IMAGE_WATER_SOUTHEAST:
$x = $this->info['width'] - $info[0];
$y = $this->info['height'] - $info[1];
break;
/* 左下角水印 */
case Image::IMAGE_WATER_SOUTHWEST:
$x = 0;
$y = $this->info['height'] - $info[1];
break;
/* 左上角水印 */
case Image::IMAGE_WATER_NORTHWEST:
$x = $y = 0;
break;
/* 右上角水印 */
case Image::IMAGE_WATER_NORTHEAST:
$x = $this->info['width'] - $info[0];
$y = 0;
break;
/* 居中水印 */
case Image::IMAGE_WATER_CENTER:
$x = ($this->info['width'] - $info[0])/2;
$y = ($this->info['height'] - $info[1])/2;
break;
/* 下居中水印 */
case Image::IMAGE_WATER_SOUTH:
$x = ($this->info['width'] - $info[0])/2;
$y = $this->info['height'] - $info[1];
break;
/* 右居中水印 */
case Image::IMAGE_WATER_EAST:
$x = $this->info['width'] - $info[0];
$y = ($this->info['height'] - $info[1])/2;
break;
/* 上居中水印 */
case Image::IMAGE_WATER_NORTH:
$x = ($this->info['width'] - $info[0])/2;
$y = 0;
break;
/* 左居中水印 */
case Image::IMAGE_WATER_WEST:
$x = 0;
$y = ($this->info['height'] - $info[1])/2;
break;
default:
/* 自定义水印坐标 */
if(is_array($locate)){
list($x, $y) = $locate;
} else {
E('不支持的水印位置类型');
}
}
do{
//添加水印
$src = imagecreatetruecolor($info[0], $info[1]);
// 调整默认颜色
$color = imagecolorallocate($src, 255, 255, 255);
imagefill($src, 0, 0, $color);
imagecopy($src, $this->img, 0, 0, $x, $y, $info[0], $info[1]);
imagecopy($src, $water, 0, 0, 0, 0, $info[0], $info[1]);
imagecopymerge($this->img, $src, $x, $y, 0, 0, $info[0], $info[1], $alpha);
//销毁零时图片资源
imagedestroy($src);
} while(!empty($this->gif) && $this->gifNext());
//销毁水印资源
imagedestroy($water);
}
/**
* 图像添加文字
* @param string $text 添加的文字
* @param string $font 字体路径
* @param integer $size 字号
* @param string $color 文字颜色
* @param integer $locate 文字写入位置
* @param integer $offset 文字相对当前位置的偏移量
* @param integer $angle 文字倾斜角度
*/
public function text($text, $font, $size, $color = '#00000000',
$locate = Image::IMAGE_WATER_SOUTHEAST, $offset = 0, $angle = 0){
//资源检测
if(empty($this->img)) E('没有可以被写入文字的图像资源');
if(!is_file($font)) E("不存在的字体文件:{$font}");
//获取文字信息
$info = imagettfbbox($size, $angle, $font, $text);
$minx = min($info[0], $info[2], $info[4], $info[6]);
$maxx = max($info[0], $info[2], $info[4], $info[6]);
$miny = min($info[1], $info[3], $info[5], $info[7]);
$maxy = max($info[1], $info[3], $info[5], $info[7]);
/* 计算文字初始坐标和尺寸 */
$x = $minx;
$y = abs($miny);
$w = $maxx - $minx;
$h = $maxy - $miny;
/* 设定文字位置 */
switch ($locate) {
/* 右下角文字 */
case Image::IMAGE_WATER_SOUTHEAST:
$x += $this->info['width'] - $w;
$y += $this->info['height'] - $h;
break;
/* 左下角文字 */
case Image::IMAGE_WATER_SOUTHWEST:
$y += $this->info['height'] - $h;
break;
/* 左上角文字 */
case Image::IMAGE_WATER_NORTHWEST:
// 起始坐标即为左上角坐标,无需调整
break;
/* 右上角文字 */
case Image::IMAGE_WATER_NORTHEAST:
$x += $this->info['width'] - $w;
break;
/* 居中文字 */
case Image::IMAGE_WATER_CENTER:
$x += ($this->info['width'] - $w)/2;
$y += ($this->info['height'] - $h)/2;
break;
/* 下居中文字 */
case Image::IMAGE_WATER_SOUTH:
$x += ($this->info['width'] - $w)/2;
$y += $this->info['height'] - $h;
break;
/* 右居中文字 */
case Image::IMAGE_WATER_EAST:
$x += $this->info['width'] - $w;
$y += ($this->info['height'] - $h)/2;
break;
/* 上居中文字 */
case Image::IMAGE_WATER_NORTH:
$x += ($this->info['width'] - $w)/2;
break;
/* 左居中文字 */
case Image::IMAGE_WATER_WEST:
$y += ($this->info['height'] - $h)/2;
break;
default:
/* 自定义文字坐标 */
if(is_array($locate)){
list($posx, $posy) = $locate;
$x += $posx;
$y += $posy;
} else {
E('不支持的文字位置类型');
}
}
/* 设置偏移量 */
if(is_array($offset)){
$offset = array_map('intval', $offset);
list($ox, $oy) = $offset;
} else{
$offset = intval($offset);
$ox = $oy = $offset;
}
/* 设置颜色 */
if(is_string($color) && 0 === strpos($color, '#')){
$color = str_split(substr($color, 1), 2);
$color = array_map('hexdec', $color);
if(empty($color[3]) || $color[3] > 127){
$color[3] = 0;
}
} elseif (!is_array($color)) {
E('错误的颜色值');
}
do{
/* 写入文字 */
$col = imagecolorallocatealpha($this->img, $color[0], $color[1], $color[2], $color[3]);
imagettftext($this->img, $size, $angle, $x + $ox, $y + $oy, $col, $font, $text);
} while(!empty($this->gif) && $this->gifNext());
}
/* 切换到GIF的下一帧并保存当前帧内部使用 */
private function gifNext(){
ob_start();
ob_implicit_flush(0);
imagegif($this->img);
$img = ob_get_clean();
$this->gif->image($img);
$next = $this->gif->nextImage();
if($next){
$this->img = imagecreatefromstring($next);
return $next;
} else {
$this->img = imagecreatefromstring($this->gif->image());
return false;
}
}
/**
* 析构方法,用于销毁图像资源
*/
public function __destruct() {
empty($this->img) || imagedestroy($this->img);
}
}

View File

@@ -0,0 +1,593 @@
<?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: 麦当苗儿 <zuojiazi@vip.qq.com> <http://www.zjzit.cn>
// +----------------------------------------------------------------------
// | ImageImagick.class.php 2013-03-06
// +----------------------------------------------------------------------
namespace Think\Image\Driver;
use Think\Image;
class Imagick{
/**
* 图像资源对象
* @var resource
*/
private $img;
/**
* 图像信息包括width,height,type,mime,size
* @var array
*/
private $info;
/**
* 构造方法,可用于打开一张图像
* @param string $imgname 图像路径
*/
public function __construct($imgname = null) {
$imgname && $this->open($imgname);
}
/**
* 打开一张图像
* @param string $imgname 图像路径
*/
public function open($imgname){
//检测图像文件
if(!is_file($imgname)) E('不存在的图像文件');
//销毁已存在的图像
empty($this->img) || $this->img->destroy();
//载入图像
$this->img = new \Imagick(realpath($imgname));
//设置图像信息
$this->info = array(
'width' => $this->img->getImageWidth(),
'height' => $this->img->getImageHeight(),
'type' => strtolower($this->img->getImageFormat()),
'mime' => $this->img->getImageMimeType(),
);
}
/**
* 保存图像
* @param string $imgname 图像保存名称
* @param string $type 图像类型
* @param integer $quality JPEG图像质量
* @param boolean $interlace 是否对JPEG类型图像设置隔行扫描
*/
public function save($imgname, $type = null, $quality=80,$interlace = true){
if(empty($this->img)) E('没有可以被保存的图像资源');
//设置图片类型
if(is_null($type)){
$type = $this->info['type'];
} else {
$type = strtolower($type);
$this->img->setImageFormat($type);
}
//JPEG图像设置隔行扫描
if('jpeg' == $type || 'jpg' == $type){
$this->img->setImageInterlaceScheme(1);
}
// 设置图像质量
$this->img->setImageCompressionQuality($quality);
//去除图像配置信息
$this->img->stripImage();
//保存图像
$imgname = realpath(dirname($imgname)) . '/' . basename($imgname); //强制绝对路径
if ('gif' == $type) {
$this->img->writeImages($imgname, true);
} else {
$this->img->writeImage($imgname);
}
}
/**
* 返回图像宽度
* @return integer 图像宽度
*/
public function width(){
if(empty($this->img)) E('没有指定图像资源');
return $this->info['width'];
}
/**
* 返回图像高度
* @return integer 图像高度
*/
public function height(){
if(empty($this->img)) E('没有指定图像资源');
return $this->info['height'];
}
/**
* 返回图像类型
* @return string 图像类型
*/
public function type(){
if(empty($this->img)) E('没有指定图像资源');
return $this->info['type'];
}
/**
* 返回图像MIME类型
* @return string 图像MIME类型
*/
public function mime(){
if(empty($this->img)) E('没有指定图像资源');
return $this->info['mime'];
}
/**
* 返回图像尺寸数组 0 - 图像宽度1 - 图像高度
* @return array 图像尺寸
*/
public function size(){
if(empty($this->img)) E('没有指定图像资源');
return array($this->info['width'], $this->info['height']);
}
/**
* 裁剪图像
* @param integer $w 裁剪区域宽度
* @param integer $h 裁剪区域高度
* @param integer $x 裁剪区域x坐标
* @param integer $y 裁剪区域y坐标
* @param integer $width 图像保存宽度
* @param integer $height 图像保存高度
*/
public function crop($w, $h, $x = 0, $y = 0, $width = null, $height = null){
if(empty($this->img)) E('没有可以被裁剪的图像资源');
//设置保存尺寸
empty($width) && $width = $w;
empty($height) && $height = $h;
//裁剪图片
if('gif' == $this->info['type']){
$img = $this->img->coalesceImages();
$this->img->destroy(); //销毁原图
//循环裁剪每一帧
do {
$this->_crop($w, $h, $x, $y, $width, $height, $img);
} while ($img->nextImage());
//压缩图片
$this->img = $img->deconstructImages();
$img->destroy(); //销毁零时图片
} else {
$this->_crop($w, $h, $x, $y, $width, $height);
}
}
/* 裁剪图片,内部调用 */
private function _crop($w, $h, $x, $y, $width, $height, $img = null){
is_null($img) && $img = $this->img;
//裁剪
$info = $this->info;
if($x != 0 || $y != 0 || $w != $info['width'] || $h != $info['height']){
$img->cropImage($w, $h, $x, $y);
$img->setImagePage($w, $h, 0, 0); //调整画布和图片一致
}
//调整大小
if($w != $width || $h != $height){
$img->sampleImage($width, $height);
}
//设置缓存尺寸
$this->info['width'] = $width;
$this->info['height'] = $height;
}
/**
* 生成缩略图
* @param integer $width 缩略图最大宽度
* @param integer $height 缩略图最大高度
* @param integer $type 缩略图裁剪类型
*/
public function thumb($width, $height, $type = Image::IMAGE_THUMB_SCALE){
if(empty($this->img)) E('没有可以被缩略的图像资源');
//原图宽度和高度
$w = $this->info['width'];
$h = $this->info['height'];
/* 计算缩略图生成的必要参数 */
switch ($type) {
/* 等比例缩放 */
case Image::IMAGE_THUMB_SCALE:
//原图尺寸小于缩略图尺寸则不进行缩略
if($w < $width && $h < $height) return;
//计算缩放比例
$scale = min($width/$w, $height/$h);
//设置缩略图的坐标及宽度和高度
$x = $y = 0;
$width = $w * $scale;
$height = $h * $scale;
break;
/* 居中裁剪 */
case Image::IMAGE_THUMB_CENTER:
//计算缩放比例
$scale = max($width/$w, $height/$h);
//设置缩略图的坐标及宽度和高度
$w = $width/$scale;
$h = $height/$scale;
$x = ($this->info['width'] - $w)/2;
$y = ($this->info['height'] - $h)/2;
break;
/* 左上角裁剪 */
case Image::IMAGE_THUMB_NORTHWEST:
//计算缩放比例
$scale = max($width/$w, $height/$h);
//设置缩略图的坐标及宽度和高度
$x = $y = 0;
$w = $width/$scale;
$h = $height/$scale;
break;
/* 右下角裁剪 */
case Image::IMAGE_THUMB_SOUTHEAST:
//计算缩放比例
$scale = max($width/$w, $height/$h);
//设置缩略图的坐标及宽度和高度
$w = $width/$scale;
$h = $height/$scale;
$x = $this->info['width'] - $w;
$y = $this->info['height'] - $h;
break;
/* 填充 */
case Image::IMAGE_THUMB_FILLED:
//计算缩放比例
if($w < $width && $h < $height){
$scale = 1;
} else {
$scale = min($width/$w, $height/$h);
}
//设置缩略图的坐标及宽度和高度
$neww = $w * $scale;
$newh = $h * $scale;
$posx = ($width - $w * $scale)/2;
$posy = ($height - $h * $scale)/2;
//创建一张新图像
$newimg = new \Imagick();
$newimg->newImage($width, $height, 'white', $this->info['type']);
if('gif' == $this->info['type']){
$imgs = $this->img->coalesceImages();
$img = new \Imagick();
$this->img->destroy(); //销毁原图
//循环填充每一帧
do {
//填充图像
$image = $this->_fill($newimg, $posx, $posy, $neww, $newh, $imgs);
$img->addImage($image);
$img->setImageDelay($imgs->getImageDelay());
$img->setImagePage($width, $height, 0, 0);
$image->destroy(); //销毁零时图片
} while ($imgs->nextImage());
//压缩图片
$this->img->destroy();
$this->img = $img->deconstructImages();
$imgs->destroy(); //销毁零时图片
$img->destroy(); //销毁零时图片
} else {
//填充图像
$img = $this->_fill($newimg, $posx, $posy, $neww, $newh);
//销毁原图
$this->img->destroy();
$this->img = $img;
}
//设置新图像属性
$this->info['width'] = $width;
$this->info['height'] = $height;
return;
/* 固定 */
case Image::IMAGE_THUMB_FIXED:
$x = $y = 0;
break;
default:
E('不支持的缩略图裁剪类型');
}
/* 裁剪图像 */
$this->crop($w, $h, $x, $y, $width, $height);
}
/* 填充指定图像,内部使用 */
private function _fill($newimg, $posx, $posy, $neww, $newh, $img = null){
is_null($img) && $img = $this->img;
/* 将指定图片绘入空白图片 */
$draw = new \ImagickDraw();
$draw->composite($img->getImageCompose(), $posx, $posy, $neww, $newh, $img);
$image = $newimg->clone();
$image->drawImage($draw);
$draw->destroy();
return $image;
}
/**
* 添加水印
* @param string $source 水印图片路径
* @param integer $locate 水印位置
* @param integer $alpha 水印透明度
*/
public function water($source, $locate = Image::IMAGE_WATER_SOUTHEAST,$alpha=80){
//资源检测
if(empty($this->img)) E('没有可以被添加水印的图像资源');
if(!is_file($source)) E('水印图像不存在');
//创建水印图像资源
$water = new \Imagick(realpath($source));
$info = array($water->getImageWidth(), $water->getImageHeight());
/* 设定水印位置 */
switch ($locate) {
/* 右下角水印 */
case Image::IMAGE_WATER_SOUTHEAST:
$x = $this->info['width'] - $info[0];
$y = $this->info['height'] - $info[1];
break;
/* 左下角水印 */
case Image::IMAGE_WATER_SOUTHWEST:
$x = 0;
$y = $this->info['height'] - $info[1];
break;
/* 左上角水印 */
case Image::IMAGE_WATER_NORTHWEST:
$x = $y = 0;
break;
/* 右上角水印 */
case Image::IMAGE_WATER_NORTHEAST:
$x = $this->info['width'] - $info[0];
$y = 0;
break;
/* 居中水印 */
case Image::IMAGE_WATER_CENTER:
$x = ($this->info['width'] - $info[0])/2;
$y = ($this->info['height'] - $info[1])/2;
break;
/* 下居中水印 */
case Image::IMAGE_WATER_SOUTH:
$x = ($this->info['width'] - $info[0])/2;
$y = $this->info['height'] - $info[1];
break;
/* 右居中水印 */
case Image::IMAGE_WATER_EAST:
$x = $this->info['width'] - $info[0];
$y = ($this->info['height'] - $info[1])/2;
break;
/* 上居中水印 */
case Image::IMAGE_WATER_NORTH:
$x = ($this->info['width'] - $info[0])/2;
$y = 0;
break;
/* 左居中水印 */
case Image::IMAGE_WATER_WEST:
$x = 0;
$y = ($this->info['height'] - $info[1])/2;
break;
default:
/* 自定义水印坐标 */
if(is_array($locate)){
list($x, $y) = $locate;
} else {
E('不支持的水印位置类型');
}
}
//创建绘图资源
$draw = new \ImagickDraw();
$draw->composite($water->getImageCompose(), $x, $y, $info[0], $info[1], $water);
if('gif' == $this->info['type']){
$img = $this->img->coalesceImages();
$this->img->destroy(); //销毁原图
do{
//添加水印
$img->drawImage($draw);
} while ($img->nextImage());
//压缩图片
$this->img = $img->deconstructImages();
$img->destroy(); //销毁零时图片
} else {
//添加水印
$this->img->drawImage($draw);
}
//销毁水印资源
$draw->destroy();
$water->destroy();
}
/**
* 图像添加文字
* @param string $text 添加的文字
* @param string $font 字体路径
* @param integer $size 字号
* @param string $color 文字颜色
* @param integer $locate 文字写入位置
* @param integer $offset 文字相对当前位置的偏移量
* @param integer $angle 文字倾斜角度
*/
public function text($text, $font, $size, $color = '#00000000',
$locate = Image::IMAGE_WATER_SOUTHEAST, $offset = 0, $angle = 0){
//资源检测
if(empty($this->img)) E('没有可以被写入文字的图像资源');
if(!is_file($font)) E("不存在的字体文件:{$font}");
//获取颜色和透明度
if(is_array($color)){
$color = array_map('dechex', $color);
foreach ($color as &$value) {
$value = str_pad($value, 2, '0', STR_PAD_LEFT);
}
$color = '#' . implode('', $color);
} elseif(!is_string($color) || 0 !== strpos($color, '#')) {
E('错误的颜色值');
}
$col = substr($color, 0, 7);
$alp = strlen($color) == 9 ? substr($color, -2) : 0;
//获取文字信息
$draw = new \ImagickDraw();
$draw->setFont(realpath($font));
$draw->setFontSize($size);
$draw->setFillColor($col);
$draw->setFillAlpha(1-hexdec($alp)/127);
$draw->setTextAntialias(true);
$draw->setStrokeAntialias(true);
$metrics = $this->img->queryFontMetrics($draw, $text);
/* 计算文字初始坐标和尺寸 */
$x = 0;
$y = $metrics['ascender'];
$w = $metrics['textWidth'];
$h = $metrics['textHeight'];
/* 设定文字位置 */
switch ($locate) {
/* 右下角文字 */
case Image::IMAGE_WATER_SOUTHEAST:
$x += $this->info['width'] - $w;
$y += $this->info['height'] - $h;
break;
/* 左下角文字 */
case Image::IMAGE_WATER_SOUTHWEST:
$y += $this->info['height'] - $h;
break;
/* 左上角文字 */
case Image::IMAGE_WATER_NORTHWEST:
// 起始坐标即为左上角坐标,无需调整
break;
/* 右上角文字 */
case Image::IMAGE_WATER_NORTHEAST:
$x += $this->info['width'] - $w;
break;
/* 居中文字 */
case Image::IMAGE_WATER_CENTER:
$x += ($this->info['width'] - $w)/2;
$y += ($this->info['height'] - $h)/2;
break;
/* 下居中文字 */
case Image::IMAGE_WATER_SOUTH:
$x += ($this->info['width'] - $w)/2;
$y += $this->info['height'] - $h;
break;
/* 右居中文字 */
case Image::IMAGE_WATER_EAST:
$x += $this->info['width'] - $w;
$y += ($this->info['height'] - $h)/2;
break;
/* 上居中文字 */
case Image::IMAGE_WATER_NORTH:
$x += ($this->info['width'] - $w)/2;
break;
/* 左居中文字 */
case Image::IMAGE_WATER_WEST:
$y += ($this->info['height'] - $h)/2;
break;
default:
/* 自定义文字坐标 */
if(is_array($locate)){
list($posx, $posy) = $locate;
$x += $posx;
$y += $posy;
} else {
E('不支持的文字位置类型');
}
}
/* 设置偏移量 */
if(is_array($offset)){
$offset = array_map('intval', $offset);
list($ox, $oy) = $offset;
} else{
$offset = intval($offset);
$ox = $oy = $offset;
}
/* 写入文字 */
if('gif' == $this->info['type']){
$img = $this->img->coalesceImages();
$this->img->destroy(); //销毁原图
do{
$img->annotateImage($draw, $x + $ox, $y + $oy, $angle, $text);
} while ($img->nextImage());
//压缩图片
$this->img = $img->deconstructImages();
$img->destroy(); //销毁零时图片
} else {
$this->img->annotateImage($draw, $x + $ox, $y + $oy, $angle, $text);
}
$draw->destroy();
}
/**
* 析构方法,用于销毁图像资源
*/
public function __destruct() {
empty($this->img) || $this->img->destroy();
}
}

View File

@@ -0,0 +1,104 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
namespace Think;
/**
* 日志处理类
*/
class Log {
// 日志级别 从上到下,由低到高
const EMERG = 'EMERG'; // 严重错误: 导致系统崩溃无法使用
const ALERT = 'ALERT'; // 警戒性错误: 必须被立即修改的错误
const CRIT = 'CRIT'; // 临界值错误: 超过临界值的错误例如一天24小时而输入的是25小时这样
const ERR = 'ERR'; // 一般错误: 一般性错误
const WARN = 'WARN'; // 警告性错误: 需要发出警告的错误
const NOTICE = 'NOTIC'; // 通知: 程序可以运行但是还不够完美的错误
const INFO = 'INFO'; // 信息: 程序输出信息
const DEBUG = 'DEBUG'; // 调试: 调试信息
const SQL = 'SQL'; // SQLSQL语句 注意只在调试模式开启时有效
// 日志信息
static protected $log = array();
// 日志存储
static protected $storage = null;
// 日志初始化
static public function init($config=array()){
$type = isset($config['type']) ? $config['type'] : 'File';
$class = strpos($type,'\\')? $type: 'Think\\Log\\Driver\\'. ucwords(strtolower($type));
unset($config['type']);
self::$storage = new $class($config);
}
/**
* 记录日志 并且会过滤未经设置的级别
* @static
* @access public
* @param string $message 日志信息
* @param string $level 日志级别
* @param boolean $record 是否强制记录
* @return void
*/
static function record($message,$level=self::ERR,$record=false) {
if($record || false !== strpos(C('LOG_LEVEL'),$level)) {
self::$log[] = "{$level}: {$message}\r\n";
}
}
/**
* 日志保存
* @static
* @access public
* @param integer $type 日志记录方式
* @param string $destination 写入目标
* @return void
*/
static function save($type='',$destination='') {
if(empty(self::$log)) return ;
if(empty($destination)){
$destination = C('LOG_PATH').date('y_m_d').'.log';
}
if(!self::$storage){
$type = $type ? : C('LOG_TYPE');
$class = 'Think\\Log\\Driver\\'. ucwords($type);
self::$storage = new $class();
}
$message = implode('',self::$log);
self::$storage->write($message,$destination);
// 保存后清空日志缓存
self::$log = array();
}
/**
* 日志直接写入
* @static
* @access public
* @param string $message 日志信息
* @param string $level 日志级别
* @param integer $type 日志记录方式
* @param string $destination 写入目标
* @return void
*/
static function write($message,$level=self::ERR,$type='',$destination='') {
if(!self::$storage){
$type = $type ? : C('LOG_TYPE');
$class = 'Think\\Log\\Driver\\'. ucwords($type);
$config['log_path'] = C('LOG_PATH');
self::$storage = new $class($config);
}
if(empty($destination)){
$destination = C('LOG_PATH').date('y_m_d').'.log';
}
self::$storage->write("{$level}: {$message}", $destination);
}
}

View File

@@ -0,0 +1,50 @@
<?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\Log\Driver;
class File {
protected $config = array(
'log_time_format' => ' c ',
'log_file_size' => 2097152,
'log_path' => '',
);
// 实例化并传入参数
public function __construct($config=array()){
$this->config = array_merge($this->config,$config);
}
/**
* 日志写入接口
* @access public
* @param string $log 日志信息
* @param string $destination 写入目标
* @return void
*/
public function write($log,$destination='') {
$now = date($this->config['log_time_format']);
if(empty($destination)){
$destination = $this->config['log_path'].date('y_m_d').'.log';
}
// 自动创建日志目录
$log_dir = dirname($destination);
if (!is_dir($log_dir)) {
mkdir($log_dir, 0755, true);
}
//检测日志文件大小,超过配置大小则备份日志文件重新生成
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);
}
}

View File

@@ -0,0 +1,49 @@
<?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: luofei614 <weibo.com/luofei614>
// +----------------------------------------------------------------------
namespace Think\Log\Driver;
class Sae {
protected $config = array(
'log_time_format' => ' c ',
);
// 实例化并传入参数
public function __construct($config=array()){
$this->config = array_merge($this->config,$config);
}
/**
* 日志写入接口
* @access public
* @param string $log 日志信息
* @param string $destination 写入目标
* @return void
*/
public function write($log,$destination='') {
static $is_debug=null;
$now = date($this->config['log_time_format']);
$logstr="[{$now}] ".$_SERVER['REMOTE_ADDR'].' '.$_SERVER['REQUEST_URI']."\r\n{$log}\r\n";
if(is_null($is_debug)){
preg_replace('@(\w+)\=([^;]*)@e', '$appSettings[\'\\1\']="\\2";', $_SERVER['HTTP_APPCOOKIE']);
$is_debug = in_array($_SERVER['HTTP_APPVERSION'], explode(',', $appSettings['debug'])) ? true : false;
}
if($is_debug){
sae_set_display_errors(false);//记录日志不将日志打印出来
}
sae_debug($logstr);
if($is_debug){
sae_set_display_errors(true);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,595 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
namespace Think\Model;
use Think\Model;
/**
* 高级模型扩展
*/
class AdvModel extends Model {
protected $optimLock = 'lock_version';
protected $returnType = 'array';
protected $blobFields = array();
protected $blobValues = null;
protected $serializeField = array();
protected $readonlyField = array();
protected $_filter = array();
protected $partition = array();
public function __construct($name='',$tablePrefix='',$connection='') {
if('' !== $name || is_subclass_of($this,'AdvModel') ){
// 如果是AdvModel子类或者有传入模型名称则获取字段缓存
}else{
// 空的模型 关闭字段缓存
$this->autoCheckFields = false;
}
parent::__construct($name,$tablePrefix,$connection);
}
/**
* 利用__call方法重载 实现一些特殊的Model方法 (魔术方法)
* @access public
* @param string $method 方法名称
* @param mixed $args 调用参数
* @return mixed
*/
public function __call($method,$args) {
if(strtolower(substr($method,0,3))=='top'){
// 获取前N条记录
$count = substr($method,3);
array_unshift($args,$count);
return call_user_func_array(array(&$this, 'topN'), $args);
}else{
return parent::__call($method,$args);
}
}
/**
* 对保存到数据库的数据进行处理
* @access protected
* @param mixed $data 要操作的数据
* @return boolean
*/
protected function _facade($data) {
// 检查序列化字段
$data = $this->serializeField($data);
return parent::_facade($data);
}
// 查询成功后的回调方法
protected function _after_find(&$result,$options='') {
// 检查序列化字段
$this->checkSerializeField($result);
// 获取文本字段
$this->getBlobFields($result);
// 检查字段过滤
$result = $this->getFilterFields($result);
// 缓存乐观锁
$this->cacheLockVersion($result);
}
// 查询数据集成功后的回调方法
protected function _after_select(&$resultSet,$options='') {
// 检查序列化字段
$resultSet = $this->checkListSerializeField($resultSet);
// 获取文本字段
$resultSet = $this->getListBlobFields($resultSet);
// 检查列表字段过滤
$resultSet = $this->getFilterListFields($resultSet);
}
// 写入前的回调方法
protected function _before_insert(&$data,$options='') {
// 记录乐观锁
$data = $this->recordLockVersion($data);
// 检查文本字段
$data = $this->checkBlobFields($data);
// 检查字段过滤
$data = $this->setFilterFields($data);
}
protected function _after_insert($data,$options) {
// 保存文本字段
$this->saveBlobFields($data);
}
// 更新前的回调方法
protected function _before_update(&$data,$options='') {
// 检查乐观锁
$pk = $this->getPK();
if(isset($options['where'][$pk])){
$id = $options['where'][$pk];
if(!$this->checkLockVersion($id,$data)) {
return false;
}
}
// 检查文本字段
$data = $this->checkBlobFields($data);
// 检查只读字段
$data = $this->checkReadonlyField($data);
// 检查字段过滤
$data = $this->setFilterFields($data);
}
protected function _after_update($data,$options) {
// 保存文本字段
$this->saveBlobFields($data);
}
protected function _after_delete($data,$options) {
// 删除Blob数据
$this->delBlobFields($data);
}
/**
* 记录乐观锁
* @access protected
* @param array $data 数据对象
* @return array
*/
protected function recordLockVersion($data) {
// 记录乐观锁
if($this->optimLock && !isset($data[$this->optimLock]) ) {
if(in_array($this->optimLock,$this->fields,true)) {
$data[$this->optimLock] = 0;
}
}
return $data;
}
/**
* 缓存乐观锁
* @access protected
* @param array $data 数据对象
* @return void
*/
protected function cacheLockVersion($data) {
if($this->optimLock) {
if(isset($data[$this->optimLock]) && isset($data[$this->getPk()])) {
// 只有当存在乐观锁字段和主键有值的时候才记录乐观锁
$_SESSION[$this->name.'_'.$data[$this->getPk()].'_lock_version'] = $data[$this->optimLock];
}
}
}
/**
* 检查乐观锁
* @access protected
* @param inteter $id 当前主键
* @param array $data 当前数据
* @return mixed
*/
protected function checkLockVersion($id,&$data) {
// 检查乐观锁
$identify = $this->name.'_'.$id.'_lock_version';
if($this->optimLock && isset($_SESSION[$identify])) {
$lock_version = $_SESSION[$identify];
$vo = $this->field($this->optimLock)->find($id);
$_SESSION[$identify] = $lock_version;
$curr_version = $vo[$this->optimLock];
if(isset($curr_version)) {
if($curr_version>0 && $lock_version != $curr_version) {
// 记录已经更新
$this->error = L('_RECORD_HAS_UPDATE_');
return false;
}else{
// 更新乐观锁
$save_version = $data[$this->optimLock];
if($save_version != $lock_version+1) {
$data[$this->optimLock] = $lock_version+1;
}
$_SESSION[$identify] = $lock_version+1;
}
}
}
return true;
}
/**
* 查找前N个记录
* @access public
* @param integer $count 记录个数
* @param array $options 查询表达式
* @return array
*/
public function topN($count,$options=array()) {
$options['limit'] = $count;
return $this->select($options);
}
/**
* 查询符合条件的第N条记录
* 0 表示第一条记录 -1 表示最后一条记录
* @access public
* @param integer $position 记录位置
* @param array $options 查询表达式
* @return mixed
*/
public function getN($position=0,$options=array()) {
if($position>=0) { // 正向查找
$options['limit'] = $position.',1';
$list = $this->select($options);
return $list?$list[0]:false;
}else{ // 逆序查找
$list = $this->select($options);
return $list?$list[count($list)-abs($position)]:false;
}
}
/**
* 获取满足条件的第一条记录
* @access public
* @param array $options 查询表达式
* @return mixed
*/
public function first($options=array()) {
return $this->getN(0,$options);
}
/**
* 获取满足条件的最后一条记录
* @access public
* @param array $options 查询表达式
* @return mixed
*/
public function last($options=array()) {
return $this->getN(-1,$options);
}
/**
* 返回数据
* @access public
* @param array $data 数据
* @param string $type 返回类型 默认为数组
* @return mixed
*/
public function returnResult($data,$type='') {
if('' === $type)
$type = $this->returnType;
switch($type) {
case 'array' : return $data;
case 'object': return (object)$data;
default:// 允许用户自定义返回类型
if(class_exists($type))
return new $type($data);
else
E(L('_CLASS_NOT_EXIST_').':'.$type);
}
}
/**
* 获取数据的时候过滤数据字段
* @access protected
* @param mixed $result 查询的数据
* @return array
*/
protected function getFilterFields(&$result) {
if(!empty($this->_filter)) {
foreach ($this->_filter as $field=>$filter){
if(isset($result[$field])) {
$fun = $filter[1];
if(!empty($fun)) {
if(isset($filter[2]) && $filter[2]){
// 传递整个数据对象作为参数
$result[$field] = call_user_func($fun,$result);
}else{
// 传递字段的值作为参数
$result[$field] = call_user_func($fun,$result[$field]);
}
}
}
}
}
return $result;
}
protected function getFilterListFields(&$resultSet) {
if(!empty($this->_filter)) {
foreach ($resultSet as $key=>$result)
$resultSet[$key] = $this->getFilterFields($result);
}
return $resultSet;
}
/**
* 写入数据的时候过滤数据字段
* @access protected
* @param mixed $result 查询的数据
* @return array
*/
protected function setFilterFields($data) {
if(!empty($this->_filter)) {
foreach ($this->_filter as $field=>$filter){
if(isset($data[$field])) {
$fun = $filter[0];
if(!empty($fun)) {
if(isset($filter[2]) && $filter[2]) {
// 传递整个数据对象作为参数
$data[$field] = call_user_func($fun,$data);
}else{
// 传递字段的值作为参数
$data[$field] = call_user_func($fun,$data[$field]);
}
}
}
}
}
return $data;
}
/**
* 返回数据列表
* @access protected
* @param array $resultSet 数据
* @param string $type 返回类型 默认为数组
* @return void
*/
protected function returnResultSet(&$resultSet,$type='') {
foreach ($resultSet as $key=>$data)
$resultSet[$key] = $this->returnResult($data,$type);
return $resultSet;
}
protected function checkBlobFields(&$data) {
// 检查Blob文件保存字段
if(!empty($this->blobFields)) {
foreach ($this->blobFields as $field){
if(isset($data[$field])) {
if(isset($data[$this->getPk()]))
$this->blobValues[$this->name.'/'.$data[$this->getPk()].'_'.$field] = $data[$field];
else
$this->blobValues[$this->name.'/@?id@_'.$field] = $data[$field];
unset($data[$field]);
}
}
}
return $data;
}
/**
* 获取数据集的文本字段
* @access protected
* @param mixed $resultSet 查询的数据
* @param string $field 查询的字段
* @return void
*/
protected function getListBlobFields(&$resultSet,$field='') {
if(!empty($this->blobFields)) {
foreach ($resultSet as $key=>$result){
$result = $this->getBlobFields($result,$field);
$resultSet[$key] = $result;
}
}
return $resultSet;
}
/**
* 获取数据的文本字段
* @access protected
* @param mixed $data 查询的数据
* @param string $field 查询的字段
* @return void
*/
protected function getBlobFields(&$data,$field='') {
if(!empty($this->blobFields)) {
$pk = $this->getPk();
$id = $data[$pk];
if(empty($field)) {
foreach ($this->blobFields as $field){
$identify = $this->name.'/'.$id.'_'.$field;
$data[$field] = F($identify);
}
return $data;
}else{
$identify = $this->name.'/'.$id.'_'.$field;
return F($identify);
}
}
}
/**
* 保存File方式的字段
* @access protected
* @param mixed $data 保存的数据
* @return void
*/
protected function saveBlobFields(&$data) {
if(!empty($this->blobFields)) {
foreach ($this->blobValues as $key=>$val){
if(strpos($key,'@?id@'))
$key = str_replace('@?id@',$data[$this->getPk()],$key);
F($key,$val);
}
}
}
/**
* 删除File方式的字段
* @access protected
* @param mixed $data 保存的数据
* @param string $field 查询的字段
* @return void
*/
protected function delBlobFields(&$data,$field='') {
if(!empty($this->blobFields)) {
$pk = $this->getPk();
$id = $data[$pk];
if(empty($field)) {
foreach ($this->blobFields as $field){
$identify = $this->name.'/'.$id.'_'.$field;
F($identify,null);
}
}else{
$identify = $this->name.'/'.$id.'_'.$field;
F($identify,null);
}
}
}
/**
* 检查序列化数据字段
* @access protected
* @param array $data 数据
* @return array
*/
protected function serializeField(&$data) {
// 检查序列化字段
if(!empty($this->serializeField)) {
// 定义方式 $this->serializeField = array('ser'=>array('name','email'));
foreach ($this->serializeField as $key=>$val){
if(empty($data[$key])) {
$serialize = array();
foreach ($val as $name){
if(isset($data[$name])) {
$serialize[$name] = $data[$name];
unset($data[$name]);
}
}
if(!empty($serialize)) {
$data[$key] = serialize($serialize);
}
}
}
}
return $data;
}
// 检查返回数据的序列化字段
protected function checkSerializeField(&$result) {
// 检查序列化字段
if(!empty($this->serializeField)) {
foreach ($this->serializeField as $key=>$val){
if(isset($result[$key])) {
$serialize = unserialize($result[$key]);
foreach ($serialize as $name=>$value)
$result[$name] = $value;
unset($serialize,$result[$key]);
}
}
}
return $result;
}
// 检查数据集的序列化字段
protected function checkListSerializeField(&$resultSet) {
// 检查序列化字段
if(!empty($this->serializeField)) {
foreach ($this->serializeField as $key=>$val){
foreach ($resultSet as $k=>$result){
if(isset($result[$key])) {
$serialize = unserialize($result[$key]);
foreach ($serialize as $name=>$value)
$result[$name] = $value;
unset($serialize,$result[$key]);
$resultSet[$k] = $result;
}
}
}
}
return $resultSet;
}
/**
* 检查只读字段
* @access protected
* @param array $data 数据
* @return array
*/
protected function checkReadonlyField(&$data) {
if(!empty($this->readonlyField)) {
foreach ($this->readonlyField as $key=>$field){
if(isset($data[$field]))
unset($data[$field]);
}
}
return $data;
}
/**
* 批处理执行SQL语句
* 批处理的指令都认为是execute操作
* @access public
* @param array $sql SQL批处理指令
* @return boolean
*/
public function patchQuery($sql=array()) {
if(!is_array($sql)) return false;
// 自动启动事务支持
$this->startTrans();
try{
foreach ($sql as $_sql){
$result = $this->execute($_sql);
if(false === $result) {
// 发生错误自动回滚事务
$this->rollback();
return false;
}
}
// 提交事务
$this->commit();
} catch (ThinkException $e) {
$this->rollback();
}
return true;
}
/**
* 得到分表的的数据表名
* @access public
* @param array $data 操作的数据
* @return string
*/
public function getPartitionTableName($data=array()) {
// 对数据表进行分区
if(isset($data[$this->partition['field']])) {
$field = $data[$this->partition['field']];
switch($this->partition['type']) {
case 'id':
// 按照id范围分表
$step = $this->partition['expr'];
$seq = floor($field / $step)+1;
break;
case 'year':
// 按照年份分表
if(!is_numeric($field)) {
$field = strtotime($field);
}
$seq = date('Y',$field)-$this->partition['expr']+1;
break;
case 'mod':
// 按照id的模数分表
$seq = ($field % $this->partition['num'])+1;
break;
case 'md5':
// 按照md5的序列分表
$seq = (ord(substr(md5($field),0,1)) % $this->partition['num'])+1;
break;
default :
if(function_exists($this->partition['type'])) {
// 支持指定函数哈希
$fun = $this->partition['type'];
$seq = (ord(substr($fun($field),0,1)) % $this->partition['num'])+1;
}else{
// 按照字段的首字母的值分表
$seq = (ord($field{0}) % $this->partition['num'])+1;
}
}
return $this->getTableName().'_'.$seq;
}else{
// 当设置的分表字段不在查询条件或者数据中
// 进行联合查询,必须设定 partition['num']
$tableName = array();
for($i=0;$i<$this->partition['num'];$i++)
$tableName[] = 'SELECT * FROM '.$this->getTableName().'_'.($i+1);
$tableName = '( '.implode(" UNION ",$tableName).') AS '.$this->name;
return $tableName;
}
}
}

View File

@@ -0,0 +1,403 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
namespace Think\Model;
use Think\Model;
/**
* ThinkPHP 聚合模型扩展
*/
class MergeModel extends Model {
protected $modelList = array(); // 包含的模型列表 第一个必须是主表模型
protected $masterModel = ''; // 主模型
protected $joinType = 'INNER'; // 聚合模型的查询JOIN类型
protected $fk = ''; // 外键名 默认为主表名_id
protected $mapFields = array(); // 需要处理的模型映射字段,避免混淆 array( id => 'user.id' )
/**
* 架构函数
* 取得DB类的实例对象 字段检查
* @access public
* @param string $name 模型名称
* @param string $tablePrefix 表前缀
* @param mixed $connection 数据库连接信息
*/
public function __construct($name='',$tablePrefix='',$connection=''){
parent::__construct($name,$tablePrefix,$connection);
// 聚合模型的字段信息
if(empty($this->fields) && !empty($this->modelList)){
$fields = array();
foreach($this->modelList as $model){
// 获取模型的字段信息
$result = $this->db->getFields(M($model)->getTableName());
$_fields = array_keys($result);
// $this->mapFields = array_intersect($fields,$_fields);
$fields = array_merge($fields,$_fields);
}
$this->fields = $fields;
}
// 设置第一个模型为主表模型
if(empty($this->masterModel) && !empty($this->modelList)){
$this->masterModel = $this->modelList[0];
}
// 主表的主键名
$this->pk = M($this->masterModel)->getPk();
// 设置默认外键名 仅支持单一外键
if(empty($this->fk)){
$this->fk = strtolower($this->masterModel).'_id';
}
}
/**
* 得到完整的数据表名
* @access public
* @return string
*/
public function getTableName() {
if(empty($this->trueTableName)) {
$tableName = array();
$models = $this->modelList;
foreach($models as $model){
$tableName[] = M($model)->getTableName().' '.$model;
}
$this->trueTableName = implode(',',$tableName);
}
return $this->trueTableName;
}
/**
* 自动检测数据表信息
* @access protected
* @return void
*/
protected function _checkTableInfo() {}
/**
* 新增聚合数据
* @access public
* @param mixed $data 数据
* @param array $options 表达式
* @param boolean $replace 是否replace
* @return mixed
*/
public function add($data='',$options=array(),$replace=false){
if(empty($data)) {
// 没有传递数据,获取当前数据对象的值
if(!empty($this->data)) {
$data = $this->data;
// 重置数据
$this->data = array();
}else{
$this->error = L('_DATA_TYPE_INVALID_');
return false;
}
}
// 启动事务
$this->startTrans();
// 写入主表数据
$result = M($this->masterModel)->strict(false)->add($data);
if($result){
// 写入外键数据
$data[$this->fk] = $result;
$models = $this->modelList;
array_shift($models);
// 写入附表数据
foreach($models as $model){
$res = M($model)->strict(false)->add($data);
if(!$res){
$this->rollback();
return false;
}
}
// 提交事务
$this->commit();
}else{
$this->rollback();
return false;
}
return $result;
}
/**
* 对保存到数据库的数据进行处理
* @access protected
* @param mixed $data 要操作的数据
* @return boolean
*/
protected function _facade($data) {
// 检查数据字段合法性
if(!empty($this->fields)) {
if(!empty($this->options['field'])) {
$fields = $this->options['field'];
unset($this->options['field']);
if(is_string($fields)) {
$fields = explode(',',$fields);
}
}else{
$fields = $this->fields;
}
foreach ($data as $key=>$val){
if(!in_array($key,$fields,true)){
unset($data[$key]);
}elseif(array_key_exists($key,$this->mapFields)){
// 需要处理映射字段
$data[$this->mapFields[$key]] = $val;
unset($data[$key]);
}
}
}
// 安全过滤
if(!empty($this->options['filter'])) {
$data = array_map($this->options['filter'],$data);
unset($this->options['filter']);
}
$this->_before_write($data);
return $data;
}
/**
* 保存聚合模型数据
* @access public
* @param mixed $data 数据
* @param array $options 表达式
* @return boolean
*/
public function save($data='',$options=array()){
// 根据主表的主键更新
if(empty($data)) {
// 没有传递数据,获取当前数据对象的值
if(!empty($this->data)) {
$data = $this->data;
// 重置数据
$this->data = array();
}else{
$this->error = L('_DATA_TYPE_INVALID_');
return false;
}
}
if(empty($data)){
// 没有数据则不执行
$this->error = L('_DATA_TYPE_INVALID_');
return false;
}
// 如果存在主键数据 则自动作为更新条件
$pk = $this->pk;
if(isset($data[$pk])) {
$where[$pk] = $data[$pk];
$options['where'] = $where;
unset($data[$pk]);
}
$options['join'] = '';
$options = $this->_parseOptions($options);
// 更新操作不使用JOIN
$options['table'] = $this->getTableName();
if(is_array($options['where']) && isset($options['where'][$pk])){
$pkValue = $options['where'][$pk];
}
if(false === $this->_before_update($data,$options)) {
return false;
}
$result = $this->db->update($data,$options);
if(false !== $result) {
if(isset($pkValue)) $data[$pk] = $pkValue;
$this->_after_update($data,$options);
}
return $result;
}
/**
* 删除聚合模型数据
* @access public
* @param mixed $options 表达式
* @return mixed
*/
public function delete($options=array()){
$pk = $this->pk;
if(empty($options) && empty($this->options['where'])) {
// 如果删除条件为空 则删除当前数据对象所对应的记录
if(!empty($this->data) && isset($this->data[$pk]))
return $this->delete($this->data[$pk]);
else
return false;
}
if(is_numeric($options) || is_string($options)) {
// 根据主键删除记录
if(strpos($options,',')) {
$where[$pk] = array('IN', $options);
}else{
$where[$pk] = $options;
}
$options = array();
$options['where'] = $where;
}
// 分析表达式
$options['join'] = '';
$options = $this->_parseOptions($options);
if(empty($options['where'])){
// 如果条件为空 不进行删除操作 除非设置 1=1
return false;
}
if(is_array($options['where']) && isset($options['where'][$pk])){
$pkValue = $options['where'][$pk];
}
$options['table'] = implode(',',$this->modelList);
$options['using'] = $this->getTableName();
if(false === $this->_before_delete($options)) {
return false;
}
$result = $this->db->delete($options);
if(false !== $result) {
$data = array();
if(isset($pkValue)) $data[$pk] = $pkValue;
$this->_after_delete($data,$options);
}
// 返回删除记录个数
return $result;
}
/**
* 表达式过滤方法
* @access protected
* @param string $options 表达式
* @return void
*/
protected function _options_filter(&$options) {
if(!isset($options['join'])){
$models = $this->modelList;
array_shift($models);
foreach($models as $model){
$options['join'][] = $this->joinType.' JOIN '.M($model)->getTableName().' '.$model.' ON '.$this->masterModel.'.'.$this->pk.' = '.$model.'.'.$this->fk;
}
}
$options['table'] = M($this->masterModel)->getTableName().' '.$this->masterModel;
$options['field'] = $this->checkFields(isset($options['field'])?$options['field']:'');
if(isset($options['group']))
$options['group'] = $this->checkGroup($options['group']);
if(isset($options['where']))
$options['where'] = $this->checkCondition($options['where']);
if(isset($options['order']))
$options['order'] = $this->checkOrder($options['order']);
}
/**
* 检查条件中的聚合字段
* @access protected
* @param mixed $data 条件表达式
* @return array
*/
protected function checkCondition($where) {
if(is_array($where)) {
$view = array();
foreach($where as $name=>$value){
if(array_key_exists($name,$this->mapFields)){
// 需要处理映射字段
$view[$this->mapFields[$name]] = $value;
unset($where[$name]);
}
}
$where = array_merge($where,$view);
}
return $where;
}
/**
* 检查Order表达式中的聚合字段
* @access protected
* @param string $order 字段
* @return string
*/
protected function checkOrder($order='') {
if(is_string($order) && !empty($order)) {
$orders = explode(',',$order);
$_order = array();
foreach ($orders as $order){
$array = explode(' ',trim($order));
$field = $array[0];
$sort = isset($array[1])?$array[1]:'ASC';
if(array_key_exists($field,$this->mapFields)){
// 需要处理映射字段
$field = $this->mapFields[$field];
}
$_order[] = $field.' '.$sort;
}
$order = implode(',',$_order);
}
return $order;
}
/**
* 检查Group表达式中的聚合字段
* @access protected
* @param string $group 字段
* @return string
*/
protected function checkGroup($group='') {
if(!empty($group)) {
$groups = explode(',',$group);
$_group = array();
foreach ($groups as $field){
// 解析成聚合字段
if(array_key_exists($field,$this->mapFields)){
// 需要处理映射字段
$field = $this->mapFields[$field];
}
$_group[] = $field;
}
$group = implode(',',$_group);
}
return $group;
}
/**
* 检查fields表达式中的聚合字段
* @access protected
* @param string $fields 字段
* @return string
*/
protected function checkFields($fields='') {
if(empty($fields) || '*'==$fields ) {
// 获取全部聚合字段
$fields = $this->fields;
}
if(!is_array($fields))
$fields = explode(',',$fields);
// 解析成聚合字段
$array = array();
foreach ($fields as $field){
if(array_key_exists($field,$this->mapFields)){
// 需要处理映射字段
$array[] = $this->mapFields[$field].' AS '.$field;
}else{
$array[] = $field;
}
}
$fields = implode(',',$array);
return $fields;
}
/**
* 获取数据表字段信息
* @access public
* @return array
*/
public function getDbFields(){
return $this->fields;
}
}

View File

@@ -0,0 +1,422 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ 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>
// +----------------------------------------------------------------------
namespace Think\Model;
use Think\Model;
/**
* MongoModel模型类
* 实现了ODM和ActiveRecords模式
*/
class MongoModel extends Model{
// 主键类型
const TYPE_OBJECT = 1;
const TYPE_INT = 2;
const TYPE_STRING = 3;
// 主键名称
protected $pk = '_id';
// _id 类型 1 Object 采用MongoId对象 2 Int 整形 支持自动增长 3 String 字符串Hash
protected $_idType = self::TYPE_OBJECT;
// 主键是否自增
protected $_autoinc = true;
// Mongo默认关闭字段检测 可以动态追加字段
protected $autoCheckFields = false;
// 链操作方法列表
protected $methods = array('table','order','auto','filter','validate');
/**
* 利用__call方法实现一些特殊的Model方法
* @access public
* @param string $method 方法名称
* @param array $args 调用参数
* @return mixed
*/
public function __call($method,$args) {
if(in_array(strtolower($method),$this->methods,true)) {
// 连贯操作的实现
$this->options[strtolower($method)] = $args[0];
return $this;
}elseif(strtolower(substr($method,0,5))=='getby') {
// 根据某个字段获取记录
$field = parse_name(substr($method,5));
$where[$field] =$args[0];
return $this->where($where)->find();
}elseif(strtolower(substr($method,0,10))=='getfieldby') {
// 根据某个字段获取记录的某个值
$name = parse_name(substr($method,10));
$where[$name] =$args[0];
return $this->where($where)->getField($args[1]);
}else{
E(__CLASS__.':'.$method.L('_METHOD_NOT_EXIST_'));
return;
}
}
/**
* 获取字段信息并缓存 主键和自增信息直接配置
* @access public
* @return void
*/
public function flush() {
// 缓存不存在则查询数据表信息
$fields = $this->db->getFields();
if(!$fields) { // 暂时没有数据无法获取字段信息 下次查询
return false;
}
$this->fields = array_keys($fields);
foreach ($fields as $key=>$val){
// 记录字段类型
$type[$key] = $val['type'];
}
// 记录字段类型信息
if(C('DB_FIELDTYPE_CHECK')) $this->fields['_type'] = $type;
// 2008-3-7 增加缓存开关控制
if(C('DB_FIELDS_CACHE')){
// 永久缓存数据表信息
$db = $this->dbName?$this->dbName:C('DB_NAME');
F('_fields/'.$db.'.'.$this->name,$this->fields);
}
}
// 写入数据前的回调方法 包括新增和更新
protected function _before_write(&$data) {
$pk = $this->getPk();
// 根据主键类型处理主键数据
if(isset($data[$pk]) && $this->_idType == self::TYPE_OBJECT) {
$data[$pk] = new \MongoId($data[$pk]);
}
}
/**
* count统计 配合where连贯操作
* @access public
* @return integer
*/
public function count(){
// 分析表达式
$options = $this->_parseOptions();
return $this->db->count($options);
}
/**
* 获取唯一值
* @access public
* @return array | false
*/
public function distinct($field, $where=array() ){
// 分析表达式
$this->options = $this->_parseOptions();
$this->options['where'] = array_merge((array)$this->options['where'], $where);
$command = array(
"distinct" => $this->options['table'],
"key" => $field,
"query" => $this->options['where']
);
$result = $this->command($command);
return isset($result['values']) ? $result['values'] : false;
}
/**
* 获取下一ID 用于自动增长型
* @access public
* @param string $pk 字段名 默认为主键
* @return mixed
*/
public function getMongoNextId($pk=''){
if(empty($pk)) {
$pk = $this->getPk();
}
return $this->db->getMongoNextId($pk);
}
/**
* 新增数据
* @access public
* @param mixed $data 数据
* @param array $options 表达式
* @param boolean $replace 是否replace
* @return mixed
*/
public function add($data='',$options=array(),$replace=false) {
if(empty($data)) {
// 没有传递数据,获取当前数据对象的值
if(!empty($this->data)) {
$data = $this->data;
// 重置数据
$this->data = array();
}else{
$this->error = L('_DATA_TYPE_INVALID_');
return false;
}
}
// 分析表达式
$options = $this->_parseOptions($options);
// 数据处理
$data = $this->_facade($data);
if(false === $this->_before_insert($data,$options)) {
return false;
}
// 写入数据到数据库
$result = $this->db->insert($data,$options,$replace);
if(false !== $result ) {
$this->_after_insert($data,$options);
if(isset($data[$this->getPk()])){
return $data[$this->getPk()];
}
}
return $result;
}
// 插入数据前的回调方法
protected function _before_insert(&$data,$options) {
// 写入数据到数据库
if($this->_autoinc && $this->_idType== self::TYPE_INT) { // 主键自动增长
$pk = $this->getPk();
if(!isset($data[$pk])) {
$data[$pk] = $this->db->getMongoNextId($pk);
}
}
}
public function clear(){
return $this->db->clear();
}
// 查询成功后的回调方法
protected function _after_select(&$resultSet,$options) {
array_walk($resultSet,array($this,'checkMongoId'));
}
/**
* 获取MongoId
* @access protected
* @param array $result 返回数据
* @return array
*/
protected function checkMongoId(&$result){
if(is_object($result['_id'])) {
$result['_id'] = $result['_id']->__toString();
}
return $result;
}
// 表达式过滤回调方法
protected function _options_filter(&$options) {
$id = $this->getPk();
if(isset($options['where'][$id]) && is_scalar($options['where'][$id]) && $this->_idType== self::TYPE_OBJECT) {
$options['where'][$id] = new \MongoId($options['where'][$id]);
}
}
/**
* 查询数据
* @access public
* @param mixed $options 表达式参数
* @return mixed
*/
public function find($options=array()) {
if( is_numeric($options) || is_string($options)) {
$id = $this->getPk();
$where[$id] = $options;
$options = array();
$options['where'] = $where;
}
// 分析表达式
$options = $this->_parseOptions($options);
$result = $this->db->find($options);
if(false === $result) {
return false;
}
if(empty($result)) {// 查询结果为空
return null;
}else{
$this->checkMongoId($result);
}
$this->data = $result;
$this->_after_find($this->data,$options);
return $this->data;
}
/**
* 字段值增长
* @access public
* @param string $field 字段名
* @param integer $step 增长值
* @return boolean
*/
public function setInc($field,$step=1) {
return $this->setField($field,array('inc',$step));
}
/**
* 字段值减少
* @access public
* @param string $field 字段名
* @param integer $step 减少值
* @return boolean
*/
public function setDec($field,$step=1) {
return $this->setField($field,array('inc','-'.$step));
}
/**
* 获取一条记录的某个字段值
* @access public
* @param string $field 字段名
* @param string $spea 字段数据间隔符号
* @return mixed
*/
public function getField($field,$sepa=null) {
$options['field'] = $field;
$options = $this->_parseOptions($options);
if(strpos($field,',')) { // 多字段
if(is_numeric($sepa)) {// 限定数量
$options['limit'] = $sepa;
$sepa = null;// 重置为null 返回数组
}
$resultSet = $this->db->select($options);
if(!empty($resultSet)) {
$_field = explode(',', $field);
$field = array_keys($resultSet[0]);
$key = array_shift($field);
$key2 = array_shift($field);
$cols = array();
$count = count($_field);
foreach ($resultSet as $result){
$name = $result[$key];
if(2==$count) {
$cols[$name] = $result[$key2];
}else{
$cols[$name] = is_null($sepa)?$result:implode($sepa,$result);
}
}
return $cols;
}
}else{
// 返回数据个数
if(true !== $sepa) {// 当sepa指定为true的时候 返回所有数据
$options['limit'] = is_numeric($sepa)?$sepa:1;
} // 查找符合的记录
$result = $this->db->select($options);
if(!empty($result)) {
if(1==$options['limit']) {
$result = reset($result);
return $result[$field];
}
foreach ($result as $val){
$array[] = $val[$field];
}
return $array;
}
}
return null;
}
/**
* 执行Mongo指令
* @access public
* @param array $command 指令
* @return mixed
*/
public function command($command, $options=array()) {
$options = $this->_parseOptions($options);
return $this->db->command($command, $options);
}
/**
* 执行MongoCode
* @access public
* @param string $code MongoCode
* @param array $args 参数
* @return mixed
*/
public function mongoCode($code,$args=array()) {
return $this->db->execute($code,$args);
}
// 数据库切换后回调方法
protected function _after_db() {
// 切换Collection
$this->db->switchCollection($this->getTableName(),$this->dbName?$this->dbName:C('db_name'));
}
/**
* 得到完整的数据表名 Mongo表名不带dbName
* @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 $this->trueTableName;
}
/**
* 分组查询
* @access public
* @return string
*/
public function group($key, $init, $reduce, $option=array()) {
$option = $this->_parseOptions($option);
//合并查询条件
if(isset($option['where']))
$option['condition'] = array_merge((array)$option['condition'], $option['where']);
return $this->db->group($key, $init, $reduce, $option);
}
/**
* 返回Mongo运行错误信息
* @access public
* @return json
*/
public function getLastError(){
return $this->db->command(array('getLastError'=>1));
}
/**
* 返回指定集合的统计信息,包括数据大小、已分配的存储空间和索引的大小
* @access public
* @return json
*/
public function status(){
$option = $this->_parseOptions();
return $this->db->command(array('collStats'=>$option['table']));
}
/**
* 取得当前数据库的对象
* @access public
* @return object
*/
public function getDB(){
return $this->db->getDB();
}
/**
* 取得集合对象,可以进行创建索引等查询
* @access public
* @return object
*/
public function getCollection(){
return $this->db->getCollection();
}
}

View File

@@ -0,0 +1,412 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
namespace Think\Model;
use Think\Model;
/**
* ThinkPHP关联模型扩展
*/
class RelationModel extends Model {
const HAS_ONE = 1;
const BELONGS_TO = 2;
const HAS_MANY = 3;
const MANY_TO_MANY= 4;
// 关联定义
protected $_link = array();
/**
* 动态方法实现
* @access public
* @param string $method 方法名称
* @param array $args 调用参数
* @return mixed
*/
public function __call($method,$args) {
if(strtolower(substr($method,0,8))=='relation'){
$type = strtoupper(substr($method,8));
if(in_array($type,array('ADD','SAVE','DEL'),true)) {
array_unshift($args,$type);
return call_user_func_array(array(&$this, 'opRelation'), $args);
}
}else{
return parent::__call($method,$args);
}
}
/**
* 得到关联的数据表名
* @access public
* @return string
*/
public function getRelationTableName($relation) {
$relationTable = !empty($this->tablePrefix) ? $this->tablePrefix : '';
$relationTable .= $this->tableName?$this->tableName:$this->name;
$relationTable .= '_'.$relation->getModelName();
return strtolower($relationTable);
}
// 查询成功后的回调方法
protected function _after_find(&$result,$options) {
// 获取关联数据 并附加到结果中
if(!empty($options['link']))
$this->getRelation($result,$options['link']);
}
// 查询数据集成功后的回调方法
protected function _after_select(&$result,$options) {
// 获取关联数据 并附加到结果中
if(!empty($options['link']))
$this->getRelations($result,$options['link']);
}
// 写入成功后的回调方法
protected function _after_insert($data,$options) {
// 关联写入
if(!empty($options['link']))
$this->opRelation('ADD',$data,$options['link']);
}
// 更新成功后的回调方法
protected function _after_update($data,$options) {
// 关联更新
if(!empty($options['link']))
$this->opRelation('SAVE',$data,$options['link']);
}
// 删除成功后的回调方法
protected function _after_delete($data,$options) {
// 关联删除
if(!empty($options['link']))
$this->opRelation('DEL',$data,$options['link']);
}
/**
* 对保存到数据库的数据进行处理
* @access protected
* @param mixed $data 要操作的数据
* @return boolean
*/
protected function _facade($data) {
$this->_before_write($data);
return $data;
}
/**
* 获取返回数据集的关联记录
* @access protected
* @param array $resultSet 返回数据
* @param string|array $name 关联名称
* @return array
*/
protected function getRelations(&$resultSet,$name='') {
// 获取记录集的主键列表
foreach($resultSet as $key=>$val) {
$val = $this->getRelation($val,$name);
$resultSet[$key] = $val;
}
return $resultSet;
}
/**
* 获取返回数据的关联记录
* @access protected
* @param mixed $result 返回数据
* @param string|array $name 关联名称
* @param boolean $return 是否返回关联数据本身
* @return array
*/
protected function getRelation(&$result,$name='',$return=false) {
if(!empty($this->_link)) {
foreach($this->_link as $key=>$val) {
$mappingName = !empty($val['mapping_name'])?$val['mapping_name']:$key; // 映射名称
if(empty($name) || true === $name || $mappingName == $name || (is_array($name) && in_array($mappingName,$name))) {
$mappingType = !empty($val['mapping_type'])?$val['mapping_type']:$val; // 关联类型
$mappingClass = !empty($val['class_name'])?$val['class_name']:$key; // 关联类名
$mappingFields = !empty($val['mapping_fields'])?$val['mapping_fields']:'*'; // 映射字段
$mappingCondition = !empty($val['condition'])?$val['condition']:'1=1'; // 关联条件
$mappingKey =!empty($val['mapping_key'])? $val['mapping_key'] : $this->getPk(); // 关联键名
if(strtoupper($mappingClass)==strtoupper($this->name)) {
// 自引用关联 获取父键名
$mappingFk = !empty($val['parent_key'])? $val['parent_key'] : 'parent_id';
}else{
$mappingFk = !empty($val['foreign_key'])?$val['foreign_key']:strtolower($this->name).'_id'; // 关联外键
}
// 获取关联模型对象
$model = D($mappingClass);
switch($mappingType) {
case self::HAS_ONE:
$pk = $result[$mappingKey];
$mappingCondition .= " AND {$mappingFk}='{$pk}'";
$relationData = $model->where($mappingCondition)->field($mappingFields)->find();
if (!empty($val['relation_deep'])){
$model->getRelation($relationData,$val['relation_deep']);
}
break;
case self::BELONGS_TO:
if(strtoupper($mappingClass)==strtoupper($this->name)) {
// 自引用关联 获取父键名
$mappingFk = !empty($val['parent_key'])? $val['parent_key'] : 'parent_id';
}else{
$mappingFk = !empty($val['foreign_key'])?$val['foreign_key']:strtolower($model->getModelName()).'_id'; // 关联外键
}
$fk = $result[$mappingFk];
$mappingCondition .= " AND {$model->getPk()}='{$fk}'";
$relationData = $model->where($mappingCondition)->field($mappingFields)->find();
if (!empty($val['relation_deep'])){
$model->getRelation($relationData,$val['relation_deep']);
}
break;
case self::HAS_MANY:
$pk = $result[$mappingKey];
$mappingCondition .= " AND {$mappingFk}='{$pk}'";
$mappingOrder = !empty($val['mapping_order'])?$val['mapping_order']:'';
$mappingLimit = !empty($val['mapping_limit'])?$val['mapping_limit']:'';
// 延时获取关联记录
$relationData = $model->where($mappingCondition)->field($mappingFields)->order($mappingOrder)->limit($mappingLimit)->select();
if (!empty($val['relation_deep'])){
foreach($relationData as $key=>$data){
$model->getRelation($data,$val['relation_deep']);
$relationData[$key] = $data;
}
}
break;
case self::MANY_TO_MANY:
$pk = $result[$mappingKey];
$prefix = $this->tablePrefix;
$mappingCondition = " {$mappingFk}='{$pk}'";
$mappingOrder = $val['mapping_order'];
$mappingLimit = $val['mapping_limit'];
$mappingRelationFk = $val['relation_foreign_key']?$val['relation_foreign_key']:$model->getModelName().'_id';
if(isset($val['relation_table'])){
$mappingRelationTable = preg_replace_callback("/__([A-Z_-]+)__/sU", function($match) use($prefix){ return $prefix.strtolower($match[1]);}, $val['relation_table']);
}else{
$mappingRelationTable = $this->getRelationTableName($model);
}
$sql = "SELECT b.{$mappingFields} FROM {$mappingRelationTable} AS a, ".$model->getTableName()." AS b WHERE a.{$mappingRelationFk} = b.{$model->getPk()} AND a.{$mappingCondition}";
if(!empty($val['condition'])) {
$sql .= ' AND '.$val['condition'];
}
if(!empty($mappingOrder)) {
$sql .= ' ORDER BY '.$mappingOrder;
}
if(!empty($mappingLimit)) {
$sql .= ' LIMIT '.$mappingLimit;
}
$relationData = $this->query($sql);
if (!empty($val['relation_deep'])){
foreach($relationData as $key=>$data){
$model->getRelation($data,$val['relation_deep']);
$relationData[$key] = $data;
}
}
break;
}
if(!$return){
if(isset($val['as_fields']) && in_array($mappingType,array(self::HAS_ONE,self::BELONGS_TO)) ) {
// 支持直接把关联的字段值映射成数据对象中的某个字段
// 仅仅支持HAS_ONE BELONGS_TO
$fields = explode(',',$val['as_fields']);
foreach ($fields as $field){
if(strpos($field,':')) {
list($relationName,$nick) = explode(':',$field);
$result[$nick] = $relationData[$relationName];
}else{
$result[$field] = $relationData[$field];
}
}
}else{
$result[$mappingName] = $relationData;
}
unset($relationData);
}else{
return $relationData;
}
}
}
}
return $result;
}
/**
* 操作关联数据
* @access protected
* @param string $opType 操作方式 ADD SAVE DEL
* @param mixed $data 数据对象
* @param string $name 关联名称
* @return mixed
*/
protected function opRelation($opType,$data='',$name='') {
$result = false;
if(empty($data) && !empty($this->data)){
$data = $this->data;
}elseif(!is_array($data)){
// 数据无效返回
return false;
}
if(!empty($this->_link)) {
// 遍历关联定义
foreach($this->_link as $key=>$val) {
// 操作制定关联类型
$mappingName = $val['mapping_name']?$val['mapping_name']:$key; // 映射名称
if(empty($name) || true === $name || $mappingName == $name || (is_array($name) && in_array($mappingName,$name)) ) {
// 操作制定的关联
$mappingType = !empty($val['mapping_type'])?$val['mapping_type']:$val; // 关联类型
$mappingClass = !empty($val['class_name'])?$val['class_name']:$key; // 关联类名
$mappingKey =!empty($val['mapping_key'])? $val['mapping_key'] : $this->getPk(); // 关联键名
// 当前数据对象主键值
$pk = $data[$mappingKey];
if(strtoupper($mappingClass)==strtoupper($this->name)) {
// 自引用关联 获取父键名
$mappingFk = !empty($val['parent_key'])? $val['parent_key'] : 'parent_id';
}else{
$mappingFk = !empty($val['foreign_key'])?$val['foreign_key']:strtolower($this->name).'_id'; // 关联外键
}
if(!empty($val['condition'])) {
$mappingCondition = $val['condition'];
}else{
$mappingCondition = array();
$mappingCondition[$mappingFk] = $pk;
}
// 获取关联model对象
$model = D($mappingClass);
$mappingData = isset($data[$mappingName])?$data[$mappingName]:false;
if(!empty($mappingData) || $opType == 'DEL') {
switch($mappingType) {
case self::HAS_ONE:
switch (strtoupper($opType)){
case 'ADD': // 增加关联数据
$mappingData[$mappingFk] = $pk;
$result = $model->add($mappingData);
break;
case 'SAVE': // 更新关联数据
$result = $model->where($mappingCondition)->save($mappingData);
break;
case 'DEL': // 根据外键删除关联数据
$result = $model->where($mappingCondition)->delete();
break;
}
break;
case self::BELONGS_TO:
break;
case self::HAS_MANY:
switch (strtoupper($opType)){
case 'ADD' : // 增加关联数据
$model->startTrans();
foreach ($mappingData as $val){
$val[$mappingFk] = $pk;
$result = $model->add($val);
}
$model->commit();
break;
case 'SAVE' : // 更新关联数据
$model->startTrans();
$pk = $model->getPk();
foreach ($mappingData as $vo){
if(isset($vo[$pk])) {// 更新数据
$mappingCondition = "$pk ={$vo[$pk]}";
$result = $model->where($mappingCondition)->save($vo);
}else{ // 新增数据
$vo[$mappingFk] = $data[$mappingKey];
$result = $model->add($vo);
}
}
$model->commit();
break;
case 'DEL' : // 删除关联数据
$result = $model->where($mappingCondition)->delete();
break;
}
break;
case self::MANY_TO_MANY:
$mappingRelationFk = $val['relation_foreign_key']?$val['relation_foreign_key']:$model->getModelName().'_id';// 关联
$prefix = $this->tablePrefix;
if(isset($val['relation_table'])){
$mappingRelationTable = preg_replace_callback("/__([A-Z_-]+)__/sU", function($match) use($prefix){ return $prefix.strtolower($match[1]);}, $val['relation_table']);
}else{
$mappingRelationTable = $this->getRelationTableName($model);
}
if(is_array($mappingData)) {
$ids = array();
foreach ($mappingData as $vo)
$ids[] = $vo[$mappingKey];
$relationId = implode(',',$ids);
}
switch (strtoupper($opType)){
case 'ADD': // 增加关联数据
if(isset($relationId)) {
$this->startTrans();
// 插入关联表数据
$sql = 'INSERT INTO '.$mappingRelationTable.' ('.$mappingFk.','.$mappingRelationFk.') SELECT a.'.$this->getPk().',b.'.$model->getPk().' FROM '.$this->getTableName().' AS a ,'.$model->getTableName()." AS b where a.".$this->getPk().' ='. $pk.' AND b.'.$model->getPk().' IN ('.$relationId.") ";
$result = $model->execute($sql);
if(false !== $result)
// 提交事务
$this->commit();
else
// 事务回滚
$this->rollback();
}
break;
case 'SAVE': // 更新关联数据
if(isset($relationId)) {
$this->startTrans();
// 删除关联表数据
$this->table($mappingRelationTable)->where($mappingCondition)->delete();
// 插入关联表数据
$sql = 'INSERT INTO '.$mappingRelationTable.' ('.$mappingFk.','.$mappingRelationFk.') SELECT a.'.$this->getPk().',b.'.$model->getPk().' FROM '.$this->getTableName().' AS a ,'.$model->getTableName()." AS b where a.".$this->getPk().' ='. $pk.' AND b.'.$model->getPk().' IN ('.$relationId.") ";
$result = $model->execute($sql);
if(false !== $result)
// 提交事务
$this->commit();
else
// 事务回滚
$this->rollback();
}
break;
case 'DEL': // 根据外键删除中间表关联数据
$result = $this->table($mappingRelationTable)->where($mappingCondition)->delete();
break;
}
break;
}
if (!empty($val['relation_deep'])){
$model->opRelation($opType,$mappingData,$val['relation_deep']);
}
}
}
}
}
return $result;
}
/**
* 进行关联查询
* @access public
* @param mixed $name 关联名称
* @return Model
*/
public function relation($name) {
$this->options['link'] = $name;
return $this;
}
/**
* 关联数据获取 仅用于查询后
* @access public
* @param string $name 关联名称
* @return array
*/
public function relationGet($name) {
if(empty($this->data))
return false;
return $this->getRelation($this->data,$name,true);
}
}

View File

@@ -0,0 +1,243 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
namespace Think\Model;
use Think\Model;
/**
* ThinkPHP视图模型扩展
*/
class ViewModel extends Model {
protected $viewFields = array();
/**
* 自动检测数据表信息
* @access protected
* @return void
*/
protected function _checkTableInfo() {}
/**
* 得到完整的数据表名
* @access public
* @return string
*/
public function getTableName() {
if(empty($this->trueTableName)) {
$tableName = '';
foreach ($this->viewFields as $key=>$view){
// 获取数据表名称
if(isset($view['_table'])) { // 2011/10/17 添加实际表名定义支持 可以实现同一个表的视图
$tableName .= $view['_table'];
$prefix = $this->tablePrefix;
$tableName = preg_replace_callback("/__([A-Z_-]+)__/sU", function($match) use($prefix){ return $prefix.strtolower($match[1]);}, $tableName);
}else{
$class = $key.'Model';
$Model = class_exists($class)?new $class():M($key);
$tableName .= $Model->getTableName();
}
// 表别名定义
$tableName .= !empty($view['_as'])?' '.$view['_as']:' '.$key;
// 支持ON 条件定义
$tableName .= !empty($view['_on'])?' ON '.$view['_on']:'';
// 指定JOIN类型 例如 RIGHT INNER LEFT 下一个表有效
$type = !empty($view['_type'])?$view['_type']:'';
$tableName .= ' '.strtoupper($type).' JOIN ';
$len = strlen($type.'_JOIN ');
}
$tableName = substr($tableName,0,-$len);
$this->trueTableName = $tableName;
}
return $this->trueTableName;
}
/**
* 表达式过滤方法
* @access protected
* @param string $options 表达式
* @return void
*/
protected function _options_filter(&$options) {
if(isset($options['field']))
$options['field'] = $this->checkFields($options['field']);
else
$options['field'] = $this->checkFields();
if(isset($options['group']))
$options['group'] = $this->checkGroup($options['group']);
if(isset($options['where']))
$options['where'] = $this->checkCondition($options['where']);
if(isset($options['order']))
$options['order'] = $this->checkOrder($options['order']);
}
/**
* 检查是否定义了所有字段
* @access protected
* @param string $name 模型名称
* @param array $fields 字段数组
* @return array
*/
private function _checkFields($name,$fields) {
if(false !== $pos = array_search('*',$fields)) {// 定义所有字段
$fields = array_merge($fields,M($name)->getDbFields());
unset($fields[$pos]);
}
return $fields;
}
/**
* 检查条件中的视图字段
* @access protected
* @param mixed $data 条件表达式
* @return array
*/
protected function checkCondition($where) {
if(is_array($where)) {
$view = array();
// 检查视图字段
foreach ($this->viewFields as $key=>$val){
$k = isset($val['_as'])?$val['_as']:$key;
$val = $this->_checkFields($key,$val);
foreach ($where as $name=>$value){
if(false !== $field = array_search($name,$val,true)) {
// 存在视图字段
$_key = is_numeric($field)? $k.'.'.$name : $k.'.'.$field;
$view[$_key] = $value;
unset($where[$name]);
}
}
}
$where = array_merge($where,$view);
}
return $where;
}
/**
* 检查Order表达式中的视图字段
* @access protected
* @param string $order 字段
* @return string
*/
protected function checkOrder($order='') {
if(is_string($order) && !empty($order)) {
$orders = explode(',',$order);
$_order = array();
foreach ($orders as $order){
$array = explode(' ',trim($order));
$field = $array[0];
$sort = isset($array[1])?$array[1]:'ASC';
// 解析成视图字段
foreach ($this->viewFields as $name=>$val){
$k = isset($val['_as'])?$val['_as']:$name;
$val = $this->_checkFields($name,$val);
if(false !== $_field = array_search($field,$val,true)) {
// 存在视图字段
$field = is_numeric($_field)?$k.'.'.$field:$k.'.'.$_field;
break;
}
}
$_order[] = $field.' '.$sort;
}
$order = implode(',',$_order);
}
return $order;
}
/**
* 检查Group表达式中的视图字段
* @access protected
* @param string $group 字段
* @return string
*/
protected function checkGroup($group='') {
if(!empty($group)) {
$groups = explode(',',$group);
$_group = array();
foreach ($groups as $field){
// 解析成视图字段
foreach ($this->viewFields as $name=>$val){
$k = isset($val['_as'])?$val['_as']:$name;
$val = $this->_checkFields($name,$val);
if(false !== $_field = array_search($field,$val,true)) {
// 存在视图字段
$field = is_numeric($_field)?$k.'.'.$field:$k.'.'.$_field;
break;
}
}
$_group[] = $field;
}
$group = implode(',',$_group);
}
return $group;
}
/**
* 检查fields表达式中的视图字段
* @access protected
* @param string $fields 字段
* @return string
*/
protected function checkFields($fields='') {
if(empty($fields) || '*'==$fields ) {
// 获取全部视图字段
$fields = array();
foreach ($this->viewFields as $name=>$val){
$k = isset($val['_as'])?$val['_as']:$name;
$val = $this->_checkFields($name,$val);
foreach ($val as $key=>$field){
if(is_numeric($key)) {
$fields[] = $k.'.'.$field.' AS '.$field;
}elseif('_' != substr($key,0,1)) {
// 以_开头的为特殊定义
if( false !== strpos($key,'*') || false !== strpos($key,'(') || false !== strpos($key,'.')) {
//如果包含* 或者 使用了sql方法 则不再添加前面的表名
$fields[] = $key.' AS '.$field;
}else{
$fields[] = $k.'.'.$key.' AS '.$field;
}
}
}
}
$fields = implode(',',$fields);
}else{
if(!is_array($fields))
$fields = explode(',',$fields);
// 解析成视图字段
$array = array();
foreach ($fields as $key=>$field){
if(strpos($field,'(') || strpos(strtolower($field),' as ')){
// 使用了函数或者别名
$array[] = $field;
unset($fields[$key]);
}
}
foreach ($this->viewFields as $name=>$val){
$k = isset($val['_as'])?$val['_as']:$name;
$val = $this->_checkFields($name,$val);
foreach ($fields as $key=>$field){
if(false !== $_field = array_search($field,$val,true)) {
// 存在视图字段
if(is_numeric($_field)) {
$array[] = $k.'.'.$field.' AS '.$field;
}elseif('_' != substr($_field,0,1)){
if( false !== strpos($_field,'*') || false !== strpos($_field,'(') || false !== strpos($_field,'.'))
//如果包含* 或者 使用了sql方法 则不再添加前面的表名
$array[] = $_field.' AS '.$field;
else
$array[] = $k.'.'.$_field.' AS '.$field;
}
}
}
}
$fields = implode(',',$array);
}
return $fields;
}
}

View File

@@ -0,0 +1,145 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: 麦当苗儿 <zuojiazi@vip.qq.com> <http://www.zjzit.cn>
// +----------------------------------------------------------------------
namespace Think;
class Page{
public $firstRow; // 起始行数
public $listRows; // 列表每页显示行数
public $parameter; // 分页跳转时要带的参数
public $totalRows; // 总行数
public $totalPages; // 分页总页面数
public $rollPage = 11;// 分页栏每页显示的页数
public $lastSuffix = true; // 最后一页是否显示总页数
private $p = 'p'; //分页参数名
private $url = ''; //当前链接URL
private $nowPage = 1;
// 分页显示定制
private $config = array(
'header' => '<span class="rows">共 %TOTAL_ROW% 条记录</span>',
'prev' => '<<',
'next' => '>>',
'first' => '1...',
'last' => '...%TOTAL_PAGE%',
'theme' => '%FIRST% %UP_PAGE% %LINK_PAGE% %DOWN_PAGE% %END%',
);
/**
* 架构函数
* @param array $totalRows 总的记录数
* @param array $listRows 每页显示记录数
* @param array $parameter 分页跳转的参数
*/
public function __construct($totalRows, $listRows=20, $parameter = array()) {
C('VAR_PAGE') && $this->p = C('VAR_PAGE'); //设置分页参数名称
/* 基础设置 */
$this->totalRows = $totalRows; //设置总记录数
$this->listRows = $listRows; //设置每页显示行数
$this->parameter = empty($parameter) ? $_GET : $parameter;
$this->nowPage = empty($_GET[$this->p]) ? 1 : intval($_GET[$this->p]);
$this->nowPage = $this->nowPage>0 ? $this->nowPage : 1;
$this->firstRow = $this->listRows * ($this->nowPage - 1);
}
/**
* 定制分页链接设置
* @param string $name 设置名称
* @param string $value 设置值
*/
public function setConfig($name,$value) {
if(isset($this->config[$name])) {
$this->config[$name] = $value;
}
}
/**
* 生成链接URL
* @param integer $page 页码
* @return string
*/
private function url($page){
return str_replace(urlencode('[PAGE]'), $page, $this->url);
}
/**
* 组装分页链接
* @return string
*/
public function show() {
if(0 == $this->totalRows) return '';
/* 生成URL */
$this->parameter[$this->p] = '[PAGE]';
$this->url = U(ACTION_NAME, $this->parameter);
/* 计算分页信息 */
$this->totalPages = ceil($this->totalRows / $this->listRows); //总页数
if(!empty($this->totalPages) && $this->nowPage > $this->totalPages) {
$this->nowPage = $this->totalPages;
}
/* 计算分页临时变量 */
$now_cool_page = $this->rollPage/2;
$now_cool_page_ceil = ceil($now_cool_page);
$this->lastSuffix && $this->config['last'] = $this->totalPages;
//上一页
$up_row = $this->nowPage - 1;
$up_page = $up_row > 0 ? '<a class="prev" href="' . $this->url($up_row) . '">' . $this->config['prev'] . '</a>' : '';
//下一页
$down_row = $this->nowPage + 1;
$down_page = ($down_row <= $this->totalPages) ? '<a class="next" href="' . $this->url($down_row) . '">' . $this->config['next'] . '</a>' : '';
//第一页
$the_first = '';
if($this->totalPages > $this->rollPage && ($this->nowPage - $now_cool_page) >= 1){
$the_first = '<a class="first" href="' . $this->url(1) . '">' . $this->config['first'] . '</a>';
}
//最后一页
$the_end = '';
if($this->totalPages > $this->rollPage && ($this->nowPage + $now_cool_page) < $this->totalPages){
$the_end = '<a class="end" href="' . $this->url($this->totalPages) . '">' . $this->config['last'] . '</a>';
}
//数字连接
$link_page = "";
for($i = 1; $i <= $this->rollPage; $i++){
if(($this->nowPage - $now_cool_page) <= 0 ){
$page = $i;
}elseif(($this->nowPage + $now_cool_page - 1) >= $this->totalPages){
$page = $this->totalPages - $this->rollPage + $i;
}else{
$page = $this->nowPage - $now_cool_page_ceil + $i;
}
if($page > 0 && $page != $this->nowPage){
if($page <= $this->totalPages){
$link_page .= '<a class="num" href="' . $this->url($page) . '">' . $page . '</a>';
}else{
break;
}
}else{
if($page > 0 && $this->totalPages != 1){
$link_page .= '<span class="current">' . $page . '</span>';
}
}
}
//替换分页内容
$page_str = str_replace(
array('%HEADER%', '%NOW_PAGE%', '%UP_PAGE%', '%DOWN_PAGE%', '%FIRST%', '%LINK_PAGE%', '%END%', '%TOTAL_ROW%', '%TOTAL_PAGE%'),
array($this->config['header'], $this->nowPage, $up_page, $down_page, $the_first, $link_page, $the_end, $this->totalRows, $this->totalPages),
$this->config['theme']);
return "<div>{$page_str}</div>";
}
}

View File

@@ -0,0 +1,316 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
namespace Think;
/**
* ThinkPHP路由解析类
*/
class Route {
// 路由检测
public static function check(){
$depr = C('URL_PATHINFO_DEPR');
$regx = preg_replace('/\.'.__EXT__.'$/i','',trim($_SERVER['PATH_INFO'],$depr));
// 分隔符替换 确保路由定义使用统一的分隔符
if('/' != $depr){
$regx = str_replace($depr,'/',$regx);
}
// URL映射定义静态路由
$maps = C('URL_MAP_RULES');
if(isset($maps[$regx])) {
$var = self::parseUrl($maps[$regx]);
$_GET = array_merge($var, $_GET);
return true;
}
// 动态路由处理
$routes = C('URL_ROUTE_RULES');
if(!empty($routes)) {
foreach ($routes as $rule=>$route){
if(is_numeric($rule)){
// 支持 array('rule','adddress',...) 定义路由
$rule = array_shift($route);
}
if(is_array($route) && isset($route[2])){
// 路由参数
$options = $route[2];
if(isset($options['ext']) && __EXT__ != $options['ext']){
// URL后缀检测
continue;
}
if(isset($options['method']) && REQUEST_METHOD != strtoupper($options['method'])){
// 请求类型检测
continue;
}
// 自定义检测
if(!empty($options['callback']) && is_callable($options['callback'])) {
if(false === call_user_func($options['callback'])) {
continue;
}
}
}
if(0===strpos($rule,'/') && preg_match($rule,$regx,$matches)) { // 正则路由
if($route instanceof \Closure) {
// 执行闭包
$result = self::invokeRegx($route, $matches);
// 如果返回布尔值 则继续执行
return is_bool($result) ? $result : exit;
}else{
return self::parseRegex($matches,$route,$regx);
}
}else{ // 规则路由
$len1 = substr_count($regx,'/');
$len2 = substr_count($rule,'/');
if($len1>=$len2 || strpos($rule,'[')) {
if('$' == substr($rule,-1,1)) {// 完整匹配
if($len1 != $len2) {
continue;
}else{
$rule = substr($rule,0,-1);
}
}
$match = self::checkUrlMatch($regx,$rule);
if(false !== $match) {
if($route instanceof \Closure) {
// 执行闭包
$result = self::invokeRule($route, $match);
// 如果返回布尔值 则继续执行
return is_bool($result) ? $result : exit;
}else{
return self::parseRule($rule,$route,$regx);
}
}
}
}
}
}
return false;
}
// 检测URL和规则路由是否匹配
private static function checkUrlMatch($regx,$rule) {
$m1 = explode('/',$regx);
$m2 = explode('/',$rule);
$var = array();
foreach ($m2 as $key=>$val){
if(0 === strpos($val,'[:')){
$val = substr($val,1,-1);
}
if(':' == substr($val,0,1)) {// 动态变量
if($pos = strpos($val,'|')){
// 使用函数过滤
$val = substr($val,1,$pos-1);
}
if(strpos($val,'\\')) {
$type = substr($val,-1);
if('d'==$type) {
if(isset($m1[$key]) && !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] = isset($m1[$key])?$m1[$key]:'';
}elseif(0 !== strcasecmp($val,$m1[$key])){
return false;
}
}
// 成功匹配后返回URL中的动态变量数组
return $var;
}
// 解析规范的路由地址
// 地址格式 [控制器/操作?]参数1=值1&参数2=值2...
private static function parseUrl($url) {
$var = array();
if(false !== strpos($url,'?')) { // [控制器/操作?]参数1=值1&参数2=值2...
$info = parse_url($url);
$path = explode('/',$info['path']);
parse_str($info['query'],$var);
}elseif(strpos($url,'/')){ // [控制器/操作]
$path = explode('/',$url);
}else{ // 参数1=值1&参数2=值2...
parse_str($url,$var);
}
if(isset($path)) {
$var[C('VAR_ACTION')] = array_pop($path);
if(!empty($path)) {
$var[C('VAR_CONTROLLER')] = array_pop($path);
}
if(!empty($path)) {
$var[C('VAR_MODULE')] = array_pop($path);
}
}
return $var;
}
// 解析规则路由
// '路由规则'=>'[控制器/操作]?额外参数1=值1&额外参数2=值2...'
// '路由规则'=>array('[控制器/操作]','额外参数1=值1&额外参数2=值2...')
// '路由规则'=>'外部地址'
// '路由规则'=>array('外部地址','重定向代码')
// 路由规则中 :开头 表示动态变量
// 外部地址中可以用动态变量 采用 :1 :2 的方式
// 'news/:month/:day/:id'=>array('News/read?cate=1','status=1'),
// 'new/:id'=>array('/new.php?id=:1',301), 重定向
private static function parseRule($rule,$route,$regx) {
// 获取路由地址规则
$url = is_array($route)?$route[0]:$route;
// 获取URL地址中的参数
$paths = explode('/',$regx);
// 解析路由规则
$matches = array();
$rule = explode('/',$rule);
foreach ($rule as $item){
$fun = '';
if(0 === strpos($item,'[:')){
$item = substr($item,1,-1);
}
if(0===strpos($item,':')) { // 动态变量获取
if($pos = strpos($item,'|')){
// 支持函数过滤
$fun = substr($item,$pos+1);
$item = substr($item,0,$pos);
}
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] = !empty($fun)? $fun(array_shift($paths)) : array_shift($paths);
}else{ // 过滤URL中的静态变量
array_shift($paths);
}
}
if(0=== strpos($url,'/') || 0===strpos($url,'http')) { // 路由重定向跳转
if(strpos($url,':')) { // 传递动态参数
$values = array_values($matches);
$url = preg_replace_callback('/:(\d+)/', function($match) use($values){ return $values[$match[1] - 1]; }, $url);
}
header("Location: $url", true,(is_array($route) && isset($route[1]))?$route[1]:301);
exit;
}else{
// 解析路由地址
$var = self::parseUrl($url);
// 解析路由地址里面的动态参数
$values = array_values($matches);
foreach ($var as $key=>$val){
if(0===strpos($val,':')) {
$var[$key] = $values[substr($val,1)-1];
}
}
$var = array_merge($matches,$var);
// 解析剩余的URL参数
if(!empty($paths)) {
preg_replace_callback('/(\w+)\/([^\/]+)/', function($match) use(&$var){ $var[strtolower($match[1])]=strip_tags($match[2]);}, implode('/',$paths));
}
// 解析路由自动传入参数
if(is_array($route) && isset($route[1])) {
if(is_array($route[1])){
$params = $route[1];
}else{
parse_str($route[1],$params);
}
$var = array_merge($var,$params);
}
$_GET = array_merge($var,$_GET);
}
return true;
}
// 解析正则路由
// '路由正则'=>'[控制器/操作]?参数1=值1&参数2=值2...'
// '路由正则'=>array('[控制器/操作]?参数1=值1&参数2=值2...','额外参数1=值1&额外参数2=值2...')
// '路由正则'=>'外部地址'
// '路由正则'=>array('外部地址','重定向代码')
// 参数值和外部地址中可以用动态变量 采用 :1 :2 的方式
// '/new\/(\d+)\/(\d+)/'=>array('News/read?id=:1&page=:2&cate=1','status=1'),
// '/new\/(\d+)/'=>array('/new.php?id=:1&page=:2&status=1','301'), 重定向
private static function parseRegex($matches,$route,$regx) {
// 获取路由地址规则
$url = is_array($route)?$route[0]:$route;
$url = preg_replace_callback('/:(\d+)/', function($match) use($matches){return $matches[$match[1]];}, $url);
if(0=== strpos($url,'/') || 0===strpos($url,'http')) { // 路由重定向跳转
header("Location: $url", true,(is_array($route) && isset($route[1]))?$route[1]:301);
exit;
}else{
// 解析路由地址
$var = self::parseUrl($url);
// 处理函数
foreach($var as $key=>$val){
if(strpos($val,'|')){
list($val,$fun) = explode('|',$val);
$var[$key] = $fun($val);
}
}
// 解析剩余的URL参数
$regx = substr_replace($regx,'',0,strlen($matches[0]));
if($regx) {
preg_replace_callback('/(\w+)\/([^\/]+)/', function($match) use(&$var){
$var[strtolower($match[1])] = strip_tags($match[2]);
}, $regx);
}
// 解析路由自动传入参数
if(is_array($route) && isset($route[1])) {
if(is_array($route[1])){
$params = $route[1];
}else{
parse_str($route[1],$params);
}
$var = array_merge($var,$params);
}
$_GET = array_merge($var,$_GET);
}
return true;
}
// 执行正则匹配下的闭包方法 支持参数调用
static private function invokeRegx($closure, $var = array()) {
$reflect = new \ReflectionFunction($closure);
$params = $reflect->getParameters();
$args = array();
array_shift($var);
foreach ($params as $param){
if(!empty($var)) {
$args[] = array_shift($var);
}elseif($param->isDefaultValueAvailable()){
$args[] = $param->getDefaultValue();
}
}
return $reflect->invokeArgs($args);
}
// 执行规则匹配下的闭包方法 支持参数调用
static private function invokeRule($closure, $var = array()) {
$reflect = new \ReflectionFunction($closure);
$params = $reflect->getParameters();
$args = array();
foreach ($params as $param){
$name = $param->getName();
if(isset($var[$name])) {
$args[] = $var[$name];
}elseif($param->isDefaultValueAvailable()){
$args[] = $param->getDefaultValue();
}
}
return $reflect->invokeArgs($args);
}
}

View File

@@ -0,0 +1,173 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
namespace Think\Session\Driver;
/**
* 数据库方式Session驱动
* CREATE TABLE think_session (
* session_id varchar(255) NOT NULL,
* session_expire int(11) NOT NULL,
* session_data blob,
* UNIQUE KEY `session_id` (`session_id`)
* );
*/
class Db {
/**
* Session有效时间
*/
protected $lifeTime = '';
/**
* session保存的数据库名
*/
protected $sessionTable = '';
/**
* 数据库句柄
*/
protected $hander = array();
/**
* 打开Session
* @access public
* @param string $savePath
* @param mixed $sessName
*/
public function open($savePath, $sessName) {
$this->lifeTime = C('SESSION_EXPIRE')?C('SESSION_EXPIRE'):ini_get('session.gc_maxlifetime');
$this->sessionTable = C('SESSION_TABLE')?C('SESSION_TABLE'):C("DB_PREFIX")."session";
//分布式数据库
$host = explode(',',C('DB_HOST'));
$port = explode(',',C('DB_PORT'));
$name = explode(',',C('DB_NAME'));
$user = explode(',',C('DB_USER'));
$pwd = explode(',',C('DB_PWD'));
if(1 == C('DB_DEPLOY_TYPE')){
//读写分离
if(C('DB_RW_SEPARATE')){
$w = floor(mt_rand(0,C('DB_MASTER_NUM')-1));
if(is_numeric(C('DB_SLAVE_NO'))){//指定服务器读
$r = C('DB_SLAVE_NO');
}else{
$r = floor(mt_rand(C('DB_MASTER_NUM'),count($host)-1));
}
//主数据库链接
$hander = mysql_connect(
$host[$w].(isset($port[$w])?':'.$port[$w]:':'.$port[0]),
isset($user[$w])?$user[$w]:$user[0],
isset($pwd[$w])?$pwd[$w]:$pwd[0]
);
$dbSel = mysql_select_db(
isset($name[$w])?$name[$w]:$name[0]
,$hander);
if(!$hander || !$dbSel)
return false;
$this->hander[0] = $hander;
//从数据库链接
$hander = mysql_connect(
$host[$r].(isset($port[$r])?':'.$port[$r]:':'.$port[0]),
isset($user[$r])?$user[$r]:$user[0],
isset($pwd[$r])?$pwd[$r]:$pwd[0]
);
$dbSel = mysql_select_db(
isset($name[$r])?$name[$r]:$name[0]
,$hander);
if(!$hander || !$dbSel)
return false;
$this->hander[1] = $hander;
return true;
}
}
//从数据库链接
$r = floor(mt_rand(0,count($host)-1));
$hander = mysql_connect(
$host[$r].(isset($port[$r])?':'.$port[$r]:':'.$port[0]),
isset($user[$r])?$user[$r]:$user[0],
isset($pwd[$r])?$pwd[$r]:$pwd[0]
);
$dbSel = mysql_select_db(
isset($name[$r])?$name[$r]:$name[0]
,$hander);
if(!$hander || !$dbSel)
return false;
$this->hander = $hander;
return true;
}
/**
* 关闭Session
* @access public
*/
public function close() {
if(is_array($this->hander)){
$this->gc($this->lifeTime);
return (mysql_close($this->hander[0]) && mysql_close($this->hander[1]));
}
$this->gc($this->lifeTime);
return mysql_close($this->hander);
}
/**
* 读取Session
* @access public
* @param string $sessID
*/
public function read($sessID) {
$hander = is_array($this->hander)?$this->hander[1]:$this->hander;
$res = mysql_query('SELECT session_data AS data FROM '.$this->sessionTable." WHERE session_id = '$sessID' AND session_expire >".time(),$hander);
if($res) {
$row = mysql_fetch_assoc($res);
return $row['data'];
}
return "";
}
/**
* 写入Session
* @access public
* @param string $sessID
* @param String $sessData
*/
public function write($sessID,$sessData) {
$hander = is_array($this->hander)?$this->hander[0]:$this->hander;
$expire = time() + $this->lifeTime;
$sessData = addslashes($sessData);
mysql_query('REPLACE INTO '.$this->sessionTable." ( session_id, session_expire, session_data) VALUES( '$sessID', '$expire', '$sessData')",$hander);
if(mysql_affected_rows($hander))
return true;
return false;
}
/**
* 删除Session
* @access public
* @param string $sessID
*/
public function destroy($sessID) {
$hander = is_array($this->hander)?$this->hander[0]:$this->hander;
mysql_query('DELETE FROM '.$this->sessionTable." WHERE session_id = '$sessID'",$hander);
if(mysql_affected_rows($hander))
return true;
return false;
}
/**
* Session 垃圾回收
* @access public
* @param string $sessMaxLifeTime
*/
public function gc($sessMaxLifeTime) {
$hander = is_array($this->hander)?$this->hander[0]:$this->hander;
mysql_query('DELETE FROM '.$this->sessionTable.' WHERE session_expire < '.time(),$hander);
return mysql_affected_rows($hander);
}
}

View File

@@ -0,0 +1,79 @@
<?php
namespace Think\Session\Driver;
class Memcache {
protected $lifeTime = 3600;
protected $sessionName = '';
protected $handle = null;
/**
* 打开Session
* @access public
* @param string $savePath
* @param mixed $sessName
*/
public function open($savePath, $sessName) {
$this->lifeTime = C('SESSION_EXPIRE') ? C('SESSION_EXPIRE') : $this->lifeTime;
// $this->sessionName = $sessName;
$options = array(
'timeout' => C('SESSION_TIMEOUT') ? C('SESSION_TIMEOUT') : 1,
'persistent' => C('SESSION_PERSISTENT') ? C('SESSION_PERSISTENT') : 0
);
$this->handle = new \Memcache;
$hosts = explode(',', C('MEMCACHE_HOST'));
$ports = explode(',', C('MEMCACHE_PORT'));
foreach ($hosts as $i=>$host) {
$port = isset($ports[$i]) ? $ports[$i] : $ports[0];
$this->handle->addServer($host, $port, true, 1, $options['timeout']);
}
return true;
}
/**
* 关闭Session
* @access public
*/
public function close() {
$this->gc(ini_get('session.gc_maxlifetime'));
$this->handle->close();
$this->handle = null;
return true;
}
/**
* 读取Session
* @access public
* @param string $sessID
*/
public function read($sessID) {
return $this->handle->get($this->sessionName.$sessID);
}
/**
* 写入Session
* @access public
* @param string $sessID
* @param String $sessData
*/
public function write($sessID, $sessData) {
return $this->handle->set($this->sessionName.$sessID, $sessData, 0, $this->lifeTime);
}
/**
* 删除Session
* @access public
* @param string $sessID
*/
public function destroy($sessID) {
return $this->handle->delete($this->sessionName.$sessID);
}
/**
* Session 垃圾回收
* @access public
* @param string $sessMaxLifeTime
*/
public function gc($sessMaxLifeTime) {
return true;
}
}

View File

@@ -0,0 +1,184 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: hainuo<admin@hainuo.info> liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
// | change mysql to mysqli 解决php7没有mysql扩展时数据库存放session无法操作的问题
// +----------------------------------------------------------------------
namespace Think\Session\Driver;
/**
* 数据库方式Session驱动
* CREATE TABLE think_session (
* session_id varchar(255) NOT NULL,
* session_expire int(11) NOT NULL,
* session_data blob,
* UNIQUE KEY `session_id` (`session_id`)
* );
*/
class Mysqli
{
/**
* Session有效时间
*/
protected $lifeTime = '';
/**
* session保存的数据库名
*/
protected $sessionTable = '';
/**
* 数据库句柄
*/
protected $hander = array();
/**
* 打开Session
* @access public
* @param string $savePath
* @param mixed $sessName
*/
public function open($savePath, $sessName)
{
$this->lifeTime = C('SESSION_EXPIRE') ? C('SESSION_EXPIRE') : ini_get('session.gc_maxlifetime');
$this->sessionTable = C('SESSION_TABLE') ? C('SESSION_TABLE') : C("DB_PREFIX") . "session";
//分布式数据库
$host = explode(',', C('DB_HOST'));
$port = explode(',', C('DB_PORT'));
$name = explode(',', C('DB_NAME'));
$user = explode(',', C('DB_USER'));
$pwd = explode(',', C('DB_PWD'));
if (1 == C('DB_DEPLOY_TYPE')) {
//读写分离
if (C('DB_RW_SEPARATE')) {
$w = floor(mt_rand(0, C('DB_MASTER_NUM') - 1));
if (is_numeric(C('DB_SLAVE_NO'))) {//指定服务器读
$r = C('DB_SLAVE_NO');
} else {
$r = floor(mt_rand(C('DB_MASTER_NUM'), count($host) - 1));
}
//主数据库链接
$hander = mysqli_connect(
$host[$w] . (isset($port[$w]) ? ':' . $port[$w] : ':' . $port[0]),
isset($user[$w]) ? $user[$w] : $user[0],
isset($pwd[$w]) ? $pwd[$w] : $pwd[0]
);
$dbSel = mysqli_select_db(
$hander,
isset($name[$w]) ? $name[$w] : $name[0]
);
if (!$hander || !$dbSel)
return false;
$this->hander[0] = $hander;
//从数据库链接
$hander = mysqli_connect(
$host[$r] . (isset($port[$r]) ? ':' . $port[$r] : ':' . $port[0]),
isset($user[$r]) ? $user[$r] : $user[0],
isset($pwd[$r]) ? $pwd[$r] : $pwd[0]
);
$dbSel = mysqli_select_db(
$hander,
isset($name[$r]) ? $name[$r] : $name[0]
);
if (!$hander || !$dbSel)
return false;
$this->hander[1] = $hander;
return true;
}
}
//从数据库链接
$r = floor(mt_rand(0, count($host) - 1));
$hander = mysqli_connect(
$host[$r] . (isset($port[$r]) ? ':' . $port[$r] : ':' . $port[0]),
isset($user[$r]) ? $user[$r] : $user[0],
isset($pwd[$r]) ? $pwd[$r] : $pwd[0]
);
$dbSel = mysqli_select_db(
$hander,
isset($name[$r]) ? $name[$r] : $name[0]
);
if (!$hander || !$dbSel)
return false;
$this->hander = $hander;
return true;
}
/**
* 关闭Session
* @access public
*/
public function close()
{
if (is_array($this->hander)) {
$this->gc($this->lifeTime);
return (mysqli_close($this->hander[0]) && mysqli_close($this->hander[1]));
}
$this->gc($this->lifeTime);
return mysqli_close($this->hander);
}
/**
* 读取Session
* @access public
* @param string $sessID
*/
public function read($sessID)
{
$hander = is_array($this->hander) ? $this->hander[1] : $this->hander;
$res = mysqli_query($hander, "SELECT session_data AS data FROM " . $this->sessionTable . " WHERE session_id = '$sessID' AND session_expire >" . time());
if ($res) {
$row = mysqli_fetch_assoc($res);
return $row['data'];
}
return "";
}
/**
* 写入Session
* @access public
* @param string $sessID
* @param String $sessData
*/
public function write($sessID, $sessData)
{
$hander = is_array($this->hander) ? $this->hander[0] : $this->hander;
$expire = time() + $this->lifeTime;
mysqli_query($hander, "REPLACE INTO " . $this->sessionTable . " ( session_id, session_expire, session_data) VALUES( '$sessID', '$expire', '$sessData')");
if (mysqli_affected_rows($hander))
return true;
return false;
}
/**
* 删除Session
* @access public
* @param string $sessID
*/
public function destroy($sessID)
{
$hander = is_array($this->hander) ? $this->hander[0] : $this->hander;
mysqli_query($hander, "DELETE FROM " . $this->sessionTable . " WHERE session_id = '$sessID'");
if (mysqli_affected_rows($hander))
return true;
return false;
}
/**
* Session 垃圾回收
* @access public
* @param string $sessMaxLifeTime
*/
public function gc($sessMaxLifeTime)
{
$hander = is_array($this->hander) ? $this->hander[0] : $this->hander;
mysqli_query($hander, "DELETE FROM " . $this->sessionTable . " WHERE session_expire < " . time());
return mysqli_affected_rows($hander);
}
}

View File

@@ -0,0 +1,40 @@
<?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>
// +----------------------------------------------------------------------
namespace Think;
// 分布式文件存储类
class Storage {
/**
* 操作句柄
* @var string
* @access protected
*/
static protected $handler ;
/**
* 连接分布式文件系统
* @access public
* @param string $type 文件类型
* @param array $options 配置数组
* @return void
*/
static public function connect($type='File',$options=array()) {
$class = 'Think\\Storage\\Driver\\'.ucwords($type);
self::$handler = new $class($options);
}
static public function __callstatic($method,$args){
//调用缓存驱动的方法
if(method_exists(self::$handler, $method)){
return call_user_func_array(array(self::$handler,$method), $args);
}
}
}

View File

@@ -0,0 +1,123 @@
<?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>
// +----------------------------------------------------------------------
namespace Think\Storage\Driver;
use Think\Storage;
// 本地文件写入存储类
class File extends Storage{
private $contents=array();
/**
* 架构函数
* @access public
*/
public function __construct() {
}
/**
* 文件内容读取
* @access public
* @param string $filename 文件名
* @return string
*/
public function read($filename,$type=''){
return $this->get($filename,'content',$type);
}
/**
* 文件写入
* @access public
* @param string $filename 文件名
* @param string $content 文件内容
* @return boolean
*/
public function put($filename,$content,$type=''){
$dir = dirname($filename);
if(!is_dir($dir)){
mkdir($dir,0777,true);
}
if(false === file_put_contents($filename,$content)){
E(L('_STORAGE_WRITE_ERROR_').':'.$filename);
}else{
$this->contents[$filename]=$content;
return true;
}
}
/**
* 文件追加写入
* @access public
* @param string $filename 文件名
* @param string $content 追加的文件内容
* @return boolean
*/
public function append($filename,$content,$type=''){
if(is_file($filename)){
$content = $this->read($filename,$type).$content;
}
return $this->put($filename,$content,$type);
}
/**
* 加载文件
* @access public
* @param string $filename 文件名
* @param array $vars 传入变量
* @return void
*/
public function load($_filename,$vars=null){
if(!is_null($vars)){
extract($vars, EXTR_OVERWRITE);
}
include $_filename;
}
/**
* 文件是否存在
* @access public
* @param string $filename 文件名
* @return boolean
*/
public function has($filename,$type=''){
return is_file($filename);
}
/**
* 文件删除
* @access public
* @param string $filename 文件名
* @return boolean
*/
public function unlink($filename,$type=''){
unset($this->contents[$filename]);
return is_file($filename) ? unlink($filename) : false;
}
/**
* 读取文件信息
* @access public
* @param string $filename 文件名
* @param string $name 信息名 mtime或者content
* @return boolean
*/
public function get($filename,$name,$type=''){
if(!isset($this->contents[$filename])){
if(!is_file($filename)) return false;
$this->contents[$filename]=file_get_contents($filename);
}
$content=$this->contents[$filename];
$info = array(
'mtime' => filemtime($filename),
'content' => $content
);
return $info[$name];
}
}

View File

@@ -0,0 +1,193 @@
<?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: luofei614 <weibo.com/luofei614>
// +----------------------------------------------------------------------
namespace Think\Storage\Driver;
use Think\Storage;
// SAE环境文件写入存储类
class Sae extends Storage{
/**
* 架构函数
* @access public
*/
private $mc;
private $kvs = array();
private $htmls = array();
private $contents = array();
public function __construct() {
if(!function_exists('memcache_init')){
header('Content-Type:text/html;charset=utf-8');
exit('请在SAE平台上运行代码。');
}
$this->mc = @memcache_init();
if(!$this->mc){
header('Content-Type:text/html;charset=utf-8');
exit('您未开通Memcache服务请在SAE管理平台初始化Memcache服务');
}
}
/**
* 获得SaeKv对象
*/
private function getKv(){
static $kv;
if(!$kv){
$kv = new \SaeKV();
if(!$kv->init())
E('您没有初始化KVDB请在SAE管理平台初始化KVDB服务');
}
return $kv;
}
/**
* 文件内容读取
* @access public
* @param string $filename 文件名
* @return string
*/
public function read($filename,$type=''){
switch(strtolower($type)){
case 'f':
$kv = $this->getKv();
if(!isset($this->kvs[$filename])){
$this->kvs[$filename]=$kv->get($filename);
}
return $this->kvs[$filename];
default:
return $this->get($filename,'content',$type);
}
}
/**
* 文件写入
* @access public
* @param string $filename 文件名
* @param string $content 文件内容
* @return boolean
*/
public function put($filename,$content,$type=''){
switch(strtolower($type)){
case 'f':
$kv = $this->getKv();
$this->kvs[$filename] = $content;
return $kv->set($filename,$content);
case 'html':
$kv = $this->getKv();
$content = time().$content;
$this->htmls[$filename] = $content;
return $kv->set($filename,$content);
default:
$content = time().$content;
if(!$this->mc->set($filename,$content,MEMCACHE_COMPRESSED,0)){
E(L('_STORAGE_WRITE_ERROR_').':'.$filename);
}else{
$this->contents[$filename] = $content;
return true;
}
}
}
/**
* 文件追加写入
* @access public
* @param string $filename 文件名
* @param string $content 追加的文件内容
* @return boolean
*/
public function append($filename,$content,$type=''){
if($old_content = $this->read($filename,$type)){
$content = $old_content.$content;
}
return $this->put($filename,$content,$type);
}
/**
* 加载文件
* @access public
* @param string $_filename 文件名
* @param array $vars 传入变量
* @return void
*/
public function load($_filename,$vars=null){
if(!is_null($vars))
extract($vars, EXTR_OVERWRITE);
eval('?>'.$this->read($_filename));
}
/**
* 文件是否存在
* @access public
* @param string $filename 文件名
* @return boolean
*/
public function has($filename,$type=''){
if($this->read($filename,$type)){
return true;
}else{
return false;
}
}
/**
* 文件删除
* @access public
* @param string $filename 文件名
* @return boolean
*/
public function unlink($filename,$type=''){
switch(strtolower($type)){
case 'f':
$kv = $this->getKv();
unset($this->kvs[$filename]);
return $kv->delete($filename);
case 'html':
$kv = $this->getKv();
unset($this->htmls[$filename]);
return $kv->delete($filename);
default:
unset($this->contents[$filename]);
return $this->mc->delete($filename);
}
}
/**
* 读取文件信息
* @access public
* @param string $filename 文件名
* @param string $name 信息名 mtime或者content
* @return boolean
*/
public function get($filename,$name,$type=''){
switch(strtolower($type)){
case 'html':
if(!isset($this->htmls[$filename])){
$kv = $this->getKv();
$this->htmls[$filename] = $kv->get($filename);
}
$content = $this->htmls[$filename];
break;
default:
if(!isset($this->contents[$filename])){
$this->contents[$filename] = $this->mc->get($filename);
}
$content = $this->contents[$filename];
}
if(false===$content){
return false;
}
$info = array(
'mtime' => substr($content,0,10),
'content' => substr($content,10)
);
return $info[$name];
}
}

View File

@@ -0,0 +1,700 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 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 $tagLib = array();
// 当前模板文件
protected $templateFile = '';
// 模板变量
public $tVar = array();
public $config = array();
private $literal = array();
private $block = array();
/**
* 架构函数
* @access public
*/
public function __construct(){
$this->config['cache_path'] = C('CACHE_PATH');
$this->config['template_suffix'] = C('TMPL_TEMPLATE_SUFFIX');
$this->config['cache_suffix'] = C('TMPL_CACHFILE_SUFFIX');
$this->config['tmpl_cache'] = C('TMPL_CACHE_ON');
$this->config['cache_time'] = C('TMPL_CACHE_TIME');
$this->config['taglib_begin'] = $this->stripPreg(C('TAGLIB_BEGIN'));
$this->config['taglib_end'] = $this->stripPreg(C('TAGLIB_END'));
$this->config['tmpl_begin'] = $this->stripPreg(C('TMPL_L_DELIM'));
$this->config['tmpl_end'] = $this->stripPreg(C('TMPL_R_DELIM'));
$this->config['default_tmpl'] = C('TEMPLATE_NAME');
$this->config['layout_item'] = C('TMPL_LAYOUT_ITEM');
}
private function stripPreg($str) {
return str_replace(
array('{','}','(',')','|','[',']','-','+','*','.','^','?'),
array('\{','\}','\(','\)','\|','\[','\]','\-','\+','\*','\.','\^','\?'),
$str);
}
// 模板变量获取和设置
public function get($name) {
if(isset($this->tVar[$name]))
return $this->tVar[$name];
else
return false;
}
public function set($name,$value) {
$this->tVar[$name]= $value;
}
/**
* 加载模板
* @access public
* @param string $templateFile 模板文件
* @param array $templateVar 模板变量
* @param string $prefix 模板标识前缀
* @return void
*/
public function fetch($templateFile,$templateVar,$prefix='') {
$this->tVar = $templateVar;
$templateCacheFile = $this->loadTemplate($templateFile,$prefix);
Storage::load($templateCacheFile,$this->tVar,null,'tpl');
}
/**
* 加载主模板并缓存
* @access public
* @param string $templateFile 模板文件
* @param string $prefix 模板标识前缀
* @return string
* @throws ThinkExecption
*/
public function loadTemplate ($templateFile,$prefix='') {
if(is_file($templateFile)) {
$this->templateFile = $templateFile;
// 读取模板文件内容
$tmplContent = file_get_contents($templateFile);
}else{
$tmplContent = $templateFile;
}
// 根据模版文件名定位缓存文件
$tmplCacheFile = $this->config['cache_path'].$prefix.md5($templateFile).$this->config['cache_suffix'];
// 判断是否启用布局
if(C('LAYOUT_ON')) {
if(false !== strpos($tmplContent,'{__NOLAYOUT__}')) { // 可以单独定义不使用布局
$tmplContent = str_replace('{__NOLAYOUT__}','',$tmplContent);
}else{ // 替换布局的主体内容
$layoutFile = THEME_PATH.C('LAYOUT_NAME').$this->config['template_suffix'];
// 检查布局文件
if(!is_file($layoutFile)) {
E(L('_TEMPLATE_NOT_EXIST_').':'.$layoutFile);
}
$tmplContent = str_replace($this->config['layout_item'],$tmplContent,file_get_contents($layoutFile));
}
}
// 编译模板内容
$tmplContent = $this->compiler($tmplContent);
Storage::put($tmplCacheFile,trim($tmplContent),'tpl');
return $tmplCacheFile;
}
/**
* 编译模板文件内容
* @access protected
* @param mixed $tmplContent 模板内容
* @return string
*/
protected function compiler($tmplContent) {
//模板解析
$tmplContent = $this->parse($tmplContent);
// 还原被替换的Literal标签
$tmplContent = preg_replace_callback('/<!--###literal(\d+)###-->/is', array($this, 'restoreLiteral'), $tmplContent);
// 添加安全代码
$tmplContent = '<?php if (!defined(\'THINK_PATH\')) exit();?>'.$tmplContent;
// 优化生成的php代码
$tmplContent = str_replace('?><?php','',$tmplContent);
// 模版编译过滤标签
Hook::listen('template_filter',$tmplContent);
return strip_whitespace($tmplContent);
}
/**
* 模板解析入口
* 支持普通标签和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_callback('/'.$begin.'literal'.$end.'(.*?)'.$begin.'\/literal'.$end.'/is', array($this, 'parseLiteral'),$content);
// 获取需要引入的标签库列表
// 标签库只需要定义一次,允许引入多个一次
// 一般放在文件的最前面
// 格式:<taglib name="html,mytag..." />
// 当TAGLIB_LOAD配置为true时才会进行检测
if(C('TAGLIB_LOAD')) {
$this->getIncludeTagLib($content);
if(!empty($this->tagLib)) {
// 对导入的TagLib进行解析
foreach($this->tagLib as $tagLibName) {
$this->parseTagLib($tagLibName,$content);
}
}
}
// 预先加载的标签库 无需在每个模板中使用taglib标签加载 但必须使用标签库XML前缀
if(C('TAGLIB_PRE_LOAD')) {
$tagLibs = explode(',',C('TAGLIB_PRE_LOAD'));
foreach ($tagLibs as $tag){
$this->parseTagLib($tag,$content);
}
}
// 内置标签库 无需使用taglib标签导入就可以使用 并且不需使用标签库XML前缀
$tagLibs = explode(',',C('TAGLIB_BUILD_IN'));
foreach ($tagLibs as $tag){
$this->parseTagLib($tag,$content,true);
}
//解析普通模板标签 {$tagName}
$content = preg_replace_callback('/('.$this->config['tmpl_begin'].')([^\d\w\s'.$this->config['tmpl_begin'].$this->config['tmpl_end'].'].+?)('.$this->config['tmpl_end'].')/is', array($this, 'parseTag'),$content);
return $content;
}
// 检查PHP语法
protected function parsePhp($content) {
if(ini_get('short_open_tag')){
// 开启短标签的情况要将<?标签用echo方式输出 否则无法正常输出xml标识
$content = preg_replace('/(<\?(?!php|=|$))/i', '<?php echo \'\\1\'; ?>'."\n", $content );
}
// PHP语法检查
if(C('TMPL_DENY_PHP') && false !== strpos($content,'<?php')) {
E(L('_NOT_ALLOW_PHP_'));
}
return $content;
}
// 解析模板中的布局标签
protected 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]);
if(!C('LAYOUT_ON') || C('LAYOUT_NAME') !=$array['name'] ) {
// 读取布局模板
$layoutFile = THEME_PATH.$array['name'].$this->config['template_suffix'];
$replace = isset($array['replace'])?$array['replace']:$this->config['layout_item'];
// 替换布局的主体内容
$content = str_replace($replace,$content,file_get_contents($layoutFile));
}
}else{
$content = str_replace('{__NOLAYOUT__}','',$content);
}
return $content;
}
// 解析模板中的include标签
protected function parseInclude($content, $extend = true) {
// 解析继承
if($extend)
$content = $this->parseExtend($content);
// 解析布局
$content = $this->parseLayout($content);
// 读取模板中的include标签
$find = preg_match_all('/'.$this->config['taglib_begin'].'include\s(.+?)\s*?\/'.$this->config['taglib_end'].'/is',$content,$matches);
if($find) {
for($i=0;$i<$find;$i++) {
$include = $matches[1][$i];
$array = $this->parseXmlAttrs($include);
$file = $array['file'];
unset($array['file']);
$content = str_replace($matches[0][$i],$this->parseIncludeItem($file,$array,$extend),$content);
}
}
return $content;
}
// 解析模板中的extend标签
protected function parseExtend($content) {
$begin = $this->config['taglib_begin'];
$end = $this->config['taglib_end'];
// 读取模板中的继承标签
$find = preg_match('/'.$begin.'extend\s(.+?)\s*?\/'.$end.'/is',$content,$matches);
if($find) {
//替换extend标签
$content = str_replace($matches[0],'',$content);
// 记录页面中的block标签
preg_replace_callback('/'.$begin.'block\sname=[\'"](.+?)[\'"]\s*?'.$end.'(.*?)'.$begin.'\/block'.$end.'/is', array($this, 'parseBlock'),$content);
// 读取继承模板
$array = $this->parseXmlAttrs($matches[1]);
$content = $this->parseTemplateName($array['name']);
$content = $this->parseInclude($content, false); //对继承模板中的include进行分析
// 替换block标签
$content = $this->replaceBlock($content);
}else{
$content = preg_replace_callback('/'.$begin.'block\sname=[\'"](.+?)[\'"]\s*?'.$end.'(.*?)'.$begin.'\/block'.$end.'/is', function($match){return stripslashes($match[2]);}, $content);
}
return $content;
}
/**
* 分析XML属性
* @access private
* @param string $attrs XML属性字符串
* @return array
*/
private function parseXmlAttrs($attrs) {
$xml = '<tpl><tag '.$attrs.' /></tpl>';
$xml = simplexml_load_string($xml);
if(!$xml)
E(L('_XML_TAG_ERROR_'));
$xml = (array)($xml->tag->attributes());
$array = array_change_key_case($xml['@attributes']);
return $array;
}
/**
* 替换页面中的literal标签
* @access private
* @param string $content 模板内容
* @return string|false
*/
private function parseLiteral($content) {
if(is_array($content)) $content = $content[1];
if(trim($content)=='') return '';
//$content = stripslashes($content);
$i = count($this->literal);
$parseStr = "<!--###literal{$i}###-->";
$this->literal[$i] = $content;
return $parseStr;
}
/**
* 还原被替换的literal标签
* @access private
* @param string $tag literal标签序号
* @return string|false
*/
private function restoreLiteral($tag) {
if(is_array($tag)) $tag = $tag[1];
// 还原literal标签
$parseStr = $this->literal[$tag];
// 销毁literal记录
unset($this->literal[$tag]);
return $parseStr;
}
/**
* 记录当前页面中的block标签
* @access private
* @param string $name block名称
* @param string $content 模板内容
* @return string
*/
private function parseBlock($name,$content = '') {
if(is_array($name)){
$content = $name[2];
$name = $name[1];
}
$this->block[$name] = $content;
return '';
}
/**
* 替换继承模板中的block标签
* @access private
* @param string $content 模板内容
* @return string
*/
private function replaceBlock($content){
static $parse = 0;
$begin = $this->config['taglib_begin'];
$end = $this->config['taglib_end'];
$reg = '/('.$begin.'block\sname=[\'"](.+?)[\'"]\s*?'.$end.')(.*?)'.$begin.'\/block'.$end.'/is';
if(is_string($content)){
do{
$content = preg_replace_callback($reg, array($this, 'replaceBlock'), $content);
} while ($parse && $parse--);
return $content;
} elseif(is_array($content)){
if(preg_match('/'.$begin.'block\sname=[\'"](.+?)[\'"]\s*?'.$end.'/is', $content[3])){ //存在嵌套,进一步解析
$parse = 1;
$content[3] = preg_replace_callback($reg, array($this, 'replaceBlock'), "{$content[3]}{$begin}/block{$end}");
return $content[1] . $content[3];
} else {
$name = $content[2];
$content = $content[3];
$content = isset($this->block[$name]) ? $this->block[$name] : $content;
return $content;
}
}
}
/**
* 搜索模板页面中包含的TagLib库
* 并返回列表
* @access public
* @param string $content 模板内容
* @return string|false
*/
public function getIncludeTagLib(& $content) {
//搜索是否有TagLib标签
$find = preg_match('/'.$this->config['taglib_begin'].'taglib\s(.+?)(\s*?)\/'.$this->config['taglib_end'].'\W/is',$content,$matches);
if($find) {
//替换TagLib标签
$content = str_replace($matches[0],'',$content);
//解析TagLib标签
$array = $this->parseXmlAttrs($matches[1]);
$this->tagLib = explode(',',$array['name']);
}
return;
}
/**
* TagLib库解析
* @access public
* @param string $tagLib 要解析的标签库
* @param string $content 要解析的模板内容
* @param boolean $hide 是否隐藏标签库前缀
* @return string
*/
public function parseTagLib($tagLib,&$content,$hide=false) {
$begin = $this->config['taglib_begin'];
$end = $this->config['taglib_end'];
if(strpos($tagLib,'\\')){
// 支持指定标签库的命名空间
$className = $tagLib;
$tagLib = substr($tagLib,strrpos($tagLib,'\\')+1);
}else{
$className = 'Think\\Template\TagLib\\'.ucwords($tagLib);
}
$tLib = \Think\Think::instance($className);
$that = $this;
foreach ($tLib->getTags() as $name=>$val){
$tags = array($name);
if(isset($val['alias'])) {// 别名设置
$tags = explode(',',$val['alias']);
$tags[] = $name;
}
$level = isset($val['level'])?$val['level']:1;
$closeTag = isset($val['close'])?$val['close']:true;
foreach ($tags as $tag){
$parseTag = !$hide? $tagLib.':'.$tag: $tag;// 实际要解析的标签名称
if(!method_exists($tLib,'_'.$tag)) {
// 别名可以无需定义解析方法
$tag = $name;
}
$n1 = empty($val['attr'])?'(\s*?)':'\s([^'.$end.']*)';
$this->tempVar = array($tagLib, $tag);
if (!$closeTag){
$patterns = '/'.$begin.$parseTag.$n1.'\/(\s*?)'.$end.'/is';
$content = preg_replace_callback($patterns, function($matches) use($tLib,$tag,$that){
return $that->parseXmlTag($tLib,$tag,$matches[1],$matches[2]);
},$content);
}else{
$patterns = '/'.$begin.$parseTag.$n1.$end.'(.*?)'.$begin.'\/'.$parseTag.'(\s*?)'.$end.'/is';
for($i=0;$i<$level;$i++) {
$content=preg_replace_callback($patterns,function($matches) use($tLib,$tag,$that){
return $that->parseXmlTag($tLib,$tag,$matches[1],$matches[2]);
},$content);
}
}
}
}
}
/**
* 解析标签库的标签
* 需要调用对应的标签库文件解析类
* @access public
* @param object $tagLib 标签库对象实例
* @param string $tag 标签名
* @param string $attr 标签属性
* @param string $content 标签内容
* @return string|false
*/
public function parseXmlTag($tagLib,$tag,$attr,$content) {
if(ini_get('magic_quotes_sybase'))
$attr = str_replace('\"','\'',$attr);
$parse = '_'.$tag;
$content = trim($content);
$tags = $tagLib->parseXmlAttr($attr,$tag);
return $tagLib->$parse($tags,$content);
}
/**
* 模板标签解析
* 格式: {TagName:args [|content] }
* @access public
* @param string $tagStr 标签内容
* @return string
*/
public function parseTag($tagStr){
if(is_array($tagStr)) $tagStr = $tagStr[2];
//if (MAGIC_QUOTES_GPC) {
$tagStr = stripslashes($tagStr);
//}
$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(rtrim($tagStr),-2)=='*/')){
//注释标签
return '';
}
// 未识别的标签直接返回
return C('TMPL_L_DELIM') . $tagStr .C('TMPL_R_DELIM');
}
/**
* 模板变量解析,支持使用函数
* 格式: {$varname|function1|function2=arg1,arg2}
* @access public
* @param string $varStr 变量数据
* @return string
*/
public function parseVar($varStr){
$varStr = trim($varStr);
static $_varParseList = array();
//如果已经解析过该变量字串,则直接返回变量值
if(isset($_varParseList[$varStr])) return $_varParseList[$varStr];
$parseStr = '';
$varExists = true;
if(!empty($varStr)){
$varArray = explode('|',$varStr);
//取得变量名称
$var = array_shift($varArray);
if('Think.' == substr($var,0,6)){
// 所有以Think.打头的以特殊变量对待 无需模板赋值就可以输出
$name = $this->parseThinkVar($var);
}elseif( false !== strpos($var,'.')) {
//支持 {$var.property}
$vars = explode('.',$var);
$var = array_shift($vars);
switch(strtolower(C('TMPL_VAR_IDENTIFY'))) {
case 'array': // 识别为数组
$name = '$'.$var;
foreach ($vars as $key=>$val)
$name .= '["'.$val.'"]';
break;
case 'obj': // 识别为对象
$name = '$'.$var;
foreach ($vars as $key=>$val)
$name .= '->'.$val;
break;
default: // 自动判断数组或对象 只支持二维
$name = 'is_array($'.$var.')?$'.$var.'["'.$vars[0].'"]:$'.$var.'->'.$vars[0];
}
}elseif(false !== strpos($var,'[')) {
//支持 {$var['key']} 方式输出数组
$name = "$".$var;
preg_match('/(.+?)\[(.+?)\]/is',$var,$match);
$var = $match[1];
}elseif(false !==strpos($var,':') && false ===strpos($var,'(') && false ===strpos($var,'::') && false ===strpos($var,'?')){
//支持 {$var:property} 方式输出对象的属性
$vars = explode(':',$var);
$var = str_replace(':','->',$var);
$name = "$".$var;
$var = $vars[0];
}else {
$name = "$$var";
}
//对变量使用函数
if(count($varArray)>0)
$name = $this->parseVarFunction($name,$varArray);
$parseStr = '<?php echo ('.$name.'); ?>';
}
$_varParseList[$varStr] = $parseStr;
return $parseStr;
}
/**
* 对模板变量使用函数
* 格式 {$varname|function1|function2=arg1,arg2}
* @access public
* @param string $name 变量名
* @param array $varArray 函数列表
* @return string
*/
public function parseVarFunction($name,$varArray){
//对变量使用函数
$length = count($varArray);
//取得模板禁止使用函数列表
$template_deny_funs = explode(',',C('TMPL_DENY_FUNC_LIST'));
for($i=0;$i<$length ;$i++ ){
$args = explode('=',$varArray[$i],2);
//模板函数过滤
$fun = trim($args[0]);
switch($fun) {
case 'default': // 特殊模板函数
$name = '(isset('.$name.') && ('.$name.' !== ""))?('.$name.'):'.$args[1];
break;
default: // 通用模板函数
if(!in_array($fun,$template_deny_funs)){
if(isset($args[1])){
if(strstr($args[1],'###')){
$args[1] = str_replace('###',$name,$args[1]);
$name = "$fun($args[1])";
}else{
$name = "$fun($name,$args[1])";
}
}else if(!empty($args[0])){
$name = "$fun($name)";
}
}
}
}
return $name;
}
/**
* 特殊模板变量解析
* 格式 以 $Think. 打头的变量属于特殊模板变量
* @access public
* @param string $varStr 变量字符串
* @return string
*/
public function parseThinkVar($varStr){
$vars = explode('.',$varStr);
$vars[1] = strtoupper(trim($vars[1]));
$parseStr = '';
if(count($vars)>=3){
$vars[2] = trim($vars[2]);
switch($vars[1]){
case 'SERVER':
$parseStr = '$_SERVER[\''.strtoupper($vars[2]).'\']';break;
case 'GET':
$parseStr = '$_GET[\''.$vars[2].'\']';break;
case 'POST':
$parseStr = '$_POST[\''.$vars[2].'\']';break;
case 'COOKIE':
if(isset($vars[3])) {
$parseStr = '$_COOKIE[\''.$vars[2].'\'][\''.$vars[3].'\']';
}else{
$parseStr = 'cookie(\''.$vars[2].'\')';
}
break;
case 'SESSION':
if(isset($vars[3])) {
$parseStr = '$_SESSION[\''.$vars[2].'\'][\''.$vars[3].'\']';
}else{
$parseStr = 'session(\''.$vars[2].'\')';
}
break;
case 'ENV':
$parseStr = '$_ENV[\''.strtoupper($vars[2]).'\']';break;
case 'REQUEST':
$parseStr = '$_REQUEST[\''.$vars[2].'\']';break;
case 'CONST':
$parseStr = strtoupper($vars[2]);break;
case 'LANG':
$parseStr = 'L("'.$vars[2].'")';break;
case 'CONFIG':
if(isset($vars[3])) {
$vars[2] .= '.'.$vars[3];
}
$parseStr = 'C("'.$vars[2].'")';break;
default:break;
}
}else if(count($vars)==2){
switch($vars[1]){
case 'NOW':
$parseStr = "date('Y-m-d g:i a',time())";
break;
case 'VERSION':
$parseStr = 'THINK_VERSION';
break;
case 'TEMPLATE':
$parseStr = "'".$this->templateFile."'";//'C("TEMPLATE_NAME")';
break;
case 'LDELIM':
$parseStr = 'C("TMPL_L_DELIM")';
break;
case 'RDELIM':
$parseStr = 'C("TMPL_R_DELIM")';
break;
default:
if(defined($vars[1]))
$parseStr = $vars[1];
}
}
return $parseStr;
}
/**
* 加载公共模板并缓存 和当前模板在同一路径,否则使用相对路径
* @access private
* @param string $tmplPublicName 公共模板文件名
* @param array $vars 要传递的变量列表
* @return string
*/
private function parseIncludeItem($tmplPublicName,$vars=array(),$extend){
// 分析模板文件名并读取内容
$parseStr = $this->parseTemplateName($tmplPublicName);
// 替换变量
foreach ($vars as $key=>$val) {
$parseStr = str_replace('['.$key.']',$val,$parseStr);
}
// 再次对包含文件进行模板分析
return $this->parseInclude($parseStr,$extend);
}
/**
* 分析加载的模板文件并读取内容 支持多个模板文件读取
* @access private
* @param string $tmplPublicName 模板文件名
* @return string
*/
private function parseTemplateName($templateName){
if(substr($templateName,0,1)=='$')
//支持加载变量文件名
$templateName = $this->get(substr($templateName,1));
$array = explode(',',$templateName);
$parseStr = '';
foreach ($array as $templateName){
if(empty($templateName)) continue;
if(false === strpos($templateName,$this->config['template_suffix'])) {
// 解析规则为 模块@主题/控制器/操作
$templateName = T($templateName);
}
// 获取模板文件内容
$parseStr .= file_get_contents($templateName);
}
return $parseStr;
}
}

View File

@@ -0,0 +1,41 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
namespace Think\Template\Driver;
/**
* EaseTemplate模板引擎驱动
*/
class Ease {
/**
* 渲染模板输出
* @access public
* @param string $templateFile 模板文件名
* @param array $var 模板变量
* @return void
*/
public function fetch($templateFile,$var) {
$templateFile = substr($templateFile,strlen(THEME_PATH),-5);
$CacheDir = substr(CACHE_PATH,0,-1);
$TemplateDir = substr(THEME_PATH,0,-1);
vendor('EaseTemplate.template#ease');
$config = array(
'CacheDir' => $CacheDir,
'TemplateDir' => $TemplateDir,
'TplType' => 'html'
);
if(C('TMPL_ENGINE_CONFIG')) {
$config = array_merge($config,C('TMPL_ENGINE_CONFIG'));
}
$tpl = new \EaseTemplate($config);
$tpl->set_var($var);
$tpl->set_file($templateFile);
$tpl->p();
}
}

View File

@@ -0,0 +1,39 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
namespace Think\Template\Driver;
/**
* TemplateLite模板引擎驱动
*/
class Lite {
/**
* 渲染模板输出
* @access public
* @param string $templateFile 模板文件名
* @param array $var 模板变量
* @return void
*/
public function fetch($templateFile,$var) {
vendor("TemplateLite.class#template");
$templateFile = substr($templateFile,strlen(THEME_PATH));
$tpl = new \Template_Lite();
$tpl->template_dir = THEME_PATH;
$tpl->compile_dir = CACHE_PATH ;
$tpl->cache_dir = TEMP_PATH ;
if(C('TMPL_ENGINE_CONFIG')) {
$config = C('TMPL_ENGINE_CONFIG');
foreach ($config as $key=>$val){
$tpl->{$key} = $val;
}
}
$tpl->assign($var);
$tpl->display($templateFile);
}
}

View File

@@ -0,0 +1,28 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: luofei614<weibo.com/luofei614>
// +----------------------------------------------------------------------
namespace Think\Template\Driver;
/**
* MobileTemplate模板引擎驱动
*/
class Mobile {
/**
* 渲染模板输出
* @access public
* @param string $templateFile 模板文件名
* @param array $var 模板变量
* @return void
*/
public function fetch($templateFile,$var) {
$templateFile=substr($templateFile,strlen(THEME_PATH));
$var['_think_template_path']=$templateFile;
exit(json_encode($var));
}
}

View File

@@ -0,0 +1,40 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
namespace Think\Template\Driver;
/**
* Smart模板引擎驱动
*/
class Smart {
/**
* 渲染模板输出
* @access public
* @param string $templateFile 模板文件名
* @param array $var 模板变量
* @return void
*/
public function fetch($templateFile,$var) {
$templateFile = substr($templateFile,strlen(THEME_PATH));
vendor('SmartTemplate.class#smarttemplate');
$tpl = new \SmartTemplate($templateFile);
$tpl->caching = C('TMPL_CACHE_ON');
$tpl->template_dir = THEME_PATH;
$tpl->compile_dir = CACHE_PATH ;
$tpl->cache_dir = TEMP_PATH ;
if(C('TMPL_ENGINE_CONFIG')) {
$config = C('TMPL_ENGINE_CONFIG');
foreach ($config as $key=>$val){
$tpl->{$key} = $val;
}
}
$tpl->assign($var);
$tpl->output();
}
}

View File

@@ -0,0 +1,41 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
namespace Think\Template\Driver;
/**
* Smarty模板引擎驱动
*/
class Smarty {
/**
* 渲染模板输出
* @access public
* @param string $templateFile 模板文件名
* @param array $var 模板变量
* @return void
*/
public function fetch($templateFile,$var) {
$templateFile = substr($templateFile,strlen(THEME_PATH));
vendor('Smarty.Smarty#class');
$tpl = new \Smarty();
$tpl->caching = C('TMPL_CACHE_ON');
$tpl->template_dir = THEME_PATH;
$tpl->compile_dir = CACHE_PATH ;
$tpl->cache_dir = TEMP_PATH ;
if(C('TMPL_ENGINE_CONFIG')) {
$config = C('TMPL_ENGINE_CONFIG');
foreach ($config as $key=>$val){
$tpl->{$key} = $val;
}
}
$tpl->assign($var);
$tpl->display($templateFile);
}
}

View File

@@ -0,0 +1,246 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
namespace Think\Template;
/**
* ThinkPHP标签库TagLib解析基类
*/
class TagLib {
/**
* 标签库定义XML文件
* @var string
* @access protected
*/
protected $xml = '';
protected $tags = array();// 标签定义
/**
* 标签库名称
* @var string
* @access protected
*/
protected $tagLib ='';
/**
* 标签库标签列表
* @var string
* @access protected
*/
protected $tagList = array();
/**
* 标签库分析数组
* @var string
* @access protected
*/
protected $parse = array();
/**
* 标签库是否有效
* @var string
* @access protected
*/
protected $valid = false;
/**
* 当前模板对象
* @var object
* @access protected
*/
protected $tpl;
protected $comparison = array(' nheq '=>' !== ',' heq '=>' === ',' neq '=>' != ',' eq '=>' == ',' egt '=>' >= ',' gt '=>' > ',' elt '=>' <= ',' lt '=>' < ');
/**
* 架构函数
* @access public
*/
public function __construct() {
$this->tagLib = strtolower(substr(get_class($this),6));
$this->tpl = \Think\Think::instance('Think\\Template');
}
/**
* TagLib标签属性分析 返回标签属性数组
* @access public
* @param string $tagStr 标签内容
* @return array
*/
public function parseXmlAttr($attr,$tag) {
//XML解析安全过滤
$attr = str_replace('&','___', $attr);
$xml = '<tpl><tag '.$attr.' /></tpl>';
$xml = simplexml_load_string($xml);
if(!$xml) {
E(L('_XML_TAG_ERROR_').' : '.$attr);
}
$xml = (array)($xml->tag->attributes());
if(isset($xml['@attributes'])){
$array = array_change_key_case($xml['@attributes']);
if($array) {
$tag = strtolower($tag);
if(!isset($this->tags[$tag])){
// 检测是否存在别名定义
foreach($this->tags as $key=>$val){
if(isset($val['alias']) && in_array($tag,explode(',',$val['alias']))){
$item = $val;
break;
}
}
}else{
$item = $this->tags[$tag];
}
$attrs = explode(',',$item['attr']);
if(isset($item['must'])){
$must = explode(',',$item['must']);
}else{
$must = array();
}
foreach($attrs as $name) {
if( isset($array[$name])) {
$array[$name] = str_replace('___','&',$array[$name]);
}elseif(false !== array_search($name,$must)){
E(L('_PARAM_ERROR_').':'.$name);
}
}
return $array;
}
}else{
return array();
}
}
/**
* 解析条件表达式
* @access public
* @param string $condition 表达式标签内容
* @return array
*/
public function parseCondition($condition) {
$condition = str_ireplace(array_keys($this->comparison),array_values($this->comparison),$condition);
$condition = preg_replace('/\$(\w+):(\w+)\s/is','$\\1->\\2 ',$condition);
switch(strtolower(C('TMPL_VAR_IDENTIFY'))) {
case 'array': // 识别为数组
$condition = preg_replace('/\$(\w+)\.(\w+)\s/is','$\\1["\\2"] ',$condition);
break;
case 'obj': // 识别为对象
$condition = preg_replace('/\$(\w+)\.(\w+)\s/is','$\\1->\\2 ',$condition);
break;
default: // 自动判断数组或对象 只支持二维
$condition = preg_replace('/\$(\w+)\.(\w+)\s/is','(is_array($\\1)?$\\1["\\2"]:$\\1->\\2) ',$condition);
}
if(false !== strpos($condition, '$Think'))
$condition = preg_replace_callback('/(\$Think.*?)\s/is', array($this, 'parseThinkVar'), $condition);
return $condition;
}
/**
* 自动识别构建变量
* @access public
* @param string $name 变量描述
* @return string
*/
public function autoBuildVar($name) {
if('Think.' == substr($name,0,6)){
// 特殊变量
return $this->parseThinkVar($name);
}elseif(strpos($name,'.')) {
$vars = explode('.',$name);
$var = array_shift($vars);
switch(strtolower(C('TMPL_VAR_IDENTIFY'))) {
case 'array': // 识别为数组
$name = '$'.$var;
foreach ($vars as $key=>$val){
if(0===strpos($val,'$')) {
$name .= '["{'.$val.'}"]';
}else{
$name .= '["'.$val.'"]';
}
}
break;
case 'obj': // 识别为对象
$name = '$'.$var;
foreach ($vars as $key=>$val)
$name .= '->'.$val;
break;
default: // 自动判断数组或对象 只支持二维
$name = 'is_array($'.$var.')?$'.$var.'["'.$vars[0].'"]:$'.$var.'->'.$vars[0];
}
}elseif(strpos($name,':')){
// 额外的对象方式支持
$name = '$'.str_replace(':','->',$name);
}elseif(!defined($name)) {
$name = '$'.$name;
}
return $name;
}
/**
* 用于标签属性里面的特殊模板变量解析
* 格式 以 Think. 打头的变量属于特殊模板变量
* @access public
* @param string $varStr 变量字符串
* @return string
*/
public function parseThinkVar($varStr){
if(is_array($varStr)){//用于正则替换回调函数
$varStr = $varStr[1];
}
$vars = explode('.',$varStr);
$vars[1] = strtoupper(trim($vars[1]));
$parseStr = '';
if(count($vars)>=3){
$vars[2] = trim($vars[2]);
switch($vars[1]){
case 'SERVER': $parseStr = '$_SERVER[\''.$vars[2].'\']';break;
case 'GET': $parseStr = '$_GET[\''.$vars[2].'\']';break;
case 'POST': $parseStr = '$_POST[\''.$vars[2].'\']';break;
case 'COOKIE':
if(isset($vars[3])) {
$parseStr = '$_COOKIE[\''.$vars[2].'\'][\''.$vars[3].'\']';
}elseif(C('COOKIE_PREFIX')){
$parseStr = '$_COOKIE[\''.C('COOKIE_PREFIX').$vars[2].'\']';
}else{
$parseStr = '$_COOKIE[\''.$vars[2].'\']';
}
break;
case 'SESSION':
if(isset($vars[3])) {
$parseStr = '$_SESSION[\''.$vars[2].'\'][\''.$vars[3].'\']';
}elseif(C('SESSION_PREFIX')){
$parseStr = '$_SESSION[\''.C('SESSION_PREFIX').'\'][\''.$vars[2].'\']';
}else{
$parseStr = '$_SESSION[\''.$vars[2].'\']';
}
break;
case 'ENV': $parseStr = '$_ENV[\''.$vars[2].'\']';break;
case 'REQUEST': $parseStr = '$_REQUEST[\''.$vars[2].'\']';break;
case 'CONST': $parseStr = strtoupper($vars[2]);break;
case 'LANG': $parseStr = 'L("'.$vars[2].'")';break;
case 'CONFIG': $parseStr = 'C("'.$vars[2].'")';break;
}
}else if(count($vars)==2){
switch($vars[1]){
case 'NOW': $parseStr = "date('Y-m-d g:i a',time())";break;
case 'VERSION': $parseStr = 'THINK_VERSION';break;
case 'TEMPLATE':$parseStr = 'C("TEMPLATE_NAME")';break;
case 'LDELIM': $parseStr = 'C("TMPL_L_DELIM")';break;
case 'RDELIM': $parseStr = 'C("TMPL_R_DELIM")';break;
default: if(defined($vars[1])) $parseStr = $vars[1];
}
}
return $parseStr;
}
// 获取标签定义
public function getTags(){
return $this->tags;
}
}

View File

@@ -0,0 +1,614 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 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标签库解析类
*/
class Cx extends TagLib {
// 标签定义
protected $tags = array(
// 标签定义: attr 属性列表 close 是否闭合0 或者1 默认1 alias 标签别名 level 嵌套层次
'php' => array(),
'volist' => array('attr'=>'name,id,offset,length,key,mod','level'=>3,'alias'=>'iterate'),
'foreach' => array('attr'=>'name,item,key','level'=>3),
'if' => array('attr'=>'condition','level'=>2),
'elseif' => array('attr'=>'condition','close'=>0),
'else' => array('attr'=>'','close'=>0),
'switch' => array('attr'=>'name','level'=>2),
'case' => array('attr'=>'value,break'),
'default' => array('attr'=>'','close'=>0),
'compare' => array('attr'=>'name,value,type','level'=>3,'alias'=>'eq,equal,notequal,neq,gt,lt,egt,elt,heq,nheq'),
'range' => array('attr'=>'name,value,type','level'=>3,'alias'=>'in,notin,between,notbetween'),
'empty' => array('attr'=>'name','level'=>3),
'notempty' => array('attr'=>'name','level'=>3),
'present' => array('attr'=>'name','level'=>3),
'notpresent'=> array('attr'=>'name','level'=>3),
'defined' => array('attr'=>'name','level'=>3),
'notdefined'=> array('attr'=>'name','level'=>3),
'import' => array('attr'=>'file,href,type,value,basepath','close'=>0,'alias'=>'load,css,js'),
'assign' => array('attr'=>'name,value','close'=>0),
'define' => array('attr'=>'name,value','close'=>0),
'for' => array('attr'=>'start,end,name,comparison,step', 'level'=>3),
);
/**
* php标签解析
* @access public
* @param 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 .= $this->tpl->parse($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 .= $this->tpl->parse($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->tpl->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->tpl->parseVarFunction($value,$varArray);
$value = 'case '.$value.': ';
}elseif(strpos($value,'|')){
$values = explode('|',$value);
$value = '';
foreach ($values as $val){
$value .= 'case "'.addslashes($val).'": ';
}
}else{
$value = 'case "'.$value.'": ';
}
$parseStr = '<?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->tpl->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->tpl->parseVarFunction($name,$varArray);
$type = isset($tag['type'])?$tag['type']:$type;
if('$' == substr($value,0,1)) {
$value = $this->autoBuildVar(substr($value,1));
$str = 'is_array('.$value.')?'.$value.':explode(\',\','.$value.')';
}else{
$value = '"'.$value.'"';
$str = 'explode(\',\','.$value.')';
}
if($type=='between') {
$parseStr = '<?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> $attr
* @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->tpl->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){
if(strpos ($val, '?')) {
list($val,$version) = explode('?',$val);
} else {
$version = '';
}
switch($type) {
case 'js':
$parseStr .= '<script type="text/javascript" src="'.$basepath.'/'.str_replace(array('.','#'), array('/','.'),$val).'.js'.($version?'?'.$version:'').'"></script>';
break;
case 'css':
$parseStr .= '<link rel="stylesheet" type="text/css" href="'.$basepath.'/'.str_replace(array('.','#'), array('/','.'),$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;
}
}

View File

@@ -0,0 +1,523 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 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;
/**
* Html标签库驱动
*/
class Html extends TagLib{
// 标签定义
protected $tags = array(
// 标签定义: attr 属性列表 close 是否闭合0 或者1 默认1 alias 标签别名 level 嵌套层次
'editor' => array('attr'=>'id,name,style,width,height,type','close'=>1),
'select' => array('attr'=>'name,options,values,output,multiple,id,size,first,change,selected,dblclick','close'=>0),
'grid' => array('attr'=>'id,pk,style,action,actionlist,show,datasource','close'=>0),
'list' => array('attr'=>'id,pk,style,action,actionlist,show,datasource,checkbox','close'=>0),
'imagebtn' => array('attr'=>'id,name,value,type,style,click','close'=>0),
'checkbox' => array('attr'=>'name,checkboxes,checked,separator','close'=>0),
'radio' => array('attr'=>'name,radios,checked,separator','close'=>0)
);
/**
* editor标签解析 插入可视化编辑器
* 格式: <html:editor id="editor" name="remark" type="FCKeditor" style="" >{$vo.remark}</html:editor>
* @access public
* @param array $tag 标签属性
* @return string|void
*/
public function _editor($tag,$content) {
$id = !empty($tag['id'])?$tag['id']: '_editor';
$name = $tag['name'];
$style = !empty($tag['style'])?$tag['style']:'';
$width = !empty($tag['width'])?$tag['width']: '100%';
$height = !empty($tag['height'])?$tag['height'] :'320px';
// $content = $tag['content'];
$type = $tag['type'] ;
switch(strtoupper($type)) {
case 'FCKEDITOR':
$parseStr = '<!-- 编辑器调用开始 --><script type="text/javascript" src="__ROOT__/Public/Js/FCKeditor/fckeditor.js"></script><textarea id="'.$id.'" name="'.$name.'">'.$content.'</textarea><script type="text/javascript"> var oFCKeditor = new FCKeditor( "'.$id.'","'.$width.'","'.$height.'" ) ; oFCKeditor.BasePath = "__ROOT__/Public/Js/FCKeditor/" ; oFCKeditor.ReplaceTextarea() ;function resetEditor(){setContents("'.$id.'",document.getElementById("'.$id.'").value)}; function saveEditor(){document.getElementById("'.$id.'").value = getContents("'.$id.'");} function InsertHTML(html){ var oEditor = FCKeditorAPI.GetInstance("'.$id.'") ;if (oEditor.EditMode == FCK_EDITMODE_WYSIWYG ){oEditor.InsertHtml(html) ;}else alert( "FCK必须处于WYSIWYG模式!" ) ;}</script> <!-- 编辑器调用结束 -->';
break;
case 'FCKMINI':
$parseStr = '<!-- 编辑器调用开始 --><script type="text/javascript" src="__ROOT__/Public/Js/FCKMini/fckeditor.js"></script><textarea id="'.$id.'" name="'.$name.'">'.$content.'</textarea><script type="text/javascript"> var oFCKeditor = new FCKeditor( "'.$id.'","'.$width.'","'.$height.'" ) ; oFCKeditor.BasePath = "__ROOT__/Public/Js/FCKMini/" ; oFCKeditor.ReplaceTextarea() ;function resetEditor(){setContents("'.$id.'",document.getElementById("'.$id.'").value)}; function saveEditor(){document.getElementById("'.$id.'").value = getContents("'.$id.'");} function InsertHTML(html){ var oEditor = FCKeditorAPI.GetInstance("'.$id.'") ;if (oEditor.EditMode == FCK_EDITMODE_WYSIWYG ){oEditor.InsertHtml(html) ;}else alert( "FCK必须处于WYSIWYG模式!" ) ;}</script> <!-- 编辑器调用结束 -->';
break;
case 'EWEBEDITOR':
$parseStr = "<!-- 编辑器调用开始 --><script type='text/javascript' src='__ROOT__/Public/Js/eWebEditor/js/edit.js'></script><input type='hidden' id='{$id}' name='{$name}' value='{$conent}'><iframe src='__ROOT__/Public/Js/eWebEditor/ewebeditor.htm?id={$name}' frameborder=0 scrolling=no width='{$width}' height='{$height}'></iframe><script type='text/javascript'>function saveEditor(){document.getElementById('{$id}').value = getHTML();} </script><!-- 编辑器调用结束 -->";
break;
case 'NETEASE':
$parseStr = '<!-- 编辑器调用开始 --><textarea id="'.$id.'" name="'.$name.'" style="display:none">'.$content.'</textarea><iframe ID="Editor" name="Editor" src="__ROOT__/Public/Js/HtmlEditor/index.html?ID='.$name.'" frameBorder="0" marginHeight="0" marginWidth="0" scrolling="No" style="height:'.$height.';width:'.$width.'"></iframe><!-- 编辑器调用结束 -->';
break;
case 'UBB':
$parseStr = '<script type="text/javascript" src="__ROOT__/Public/Js/UbbEditor.js"></script><div style="padding:1px;width:'.$width.';border:1px solid silver;float:left;"><script LANGUAGE="JavaScript"> showTool(); </script></div><div><TEXTAREA id="UBBEditor" name="'.$name.'" style="clear:both;float:none;width:'.$width.';height:'.$height.'" >'.$content.'</TEXTAREA></div><div style="padding:1px;width:'.$width.';border:1px solid silver;float:left;"><script LANGUAGE="JavaScript">showEmot(); </script></div>';
break;
case 'KINDEDITOR':
$parseStr = '<script type="text/javascript" src="__ROOT__/Public/Js/KindEditor/kindeditor.js"></script><script type="text/javascript"> KE.show({ id : \''.$id.'\' ,urlType : "absolute"});</script><textarea id="'.$id.'" style="'.$style.'" name="'.$name.'" >'.$content.'</textarea>';
break;
default :
$parseStr = '<textarea id="'.$id.'" style="'.$style.'" name="'.$name.'" >'.$content.'</textarea>';
}
return $parseStr;
}
/**
* imageBtn标签解析
* 格式: <html:imageBtn type="" value="" />
* @access public
* @param array $tag 标签属性
* @return string|void
*/
public function _imageBtn($tag) {
$name = $tag['name']; //名称
$value = $tag['value']; //文字
$id = isset($tag['id'])?$tag['id']:''; //ID
$style = isset($tag['style'])?$tag['style']:''; //样式名
$click = isset($tag['click'])?$tag['click']:''; //点击
$type = empty($tag['type'])?'button':$tag['type']; //按钮类型
if(!empty($name)) {
$parseStr = '<div class="'.$style.'" ><input type="'.$type.'" id="'.$id.'" name="'.$name.'" value="'.$value.'" onclick="'.$click.'" class="'.$name.' imgButton"></div>';
}else {
$parseStr = '<div class="'.$style.'" ><input type="'.$type.'" id="'.$id.'" name="'.$name.'" value="'.$value.'" onclick="'.$click.'" class="button"></div>';
}
return $parseStr;
}
/**
* imageLink标签解析
* 格式: <html:imageLink type="" value="" />
* @access public
* @param array $tag 标签属性
* @return string|void
*/
public function _imgLink($tag) {
$name = $tag['name']; //名称
$alt = $tag['alt']; //文字
$id = $tag['id']; //ID
$style = $tag['style']; //样式名
$click = $tag['click']; //点击
$type = $tag['type']; //点击
if(empty($type)) {
$type = 'button';
}
$parseStr = '<span class="'.$style.'" ><input title="'.$alt.'" type="'.$type.'" id="'.$id.'" name="'.$name.'" onmouseover="this.style.filter=\'alpha(opacity=100)\'" onmouseout="this.style.filter=\'alpha(opacity=80)\'" onclick="'.$click.'" align="absmiddle" class="'.$name.' imgLink"></span>';
return $parseStr;
}
/**
* select标签解析
* 格式: <html:select options="name" selected="value" />
* @access public
* @param array $tag 标签属性
* @return string|void
*/
public function _select($tag) {
$name = $tag['name'];
$options = $tag['options'];
$values = $tag['values'];
$output = $tag['output'];
$multiple = $tag['multiple'];
$id = $tag['id'];
$size = $tag['size'];
$first = $tag['first'];
$selected = $tag['selected'];
$style = $tag['style'];
$ondblclick = $tag['dblclick'];
$onchange = $tag['change'];
if(!empty($multiple)) {
$parseStr = '<select id="'.$id.'" name="'.$name.'" ondblclick="'.$ondblclick.'" onchange="'.$onchange.'" multiple="multiple" class="'.$style.'" size="'.$size.'" >';
}else {
$parseStr = '<select id="'.$id.'" name="'.$name.'" onchange="'.$onchange.'" ondblclick="'.$ondblclick.'" class="'.$style.'" >';
}
if(!empty($first)) {
$parseStr .= '<option value="" >'.$first.'</option>';
}
if(!empty($options)) {
$parseStr .= '<?php foreach($'.$options.' as $key=>$val) { ?>';
if(!empty($selected)) {
$parseStr .= '<?php if(!empty($'.$selected.') && ($'.$selected.' == $key || in_array($key,$'.$selected.'))) { ?>';
$parseStr .= '<option selected="selected" value="<?php echo $key ?>"><?php echo $val ?></option>';
$parseStr .= '<?php }else { ?><option value="<?php echo $key ?>"><?php echo $val ?></option>';
$parseStr .= '<?php } ?>';
}else {
$parseStr .= '<option value="<?php echo $key ?>"><?php echo $val ?></option>';
}
$parseStr .= '<?php } ?>';
}else if(!empty($values)) {
$parseStr .= '<?php for($i=0;$i<count($'.$values.');$i++) { ?>';
if(!empty($selected)) {
$parseStr .= '<?php if(isset($'.$selected.') && ((is_string($'.$selected.') && $'.$selected.' == $'.$values.'[$i]) || (is_array($'.$selected.') && in_array($'.$values.'[$i],$'.$selected.')))) { ?>';
$parseStr .= '<option selected="selected" value="<?php echo $'.$values.'[$i] ?>"><?php echo $'.$output.'[$i] ?></option>';
$parseStr .= '<?php }else { ?><option value="<?php echo $'.$values.'[$i] ?>"><?php echo $'.$output.'[$i] ?></option>';
$parseStr .= '<?php } ?>';
}else {
$parseStr .= '<option value="<?php echo $'.$values.'[$i] ?>"><?php echo $'.$output.'[$i] ?></option>';
}
$parseStr .= '<?php } ?>';
}
$parseStr .= '</select>';
return $parseStr;
}
/**
* checkbox标签解析
* 格式: <html:checkbox checkboxes="" checked="" />
* @access public
* @param array $tag 标签属性
* @return string|void
*/
public function _checkbox($tag) {
$name = $tag['name'];
$checkboxes = $tag['checkboxes'];
$checked = $tag['checked'];
$separator = $tag['separator'];
$checkboxes = $this->tpl->get($checkboxes);
$checked = $this->tpl->get($checked)?$this->tpl->get($checked):$checked;
$parseStr = '';
foreach($checkboxes as $key=>$val) {
if($checked == $key || in_array($key,$checked) ) {
$parseStr .= '<input type="checkbox" checked="checked" name="'.$name.'[]" value="'.$key.'">'.$val.$separator;
}else {
$parseStr .= '<input type="checkbox" name="'.$name.'[]" value="'.$key.'">'.$val.$separator;
}
}
return $parseStr;
}
/**
* radio标签解析
* 格式: <html:radio radios="name" checked="value" />
* @access public
* @param array $tag 标签属性
* @return string|void
*/
public function _radio($tag) {
$name = $tag['name'];
$radios = $tag['radios'];
$checked = $tag['checked'];
$separator = $tag['separator'];
$radios = $this->tpl->get($radios);
$checked = $this->tpl->get($checked)?$this->tpl->get($checked):$checked;
$parseStr = '';
foreach($radios as $key=>$val) {
if($checked == $key ) {
$parseStr .= '<input type="radio" checked="checked" name="'.$name.'[]" value="'.$key.'">'.$val.$separator;
}else {
$parseStr .= '<input type="radio" name="'.$name.'[]" value="'.$key.'">'.$val.$separator;
}
}
return $parseStr;
}
/**
* list标签解析
* 格式: <html:grid datasource="" show="vo" />
* @access public
* @param array $tag 标签属性
* @return string
*/
public function _grid($tag) {
$id = $tag['id']; //表格ID
$datasource = $tag['datasource']; //列表显示的数据源VoList名称
$pk = empty($tag['pk'])?'id':$tag['pk'];//主键名默认为id
$style = $tag['style']; //样式名
$name = !empty($tag['name'])?$tag['name']:'vo'; //Vo对象名
$action = !empty($tag['action'])?$tag['action']:false; //是否显示功能操作
$key = !empty($tag['key'])?true:false;
if(isset($tag['actionlist'])) {
$actionlist = explode(',',trim($tag['actionlist'])); //指定功能列表
}
if(substr($tag['show'],0,1)=='$') {
$show = $this->tpl->get(substr($tag['show'],1));
}else {
$show = $tag['show'];
}
$show = explode(',',$show); //列表显示字段列表
//计算表格的列数
$colNum = count($show);
if(!empty($action)) $colNum++;
if(!empty($key)) $colNum++;
//显示开始
$parseStr = "<!-- Think 系统列表组件开始 -->\n";
$parseStr .= '<table id="'.$id.'" class="'.$style.'" cellpadding=0 cellspacing=0 >';
$parseStr .= '<tr><td height="5" colspan="'.$colNum.'" class="topTd" ></td></tr>';
$parseStr .= '<tr class="row" >';
//列表需要显示的字段
$fields = array();
foreach($show as $val) {
$fields[] = explode(':',$val);
}
if(!empty($key)) {
$parseStr .= '<th width="12">No</th>';
}
foreach($fields as $field) {//显示指定的字段
$property = explode('|',$field[0]);
$showname = explode('|',$field[1]);
if(isset($showname[1])) {
$parseStr .= '<th width="'.$showname[1].'">';
}else {
$parseStr .= '<th>';
}
$parseStr .= $showname[0].'</th>';
}
if(!empty($action)) {//如果指定显示操作功能列
$parseStr .= '<th >操作</th>';
}
$parseStr .= '</tr>';
$parseStr .= '<volist name="'.$datasource.'" id="'.$name.'" ><tr class="row" >'; //支持鼠标移动单元行颜色变化 具体方法在js中定义
if(!empty($key)) {
$parseStr .= '<td>{$i}</td>';
}
foreach($fields as $field) {
//显示定义的列表字段
$parseStr .= '<td>';
if(!empty($field[2])) {
// 支持列表字段链接功能 具体方法由JS函数实现
$href = explode('|',$field[2]);
if(count($href)>1) {
//指定链接传的字段值
// 支持多个字段传递
$array = explode('^',$href[1]);
if(count($array)>1) {
foreach ($array as $a){
$temp[] = '\'{$'.$name.'.'.$a.'|addslashes}\'';
}
$parseStr .= '<a href="javascript:'.$href[0].'('.implode(',',$temp).')">';
}else{
$parseStr .= '<a href="javascript:'.$href[0].'(\'{$'.$name.'.'.$href[1].'|addslashes}\')">';
}
}else {
//如果没有指定默认传编号值
$parseStr .= '<a href="javascript:'.$field[2].'(\'{$'.$name.'.'.$pk.'|addslashes}\')">';
}
}
if(strpos($field[0],'^')) {
$property = explode('^',$field[0]);
foreach ($property as $p){
$unit = explode('|',$p);
if(count($unit)>1) {
$parseStr .= '{$'.$name.'.'.$unit[0].'|'.$unit[1].'} ';
}else {
$parseStr .= '{$'.$name.'.'.$p.'} ';
}
}
}else{
$property = explode('|',$field[0]);
if(count($property)>1) {
$parseStr .= '{$'.$name.'.'.$property[0].'|'.$property[1].'}';
}else {
$parseStr .= '{$'.$name.'.'.$field[0].'}';
}
}
if(!empty($field[2])) {
$parseStr .= '</a>';
}
$parseStr .= '</td>';
}
if(!empty($action)) {//显示功能操作
if(!empty($actionlist[0])) {//显示指定的功能项
$parseStr .= '<td>';
foreach($actionlist as $val) {
if(strpos($val,':')) {
$a = explode(':',$val);
if(count($a)>2) {
$parseStr .= '<a href="javascript:'.$a[0].'(\'{$'.$name.'.'.$a[2].'}\')">'.$a[1].'</a>&nbsp;';
}else {
$parseStr .= '<a href="javascript:'.$a[0].'(\'{$'.$name.'.'.$pk.'}\')">'.$a[1].'</a>&nbsp;';
}
}else{
$array = explode('|',$val);
if(count($array)>2) {
$parseStr .= ' <a href="javascript:'.$array[1].'(\'{$'.$name.'.'.$array[0].'}\')">'.$array[2].'</a>&nbsp;';
}else{
$parseStr .= ' {$'.$name.'.'.$val.'}&nbsp;';
}
}
}
$parseStr .= '</td>';
}
}
$parseStr .= '</tr></volist><tr><td height="5" colspan="'.$colNum.'" class="bottomTd"></td></tr></table>';
$parseStr .= "\n<!-- Think 系统列表组件结束 -->\n";
return $parseStr;
}
/**
* list标签解析
* 格式: <html:list datasource="" show="" />
* @access public
* @param array $tag 标签属性
* @return string
*/
public function _list($tag) {
$id = $tag['id']; //表格ID
$datasource = $tag['datasource']; //列表显示的数据源VoList名称
$pk = empty($tag['pk'])?'id':$tag['pk'];//主键名默认为id
$style = $tag['style']; //样式名
$name = !empty($tag['name'])?$tag['name']:'vo'; //Vo对象名
$action = $tag['action']=='true'?true:false; //是否显示功能操作
$key = !empty($tag['key'])?true:false;
$sort = $tag['sort']=='false'?false:true;
$checkbox = $tag['checkbox']; //是否显示Checkbox
if(isset($tag['actionlist'])) {
if(substr($tag['actionlist'],0,1)=='$') {
$actionlist = $this->tpl->get(substr($tag['actionlist'],1));
}else {
$actionlist = $tag['actionlist'];
}
$actionlist = explode(',',trim($actionlist)); //指定功能列表
}
if(substr($tag['show'],0,1)=='$') {
$show = $this->tpl->get(substr($tag['show'],1));
}else {
$show = $tag['show'];
}
$show = explode(',',$show); //列表显示字段列表
//计算表格的列数
$colNum = count($show);
if(!empty($checkbox)) $colNum++;
if(!empty($action)) $colNum++;
if(!empty($key)) $colNum++;
//显示开始
$parseStr = "<!-- Think 系统列表组件开始 -->\n";
$parseStr .= '<table id="'.$id.'" class="'.$style.'" cellpadding=0 cellspacing=0 >';
$parseStr .= '<tr><td height="5" colspan="'.$colNum.'" class="topTd" ></td></tr>';
$parseStr .= '<tr class="row" >';
//列表需要显示的字段
$fields = array();
foreach($show as $val) {
$fields[] = explode(':',$val);
}
if(!empty($checkbox) && 'true'==strtolower($checkbox)) {//如果指定需要显示checkbox列
$parseStr .='<th width="8"><input type="checkbox" id="check" onclick="CheckAll(\''.$id.'\')"></th>';
}
if(!empty($key)) {
$parseStr .= '<th width="12">No</th>';
}
foreach($fields as $field) {//显示指定的字段
$property = explode('|',$field[0]);
$showname = explode('|',$field[1]);
if(isset($showname[1])) {
$parseStr .= '<th width="'.$showname[1].'">';
}else {
$parseStr .= '<th>';
}
$showname[2] = isset($showname[2])?$showname[2]:$showname[0];
if($sort) {
$parseStr .= '<a href="javascript:sortBy(\''.$property[0].'\',\'{$sort}\',\''.ACTION_NAME.'\')" title="按照'.$showname[2].'{$sortType} ">'.$showname[0].'<eq name="order" value="'.$property[0].'" ><img src="__PUBLIC__/images/{$sortImg}.gif" width="12" height="17" border="0" align="absmiddle"></eq></a></th>';
}else{
$parseStr .= $showname[0].'</th>';
}
}
if(!empty($action)) {//如果指定显示操作功能列
$parseStr .= '<th >操作</th>';
}
$parseStr .= '</tr>';
$parseStr .= '<volist name="'.$datasource.'" id="'.$name.'" ><tr class="row" '; //支持鼠标移动单元行颜色变化 具体方法在js中定义
if(!empty($checkbox)) {
// $parseStr .= 'onmouseover="over(event)" onmouseout="out(event)" onclick="change(event)" ';
}
$parseStr .= '>';
if(!empty($checkbox)) {//如果需要显示checkbox 则在每行开头显示checkbox
$parseStr .= '<td><input type="checkbox" name="key" value="{$'.$name.'.'.$pk.'}"></td>';
}
if(!empty($key)) {
$parseStr .= '<td>{$i}</td>';
}
foreach($fields as $field) {
//显示定义的列表字段
$parseStr .= '<td>';
if(!empty($field[2])) {
// 支持列表字段链接功能 具体方法由JS函数实现
$href = explode('|',$field[2]);
if(count($href)>1) {
//指定链接传的字段值
// 支持多个字段传递
$array = explode('^',$href[1]);
if(count($array)>1) {
foreach ($array as $a){
$temp[] = '\'{$'.$name.'.'.$a.'|addslashes}\'';
}
$parseStr .= '<a href="javascript:'.$href[0].'('.implode(',',$temp).')">';
}else{
$parseStr .= '<a href="javascript:'.$href[0].'(\'{$'.$name.'.'.$href[1].'|addslashes}\')">';
}
}else {
//如果没有指定默认传编号值
$parseStr .= '<a href="javascript:'.$field[2].'(\'{$'.$name.'.'.$pk.'|addslashes}\')">';
}
}
if(strpos($field[0],'^')) {
$property = explode('^',$field[0]);
foreach ($property as $p){
$unit = explode('|',$p);
if(count($unit)>1) {
$parseStr .= '{$'.$name.'.'.$unit[0].'|'.$unit[1].'} ';
}else {
$parseStr .= '{$'.$name.'.'.$p.'} ';
}
}
}else{
$property = explode('|',$field[0]);
if(count($property)>1) {
$parseStr .= '{$'.$name.'.'.$property[0].'|'.$property[1].'}';
}else {
$parseStr .= '{$'.$name.'.'.$field[0].'}';
}
}
if(!empty($field[2])) {
$parseStr .= '</a>';
}
$parseStr .= '</td>';
}
if(!empty($action)) {//显示功能操作
if(!empty($actionlist[0])) {//显示指定的功能项
$parseStr .= '<td>';
foreach($actionlist as $val) {
if(strpos($val,':')) {
$a = explode(':',$val);
if(count($a)>2) {
$parseStr .= '<a href="javascript:'.$a[0].'(\'{$'.$name.'.'.$a[2].'}\')">'.$a[1].'</a>&nbsp;';
}else {
$parseStr .= '<a href="javascript:'.$a[0].'(\'{$'.$name.'.'.$pk.'}\')">'.$a[1].'</a>&nbsp;';
}
}else{
$array = explode('|',$val);
if(count($array)>2) {
$parseStr .= ' <a href="javascript:'.$array[1].'(\'{$'.$name.'.'.$array[0].'}\')">'.$array[2].'</a>&nbsp;';
}else{
$parseStr .= ' {$'.$name.'.'.$val.'}&nbsp;';
}
}
}
$parseStr .= '</td>';
}
}
$parseStr .= '</tr></volist><tr><td height="5" colspan="'.$colNum.'" class="bottomTd"></td></tr></table>';
$parseStr .= "\n<!-- Think 系统列表组件结束 -->\n";
return $parseStr;
}
}

View File

@@ -0,0 +1,344 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
namespace Think;
/**
* ThinkPHP 引导类
*/
class Think {
// 类映射
private static $_map = array();
// 实例化对象
private static $_instance = array();
/**
* 应用程序初始化
* @access public
* @return void
*/
static public function start() {
// 注册AUTOLOAD方法
spl_autoload_register('Think\Think::autoload');
// 设定错误和异常处理
register_shutdown_function('Think\Think::fatalError');
set_error_handler('Think\Think::appError');
set_exception_handler('Think\Think::appException');
// 初始化文件存储方式
Storage::connect(STORAGE_TYPE);
$runtimefile = RUNTIME_PATH.APP_MODE.'~runtime.php';
if(!APP_DEBUG && Storage::has($runtimefile)){
Storage::load($runtimefile);
}else{
if(Storage::has($runtimefile))
Storage::unlink($runtimefile);
$content = '';
// 读取应用模式
$mode = include is_file(CONF_PATH.'core.php')?CONF_PATH.'core.php':MODE_PATH.APP_MODE.'.php';
// 加载核心文件
foreach ($mode['core'] as $file){
if(is_file($file)) {
include $file;
if(!APP_DEBUG) $content .= compile($file);
}
}
// 加载应用模式配置文件
foreach ($mode['config'] as $key=>$file){
is_numeric($key)?C(load_config($file)):C($key,load_config($file));
}
// 读取当前应用模式对应的配置文件
if('common' != APP_MODE && is_file(CONF_PATH.'config_'.APP_MODE.CONF_EXT))
C(load_config(CONF_PATH.'config_'.APP_MODE.CONF_EXT));
// 加载模式别名定义
if(isset($mode['alias'])){
self::addMap(is_array($mode['alias'])?$mode['alias']:include $mode['alias']);
}
// 加载应用别名定义文件
if(is_file(CONF_PATH.'alias.php'))
self::addMap(include CONF_PATH.'alias.php');
// 加载模式行为定义
if(isset($mode['tags'])) {
Hook::import(is_array($mode['tags'])?$mode['tags']:include $mode['tags']);
}
// 加载应用行为定义
if(is_file(CONF_PATH.'tags.php'))
// 允许应用增加开发模式配置定义
Hook::import(include CONF_PATH.'tags.php');
// 加载框架底层语言包
L(include THINK_PATH.'Lang/'.strtolower(C('DEFAULT_LANG')).'.php');
if(!APP_DEBUG){
$content .= "\nnamespace { Think\\Think::addMap(".var_export(self::$_map,true).");";
$content .= "\nL(".var_export(L(),true).");\nC(".var_export(C(),true).');Think\Hook::import('.var_export(Hook::get(),true).');}';
Storage::put($runtimefile,strip_whitespace('<?php '.$content));
}else{
// 调试模式加载系统默认的配置文件
C(include THINK_PATH.'Conf/debug.php');
// 读取应用调试配置文件
if(is_file(CONF_PATH.'debug'.CONF_EXT))
C(include CONF_PATH.'debug'.CONF_EXT);
}
}
// 读取当前应用状态对应的配置文件
if(APP_STATUS && is_file(CONF_PATH.APP_STATUS.CONF_EXT))
C(include CONF_PATH.APP_STATUS.CONF_EXT);
// 设置系统时区
date_default_timezone_set(C('DEFAULT_TIMEZONE'));
// 检查应用目录结构 如果不存在则自动创建
if(C('CHECK_APP_DIR')) {
$module = defined('BIND_MODULE') ? BIND_MODULE : C('DEFAULT_MODULE');
if(!is_dir(APP_PATH.$module) || !is_dir(LOG_PATH)){
// 检测应用目录结构
Build::checkDir($module);
}
}
// 记录加载文件时间
G('loadTime');
// 运行应用
App::run();
}
// 注册classmap
static public function addMap($class, $map=''){
if(is_array($class)){
self::$_map = array_merge(self::$_map, $class);
}else{
self::$_map[$class] = $map;
}
}
// 获取classmap
static public function getMap($class=''){
if(''===$class){
return self::$_map;
}elseif(isset(self::$_map[$class])){
return self::$_map[$class];
}else{
return null;
}
}
/**
* 类库自动加载
* @param string $class 对象类名
* @return void
*/
public static function autoload($class) {
// 检查是否存在映射
if(isset(self::$_map[$class])) {
include self::$_map[$class];
}elseif(false !== strpos($class,'\\')){
$name = strstr($class, '\\', true);
if(in_array($name,array('Think','Org','Behavior','Com','Vendor')) || is_dir(LIB_PATH.$name)){
// Library目录下面的命名空间自动定位
$path = LIB_PATH;
}else{
// 检测自定义命名空间 否则就以模块为命名空间
$namespace = C('AUTOLOAD_NAMESPACE');
$path = isset($namespace[$name])? dirname($namespace[$name]).'/' : APP_PATH;
}
$filename = $path . str_replace('\\', '/', $class) . EXT;
if(is_file($filename)) {
// Win环境下面严格区分大小写
if (IS_WIN && false === strpos(str_replace('/', '\\', realpath($filename)), $class . EXT)){
return ;
}
include $filename;
}
}elseif (!C('APP_USE_NAMESPACE')) {
// 自动加载的类库层
foreach(explode(',',C('APP_AUTOLOAD_LAYER')) as $layer){
if(substr($class,-strlen($layer))==$layer){
if(require_cache(MODULE_PATH.$layer.'/'.$class.EXT)) {
return ;
}
}
}
// 根据自动加载路径设置进行尝试搜索
foreach (explode(',',C('APP_AUTOLOAD_PATH')) as $path){
if(import($path.'.'.$class))
// 如果加载类成功则返回
return ;
}
}
}
/**
* 取得对象实例 支持调用类的静态方法
* @param string $class 对象类名
* @param string $method 类的静态方法名
* @return object
*/
static public function instance($class,$method='') {
$identify = $class.$method;
if(!isset(self::$_instance[$identify])) {
if(class_exists($class)){
$o = new $class();
if(!empty($method) && method_exists($o,$method))
self::$_instance[$identify] = call_user_func(array(&$o, $method));
else
self::$_instance[$identify] = $o;
}
else
self::halt(L('_CLASS_NOT_EXIST_').':'.$class);
}
return self::$_instance[$identify];
}
/**
* 自定义异常处理
* @access public
* @param mixed $e 异常对象
*/
static public function appException($e) {
$error = array();
$error['message'] = $e->getMessage();
$trace = $e->getTrace();
if('E'==$trace[0]['function']) {
$error['file'] = $trace[0]['file'];
$error['line'] = $trace[0]['line'];
}else{
$error['file'] = $e->getFile();
$error['line'] = $e->getLine();
}
$error['trace'] = $e->getTraceAsString();
Log::record($error['message'],Log::ERR);
// 发送404信息
header('HTTP/1.1 404 Not Found');
header('Status:404 Not Found');
self::halt($error);
}
/**
* 自定义错误处理
* @access public
* @param int $errno 错误类型
* @param string $errstr 错误信息
* @param string $errfile 错误文件
* @param int $errline 错误行数
* @return void
*/
static public function appError($errno, $errstr, $errfile, $errline) {
switch ($errno) {
case E_ERROR:
case E_PARSE:
case E_CORE_ERROR:
case E_COMPILE_ERROR:
case E_USER_ERROR:
ob_end_clean();
$errorStr = "$errstr ".$errfile."$errline 行.";
if(C('LOG_RECORD')) Log::write("[$errno] ".$errorStr,Log::ERR);
self::halt($errorStr);
break;
default:
$errorStr = "[$errno] $errstr ".$errfile."$errline 行.";
self::trace($errorStr,'','NOTIC');
break;
}
}
// 致命错误捕获
static public function fatalError() {
Log::save();
if ($e = error_get_last()) {
switch($e['type']){
case E_ERROR:
case E_PARSE:
case E_CORE_ERROR:
case E_COMPILE_ERROR:
case E_USER_ERROR:
ob_end_clean();
self::halt($e);
break;
}
}
}
/**
* 错误输出
* @param mixed $error 错误
* @return void
*/
static public function halt($error) {
$e = array();
if (APP_DEBUG || IS_CLI) {
//调试模式下输出错误信息
if (!is_array($error)) {
$trace = debug_backtrace();
$e['message'] = $error;
$e['file'] = $trace[0]['file'];
$e['line'] = $trace[0]['line'];
ob_start();
debug_print_backtrace();
$e['trace'] = ob_get_clean();
} else {
$e = $error;
}
if(IS_CLI){
exit(iconv('UTF-8','gbk',$e['message']).PHP_EOL.'FILE: '.$e['file'].'('.$e['line'].')'.PHP_EOL.$e['trace']);
}
} else {
//否则定向到错误页面
$error_page = C('ERROR_PAGE');
if (!empty($error_page)) {
redirect($error_page);
} else {
$message = is_array($error) ? $error['message'] : $error;
$e['message'] = C('SHOW_ERROR_MSG')? $message : C('ERROR_MESSAGE');
}
}
// 包含异常页面模板
$exceptionFile = C('TMPL_EXCEPTION_FILE',null,THINK_PATH.'Tpl/think_exception.tpl');
include $exceptionFile;
exit;
}
/**
* 添加和获取页面Trace记录
* @param string $value 变量
* @param string $label 标签
* @param string $level 日志级别(或者页面Trace的选项卡)
* @param boolean $record 是否记录日志
* @return void|array
*/
static public function trace($value='[think]',$label='',$level='DEBUG',$record=false) {
static $_trace = array();
if('[think]' === $value){ // 获取trace信息
return $_trace;
}else{
$info = ($label?$label.':':'').print_r($value,true);
$level = strtoupper($level);
if((defined('IS_AJAX') && IS_AJAX) || !C('SHOW_PAGE_TRACE') || $record) {
Log::record($info,$level,$record);
}else{
if(!isset($_trace[$level]) || count($_trace[$level])>C('TRACE_MAX_RECORD')) {
$_trace[$level] = array();
}
$_trace[$level][] = $info;
}
}
}
}

View File

@@ -0,0 +1,429 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: 麦当苗儿 <zuojiazi@vip.qq.com> <http://www.zjzit.cn>
// +----------------------------------------------------------------------
namespace Think;
class Upload {
/**
* 默认上传配置
* @var array
*/
private $config = array(
'mimes' => array(), //允许上传的文件MiMe类型
'maxSize' => 0, //上传的文件大小限制 (0-不做限制)
'exts' => array(), //允许上传的文件后缀
'autoSub' => true, //自动子目录保存文件
'subName' => array('date', 'Y-m-d'), //子目录创建方式,[0]-函数名,[1]-参数,多个参数使用数组
'rootPath' => './Uploads/', //保存根路径
'savePath' => '', //保存路径
'saveName' => array('uniqid', ''), //上传文件命名规则,[0]-函数名,[1]-参数,多个参数使用数组
'saveExt' => '', //文件保存后缀,空则使用原后缀
'replace' => false, //存在同名是否覆盖
'hash' => true, //是否生成hash编码
'callback' => false, //检测文件是否存在回调,如果存在返回文件信息数组
'driver' => '', // 文件上传驱动
'driverConfig' => array(), // 上传驱动配置
);
/**
* 上传错误信息
* @var string
*/
private $error = ''; //上传错误信息
/**
* 上传驱动实例
* @var Object
*/
private $uploader;
/**
* 构造方法,用于构造上传实例
* @param array $config 配置
* @param string $driver 要使用的上传驱动 LOCAL-本地上传驱动FTP-FTP上传驱动
*/
public function __construct($config = array(), $driver = '', $driverConfig = null){
/* 获取配置 */
$this->config = array_merge($this->config, $config);
/* 设置上传驱动 */
$this->setDriver($driver, $driverConfig);
/* 调整配置,把字符串配置参数转换为数组 */
if(!empty($this->config['mimes'])){
if(is_string($this->mimes)) {
$this->config['mimes'] = explode(',', $this->mimes);
}
$this->config['mimes'] = array_map('strtolower', $this->mimes);
}
if(!empty($this->config['exts'])){
if (is_string($this->exts)){
$this->config['exts'] = explode(',', $this->exts);
}
$this->config['exts'] = array_map('strtolower', $this->exts);
}
}
/**
* 使用 $this->name 获取配置
* @param string $name 配置名称
* @return multitype 配置值
*/
public function __get($name) {
return $this->config[$name];
}
public function __set($name,$value){
if(isset($this->config[$name])) {
$this->config[$name] = $value;
if($name == 'driverConfig'){
//改变驱动配置后重置上传驱动
//注意:必须选改变驱动然后再改变驱动配置
$this->setDriver();
}
}
}
public function __isset($name){
return isset($this->config[$name]);
}
/**
* 获取最后一次上传错误信息
* @return string 错误信息
*/
public function getError(){
return $this->error;
}
/**
* 上传单个文件
* @param array $file 文件数组
* @return array 上传成功后的文件信息
*/
public function uploadOne($file){
$info = $this->upload(array($file));
return $info ? $info[0] : $info;
}
/**
* 上传文件
* @param 文件信息数组 $files ,通常是 $_FILES数组
*/
public function upload($files='') {
if('' === $files){
$files = $_FILES;
}
if(empty($files)){
$this->error = '没有上传的文件!';
return false;
}
/* 检测上传根目录 */
if(!$this->uploader->checkRootPath($this->rootPath)){
$this->error = $this->uploader->getError();
return false;
}
/* 检查上传目录 */
if(!$this->uploader->checkSavePath($this->savePath)){
$this->error = $this->uploader->getError();
return false;
}
/* 逐个检测并上传文件 */
$info = array();
if(function_exists('finfo_open')){
$finfo = finfo_open ( FILEINFO_MIME_TYPE );
}
// 对上传文件数组信息处理
$files = $this->dealFiles($files);
foreach ($files as $key => $file) {
$file['name'] = strip_tags($file['name']);
if(!isset($file['key'])) $file['key'] = $key;
/* 通过扩展获取文件类型可解决FLASH上传$FILES数组返回文件类型错误的问题 */
if(isset($finfo)){
$file['type'] = finfo_file ( $finfo , $file['tmp_name'] );
}
/* 获取上传文件后缀,允许上传无后缀文件 */
$file['ext'] = pathinfo($file['name'], PATHINFO_EXTENSION);
/* 文件上传检测 */
if (!$this->check($file)){
continue;
}
/* 获取文件hash */
if($this->hash){
$file['md5'] = md5_file($file['tmp_name']);
$file['sha1'] = sha1_file($file['tmp_name']);
}
/* 调用回调函数检测文件是否存在 */
$data = call_user_func($this->callback, $file);
if( $this->callback && $data ){
if ( file_exists('.'.$data['path']) ) {
$info[$key] = $data;
continue;
}elseif($this->removeTrash){
call_user_func($this->removeTrash,$data);//删除垃圾据
}
}
/* 生成保存文件名 */
$savename = $this->getSaveName($file);
if(false == $savename){
continue;
} else {
$file['savename'] = $savename;
}
/* 检测并创建子目录 */
$subpath = $this->getSubPath($file['name']);
if(false === $subpath){
continue;
} else {
$file['savepath'] = $this->savePath . $subpath;
}
/* 对图像文件进行严格检测 */
$ext = strtolower($file['ext']);
if(in_array($ext, array('gif','jpg','jpeg','bmp','png','swf'))) {
$imginfo = getimagesize($file['tmp_name']);
if(empty($imginfo) || ($ext == 'gif' && empty($imginfo['bits']))){
$this->error = '非法图像文件!';
continue;
}
}
/* 保存文件 并记录保存成功的文件 */
if ($this->uploader->save($file,$this->replace)) {
unset($file['error'], $file['tmp_name']);
$info[$key] = $file;
} else {
$this->error = $this->uploader->getError();
}
}
if(isset($finfo)){
finfo_close($finfo);
}
return empty($info) ? false : $info;
}
/**
* 转换上传文件数组变量为正确的方式
* @access private
* @param array $files 上传的文件变量
* @return array
*/
private function dealFiles($files) {
$fileArray = array();
$n = 0;
foreach ($files as $key=>$file){
if(is_array($file['name'])) {
$keys = array_keys($file);
$count = count($file['name']);
for ($i=0; $i<$count; $i++) {
$fileArray[$n]['key'] = $key;
foreach ($keys as $_key){
$fileArray[$n][$_key] = $file[$_key][$i];
}
$n++;
}
}else{
$fileArray = $files;
break;
}
}
return $fileArray;
}
/**
* 设置上传驱动
* @param string $driver 驱动名称
* @param array $config 驱动配置
*/
private function setDriver($driver = null, $config = null){
$driver = $driver ? : ($this->driver ? : C('FILE_UPLOAD_TYPE'));
$config = $config ? : ($this->driverConfig ? : C('UPLOAD_TYPE_CONFIG'));
$class = strpos($driver,'\\')? $driver : 'Think\\Upload\\Driver\\'.ucfirst(strtolower($driver));
$this->uploader = new $class($config);
if(!$this->uploader){
E("不存在上传驱动:{$name}");
}
}
/**
* 检查上传的文件
* @param array $file 文件信息
*/
private function check($file) {
/* 文件上传失败,捕获错误代码 */
if ($file['error']) {
$this->error($file['error']);
return false;
}
/* 无效上传 */
if (empty($file['name'])){
$this->error = '未知上传错误!';
}
/* 检查是否合法上传 */
if (!is_uploaded_file($file['tmp_name'])) {
$this->error = '非法上传文件!';
return false;
}
/* 检查文件大小 */
if (!$this->checkSize($file['size'])) {
$this->error = '上传文件大小不符!';
return false;
}
/* 检查文件Mime类型 */
//TODO:FLASH上传的文件获取到的mime类型都为application/octet-stream
if (!$this->checkMime($file['type'])) {
$this->error = '上传文件MIME类型不允许';
return false;
}
/* 检查文件后缀 */
if (!$this->checkExt($file['ext'])) {
$this->error = '上传文件后缀不允许';
return false;
}
/* 通过检测 */
return true;
}
/**
* 获取错误代码信息
* @param string $errorNo 错误号
*/
private function error($errorNo) {
switch ($errorNo) {
case 1:
$this->error = '上传的文件超过了 php.ini 中 upload_max_filesize 选项限制的值!';
break;
case 2:
$this->error = '上传文件的大小超过了 HTML 表单中 MAX_FILE_SIZE 选项指定的值!';
break;
case 3:
$this->error = '文件只有部分被上传!';
break;
case 4:
$this->error = '没有文件被上传!';
break;
case 6:
$this->error = '找不到临时文件夹!';
break;
case 7:
$this->error = '文件写入失败!';
break;
default:
$this->error = '未知上传错误!';
}
}
/**
* 检查文件大小是否合法
* @param integer $size 数据
*/
private function checkSize($size) {
return !($size > $this->maxSize) || (0 == $this->maxSize);
}
/**
* 检查上传的文件MIME类型是否合法
* @param string $mime 数据
*/
private function checkMime($mime) {
return empty($this->config['mimes']) ? true : in_array(strtolower($mime), $this->mimes);
}
/**
* 检查上传的文件后缀是否合法
* @param string $ext 后缀
*/
private function checkExt($ext) {
return empty($this->config['exts']) ? true : in_array(strtolower($ext), $this->exts);
}
/**
* 根据上传文件命名规则取得保存文件名
* @param string $file 文件信息
*/
private function getSaveName($file) {
$rule = $this->saveName;
if (empty($rule)) { //保持文件名不变
/* 解决pathinfo中文文件名BUG */
$filename = substr(pathinfo("_{$file['name']}", PATHINFO_FILENAME), 1);
$savename = $filename;
} else {
$savename = $this->getName($rule, $file['name']);
if(empty($savename)){
$this->error = '文件命名规则错误!';
return false;
}
}
/* 文件保存后缀,支持强制更改文件后缀 */
$ext = empty($this->config['saveExt']) ? $file['ext'] : $this->saveExt;
return $savename . '.' . $ext;
}
/**
* 获取子目录的名称
* @param array $file 上传的文件信息
*/
private function getSubPath($filename) {
$subpath = '';
$rule = $this->subName;
if ($this->autoSub && !empty($rule)) {
$subpath = $this->getName($rule, $filename) . '/';
if(!empty($subpath) && !$this->uploader->mkdir($this->savePath . $subpath)){
$this->error = $this->uploader->getError();
return false;
}
}
return $subpath;
}
/**
* 根据指定的规则获取文件或目录名称
* @param array $rule 规则
* @param string $filename 原文件名
* @return string 文件或目录名称
*/
private function getName($rule, $filename){
$name = '';
if(is_array($rule)){ //数组规则
$func = $rule[0];
$param = (array)$rule[1];
foreach ($param as &$value) {
$value = str_replace('__FILE__', $filename, $value);
}
$name = call_user_func_array($func, $param);
} elseif (is_string($rule)){ //字符串规则
if(function_exists($rule)){
$name = call_user_func($rule);
} else {
$name = $rule;
}
}
return $name;
}
}

View File

@@ -0,0 +1,238 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: Jay <yangweijiester@gmail.com> <http://code-tech.diandian.com>
// +----------------------------------------------------------------------
namespace Think\Upload\Driver;
use Think\Upload\Driver\Bcs\BaiduBcs;
class Bcs {
/**
* 上传文件根目录
* @var string
*/
private $rootPath;
const DEFAULT_URL = 'bcs.duapp.com';
/**
* 上传错误信息
* @var string
*/
private $error = '';
public $config = array(
'AccessKey'=> '',
'SecretKey'=> '', //百度云服务器
'bucket' => '', //空间名称
'rename' => false,
'timeout' => 3600, //超时时间
);
public $bcs = null;
/**
* 构造函数,用于设置上传根路径
* @param array $config FTP配置
*/
public function __construct($config){
/* 默认FTP配置 */
$this->config = array_merge($this->config, $config);
$bcsClass = dirname(__FILE__). "/Bcs/bcs.class.php";
if(is_file($bcsClass))
require_once($bcsClass);
$this->bcs = new BaiduBCS ( $this->config['AccessKey'], $this->config['SecretKey'], self:: DEFAULT_URL );
}
/**
* 检测上传根目录(百度云上传时支持自动创建目录,直接返回)
* @param string $rootpath 根目录
* @return boolean true-检测通过false-检测失败
*/
public function checkRootPath($rootpath){
/* 设置根目录 */
$this->rootPath = str_replace('./', '/', $rootpath);
return true;
}
/**
* 检测上传目录(百度云上传时支持自动创建目录,直接返回)
* @param string $savepath 上传目录
* @return boolean 检测结果true-通过false-失败
*/
public function checkSavePath($savepath){
return true;
}
/**
* 创建文件夹 (百度云上传时支持自动创建目录,直接返回)
* @param string $savepath 目录名称
* @return boolean true-创建成功false-创建失败
*/
public function mkdir($savepath){
return true;
}
/**
* 保存指定文件
* @param array $file 保存的文件信息
* @param boolean $replace 同名文件是否覆盖
* @return boolean 保存状态true-成功false-失败
*/
public function save(&$file,$replace=true) {
$opt = array ();
$opt ['acl'] = BaiduBCS::BCS_SDK_ACL_TYPE_PUBLIC_WRITE;
$opt ['curlopts'] = array (
CURLOPT_CONNECTTIMEOUT => 10,
CURLOPT_TIMEOUT => 1800
);
$object = "/{$file['savepath']}{$file['savename']}";
$response = $this->bcs->create_object ( $this->config['bucket'], $object, $file['tmp_name'], $opt );
$url = $this->download($object);
$file['url'] = $url;
return $response->isOK() ? true : false;
}
public function download($file){
$file = str_replace('./', '/', $file);
$opt = array();
$opt['time'] = mktime('2049-12-31'); //这是最长有效时间!--
$response = $this->bcs->generate_get_object_url ( $this->config['bucket'], $file, $opt );
return $response;
}
/**
* 获取最后一次上传错误信息
* @return string 错误信息
*/
public function getError(){
return $this->error;
}
/**
* 请求百度云服务器
* @param string $path 请求的PATH
* @param string $method 请求方法
* @param array $headers 请求header
* @param resource $body 上传文件资源
* @return boolean
*/
private function request($path, $method, $headers = null, $body = null){
$ch = curl_init($path);
$_headers = array('Expect:');
if (!is_null($headers) && is_array($headers)){
foreach($headers as $k => $v) {
array_push($_headers, "{$k}: {$v}");
}
}
$length = 0;
$date = gmdate('D, d M Y H:i:s \G\M\T');
if (!is_null($body)) {
if(is_resource($body)){
fseek($body, 0, SEEK_END);
$length = ftell($body);
fseek($body, 0);
array_push($_headers, "Content-Length: {$length}");
curl_setopt($ch, CURLOPT_INFILE, $body);
curl_setopt($ch, CURLOPT_INFILESIZE, $length);
} else {
$length = @strlen($body);
array_push($_headers, "Content-Length: {$length}");
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
}
} else {
array_push($_headers, "Content-Length: {$length}");
}
// array_push($_headers, 'Authorization: ' . $this->sign($method, $uri, $date, $length));
array_push($_headers, "Date: {$date}");
curl_setopt($ch, CURLOPT_HTTPHEADER, $_headers);
curl_setopt($ch, CURLOPT_TIMEOUT, $this->config['timeout']);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
if ($method == 'PUT' || $method == 'POST') {
curl_setopt($ch, CURLOPT_POST, 1);
} else {
curl_setopt($ch, CURLOPT_POST, 0);
}
if ($method == 'HEAD') {
curl_setopt($ch, CURLOPT_NOBODY, true);
}
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
list($header, $body) = explode("\r\n\r\n", $response, 2);
if ($status == 200) {
if ($method == 'GET') {
return $body;
} else {
$data = $this->response($header);
return count($data) > 0 ? $data : true;
}
} else {
$this->error($header);
return false;
}
}
/**
* 获取响应数据
* @param string $text 响应头字符串
* @return array 响应数据列表
*/
private function response($text){
$items = json_decode($text, true);
return $items;
}
/**
* 生成请求签名
* @return string 请求签名
*/
private function sign($method, $Bucket, $object='/', $size=''){
if(!$size)
$size = $this->config['size'];
$param = array(
'ak'=>$this->config['AccessKey'],
'sk'=>$this->config['SecretKey'],
'size'=>$size,
'bucket'=>$Bucket,
'host'=>self :: DEFAULT_URL,
'date'=>time()+$this->config['timeout'],
'ip'=>'',
'object'=>$object
);
$response = $this->request($this->apiurl.'?'.http_build_query($param), 'POST');
if($response)
$response = json_decode($response, true);
return $response['content'][$method];
}
/**
* 获取请求错误信息
* @param string $header 请求返回头信息
*/
private function error($header) {
list($status, $stash) = explode("\r\n", $header, 2);
list($v, $code, $message) = explode(" ", $status, 3);
$message = is_null($message) ? 'File Not Found' : "[{$status}]:{$message}";
$this->error = $message;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,137 @@
<?php
namespace Think\Upload\Driver\Bcs;
class BCS_MimeTypes {
public static $mime_types = array (
'3gp' => 'video/3gpp', 'ai' => 'application/postscript',
'aif' => 'audio/x-aiff', 'aifc' => 'audio/x-aiff',
'aiff' => 'audio/x-aiff', 'asc' => 'text/plain',
'atom' => 'application/atom+xml', 'au' => 'audio/basic',
'avi' => 'video/x-msvideo', 'bcpio' => 'application/x-bcpio',
'bin' => 'application/octet-stream', 'bmp' => 'image/bmp',
'cdf' => 'application/x-netcdf', 'cgm' => 'image/cgm',
'class' => 'application/octet-stream',
'cpio' => 'application/x-cpio',
'cpt' => 'application/mac-compactpro',
'csh' => 'application/x-csh', 'css' => 'text/css',
'dcr' => 'application/x-director', 'dif' => 'video/x-dv',
'dir' => 'application/x-director', 'djv' => 'image/vnd.djvu',
'djvu' => 'image/vnd.djvu',
'dll' => 'application/octet-stream',
'dmg' => 'application/octet-stream',
'dms' => 'application/octet-stream',
'doc' => 'application/msword', 'dtd' => 'application/xml-dtd',
'dv' => 'video/x-dv', 'dvi' => 'application/x-dvi',
'dxr' => 'application/x-director',
'eps' => 'application/postscript', 'etx' => 'text/x-setext',
'exe' => 'application/octet-stream',
'ez' => 'application/andrew-inset', 'flv' => 'video/x-flv',
'gif' => 'image/gif', 'gram' => 'application/srgs',
'grxml' => 'application/srgs+xml',
'gtar' => 'application/x-gtar', 'gz' => 'application/x-gzip',
'hdf' => 'application/x-hdf',
'hqx' => 'application/mac-binhex40', 'htm' => 'text/html',
'html' => 'text/html', 'ice' => 'x-conference/x-cooltalk',
'ico' => 'image/x-icon', 'ics' => 'text/calendar',
'ief' => 'image/ief', 'ifb' => 'text/calendar',
'iges' => 'model/iges', 'igs' => 'model/iges',
'jnlp' => 'application/x-java-jnlp-file', 'jp2' => 'image/jp2',
'jpe' => 'image/jpeg', 'jpeg' => 'image/jpeg',
'jpg' => 'image/jpeg', 'js' => 'application/x-javascript',
'kar' => 'audio/midi', 'latex' => 'application/x-latex',
'lha' => 'application/octet-stream',
'lzh' => 'application/octet-stream',
'm3u' => 'audio/x-mpegurl', 'm4a' => 'audio/mp4a-latm',
'm4p' => 'audio/mp4a-latm', 'm4u' => 'video/vnd.mpegurl',
'm4v' => 'video/x-m4v', 'mac' => 'image/x-macpaint',
'man' => 'application/x-troff-man',
'mathml' => 'application/mathml+xml',
'me' => 'application/x-troff-me', 'mesh' => 'model/mesh',
'mid' => 'audio/midi', 'midi' => 'audio/midi',
'mif' => 'application/vnd.mif', 'mov' => 'video/quicktime',
'movie' => 'video/x-sgi-movie', 'mp2' => 'audio/mpeg',
'mp3' => 'audio/mpeg', 'mp4' => 'video/mp4',
'mpe' => 'video/mpeg', 'mpeg' => 'video/mpeg',
'mpg' => 'video/mpeg', 'mpga' => 'audio/mpeg',
'ms' => 'application/x-troff-ms', 'msh' => 'model/mesh',
'mxu' => 'video/vnd.mpegurl', 'nc' => 'application/x-netcdf',
'oda' => 'application/oda', 'ogg' => 'application/ogg',
'ogv' => 'video/ogv', 'pbm' => 'image/x-portable-bitmap',
'pct' => 'image/pict', 'pdb' => 'chemical/x-pdb',
'pdf' => 'application/pdf',
'pgm' => 'image/x-portable-graymap',
'pgn' => 'application/x-chess-pgn', 'pic' => 'image/pict',
'pict' => 'image/pict', 'png' => 'image/png',
'pnm' => 'image/x-portable-anymap',
'pnt' => 'image/x-macpaint', 'pntg' => 'image/x-macpaint',
'ppm' => 'image/x-portable-pixmap',
'ppt' => 'application/vnd.ms-powerpoint',
'ps' => 'application/postscript', 'qt' => 'video/quicktime',
'qti' => 'image/x-quicktime', 'qtif' => 'image/x-quicktime',
'ra' => 'audio/x-pn-realaudio',
'ram' => 'audio/x-pn-realaudio', 'ras' => 'image/x-cmu-raster',
'rdf' => 'application/rdf+xml', 'rgb' => 'image/x-rgb',
'rm' => 'application/vnd.rn-realmedia',
'roff' => 'application/x-troff', 'rtf' => 'text/rtf',
'rtx' => 'text/richtext', 'sgm' => 'text/sgml',
'sgml' => 'text/sgml', 'sh' => 'application/x-sh',
'shar' => 'application/x-shar', 'silo' => 'model/mesh',
'sit' => 'application/x-stuffit',
'skd' => 'application/x-koan', 'skm' => 'application/x-koan',
'skp' => 'application/x-koan', 'skt' => 'application/x-koan',
'smi' => 'application/smil', 'smil' => 'application/smil',
'snd' => 'audio/basic', 'so' => 'application/octet-stream',
'spl' => 'application/x-futuresplash',
'src' => 'application/x-wais-source',
'sv4cpio' => 'application/x-sv4cpio',
'sv4crc' => 'application/x-sv4crc', 'svg' => 'image/svg+xml',
'swf' => 'application/x-shockwave-flash',
't' => 'application/x-troff', 'tar' => 'application/x-tar',
'tcl' => 'application/x-tcl', 'tex' => 'application/x-tex',
'texi' => 'application/x-texinfo',
'texinfo' => 'application/x-texinfo', 'tif' => 'image/tiff',
'tiff' => 'image/tiff', 'tr' => 'application/x-troff',
'tsv' => 'text/tab-separated-values', 'txt' => 'text/plain',
'ustar' => 'application/x-ustar',
'vcd' => 'application/x-cdlink', 'vrml' => 'model/vrml',
'vxml' => 'application/voicexml+xml', 'wav' => 'audio/x-wav',
'wbmp' => 'image/vnd.wap.wbmp',
'wbxml' => 'application/vnd.wap.wbxml', 'webm' => 'video/webm',
'wml' => 'text/vnd.wap.wml',
'wmlc' => 'application/vnd.wap.wmlc',
'wmls' => 'text/vnd.wap.wmlscript',
'wmlsc' => 'application/vnd.wap.wmlscriptc',
'wmv' => 'video/x-ms-wmv', 'wrl' => 'model/vrml',
'xbm' => 'image/x-xbitmap', 'xht' => 'application/xhtml+xml',
'xhtml' => 'application/xhtml+xml',
'xls' => 'application/vnd.ms-excel',
'xml' => 'application/xml', 'xpm' => 'image/x-xpixmap',
'xsl' => 'application/xml', 'xslt' => 'application/xslt+xml',
'xul' => 'application/vnd.mozilla.xul+xml',
'xwd' => 'image/x-xwindowdump', 'xyz' => 'chemical/x-xyz',
'zip' => 'application/zip',
//add by zhengkan 20110905
"apk" => "application/vnd.android.package-archive",
"bin" => "application/octet-stream",
"cab" => "application/vnd.ms-cab-compressed",
"gb" => "application/chinese-gb",
"gba" => "application/octet-stream",
"gbc" => "application/octet-stream",
"jad" => "text/vnd.sun.j2me.app-descriptor",
"jar" => "application/java-archive",
"nes" => "application/octet-stream",
"rar" => "application/x-rar-compressed",
"sis" => "application/vnd.symbian.install",
"sisx" => "x-epoc/x-sisx-app",
"smc" => "application/octet-stream",
"smd" => "application/octet-stream",
"swf" => "application/x-shockwave-flash",
"zip" => "application/x-zip-compressed",
"wap" => "text/vnd.wap.wml wml", "mrp" => "application/mrp",
//add by zhengkan 20110914
"wma" => "audio/x-ms-wma",
"lrc" => "application/lrc" );
public static function get_mimetype($ext) {
$ext = strtolower ( $ext );
return (isset ( self::$mime_types [$ext] ) ? self::$mime_types [$ext] : 'application/octet-stream');
}
}

View File

@@ -0,0 +1,837 @@
<?php
namespace Think\Upload\Driver\Bcs;
/**
* Handles all HTTP requests using cURL and manages the responses.
*
* @version 2011.03.01
* @copyright 2006-2011 Ryan Parman
* @copyright 2006-2010 Foleeo Inc.
* @copyright 2010-2011 Amazon.com, Inc. or its affiliates.
* @copyright 2008-2011 Contributors
* @license http://opensource.org/licenses/bsd-license.php Simplified BSD License
*/
class BCS_RequestCore {
/**
* The URL being requested.
*/
public $request_url;
/**
* The headers being sent in the request.
*/
public $request_headers;
/**
* The body being sent in the request.
*/
public $request_body;
/**
* The response returned by the request.
*/
public $response;
/**
* The headers returned by the request.
*/
public $response_headers;
/**
* The body returned by the request.
*/
public $response_body;
/**
* The HTTP status code returned by the request.
*/
public $response_code;
/**
* Additional response data.
*/
public $response_info;
/**
* The handle for the cURL object.
*/
public $curl_handle;
/**
* The method by which the request is being made.
*/
public $method;
/**
* Stores the proxy settings to use for the request.
*/
public $proxy = null;
/**
* The username to use for the request.
*/
public $username = null;
/**
* The password to use for the request.
*/
public $password = null;
/**
* Custom CURLOPT settings.
*/
public $curlopts = null;
/**
* The state of debug mode.
*/
public $debug_mode = false;
/**
* The default class to use for HTTP Requests (defaults to <BCS_RequestCore>).
*/
public $request_class = 'BCS_RequestCore';
/**
* The default class to use for HTTP Responses (defaults to <BCS_ResponseCore>).
*/
public $response_class = 'BCS_ResponseCore';
/**
* Default useragent string to use.
*/
public $useragent = 'BCS_RequestCore/1.4.2';
/**
* File to read from while streaming up.
*/
public $read_file = null;
/**
* The resource to read from while streaming up.
*/
public $read_stream = null;
/**
* The size of the stream to read from.
*/
public $read_stream_size = null;
/**
* The length already read from the stream.
*/
public $read_stream_read = 0;
/**
* File to write to while streaming down.
*/
public $write_file = null;
/**
* The resource to write to while streaming down.
*/
public $write_stream = null;
/**
* Stores the intended starting seek position.
*/
public $seek_position = null;
/**
* The user-defined callback function to call when a stream is read from.
*/
public $registered_streaming_read_callback = null;
/**
* The user-defined callback function to call when a stream is written to.
*/
public $registered_streaming_write_callback = null;
/*%******************************************************************************************%*/
// CONSTANTS
/**
* GET HTTP Method
*/
const HTTP_GET = 'GET';
/**
* POST HTTP Method
*/
const HTTP_POST = 'POST';
/**
* PUT HTTP Method
*/
const HTTP_PUT = 'PUT';
/**
* DELETE HTTP Method
*/
const HTTP_DELETE = 'DELETE';
/**
* HEAD HTTP Method
*/
const HTTP_HEAD = 'HEAD';
/*%******************************************************************************************%*/
// CONSTRUCTOR/DESTRUCTOR
/**
* Constructs a new instance of this class.
*
* @param string $url (Optional) The URL to request or service endpoint to query.
* @param string $proxy (Optional) The faux-url to use for proxy settings. Takes the following format: `proxy://user:pass@hostname:port`
* @param array $helpers (Optional) An associative array of classnames to use for request, and response functionality. Gets passed in automatically by the calling class.
* @return $this A reference to the current instance.
*/
public function __construct($url = null, $proxy = null, $helpers = null) {
// Set some default values.
$this->request_url = $url;
$this->method = self::HTTP_GET;
$this->request_headers = array ();
$this->request_body = '';
// Set a new Request class if one was set.
if (isset ( $helpers ['request'] ) && ! empty ( $helpers ['request'] )) {
$this->request_class = $helpers ['request'];
}
// Set a new Request class if one was set.
if (isset ( $helpers ['response'] ) && ! empty ( $helpers ['response'] )) {
$this->response_class = $helpers ['response'];
}
if ($proxy) {
$this->set_proxy ( $proxy );
}
return $this;
}
/**
* Destructs the instance. Closes opened file handles.
*
* @return $this A reference to the current instance.
*/
public function __destruct() {
if (isset ( $this->read_file ) && isset ( $this->read_stream )) {
fclose ( $this->read_stream );
}
if (isset ( $this->write_file ) && isset ( $this->write_stream )) {
fclose ( $this->write_stream );
}
return $this;
}
/*%******************************************************************************************%*/
// REQUEST METHODS
/**
* Sets the credentials to use for authentication.
*
* @param string $user (Required) The username to authenticate with.
* @param string $pass (Required) The password to authenticate with.
* @return $this A reference to the current instance.
*/
public function set_credentials($user, $pass) {
$this->username = $user;
$this->password = $pass;
return $this;
}
/**
* Adds a custom HTTP header to the cURL request.
*
* @param string $key (Required) The custom HTTP header to set.
* @param mixed $value (Required) The value to assign to the custom HTTP header.
* @return $this A reference to the current instance.
*/
public function add_header($key, $value) {
$this->request_headers [$key] = $value;
return $this;
}
/**
* Removes an HTTP header from the cURL request.
*
* @param string $key (Required) The custom HTTP header to set.
* @return $this A reference to the current instance.
*/
public function remove_header($key) {
if (isset ( $this->request_headers [$key] )) {
unset ( $this->request_headers [$key] );
}
return $this;
}
/**
* Set the method type for the request.
*
* @param string $method (Required) One of the following constants: <HTTP_GET>, <HTTP_POST>, <HTTP_PUT>, <HTTP_HEAD>, <HTTP_DELETE>.
* @return $this A reference to the current instance.
*/
public function set_method($method) {
$this->method = strtoupper ( $method );
return $this;
}
/**
* Sets a custom useragent string for the class.
*
* @param string $ua (Required) The useragent string to use.
* @return $this A reference to the current instance.
*/
public function set_useragent($ua) {
$this->useragent = $ua;
return $this;
}
/**
* Set the body to send in the request.
*
* @param string $body (Required) The textual content to send along in the body of the request.
* @return $this A reference to the current instance.
*/
public function set_body($body) {
$this->request_body = $body;
return $this;
}
/**
* Set the URL to make the request to.
*
* @param string $url (Required) The URL to make the request to.
* @return $this A reference to the current instance.
*/
public function set_request_url($url) {
$this->request_url = $url;
return $this;
}
/**
* Set additional CURLOPT settings. These will merge with the default settings, and override if
* there is a duplicate.
*
* @param array $curlopts (Optional) A set of key-value pairs that set `CURLOPT` options. These will merge with the existing CURLOPTs, and ones passed here will override the defaults. Keys should be the `CURLOPT_*` constants, not strings.
* @return $this A reference to the current instance.
*/
public function set_curlopts($curlopts) {
$this->curlopts = $curlopts;
return $this;
}
/**
* Sets the length in bytes to read from the stream while streaming up.
*
* @param integer $size (Required) The length in bytes to read from the stream.
* @return $this A reference to the current instance.
*/
public function set_read_stream_size($size) {
$this->read_stream_size = $size;
return $this;
}
/**
* Sets the resource to read from while streaming up. Reads the stream from its current position until
* EOF or `$size` bytes have been read. If `$size` is not given it will be determined by <php:fstat()> and
* <php:ftell()>.
*
* @param resource $resource (Required) The readable resource to read from.
* @param integer $size (Optional) The size of the stream to read.
* @return $this A reference to the current instance.
*/
public function set_read_stream($resource, $size = null) {
if (! isset ( $size ) || $size < 0) {
$stats = fstat ( $resource );
if ($stats && $stats ['size'] >= 0) {
$position = ftell ( $resource );
if ($position !== false && $position >= 0) {
$size = $stats ['size'] - $position;
}
}
}
$this->read_stream = $resource;
return $this->set_read_stream_size ( $size );
}
/**
* Sets the file to read from while streaming up.
*
* @param string $location (Required) The readable location to read from.
* @return $this A reference to the current instance.
*/
public function set_read_file($location) {
$this->read_file = $location;
$read_file_handle = fopen ( $location, 'r' );
return $this->set_read_stream ( $read_file_handle );
}
/**
* Sets the resource to write to while streaming down.
*
* @param resource $resource (Required) The writeable resource to write to.
* @return $this A reference to the current instance.
*/
public function set_write_stream($resource) {
$this->write_stream = $resource;
return $this;
}
/**
* Sets the file to write to while streaming down.
*
* @param string $location (Required) The writeable location to write to.
* @return $this A reference to the current instance.
*/
public function set_write_file($location) {
$this->write_file = $location;
$write_file_handle = fopen ( $location, 'w' );
return $this->set_write_stream ( $write_file_handle );
}
/**
* Set the proxy to use for making requests.
*
* @param string $proxy (Required) The faux-url to use for proxy settings. Takes the following format: `proxy://user:pass@hostname:port`
* @return $this A reference to the current instance.
*/
public function set_proxy($proxy) {
$proxy = parse_url ( $proxy );
$proxy ['user'] = isset ( $proxy ['user'] ) ? $proxy ['user'] : null;
$proxy ['pass'] = isset ( $proxy ['pass'] ) ? $proxy ['pass'] : null;
$proxy ['port'] = isset ( $proxy ['port'] ) ? $proxy ['port'] : null;
$this->proxy = $proxy;
return $this;
}
/**
* Set the intended starting seek position.
*
* @param integer $position (Required) The byte-position of the stream to begin reading from.
* @return $this A reference to the current instance.
*/
public function set_seek_position($position) {
$this->seek_position = isset ( $position ) ? ( integer ) $position : null;
return $this;
}
/**
* Register a callback function to execute whenever a data stream is read from using
* <CFRequest::streaming_read_callback()>.
*
* The user-defined callback function should accept three arguments:
*
* <ul>
* <li><code>$curl_handle</code> - <code>resource</code> - Required - The cURL handle resource that represents the in-progress transfer.</li>
* <li><code>$file_handle</code> - <code>resource</code> - Required - The file handle resource that represents the file on the local file system.</li>
* <li><code>$length</code> - <code>integer</code> - Required - The length in kilobytes of the data chunk that was transferred.</li>
* </ul>
*
* @param string|array|function $callback (Required) The callback function is called by <php:call_user_func()>, so you can pass the following values: <ul>
* <li>The name of a global function to execute, passed as a string.</li>
* <li>A method to execute, passed as <code>array('ClassName', 'MethodName')</code>.</li>
* <li>An anonymous function (PHP 5.3+).</li></ul>
* @return $this A reference to the current instance.
*/
public function register_streaming_read_callback($callback) {
$this->registered_streaming_read_callback = $callback;
return $this;
}
/**
* Register a callback function to execute whenever a data stream is written to using
* <CFRequest::streaming_write_callback()>.
*
* The user-defined callback function should accept two arguments:
*
* <ul>
* <li><code>$curl_handle</code> - <code>resource</code> - Required - The cURL handle resource that represents the in-progress transfer.</li>
* <li><code>$length</code> - <code>integer</code> - Required - The length in kilobytes of the data chunk that was transferred.</li>
* </ul>
*
* @param string|array|function $callback (Required) The callback function is called by <php:call_user_func()>, so you can pass the following values: <ul>
* <li>The name of a global function to execute, passed as a string.</li>
* <li>A method to execute, passed as <code>array('ClassName', 'MethodName')</code>.</li>
* <li>An anonymous function (PHP 5.3+).</li></ul>
* @return $this A reference to the current instance.
*/
public function register_streaming_write_callback($callback) {
$this->registered_streaming_write_callback = $callback;
return $this;
}
/*%******************************************************************************************%*/
// PREPARE, SEND, AND PROCESS REQUEST
/**
* A callback function that is invoked by cURL for streaming up.
*
* @param resource $curl_handle (Required) The cURL handle for the request.
* @param resource $file_handle (Required) The open file handle resource.
* @param integer $length (Required) The maximum number of bytes to read.
* @return binary Binary data from a stream.
*/
public function streaming_read_callback($curl_handle, $file_handle, $length) {
// Once we've sent as much as we're supposed to send...
if ($this->read_stream_read >= $this->read_stream_size) {
// Send EOF
return '';
}
// If we're at the beginning of an upload and need to seek...
if ($this->read_stream_read == 0 && isset ( $this->seek_position ) && $this->seek_position !== ftell ( $this->read_stream )) {
if (fseek ( $this->read_stream, $this->seek_position ) !== 0) {
throw new BCS_RequestCore_Exception ( 'The stream does not support seeking and is either not at the requested position or the position is unknown.' );
}
}
$read = fread ( $this->read_stream, min ( $this->read_stream_size - $this->read_stream_read, $length ) ); // Remaining upload data or cURL's requested chunk size
$this->read_stream_read += strlen ( $read );
$out = $read === false ? '' : $read;
// Execute callback function
if ($this->registered_streaming_read_callback) {
call_user_func ( $this->registered_streaming_read_callback, $curl_handle, $file_handle, $out );
}
return $out;
}
/**
* A callback function that is invoked by cURL for streaming down.
*
* @param resource $curl_handle (Required) The cURL handle for the request.
* @param binary $data (Required) The data to write.
* @return integer The number of bytes written.
*/
public function streaming_write_callback($curl_handle, $data) {
$length = strlen ( $data );
$written_total = 0;
$written_last = 0;
while ( $written_total < $length ) {
$written_last = fwrite ( $this->write_stream, substr ( $data, $written_total ) );
if ($written_last === false) {
return $written_total;
}
$written_total += $written_last;
}
// Execute callback function
if ($this->registered_streaming_write_callback) {
call_user_func ( $this->registered_streaming_write_callback, $curl_handle, $written_total );
}
return $written_total;
}
/**
* Prepares and adds the details of the cURL request. This can be passed along to a <php:curl_multi_exec()>
* function.
*
* @return resource The handle for the cURL object.
*/
public function prep_request() {
$curl_handle = curl_init ();
// Set default options.
curl_setopt ( $curl_handle, CURLOPT_URL, $this->request_url );
curl_setopt ( $curl_handle, CURLOPT_FILETIME, true );
curl_setopt ( $curl_handle, CURLOPT_FRESH_CONNECT, false );
curl_setopt ( $curl_handle, CURLOPT_SSL_VERIFYPEER, false );
curl_setopt ( $curl_handle, CURLOPT_SSL_VERIFYHOST, true );
curl_setopt ( $curl_handle, CURLOPT_CLOSEPOLICY, CURLCLOSEPOLICY_LEAST_RECENTLY_USED );
curl_setopt ( $curl_handle, CURLOPT_MAXREDIRS, 5 );
curl_setopt ( $curl_handle, CURLOPT_HEADER, true );
curl_setopt ( $curl_handle, CURLOPT_RETURNTRANSFER, true );
curl_setopt ( $curl_handle, CURLOPT_TIMEOUT, 5184000 );
curl_setopt ( $curl_handle, CURLOPT_CONNECTTIMEOUT, 120 );
curl_setopt ( $curl_handle, CURLOPT_NOSIGNAL, true );
curl_setopt ( $curl_handle, CURLOPT_REFERER, $this->request_url );
curl_setopt ( $curl_handle, CURLOPT_USERAGENT, $this->useragent );
curl_setopt ( $curl_handle, CURLOPT_READFUNCTION, array (
$this,
'streaming_read_callback' ) );
if ($this->debug_mode) {
curl_setopt ( $curl_handle, CURLOPT_VERBOSE, true );
}
//if (! ini_get ( 'safe_mode' )) {
//modify by zhengkan
//curl_setopt($curl_handle, CURLOPT_FOLLOWLOCATION, true);
//}
// Enable a proxy connection if requested.
if ($this->proxy) {
curl_setopt ( $curl_handle, CURLOPT_HTTPPROXYTUNNEL, true );
$host = $this->proxy ['host'];
$host .= ($this->proxy ['port']) ? ':' . $this->proxy ['port'] : '';
curl_setopt ( $curl_handle, CURLOPT_PROXY, $host );
if (isset ( $this->proxy ['user'] ) && isset ( $this->proxy ['pass'] )) {
curl_setopt ( $curl_handle, CURLOPT_PROXYUSERPWD, $this->proxy ['user'] . ':' . $this->proxy ['pass'] );
}
}
// Set credentials for HTTP Basic/Digest Authentication.
if ($this->username && $this->password) {
curl_setopt ( $curl_handle, CURLOPT_HTTPAUTH, CURLAUTH_ANY );
curl_setopt ( $curl_handle, CURLOPT_USERPWD, $this->username . ':' . $this->password );
}
// Handle the encoding if we can.
if (extension_loaded ( 'zlib' )) {
curl_setopt ( $curl_handle, CURLOPT_ENCODING, '' );
}
// Process custom headers
if (isset ( $this->request_headers ) && count ( $this->request_headers )) {
$temp_headers = array ();
foreach ( $this->request_headers as $k => $v ) {
$temp_headers [] = $k . ': ' . $v;
}
curl_setopt ( $curl_handle, CURLOPT_HTTPHEADER, $temp_headers );
}
switch ($this->method) {
case self::HTTP_PUT :
curl_setopt ( $curl_handle, CURLOPT_CUSTOMREQUEST, 'PUT' );
if (isset ( $this->read_stream )) {
if (! isset ( $this->read_stream_size ) || $this->read_stream_size < 0) {
throw new BCS_RequestCore_Exception ( 'The stream size for the streaming upload cannot be determined.' );
}
curl_setopt ( $curl_handle, CURLOPT_INFILESIZE, $this->read_stream_size );
curl_setopt ( $curl_handle, CURLOPT_UPLOAD, true );
} else {
curl_setopt ( $curl_handle, CURLOPT_POSTFIELDS, $this->request_body );
}
break;
case self::HTTP_POST :
curl_setopt ( $curl_handle, CURLOPT_POST, true );
curl_setopt ( $curl_handle, CURLOPT_POSTFIELDS, $this->request_body );
break;
case self::HTTP_HEAD :
curl_setopt ( $curl_handle, CURLOPT_CUSTOMREQUEST, self::HTTP_HEAD );
curl_setopt ( $curl_handle, CURLOPT_NOBODY, 1 );
break;
default : // Assumed GET
curl_setopt ( $curl_handle, CURLOPT_CUSTOMREQUEST, $this->method );
if (isset ( $this->write_stream )) {
curl_setopt ( $curl_handle, CURLOPT_WRITEFUNCTION, array (
$this,
'streaming_write_callback' ) );
curl_setopt ( $curl_handle, CURLOPT_HEADER, false );
} else {
curl_setopt ( $curl_handle, CURLOPT_POSTFIELDS, $this->request_body );
}
break;
}
// Merge in the CURLOPTs
if (isset ( $this->curlopts ) && sizeof ( $this->curlopts ) > 0) {
foreach ( $this->curlopts as $k => $v ) {
curl_setopt ( $curl_handle, $k, $v );
}
}
return $curl_handle;
}
/**
* is the environment BAE?
* @return boolean the result of the answer
*/
private function isBaeEnv() {
if (isset ( $_SERVER ['HTTP_HOST'] )) {
$host = $_SERVER ['HTTP_HOST'];
$pos = strpos ( $host, '.' );
if ($pos !== false) {
$substr = substr ( $host, $pos + 1 );
if ($substr == 'duapp.com') {
return true;
}
}
}
if (isset ( $_SERVER ["HTTP_BAE_LOGID"] )) {
return true;
}
return false;
}
/**
* Take the post-processed cURL data and break it down into useful header/body/info chunks. Uses the
* data stored in the `curl_handle` and `response` properties unless replacement data is passed in via
* parameters.
*
* @param resource $curl_handle (Optional) The reference to the already executed cURL request.
* @param string $response (Optional) The actual response content itself that needs to be parsed.
* @return BCS_ResponseCore A <BCS_ResponseCore> object containing a parsed HTTP response.
*/
public function process_response($curl_handle = null, $response = null) {
// Accept a custom one if it's passed.
if ($curl_handle && $response) {
$this->curl_handle = $curl_handle;
$this->response = $response;
}
// As long as this came back as a valid resource...
if (is_resource ( $this->curl_handle )) {
// Determine what's what.
$header_size = curl_getinfo ( $this->curl_handle, CURLINFO_HEADER_SIZE );
$this->response_headers = substr ( $this->response, 0, $header_size );
$this->response_body = substr ( $this->response, $header_size );
$this->response_code = curl_getinfo ( $this->curl_handle, CURLINFO_HTTP_CODE );
$this->response_info = curl_getinfo ( $this->curl_handle );
// Parse out the headers
$this->response_headers = explode ( "\r\n\r\n", trim ( $this->response_headers ) );
$this->response_headers = array_pop ( $this->response_headers );
$this->response_headers = explode ( "\r\n", $this->response_headers );
array_shift ( $this->response_headers );
// Loop through and split up the headers.
$header_assoc = array ();
foreach ( $this->response_headers as $header ) {
$kv = explode ( ': ', $header );
//$header_assoc [strtolower ( $kv [0] )] = $kv [1];
$header_assoc [$kv [0]] = $kv [1];
}
// Reset the headers to the appropriate property.
$this->response_headers = $header_assoc;
$this->response_headers ['_info'] = $this->response_info;
$this->response_headers ['_info'] ['method'] = $this->method;
if ($curl_handle && $response) {
$class='\Think\Upload\Driver\Bcs\\'. $this->response_class;
return new $class ( $this->response_headers, $this->response_body, $this->response_code, $this->curl_handle );
}
}
// Return false
return false;
}
/**
* Sends the request, calling necessary utility functions to update built-in properties.
*
* @param boolean $parse (Optional) Whether to parse the response with BCS_ResponseCore or not.
* @return string The resulting unparsed data from the request.
*/
public function send_request($parse = false) {
if (false === $this->isBaeEnv ()) {
set_time_limit ( 0 );
}
$curl_handle = $this->prep_request ();
$this->response = curl_exec ( $curl_handle );
if ($this->response === false ||
($this->method === self::HTTP_GET &&
curl_errno($curl_handle) === CURLE_PARTIAL_FILE)) {
throw new BCS_RequestCore_Exception ( 'cURL resource: ' . ( string ) $curl_handle . '; cURL error: ' . curl_error ( $curl_handle ) . ' (' . curl_errno ( $curl_handle ) . ')' );
}
$parsed_response = $this->process_response ( $curl_handle, $this->response );
curl_close ( $curl_handle );
if ($parse) {
return $parsed_response;
}
return $this->response;
}
/**
* Sends the request using <php:curl_multi_exec()>, enabling parallel requests. Uses the "rolling" method.
*
* @param array $handles (Required) An indexed array of cURL handles to process simultaneously.
* @param array $opt (Optional) An associative array of parameters that can have the following keys: <ul>
* <li><code>callback</code> - <code>string|array</code> - Optional - The string name of a function to pass the response data to. If this is a method, pass an array where the <code>[0]</code> index is the class and the <code>[1]</code> index is the method name.</li>
* <li><code>limit</code> - <code>integer</code> - Optional - The number of simultaneous requests to make. This can be useful for scaling around slow server responses. Defaults to trusting cURLs judgement as to how many to use.</li></ul>
* @return array Post-processed cURL responses.
*/
public function send_multi_request($handles, $opt = null) {
if (false === $this->isBaeEnv ()) {
set_time_limit ( 0 );
}
// Skip everything if there are no handles to process.
if (count ( $handles ) === 0)
return array ();
if (! $opt)
$opt = array ();
// Initialize any missing options
$limit = isset ( $opt ['limit'] ) ? $opt ['limit'] : - 1;
// Initialize
$handle_list = $handles;
$http = new $this->request_class ();
$multi_handle = curl_multi_init ();
$handles_post = array ();
$added = count ( $handles );
$last_handle = null;
$count = 0;
$i = 0;
// Loop through the cURL handles and add as many as it set by the limit parameter.
while ( $i < $added ) {
if ($limit > 0 && $i >= $limit)
break;
curl_multi_add_handle ( $multi_handle, array_shift ( $handles ) );
$i ++;
}
do {
$active = false;
// Start executing and wait for a response.
while ( ($status = curl_multi_exec ( $multi_handle, $active )) === CURLM_CALL_MULTI_PERFORM ) {
// Start looking for possible responses immediately when we have to add more handles
if (count ( $handles ) > 0)
break;
}
// Figure out which requests finished.
$to_process = array ();
while ( $done = curl_multi_info_read ( $multi_handle ) ) {
// Since curl_errno() isn't reliable for handles that were in multirequests, we check the 'result' of the info read, which contains the curl error number, (listed here http://curl.haxx.se/libcurl/c/libcurl-errors.html )
if ($done ['result'] > 0) {
throw new BCS_RequestCore_Exception ( 'cURL resource: ' . ( string ) $done ['handle'] . '; cURL error: ' . curl_error ( $done ['handle'] ) . ' (' . $done ['result'] . ')' );
} // Because curl_multi_info_read() might return more than one message about a request, we check to see if this request is already in our array of completed requests
elseif (! isset ( $to_process [( int ) $done ['handle']] )) {
$to_process [( int ) $done ['handle']] = $done;
}
}
// Actually deal with the request
foreach ( $to_process as $pkey => $done ) {
$response = $http->process_response ( $done ['handle'], curl_multi_getcontent ( $done ['handle'] ) );
$key = array_search ( $done ['handle'], $handle_list, true );
$handles_post [$key] = $response;
if (count ( $handles ) > 0) {
curl_multi_add_handle ( $multi_handle, array_shift ( $handles ) );
}
curl_multi_remove_handle ( $multi_handle, $done ['handle'] );
curl_close ( $done ['handle'] );
}
} while ( $active || count ( $handles_post ) < $added );
curl_multi_close ( $multi_handle );
ksort ( $handles_post, SORT_NUMERIC );
return $handles_post;
}
/*%******************************************************************************************%*/
// RESPONSE METHODS
/**
* Get the HTTP response headers from the request.
*
* @param string $header (Optional) A specific header value to return. Defaults to all headers.
* @return string|array All or selected header values.
*/
public function get_response_header($header = null) {
if ($header) {
// return $this->response_headers [strtolower ( $header )];
return $this->response_headers [$header];
}
return $this->response_headers;
}
/**
* Get the HTTP response body from the request.
*
* @return string The response body.
*/
public function get_response_body() {
return $this->response_body;
}
/**
* Get the HTTP response code from the request.
*
* @return string The HTTP response code.
*/
public function get_response_code() {
return $this->response_code;
}
}
/**
* Container for all response-related methods.
*/
class BCS_ResponseCore {
/**
* Stores the HTTP header information.
*/
public $header;
/**
* Stores the SimpleXML response.
*/
public $body;
/**
* Stores the HTTP response code.
*/
public $status;
/**
* Constructs a new instance of this class.
*
* @param array $header (Required) Associative array of HTTP headers (typically returned by <BCS_RequestCore::get_response_header()>).
* @param string $body (Required) XML-formatted response from AWS.
* @param integer $status (Optional) HTTP response status code from the request.
* @return object Contains an <php:array> `header` property (HTTP headers as an associative array), a <php:SimpleXMLElement> or <php:string> `body` property, and an <php:integer> `status` code.
*/
public function __construct($header, $body, $status = null) {
$this->header = $header;
$this->body = $body;
$this->status = $status;
return $this;
}
/**
* Did we receive the status code we expected?
*
* @param integer|array $codes (Optional) The status code(s) to expect. Pass an <php:integer> for a single acceptable value, or an <php:array> of integers for multiple acceptable values.
* @return boolean Whether we received the expected status code or not.
*/
public function isOK($codes = array(200, 201, 204, 206)) {
if (is_array ( $codes )) {
return in_array ( $this->status, $codes );
}
return $this->status === $codes;
}
}
/**
* Default BCS_RequestCore Exception.
*/
class BCS_RequestCore_Exception extends \Exception {
}

View File

@@ -0,0 +1,163 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: 麦当苗儿 <zuojiazi@vip.qq.com> <http://www.zjzit.cn>
// +----------------------------------------------------------------------
namespace Think\Upload\Driver;
class Ftp {
/**
* 上传文件根目录
* @var string
*/
private $rootPath;
/**
* 本地上传错误信息
* @var string
*/
private $error = ''; //上传错误信息
/**
* FTP连接
* @var resource
*/
private $link;
private $config = array(
'host' => '', //服务器
'port' => 21, //端口
'timeout' => 90, //超时时间
'username' => '', //用户名
'password' => '', //密码
);
/**
* 构造函数,用于设置上传根路径
* @param array $config FTP配置
*/
public function __construct($config){
/* 默认FTP配置 */
$this->config = array_merge($this->config, $config);
/* 登录FTP服务器 */
if(!$this->login()){
E($this->error);
}
}
/**
* 检测上传根目录
* @param string $rootpath 根目录
* @return boolean true-检测通过false-检测失败
*/
public function checkRootPath($rootpath){
/* 设置根目录 */
$this->rootPath = ftp_pwd($this->link) . '/' . ltrim($rootpath, '/');
if(!@ftp_chdir($this->link, $this->rootPath)){
$this->error = '上传根目录不存在!';
return false;
}
return true;
}
/**
* 检测上传目录
* @param string $savepath 上传目录
* @return boolean 检测结果true-通过false-失败
*/
public function checkSavePath($savepath){
/* 检测并创建目录 */
if (!$this->mkdir($savepath)) {
return false;
} else {
//TODO:检测目录是否可写
return true;
}
}
/**
* 保存指定文件
* @param array $file 保存的文件信息
* @param boolean $replace 同名文件是否覆盖
* @return boolean 保存状态true-成功false-失败
*/
public function save($file, $replace=true) {
$filename = $this->rootPath . $file['savepath'] . $file['savename'];
/* 不覆盖同名文件 */
// if (!$replace && is_file($filename)) {
// $this->error = '存在同名文件' . $file['savename'];
// return false;
// }
/* 移动文件 */
if (!ftp_put($this->link, $filename, $file['tmp_name'], FTP_BINARY)) {
$this->error = '文件上传保存错误!';
return false;
}
return true;
}
/**
* 创建目录
* @param string $savepath 要创建的目录
* @return boolean 创建状态true-成功false-失败
*/
public function mkdir($savepath){
$dir = $this->rootPath . $savepath;
if(ftp_chdir($this->link, $dir)){
return true;
}
if(ftp_mkdir($this->link, $dir)){
return true;
} elseif($this->mkdir(dirname($savepath)) && ftp_mkdir($this->link, $dir)) {
return true;
} else {
$this->error = "目录 {$savepath} 创建失败!";
return false;
}
}
/**
* 获取最后一次上传错误信息
* @return string 错误信息
*/
public function getError(){
return $this->error;
}
/**
* 登录到FTP服务器
* @return boolean true-登录成功false-登录失败
*/
private function login(){
extract($this->config);
$this->link = ftp_connect($host, $port, $timeout);
if($this->link) {
if (ftp_login($this->link, $username, $password)) {
return true;
} else {
$this->error = "无法登录到FTP服务器username - {$username}";
}
} else {
$this->error = "无法连接到FTP服务器{$host}";
}
return false;
}
/**
* 析构方法用于断开当前FTP连接
*/
public function __destruct() {
ftp_close($this->link);
}
}

View File

@@ -0,0 +1,118 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: 麦当苗儿 <zuojiazi@vip.qq.com> <http://www.zjzit.cn>
// +----------------------------------------------------------------------
namespace Think\Upload\Driver;
class Local{
/**
* 上传文件根目录
* @var string
*/
private $rootPath;
/**
* 本地上传错误信息
* @var string
*/
private $error = ''; //上传错误信息
/**
* 构造函数,用于设置上传根路径
*/
public function __construct($config = null){
}
/**
* 检测上传根目录
* @param string $rootpath 根目录
* @return boolean true-检测通过false-检测失败
*/
public function checkRootPath($rootpath){
if(!(is_dir($rootpath) && is_writable($rootpath))){
$this->error = '上传根目录不存在!请尝试手动创建:'.$rootpath;
return false;
}
$this->rootPath = $rootpath;
return true;
}
/**
* 检测上传目录
* @param string $savepath 上传目录
* @return boolean 检测结果true-通过false-失败
*/
public function checkSavePath($savepath){
/* 检测并创建目录 */
if (!$this->mkdir($savepath)) {
return false;
} else {
/* 检测目录是否可写 */
if (!is_writable($this->rootPath . $savepath)) {
$this->error = '上传目录 ' . $savepath . ' 不可写!';
return false;
} else {
return true;
}
}
}
/**
* 保存指定文件
* @param array $file 保存的文件信息
* @param boolean $replace 同名文件是否覆盖
* @return boolean 保存状态true-成功false-失败
*/
public function save($file, $replace=true) {
$filename = $this->rootPath . $file['savepath'] . $file['savename'];
/* 不覆盖同名文件 */
if (!$replace && is_file($filename)) {
$this->error = '存在同名文件' . $file['savename'];
return false;
}
/* 移动文件 */
if (!move_uploaded_file($file['tmp_name'], $filename)) {
$this->error = '文件上传保存错误!';
return false;
}
return true;
}
/**
* 创建目录
* @param string $savepath 要创建的穆里
* @return boolean 创建状态true-成功false-失败
*/
public function mkdir($savepath){
$dir = $this->rootPath . $savepath;
if(is_dir($dir)){
return true;
}
if(mkdir($dir, 0777, true)){
return true;
} else {
$this->error = "目录 {$savepath} 创建失败!";
return false;
}
}
/**
* 获取最后一次上传错误信息
* @return string 错误信息
*/
public function getError(){
return $this->error;
}
}

View File

@@ -0,0 +1,102 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: yangweijie <yangweijiester@gmail.com> <http://www.code-tech.diandian.com>
// +----------------------------------------------------------------------
namespace Think\Upload\Driver;
use Think\Upload\Driver\Qiniu\QiniuStorage;
class Qiniu{
/**
* 上传文件根目录
* @var string
*/
private $rootPath;
/**
* 上传错误信息
* @var string
*/
private $error = '';
private $config = array(
'secretKey' => '', //七牛服务器
'accessKey' => '', //七牛用户
'domain' => '', //七牛密码
'bucket' => '', //空间名称
'timeout' => 300, //超时时间
);
/**
* 构造函数,用于设置上传根路径
* @param array $config FTP配置
*/
public function __construct($config){
$this->config = array_merge($this->config, $config);
/* 设置根目录 */
$this->qiniu = new QiniuStorage($config);
}
/**
* 检测上传根目录(七牛上传时支持自动创建目录,直接返回)
* @param string $rootpath 根目录
* @return boolean true-检测通过false-检测失败
*/
public function checkRootPath($rootpath){
$this->rootPath = trim($rootpath, './') . '/';
return true;
}
/**
* 检测上传目录(七牛上传时支持自动创建目录,直接返回)
* @param string $savepath 上传目录
* @return boolean 检测结果true-通过false-失败
*/
public function checkSavePath($savepath){
return true;
}
/**
* 创建文件夹 (七牛上传时支持自动创建目录,直接返回)
* @param string $savepath 目录名称
* @return boolean true-创建成功false-创建失败
*/
public function mkdir($savepath){
return true;
}
/**
* 保存指定文件
* @param array $file 保存的文件信息
* @param boolean $replace 同名文件是否覆盖
* @return boolean 保存状态true-成功false-失败
*/
public function save(&$file,$replace=true) {
$file['name'] = $file['savepath'] . $file['savename'];
$key = str_replace('/', '_', $file['name']);
$upfile = array(
'name'=>'file',
'fileName'=>$key,
'fileBody'=>file_get_contents($file['tmp_name'])
);
$config = array();
$result = $this->qiniu->upload($config, $upfile);
$url = $this->qiniu->downlink($key);
$file['url'] = $url;
return false ===$result ? false : true;
}
/**
* 获取最后一次上传错误信息
* @return string 错误信息
*/
public function getError(){
return $this->qiniu->errorStr;
}
}

View File

@@ -0,0 +1,333 @@
<?php
namespace Think\Upload\Driver\Qiniu;
class QiniuStorage {
public $QINIU_RSF_HOST = 'http://rsf.qbox.me';
public $QINIU_RS_HOST = 'http://rs.qbox.me';
public $QINIU_UP_HOST = 'http://up.qiniu.com';
public $timeout = '';
public function __construct($config){
$this->sk = $config['secretKey'];
$this->ak = $config['accessKey'];
$this->domain = $config['domain'];
$this->bucket = $config['bucket'];
$this->timeout = isset($config['timeout'])? $config['timeout'] : 3600;
}
static function sign($sk, $ak, $data){
$sign = hash_hmac('sha1', $data, $sk, true);
return $ak . ':' . self::Qiniu_Encode($sign);
}
static function signWithData($sk, $ak, $data){
$data = self::Qiniu_Encode($data);
return self::sign($sk, $ak, $data) . ':' . $data;
}
public function accessToken($url, $body=''){
$parsed_url = parse_url($url);
$path = $parsed_url['path'];
$access = $path;
if (isset($parsed_url['query'])) {
$access .= "?" . $parsed_url['query'];
}
$access .= "\n";
if($body){
$access .= $body;
}
return self::sign($this->sk, $this->ak, $access);
}
public function UploadToken($sk ,$ak ,$param){
$param['deadline'] = $param['Expires'] == 0? 3600: $param['Expires'];
$param['deadline'] += time();
$data = array('scope'=> $this->bucket, 'deadline'=>$param['deadline']);
if (!empty($param['CallbackUrl'])) {
$data['callbackUrl'] = $param['CallbackUrl'];
}
if (!empty($param['CallbackBody'])) {
$data['callbackBody'] = $param['CallbackBody'];
}
if (!empty($param['ReturnUrl'])) {
$data['returnUrl'] = $param['ReturnUrl'];
}
if (!empty($param['ReturnBody'])) {
$data['returnBody'] = $param['ReturnBody'];
}
if (!empty($param['AsyncOps'])) {
$data['asyncOps'] = $param['AsyncOps'];
}
if (!empty($param['EndUser'])) {
$data['endUser'] = $param['EndUser'];
}
$data = json_encode($data);
return self::SignWithData($sk, $ak, $data);
}
public function upload($config, $file){
$uploadToken = $this->UploadToken($this->sk, $this->ak, $config);
$url = "{$this->QINIU_UP_HOST}";
$mimeBoundary = md5(microtime());
$header = array('Content-Type'=>'multipart/form-data;boundary='.$mimeBoundary);
$data = array();
$fields = array(
'token' => $uploadToken,
'key' => $config['saveName']? : $file['fileName'],
);
if(is_array($config['custom_fields']) && $config['custom_fields'] !== array()){
$fields = array_merge($fields, $config['custom_fields']);
}
foreach ($fields as $name => $val) {
array_push($data, '--' . $mimeBoundary);
array_push($data, "Content-Disposition: form-data; name=\"$name\"");
array_push($data, '');
array_push($data, $val);
}
//文件
array_push($data, '--' . $mimeBoundary);
$name = $file['name'];
$fileName = $file['fileName'];
$fileBody = $file['fileBody'];
$fileName = self::Qiniu_escapeQuotes($fileName);
array_push($data, "Content-Disposition: form-data; name=\"$name\"; filename=\"$fileName\"");
array_push($data, 'Content-Type: application/octet-stream');
array_push($data, '');
array_push($data, $fileBody);
array_push($data, '--' . $mimeBoundary . '--');
array_push($data, '');
$body = implode("\r\n", $data);
$response = $this->request($url, 'POST', $header, $body);
return $response;
}
public function dealWithType($key, $type){
$param = $this->buildUrlParam();
$url = '';
switch($type){
case 'img':
$url = $this->downLink($key);
if($param['imageInfo']){
$url .= '?imageInfo';
}else if($param['exif']){
$url .= '?exif';
}else if($param['imageView']){
$url .= '?imageView/'.$param['mode'];
if($param['w'])
$url .= "/w/{$param['w']}";
if($param['h'])
$url .= "/h/{$param['h']}";
if($param['q'])
$url .= "/q/{$param['q']}";
if($param['format'])
$url .= "/format/{$param['format']}";
}
break;
case 'video': //TODO 视频处理
case 'doc':
$url = $this->downLink($key);
$url .= '?md2html';
if(isset($param['mode']))
$url .= '/'.(int)$param['mode'];
if($param['cssurl'])
$url .= '/'. self::Qiniu_Encode($param['cssurl']);
break;
}
return $url;
}
public function buildUrlParam(){
return $_REQUEST;
}
//获取某个路径下的文件列表
public function getList($query = array(), $path = ''){
$query = array_merge(array('bucket'=>$this->bucket), $query);
$url = "{$this->QINIU_RSF_HOST}/list?".http_build_query($query);
$accessToken = $this->accessToken($url);
$response = $this->request($url, 'POST', array('Authorization'=>"QBox $accessToken"));
return $response;
}
//获取某个文件的信息
public function info($key){
$key = trim($key);
$url = "{$this->QINIU_RS_HOST}/stat/" . self::Qiniu_Encode("{$this->bucket}:{$key}");
$accessToken = $this->accessToken($url);
$response = $this->request($url, 'POST', array(
'Authorization' => "QBox $accessToken",
));
return $response;
}
//获取文件下载资源链接
public function downLink($key){
$key = urlencode($key);
$key = self::Qiniu_escapeQuotes($key);
$url = "http://{$this->domain}/{$key}";
return $url;
}
//重命名单个文件
public function rename($file, $new_file){
$key = trim($file);
$url = "{$this->QINIU_RS_HOST}/move/" . self::Qiniu_Encode("{$this->bucket}:{$key}") .'/'. self::Qiniu_Encode("{$this->bucket}:{$new_file}");
trace($url);
$accessToken = $this->accessToken($url);
$response = $this->request($url, 'POST', array('Authorization'=>"QBox $accessToken"));
return $response;
}
//删除单个文件
public function del($file){
$key = trim($file);
$url = "{$this->QINIU_RS_HOST}/delete/" . self::Qiniu_Encode("{$this->bucket}:{$key}");
$accessToken = $this->accessToken($url);
$response = $this->request($url, 'POST', array('Authorization'=>"QBox $accessToken"));
return $response;
}
//批量删除文件
public function delBatch($files){
$url = $this->QINIU_RS_HOST . '/batch';
$ops = array();
foreach ($files as $file) {
$ops[] = "/delete/". self::Qiniu_Encode("{$this->bucket}:{$file}");
}
$params = 'op=' . implode('&op=', $ops);
$url .= '?'.$params;
trace($url);
$accessToken = $this->accessToken($url);
$response = $this->request($url, 'POST', array('Authorization'=>"QBox $accessToken"));
return $response;
}
static function Qiniu_Encode($str) {// URLSafeBase64Encode
$find = array('+', '/');
$replace = array('-', '_');
return str_replace($find, $replace, base64_encode($str));
}
static function Qiniu_escapeQuotes($str){
$find = array("\\", "\"");
$replace = array("\\\\", "\\\"");
return str_replace($find, $replace, $str);
}
/**
* 请求云服务器
* @param string $path 请求的PATH
* @param string $method 请求方法
* @param array $headers 请求header
* @param resource $body 上传文件资源
* @return boolean
*/
private function request($path, $method, $headers = null, $body = null){
$ch = curl_init($path);
$_headers = array('Expect:');
if (!is_null($headers) && is_array($headers)){
foreach($headers as $k => $v) {
array_push($_headers, "{$k}: {$v}");
}
}
$length = 0;
$date = gmdate('D, d M Y H:i:s \G\M\T');
if (!is_null($body)) {
if(is_resource($body)){
fseek($body, 0, SEEK_END);
$length = ftell($body);
fseek($body, 0);
array_push($_headers, "Content-Length: {$length}");
curl_setopt($ch, CURLOPT_INFILE, $body);
curl_setopt($ch, CURLOPT_INFILESIZE, $length);
} else {
$length = @strlen($body);
array_push($_headers, "Content-Length: {$length}");
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
}
} else {
array_push($_headers, "Content-Length: {$length}");
}
// array_push($_headers, 'Authorization: ' . $this->sign($method, $uri, $date, $length));
array_push($_headers, "Date: {$date}");
curl_setopt($ch, CURLOPT_HTTPHEADER, $_headers);
curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeout);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
if ($method == 'PUT' || $method == 'POST') {
curl_setopt($ch, CURLOPT_POST, 1);
} else {
curl_setopt($ch, CURLOPT_POST, 0);
}
if ($method == 'HEAD') {
curl_setopt($ch, CURLOPT_NOBODY, true);
}
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
list($header, $body) = explode("\r\n\r\n", $response, 2);
if ($status == 200) {
if ($method == 'GET') {
return $body;
} else {
return $this->response($response);
}
} else {
$this->error($header , $body);
return false;
}
}
/**
* 获取响应数据
* @param string $text 响应头字符串
* @return array 响应数据列表
*/
private function response($text){
$headers = explode(PHP_EOL, $text);
$items = array();
foreach($headers as $header) {
$header = trim($header);
if(strpos($header, '{') !== False){
$items = json_decode($header, 1);
break;
}
}
return $items;
}
/**
* 获取请求错误信息
* @param string $header 请求返回头信息
*/
private function error($header, $body) {
list($status, $stash) = explode("\r\n", $header, 2);
list($v, $code, $message) = explode(" ", $status, 3);
$message = is_null($message) ? 'File Not Found' : "[{$status}]:{$message}]";
$this->error = $message;
$this->errorStr = json_decode($body ,1);
$this->errorStr = $this->errorStr['error'];
}
}

View File

@@ -0,0 +1,106 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: luofei614<weibo.com/luofei614>
// +----------------------------------------------------------------------
namespace Think\Upload\Driver;
class Sae{
/**
* Storage的Domain
* @var string
*/
private $domain = '';
private $rootPath = '';
/**
* 本地上传错误信息
* @var string
*/
private $error = '';
/**
* 构造函数设置storage的domain 如果有传配置则domain为配置项如果没有传domain为第一个路径的目录名称。
* @param mixed $config 上传配置
*/
public function __construct($config = null){
if(is_array($config) && !empty($config['domain'])){
$this->domain = strtolower($config['domain']);
}
}
/**
* 检测上传根目录
* @param string $rootpath 根目录
* @return boolean true-检测通过false-检测失败
*/
public function checkRootPath($rootpath){
$rootpath = trim($rootpath,'./');
if(!$this->domain){
$rootpath = explode('/', $rootpath);
$this->domain = strtolower(array_shift($rootpath));
$rootpath = implode('/', $rootpath);
}
$this->rootPath = $rootpath;
$st = new \SaeStorage();
if(false===$st->getDomainCapacity($this->domain)){
$this->error = '您好像没有建立Storage的domain['.$this->domain.']';
return false;
}
return true;
}
/**
* 检测上传目录
* @param string $savepath 上传目录
* @return boolean 检测结果true-通过false-失败
*/
public function checkSavePath($savepath){
return true;
}
/**
* 保存指定文件
* @param array $file 保存的文件信息
* @param boolean $replace 同名文件是否覆盖
* @return boolean 保存状态true-成功false-失败
*/
public function save(&$file, $replace=true) {
$filename = ltrim($this->rootPath .'/'. $file['savepath'] . $file['savename'],'/');
$st = new \SaeStorage();
/* 不覆盖同名文件 */
if (!$replace && $st->fileExists($this->domain,$filename)) {
$this->error = '存在同名文件' . $file['savename'];
return false;
}
/* 移动文件 */
if (!$st->upload($this->domain,$filename,$file['tmp_name'])) {
$this->error = '文件上传保存错误!['.$st->errno().']:'.$st->errmsg();
return false;
}else{
$file['url'] = $st->getUrl($this->domain, $filename);
}
return true;
}
public function mkdir(){
return true;
}
/**
* 获取最后一次上传错误信息
* @return string 错误信息
*/
public function getError(){
return $this->error;
}
}

View File

@@ -0,0 +1,218 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: 麦当苗儿 <zuojiazi@vip.qq.com> <http://www.zjzit.cn>
// +----------------------------------------------------------------------
namespace Think\Upload\Driver;
class Upyun{
/**
* 上传文件根目录
* @var string
*/
private $rootPath;
/**
* 上传错误信息
* @var string
*/
private $error = '';
private $config = array(
'host' => '', //又拍云服务器
'username' => '', //又拍云用户
'password' => '', //又拍云密码
'bucket' => '', //空间名称
'timeout' => 90, //超时时间
);
/**
* 构造函数,用于设置上传根路径
* @param array $config FTP配置
*/
public function __construct($config){
/* 默认FTP配置 */
$this->config = array_merge($this->config, $config);
$this->config['password'] = md5($this->config['password']);
}
/**
* 检测上传根目录(又拍云上传时支持自动创建目录,直接返回)
* @param string $rootpath 根目录
* @return boolean true-检测通过false-检测失败
*/
public function checkRootPath($rootpath){
/* 设置根目录 */
$this->rootPath = trim($rootpath, './') . '/';
return true;
}
/**
* 检测上传目录(又拍云上传时支持自动创建目录,直接返回)
* @param string $savepath 上传目录
* @return boolean 检测结果true-通过false-失败
*/
public function checkSavePath($savepath){
return true;
}
/**
* 创建文件夹 (又拍云上传时支持自动创建目录,直接返回)
* @param string $savepath 目录名称
* @return boolean true-创建成功false-创建失败
*/
public function mkdir($savepath){
return true;
}
/**
* 保存指定文件
* @param array $file 保存的文件信息
* @param boolean $replace 同名文件是否覆盖
* @return boolean 保存状态true-成功false-失败
*/
public function save($file, $replace = true) {
$header['Content-Type'] = $file['type'];
$header['Content-MD5'] = $file['md5'];
$header['Mkdir'] = 'true';
$resource = fopen($file['tmp_name'], 'r');
$save = $this->rootPath . $file['savepath'] . $file['savename'];
$data = $this->request($save, 'PUT', $header, $resource);
return false === $data ? false : true;
}
/**
* 获取最后一次上传错误信息
* @return string 错误信息
*/
public function getError(){
return $this->error;
}
/**
* 请求又拍云服务器
* @param string $path 请求的PATH
* @param string $method 请求方法
* @param array $headers 请求header
* @param resource $body 上传文件资源
* @return boolean
*/
private function request($path, $method, $headers = null, $body = null){
$uri = "/{$this->config['bucket']}/{$path}";
$ch = curl_init($this->config['host'] . $uri);
$_headers = array('Expect:');
if (!is_null($headers) && is_array($headers)){
foreach($headers as $k => $v) {
array_push($_headers, "{$k}: {$v}");
}
}
$length = 0;
$date = gmdate('D, d M Y H:i:s \G\M\T');
if (!is_null($body)) {
if(is_resource($body)){
fseek($body, 0, SEEK_END);
$length = ftell($body);
fseek($body, 0);
array_push($_headers, "Content-Length: {$length}");
curl_setopt($ch, CURLOPT_INFILE, $body);
curl_setopt($ch, CURLOPT_INFILESIZE, $length);
} else {
$length = @strlen($body);
array_push($_headers, "Content-Length: {$length}");
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
}
} else {
array_push($_headers, "Content-Length: {$length}");
}
array_push($_headers, 'Authorization: ' . $this->sign($method, $uri, $date, $length));
array_push($_headers, "Date: {$date}");
curl_setopt($ch, CURLOPT_HTTPHEADER, $_headers);
curl_setopt($ch, CURLOPT_TIMEOUT, $this->config['timeout']);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 0);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
if ($method == 'PUT' || $method == 'POST') {
curl_setopt($ch, CURLOPT_POST, 1);
} else {
curl_setopt($ch, CURLOPT_POST, 0);
}
if ($method == 'HEAD') {
curl_setopt($ch, CURLOPT_NOBODY, true);
}
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
list($header, $body) = explode("\r\n\r\n", $response, 2);
if ($status == 200) {
if ($method == 'GET') {
return $body;
} else {
$data = $this->response($header);
return count($data) > 0 ? $data : true;
}
} else {
$this->error($header);
return false;
}
}
/**
* 获取响应数据
* @param string $text 响应头字符串
* @return array 响应数据列表
*/
private function response($text){
$headers = explode("\r\n", $text);
$items = array();
foreach($headers as $header) {
$header = trim($header);
if(strpos($header, 'x-upyun') !== False){
list($k, $v) = explode(':', $header);
$items[trim($k)] = in_array(substr($k,8,5), array('width','heigh','frame')) ? intval($v) : trim($v);
}
}
return $items;
}
/**
* 生成请求签名
* @param string $method 请求方法
* @param string $uri 请求URI
* @param string $date 请求时间
* @param integer $length 请求内容大小
* @return string 请求签名
*/
private function sign($method, $uri, $date, $length){
$sign = "{$method}&{$uri}&{$date}&{$length}&{$this->config['password']}";
return 'UpYun ' . $this->config['username'] . ':' . md5($sign);
}
/**
* 获取请求错误信息
* @param string $header 请求返回头信息
*/
private function error($header) {
list($status, $stash) = explode("\r\n", $header, 2);
list($v, $code, $message) = explode(" ", $status, 3);
$message = is_null($message) ? 'File Not Found' : "[{$status}]:{$message}";
$this->error = $message;
}
}

View File

@@ -0,0 +1,293 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2014 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: 麦当苗儿 <zuojiazi@vip.qq.com> <http://www.zjzit.cn>
// +----------------------------------------------------------------------
namespace Think;
class Verify {
protected $config = array(
'seKey' => 'ThinkPHP.CN', // 验证码加密密钥
'codeSet' => '2345678abcdefhijkmnpqrstuvwxyzABCDEFGHJKLMNPQRTUVWXY', // 验证码字符集合
'expire' => 1800, // 验证码过期时间s
'useZh' => false, // 使用中文验证码
'zhSet' => '们以我到他会作时要动国产的一是工就年阶义发成部民可出能方进在了不和有大这主中人上为来分生对于学下级地个用同行面说种过命度革而多子后自社加小机也经力线本电高量长党得实家定深法表着水理化争现所二起政三好十战无农使性前等反体合斗路图把结第里正新开论之物从当两些还天资事队批点育重其思与间内去因件日利相由压员气业代全组数果期导平各基或月毛然如应形想制心样干都向变关问比展那它最及外没看治提五解系林者米群头意只明四道马认次文通但条较克又公孔领军流入接席位情运器并飞原油放立题质指建区验活众很教决特此常石强极土少已根共直团统式转别造切九你取西持总料连任志观调七么山程百报更见必真保热委手改管处己将修支识病象几先老光专什六型具示复安带每东增则完风回南广劳轮科北打积车计给节做务被整联步类集号列温装即毫知轴研单色坚据速防史拉世设达尔场织历花受求传口断况采精金界品判参层止边清至万确究书术状厂须离再目海交权且儿青才证低越际八试规斯近注办布门铁需走议县兵固除般引齿千胜细影济白格效置推空配刀叶率述今选养德话查差半敌始片施响收华觉备名红续均药标记难存测士身紧液派准斤角降维板许破述技消底床田势端感往神便贺村构照容非搞亚磨族火段算适讲按值美态黄易彪服早班麦削信排台声该击素张密害侯草何树肥继右属市严径螺检左页抗苏显苦英快称坏移约巴材省黑武培著河帝仅针怎植京助升王眼她抓含苗副杂普谈围食射源例致酸旧却充足短划剂宣环落首尺波承粉践府鱼随考刻靠够满夫失包住促枝局菌杆周护岩师举曲春元超负砂封换太模贫减阳扬江析亩木言球朝医校古呢稻宋听唯输滑站另卫字鼓刚写刘微略范供阿块某功套友限项余倒卷创律雨让骨远帮初皮播优占死毒圈伟季训控激找叫云互跟裂粮粒母练塞钢顶策双留误础吸阻故寸盾晚丝女散焊功株亲院冷彻弹错散商视艺灭版烈零室轻血倍缺厘泵察绝富城冲喷壤简否柱李望盘磁雄似困巩益洲脱投送奴侧润盖挥距触星松送获兴独官混纪依未突架宽冬章湿偏纹吃执阀矿寨责熟稳夺硬价努翻奇甲预职评读背协损棉侵灰虽矛厚罗泥辟告卵箱掌氧恩爱停曾溶营终纲孟钱待尽俄缩沙退陈讨奋械载胞幼哪剥迫旋征槽倒握担仍呀鲜吧卡粗介钻逐弱脚怕盐末阴丰雾冠丙街莱贝辐肠付吉渗瑞惊顿挤秒悬姆烂森糖圣凹陶词迟蚕亿矩康遵牧遭幅园腔订香肉弟屋敏恢忘编印蜂急拿扩伤飞露核缘游振操央伍域甚迅辉异序免纸夜乡久隶缸夹念兰映沟乙吗儒杀汽磷艰晶插埃燃欢铁补咱芽永瓦倾阵碳演威附牙芽永瓦斜灌欧献顺猪洋腐请透司危括脉宜笑若尾束壮暴企菜穗楚汉愈绿拖牛份染既秋遍锻玉夏疗尖殖井费州访吹荣铜沿替滚客召旱悟刺脑措贯藏敢令隙炉壳硫煤迎铸粘探临薄旬善福纵择礼愿伏残雷延烟句纯渐耕跑泽慢栽鲁赤繁境潮横掉锥希池败船假亮谓托伙哲怀割摆贡呈劲财仪沉炼麻罪祖息车穿货销齐鼠抽画饲龙库守筑房歌寒喜哥洗蚀废纳腹乎录镜妇恶脂庄擦险赞钟摇典柄辩竹谷卖乱虚桥奥伯赶垂途额壁网截野遗静谋弄挂课镇妄盛耐援扎虑键归符庆聚绕摩忙舞遇索顾胶羊湖钉仁音迹碎伸灯避泛亡答勇频皇柳哈揭甘诺概宪浓岛袭谁洪谢炮浇斑讯懂灵蛋闭孩释乳巨徒私银伊景坦累匀霉杜乐勒隔弯绩招绍胡呼痛峰零柴簧午跳居尚丁秦稍追梁折耗碱殊岗挖氏刃剧堆赫荷胸衡勤膜篇登驻案刊秧缓凸役剪川雪链渔啦脸户洛孢勃盟买杨宗焦赛旗滤硅炭股坐蒸凝竟陷枪黎救冒暗洞犯筒您宋弧爆谬涂味津臂障褐陆啊健尊豆拔莫抵桑坡缝警挑污冰柬嘴啥饭塑寄赵喊垫丹渡耳刨虎笔稀昆浪萨茶滴浅拥穴覆伦娘吨浸袖珠雌妈紫戏塔锤震岁貌洁剖牢锋疑霸闪埔猛诉刷狠忽灾闹乔唐漏闻沈熔氯荒茎男凡抢像浆旁玻亦忠唱蒙予纷捕锁尤乘乌智淡允叛畜俘摸锈扫毕璃宝芯爷鉴秘净蒋钙肩腾枯抛轨堂拌爸循诱祝励肯酒绳穷塘燥泡袋朗喂铝软渠颗惯贸粪综墙趋彼届墨碍启逆卸航衣孙龄岭骗休借', // 中文验证码字符串
'useImgBg' => false, // 使用背景图片
'fontSize' => 25, // 验证码字体大小(px)
'useCurve' => true, // 是否画混淆曲线
'useNoise' => true, // 是否添加杂点
'imageH' => 0, // 验证码图片高度
'imageW' => 0, // 验证码图片宽度
'length' => 5, // 验证码位数
'fontttf' => '', // 验证码字体,不设置随机获取
'bg' => array(243, 251, 254), // 背景颜色
'reset' => true, // 验证成功后是否重置
);
private $_image = NULL; // 验证码图片实例
private $_color = NULL; // 验证码字体颜色
/**
* 架构方法 设置参数
* @access public
* @param array $config 配置参数
*/
public function __construct($config=array()){
$this->config = array_merge($this->config, $config);
}
/**
* 使用 $this->name 获取配置
* @access public
* @param string $name 配置名称
* @return multitype 配置值
*/
public function __get($name) {
return $this->config[$name];
}
/**
* 设置验证码配置
* @access public
* @param string $name 配置名称
* @param string $value 配置值
* @return void
*/
public function __set($name,$value){
if(isset($this->config[$name])) {
$this->config[$name] = $value;
}
}
/**
* 检查配置
* @access public
* @param string $name 配置名称
* @return bool
*/
public function __isset($name){
return isset($this->config[$name]);
}
/**
* 验证验证码是否正确
* @access public
* @param string $code 用户验证码
* @param string $id 验证码标识
* @return bool 用户验证码是否正确
*/
public function check($code, $id = '') {
$key = $this->authcode($this->seKey).$id;
// 验证码不能为空
$secode = session($key);
if(empty($code) || empty($secode)) {
return false;
}
// session 过期
if(NOW_TIME - $secode['verify_time'] > $this->expire) {
session($key, null);
return false;
}
if($this->authcode(strtoupper($code)) == $secode['verify_code']) {
$this->reset && session($key, null);
return true;
}
return false;
}
/**
* 输出验证码并把验证码的值保存的session中
* 验证码保存到session的格式为 array('verify_code' => '验证码值', 'verify_time' => '验证码创建时间');
* @access public
* @param string $id 要生成验证码的标识
* @return void
*/
public function entry($id = '') {
// 图片宽(px)
$this->imageW || $this->imageW = $this->length*$this->fontSize*1.5 + $this->length*$this->fontSize/2;
// 图片高(px)
$this->imageH || $this->imageH = $this->fontSize * 2.5;
// 建立一幅 $this->imageW x $this->imageH 的图像
$this->_image = imagecreate($this->imageW, $this->imageH);
// 设置背景
imagecolorallocate($this->_image, $this->bg[0], $this->bg[1], $this->bg[2]);
// 验证码字体随机颜色
$this->_color = imagecolorallocate($this->_image, mt_rand(1,150), mt_rand(1,150), mt_rand(1,150));
// 验证码使用随机字体
$ttfPath = dirname(__FILE__) . '/Verify/' . ($this->useZh ? 'zhttfs' : 'ttfs') . '/';
if(empty($this->fontttf)){
$dir = dir($ttfPath);
$ttfs = array();
while (false !== ($file = $dir->read())) {
if($file[0] != '.' && substr($file, -4) == '.ttf') {
$ttfs[] = $file;
}
}
$dir->close();
$this->fontttf = $ttfs[array_rand($ttfs)];
}
$this->fontttf = $ttfPath . $this->fontttf;
if($this->useImgBg) {
$this->_background();
}
if ($this->useNoise) {
// 绘杂点
$this->_writeNoise();
}
if ($this->useCurve) {
// 绘干扰线
$this->_writeCurve();
}
// 绘验证码
$code = array(); // 验证码
$codeNX = 0; // 验证码第N个字符的左边距
if($this->useZh){ // 中文验证码
for ($i = 0; $i<$this->length; $i++) {
$code[$i] = iconv_substr($this->zhSet,floor(mt_rand(0,mb_strlen($this->zhSet,'utf-8')-1)),1,'utf-8');
imagettftext($this->_image, $this->fontSize, mt_rand(-40, 40), $this->fontSize*($i+1)*1.5, $this->fontSize + mt_rand(10, 20), $this->_color, $this->fontttf, $code[$i]);
}
}else{
for ($i = 0; $i<$this->length; $i++) {
$code[$i] = $this->codeSet[mt_rand(0, strlen($this->codeSet)-1)];
$codeNX += mt_rand($this->fontSize*1.2, $this->fontSize*1.6);
imagettftext($this->_image, $this->fontSize, mt_rand(-40, 40), $codeNX, $this->fontSize*1.6, $this->_color, $this->fontttf, $code[$i]);
}
}
// 保存验证码
$key = $this->authcode($this->seKey);
$code = $this->authcode(strtoupper(implode('', $code)));
$secode = array();
$secode['verify_code'] = $code; // 把校验码保存到session
$secode['verify_time'] = NOW_TIME; // 验证码创建时间
session($key.$id, $secode);
header('Cache-Control: private, max-age=0, no-store, no-cache, must-revalidate');
header('Cache-Control: post-check=0, pre-check=0', false);
header('Pragma: no-cache');
header("content-type: image/png");
// 输出图像
imagepng($this->_image);
imagedestroy($this->_image);
}
/**
* 画一条由两条连在一起构成的随机正弦函数曲线作干扰线(你可以改成更帅的曲线函数)
*
* 高中的数学公式咋都忘了涅,写出来
* 正弦型函数解析式y=Asin(ωx+φ)+b
* 各常数值对函数图像的影响:
* A决定峰值即纵向拉伸压缩的倍数
* b表示波形在Y轴的位置关系或纵向移动距离上加下减
* φ决定波形与X轴位置关系或横向移动距离左加右减
* ω决定周期最小正周期T=2π/∣ω∣)
*
*/
private function _writeCurve() {
$px = $py = 0;
// 曲线前部分
$A = mt_rand(1, $this->imageH/2); // 振幅
$b = mt_rand(-$this->imageH/4, $this->imageH/4); // Y轴方向偏移量
$f = mt_rand(-$this->imageH/4, $this->imageH/4); // X轴方向偏移量
$T = mt_rand($this->imageH, $this->imageW*2); // 周期
$w = (2* M_PI)/$T;
$px1 = 0; // 曲线横坐标起始位置
$px2 = mt_rand($this->imageW/2, $this->imageW * 0.8); // 曲线横坐标结束位置
for ($px=$px1; $px<=$px2; $px = $px + 1) {
if ($w!=0) {
$py = $A * sin($w*$px + $f)+ $b + $this->imageH/2; // y = Asin(ωx+φ) + b
$i = (int) ($this->fontSize/5);
while ($i > 0) {
imagesetpixel($this->_image, $px + $i , $py + $i, $this->_color); // 这里(while)循环画像素点比imagettftext和imagestring用字体大小一次画出不用这while循环性能要好很多
$i--;
}
}
}
// 曲线后部分
$A = mt_rand(1, $this->imageH/2); // 振幅
$f = mt_rand(-$this->imageH/4, $this->imageH/4); // X轴方向偏移量
$T = mt_rand($this->imageH, $this->imageW*2); // 周期
$w = (2* M_PI)/$T;
$b = $py - $A * sin($w*$px + $f) - $this->imageH/2;
$px1 = $px2;
$px2 = $this->imageW;
for ($px=$px1; $px<=$px2; $px=$px+ 1) {
if ($w!=0) {
$py = $A * sin($w*$px + $f)+ $b + $this->imageH/2; // y = Asin(ωx+φ) + b
$i = (int) ($this->fontSize/5);
while ($i > 0) {
imagesetpixel($this->_image, $px + $i, $py + $i, $this->_color);
$i--;
}
}
}
}
/**
* 画杂点
* 往图片上写不同颜色的字母或数字
*/
private function _writeNoise() {
$codeSet = '2345678abcdefhijkmnpqrstuvwxyz';
for($i = 0; $i < 10; $i++){
//杂点颜色
$noiseColor = imagecolorallocate($this->_image, mt_rand(150,225), mt_rand(150,225), mt_rand(150,225));
for($j = 0; $j < 5; $j++) {
// 绘杂点
imagestring($this->_image, 5, mt_rand(-10, $this->imageW), mt_rand(-10, $this->imageH), $codeSet[mt_rand(0, 29)], $noiseColor);
}
}
}
/**
* 绘制背景图片
* 注:如果验证码输出图片比较大,将占用比较多的系统资源
*/
private function _background() {
$path = dirname(__FILE__).'/Verify/bgs/';
$dir = dir($path);
$bgs = array();
while (false !== ($file = $dir->read())) {
if($file[0] != '.' && substr($file, -4) == '.jpg') {
$bgs[] = $path . $file;
}
}
$dir->close();
$gb = $bgs[array_rand($bgs)];
list($width, $height) = @getimagesize($gb);
// Resample
$bgImage = @imagecreatefromjpeg($gb);
@imagecopyresampled($this->_image, $bgImage, 0, 0, 0, 0, $this->imageW, $this->imageH, $width, $height);
@imagedestroy($bgImage);
}
/* 加密验证码 */
private function authcode($str){
$key = substr(md5($this->seKey), 5, 8);
$str = substr(md5($str), 8, 10);
return md5($key . $str);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More