目录结构调整

This commit is contained in:
2016-06-30 16:53:58 +08:00
parent 7eaa319115
commit 52f669abec
107 changed files with 4600 additions and 476 deletions

226
core/extend/com/Auth.php Normal file
View File

@@ -0,0 +1,226 @@
<?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 com;
/**
* 权限认证类
* 功能特性:
* 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() {
if (config('auth_config')) {
//可设置配置项 auth_config, 此配置项为数组。
$this->_config = array_merge($this->_config, config('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 = \think\Db::name($this->_config['auth_group_access'])
->alias('a')
->join($this->_config['auth_group']." g", "g.id=a.group_id")
->where("a.uid='$uid' and g.status='1'")
->field('uid,group_id,title,rules')->select();
$groups[$uid] = $user_groups ? $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 = \think\Db::name($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]=\think\Db::name($this->_config['auth_user'])->where(array('uid'=>$uid))->find();
}
return $userinfo[$uid];
}
}

114
core/extend/com/Cart.php Normal file
View File

@@ -0,0 +1,114 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2013 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace com;
class Cart{
private $goods = 'book';
private $items = array();
public function __construct(){
$this->items = session('sent_cart') ? session('sent_cart') : array();
}
/**
* 添加购物车
* @param integer $id 商品ID标识
* @param integer $num 添加的数量
*/
public function addItem($id,$num=1) {
if ($this->hasItem($id)) {
$this->incNum($id,$num);
return;
}
$this->items[$id] = $num;
session('sent_cart', $this->items);
}
/**
* 判断是否有某个商品
* @param integer $id 商品ID标识
* @return boolean
*/
protected function hasItem($id) {
return isset($this->items[$id]);
}
/**
* 删除商品
* @param integer $id 商品ID标识
*/
public function delItem($id) {
unset($this->items[$id]);
session('sent_cart', $this->items);
}
public function modNum($id,$num=1) {
if (!$this->hasItem($id)) {
return false;
}
$this->items[$id] = $num;
session('sent_cart', $this->items);
}
public function incNum($id,$num=1) {
if ($this->hasItem($id)) {
$this->items[$id] += $num;
}
session('sent_cart', $this->items);
}
public function decNum($id,$num=1) {
if ($this->hasItem($id)) {
$this->items[$id] -= $num;
}
if ($this->items[$id] <1) {
$this->delItem($id);
}
session('sent_cart', $this->items);
}
public function getCount() {
return count($this->items);
}
public function getNum(){
if ($this->getCount() == 0) {
return 0;
}
$sum = 0;
foreach ($this->items as $item) {
$sum += $item;
}
return $sum;
}
public function all(){
$list = array();
foreach ($this->items as $key => $value) {
$goods = \think\Db::name($this->goods)->where(array('id'=>$key))->find();
$list[] = array(
'id' => $goods['id'],
'name' => $goods['book_name'],
'price' => $goods['price'],
'cover_id' => $goods['cover_id'],
'price_count' => $value*$goods['price'],
'num' => $value
);
}
return $list;
}
public function clear() {
$this->items = array();
session('sent_cart', $this->items);
}
}

View File

@@ -0,0 +1,212 @@
<?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: 麦当苗儿 <zuojiazi@vip.qq.com> <http://www.zjzit.cn>
// +----------------------------------------------------------------------
namespace com;
use think\Db;
//数据导出模型
class Database{
/**
* 文件指针
* @var resource
*/
private $fp;
/**
* 备份文件信息 part - 卷号name - 文件名
* @var array
*/
private $file;
/**
* 当前打开文件大小
* @var integer
*/
private $size = 0;
/**
* 备份配置
* @var integer
*/
private $config;
/**
* 数据库备份构造方法
* @param array $file 备份或还原的文件信息
* @param array $config 备份配置信息
* @param string $type 执行类型export - 备份数据, import - 还原数据
*/
public function __construct($file, $config, $type = 'export'){
$this->file = $file;
$this->config = $config;
}
/**
* 打开一个卷,用于写入数据
* @param integer $size 写入数据的大小
*/
private function open($size){
if($this->fp){
$this->size += $size;
if($this->size > $this->config['part']){
$this->config['compress'] ? @gzclose($this->fp) : @fclose($this->fp);
$this->fp = null;
$this->file['part']++;
session('backup_file', $this->file);
$this->create();
}
} else {
$backuppath = $this->config['path'];
$filename = "{$backuppath}{$this->file['name']}-{$this->file['part']}.sql";
if($this->config['compress']){
$filename = "{$filename}.gz";
$this->fp = @gzopen($filename, "a{$this->config['level']}");
} else {
$this->fp = @fopen($filename, 'a');
}
$this->size = filesize($filename) + $size;
}
}
/**
* 写入初始数据
* @return boolean true - 写入成功false - 写入失败
*/
public function create(){
$sql = "-- -----------------------------\n";
$sql .= "-- SentCMS MySQL Data Transfer \n";
$sql .= "-- \n";
$sql .= "-- Host : " . config('database.hostname') . "\n";
$sql .= "-- Port : " . config('database.hostport') . "\n";
$sql .= "-- Database : " . config('database.database') . "\n";
$sql .= "-- \n";
$sql .= "-- Part : #{$this->file['part']}\n";
$sql .= "-- Date : " . date("Y-m-d H:i:s") . "\n";
$sql .= "-- -----------------------------\n\n";
$sql .= "SET FOREIGN_KEY_CHECKS = 0;\n\n";
return $this->write($sql);
}
/**
* 写入SQL语句
* @param string $sql 要写入的SQL语句
* @return boolean true - 写入成功false - 写入失败!
*/
private function write($sql){
$size = strlen($sql);
//由于压缩原因无法计算出压缩后的长度这里假设压缩率为50%
//一般情况压缩率都会高于50%
$size = $this->config['compress'] ? $size / 2 : $size;
$this->open($size);
return $this->config['compress'] ? @gzwrite($this->fp, $sql) : @fwrite($this->fp, $sql);
}
/**
* 备份表结构
* @param string $table 表名
* @param integer $start 起始行数
* @return boolean false - 备份失败
*/
public function backup($table, $start){
//创建DB对象
$db = \think\Db::connect();
//备份表结构
if(0 == $start){
$result = $db->query("SHOW CREATE TABLE `{$table}`");
$sql = "\n";
$sql .= "-- -----------------------------\n";
$sql .= "-- Table structure for `{$table}`\n";
$sql .= "-- -----------------------------\n";
$sql .= "DROP TABLE IF EXISTS `{$table}`;\n";
$sql .= trim($result[0]['Create Table']) . ";\n\n";
if(false === $this->write($sql)){
return false;
}
}
//数据总数
$result = $db->query("SELECT COUNT(*) AS count FROM `{$table}`");
$count = $result['0']['count'];
//备份表数据
if($count){
//写入数据注释
if(0 == $start){
$sql = "-- -----------------------------\n";
$sql .= "-- Records of `{$table}`\n";
$sql .= "-- -----------------------------\n";
$this->write($sql);
}
//备份数据记录
$result = $db->query("SELECT * FROM `{$table}` LIMIT {$start}, 1000");
foreach ($result as $row) {
$row = array_map('addslashes', $row);
$sql = "INSERT INTO `{$table}` VALUES ('" . str_replace(array("\r","\n"),array('\r','\n'),implode("', '", $row)) . "');\n";
if(false === $this->write($sql)){
return false;
}
}
//还有更多数据
if($count > $start + 1000){
return array($start + 1000, $count);
}
}
//备份下一表
return 0;
}
public function import($start){
//还原数据
$db = \think\Db::connect();
if($this->config['compress']){
$gz = gzopen($this->file[1], 'r');
$size = 0;
} else {
$size = filesize($this->file[1]);
$gz = fopen($this->file[1], 'r');
}
$sql = '';
if($start){
$this->config['compress'] ? gzseek($gz, $start) : fseek($gz, $start);
}
for($i = 0; $i < 1000; $i++){
$sql .= $this->config['compress'] ? gzgets($gz) : fgets($gz);
if(preg_match('/.*;$/', trim($sql))){
if(false !== $db->execute($sql)){
$start += strlen($sql);
} else {
return false;
}
$sql = '';
} elseif ($this->config['compress'] ? gzeof($gz) : feof($gz)) {
return 0;
}
}
return array($start, $size);
}
/**
* 析构方法,用于关闭文件资源
*/
public function __destruct(){
//$this->config['compress'] ? @gzclose($this->fp) : @fclose($this->fp);
}
}

View File

@@ -0,0 +1,274 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2013 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: colin <colin@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace com;
use think\Db;
/**
* 数据库管理类
* @author colin <colin@tensent.cn>
*/
class Datatable{
protected $table; /*数据库操作的表*/
protected $fields = array(); /*数据库操作字段*/
protected $charset = 'utf8'; /*数据库操作字符集*/
public $prefix = ''; /*数据库操作表前缀*/
protected $model_table_prefix = ''; /*模型默认创建的表前缀*/
protected $engine_type = 'MyISAM'; /*数据库引擎*/
protected $key = 'id'; /*数据库主键*/
public $sql = ''; /*最后生成的sql语句*/
/**
* 初始化数据库信息
* @author colin <colin@tensent.cn>
*/
public function __construct(){
//创建DB对象
$this->prefix = config('database.prefix');
$this->model_table_prefix = config('model_table_prefix');
}
/**
* 开始创建表
* @var $table 表名
* @author colin <colin@tensent.cn>
*/
public function start_table($table){
$this->table = $this->getTablename($table,true);
$this->sql .= "CREATE TABLE IF NOT EXISTS `".$this->table."`(";
return $this;
}
/**
* 创建字段
* @var $sql 要执行的字段sql语句可以为array()或者strubf
* @author colin <colin@tensent.cn>
*/
public function create_field($sql){
$this->sql .= $sql.',';
return $this;
}
/**
* 快速创建ID字段
* @var length 字段的长度
* @var comment 字段的描述
* @author colin <colin@tensent.cn>
*/
public function create_id($key = 'id', $length = 11 , $comment = '主键' , $is_auto_increment = true){
$auto_increment = $is_auto_increment ? 'AUTO_INCREMENT' : '';
$this->sql .= "`{$key}` int({$length}) unsigned NOT NULL $auto_increment COMMENT '{$comment}',";
return $this;
}
/**
* 快速创建ID字段
* @var length 字段的长度
* @var comment 字段的描述
* @author colin <colin@tensent.cn>
*/
public function create_uid(){
$this->sql .= "`uid` int(11) NOT NULL DEFAULT '0' COMMENT '用户uid',";
return $this;
}
/**
* 追加字段
* @var $table 追加字段的表名
* @var $attr 属性列表
* @var $is_more 是否为多条同时插入
* @author colin <colin@tensent.cn>
*/
public function colum_field($table,$attr = array()){
$field_attr['table'] = $table ? $this->getTablename($table,true) : $this->table;
$field_attr['field'] = $attr['field'];
$field_attr['type'] = $attr['type'] ? $attr['type'] : 'varchar';
if (intval($attr['length']) && $attr['length']) {
$field_attr['length'] = "(".$attr['length'].")";
}else{
$field_attr['length'] = "";
}
$field_attr['is_null'] = $attr['is_null'] ? 'NOT NULL' : 'null';
$field_attr['default'] = $attr['default'] != '' ? 'default "'.$attr['default'].'"' : 'default null';
if($field_attr['is_null'] == 'null'){
$field_attr['default'] = $field_attr['default'];
}else{
$field_attr['default'] = '';
}
$field_attr['comment'] = (isset($attr['comment']) && $attr['comment']) ? $attr['comment'] : '';
$field_attr['oldname'] = (isset($attr['oldname']) && $attr['oldname']) ? $attr['oldname'] : '';
$field_attr['newname'] = (isset($attr['newname']) && $attr['newname']) ? $attr['newname'] : $field_attr['field'];
$field_attr['after'] = (isset($attr['after']) && $attr['after']) ? ' AFTER `'.$attr['after'].'`' : '';
$field_attr['action'] = (isset($attr['action']) && $attr['action']) ? $attr['action'] : 'ADD';
//确认表是否存在
if($field_attr['action'] == 'ADD'){
$this->sql = "ALTER TABLE `{$field_attr['table']}` ADD `{$field_attr['field']}` {$field_attr['type']}{$field_attr['length']} {$field_attr['is_null']} {$field_attr['default']} COMMENT '{$field_attr['comment']}'";
}elseif($field_attr['action'] == 'CHANGE'){
$this->sql = "ALTER TABLE `{$field_attr['table']}` CHANGE `{$field_attr['oldname']}` `{$field_attr['newname']}` {$field_attr['type']}{$field_attr['length']} {$field_attr['is_null']} {$field_attr['default']} COMMENT '{$field_attr['comment']}'";
}
return $this;
}
/**
* 删除字段
* @var $table 追加字段的表名
* @var $field 字段名
* @author colin <colin@tensent.cn>
*/
public function del_field($table,$field){
$table = $table ? $this->getTablename($table,true) : $this->table;
$this->sql = "ALTER TABLE `$table` DROP `$field`";
return $this;
}
/**
* 删除数据表
* @var $table 追加字段的表名
* @author colin <colin@tensent.cn>
*/
public function del_table($table){
$table = $table ? $this->getTablename($table,true) : $this->table;
$this->sql = "DROP TABLE `$table`";
return $this;
}
/**
* 主键设置
* @var $key 要被设置主键的字段
* @author colin <colin@tensent.cn>
*/
public function create_key($key = null){
if(null != $key){
$this->key = $key;
}
$this->sql .= "PRIMARY KEY (`".$this->key."`)";
return $this;
}
/**
* 结束表
* @var $engine_type 数据库引擎
* @var $comment 表注释
* @var $charset 数据库编码
* @author colin <colin@tensent.cn>
*/
public function end_table($comment,$engine_type = null,$charset = null){
if(null != $charset){
$this->charset = $charset;
}
if(null != $engine_type){
$this->engine_type = $engine_type;
}
$end = "ENGINE=".$this->engine_type." AUTO_INCREMENT=1 DEFAULT CHARSET=".$this->charset." ROW_FORMAT=DYNAMIC COMMENT='".$comment."';";
$this->sql .= ")".$end;
return $this;
}
/**
* 创建动作
* @return int 0
* @author colin <colin@tensent.cn>
*/
public function create(){
$res = Db::execute($this->sql);
return $res !== false;
}
/**
* create的别名
* @return int 0
* @author colin <colin@tensent.cn>
*/
public function query(){
return $this->create();
}
/**
* 获取最后生成的sql语句
* @author colin <colin@tensent.cn>
*/
public function getLastSql(){
return $this->sql;
}
/**
* 获取指定的表名
* @var $table 要获取名字的表名
* @var $prefix 获取表前缀? 默认为不获取 false
* @author colin <colin@tensent.cn>
*/
public function getTablename($table , $prefix = false){
if(false == $prefix){
$this->table = $this->model_table_prefix.$table;
}else{
$this->table = $this->prefix.$this->model_table_prefix.$table;
}
return $this->table;
}
/**
* 获取指定表名的所有字段及详细信息
* @var $table 要获取名字的表名 可以为sent_tengsu_photo、tengsu_photo、photo
* @author colin <colin@tensent.cn>
*/
public function getFields($table){
if(false == $table){
$table = $this->table;//为空调用当前table
}else{
$table = $table;
}
$patten = "/\./";
if(!preg_match_all($patten,$table)){
//匹配_
$patten = "/_+/";
if(!preg_match_all($patten, $table)){
$table = $this->prefix.$this->model_table_prefix.$table;
}else{
//匹配是否包含表前缀,如果是 那么就是手动输入
$patten = "/$this->prefix/";
if(!preg_match_all($patten,$table)){
$table = $this->prefix.$table;
}
}
}
$sql = "SHOW FULL FIELDS FROM $table";
return Db::query($sql);
}
/**
* 确认表是否存在
* @var $table 表名 可以为sent_tengsu_photo、tengsu_photo、photo
* @author colin <colin@tensent.cn>
* @return boolen
*/
public function CheckTable($table){
//获取表名
$this->table = $this->getTablename($table,true);
$result = Db::execute("SHOW TABLES LIKE '%$this->table%'");
return $result;
}
/**
* 确认字段是否存在
* @var $table 表名 可以为sent_tengsu_photo、tengsu_photo、photo
* @var $field 字段名 要检查的字段名
* @author colin <colin@tensent.cn>
* @return boolen
*/
public function CheckField($table,$field){
//检查字段是否存在
$table = $this->getTablename($table,true);
if(!Db::query("Describe $table $field")){
return false;
}else{
return true;
}
}
}

2343
core/extend/com/Email.php Normal file

File diff suppressed because it is too large Load Diff

80
core/extend/com/Pay.php Normal file
View File

@@ -0,0 +1,80 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2013 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace com;
class Pay{
/**
* 支付驱动实例
* @var Object
*/
private $payer;
/**
* 配置参数
* @var type
*/
private $config;
public function __construct($driver) {
//获取配置
$this->getConfig($driver);
/* 配置 */
$pos = strrpos($driver, '\\');
$pos = $pos === false ? 0 : $pos + 1;
$apitype = strtolower(substr($driver, $pos));
$this->config['notify_url'] = url('user/pay/notify',array('apitype'=>$apitype), false, true);
$this->config['return_url'] = url("user/pay/returnback", array('apitype' => $apitype, 'method' => 'return'), false, true);
$this->config['pey_type'] = $driver;
/* 设置支付驱动 */
$class = strpos($driver, '\\') ? $driver : 'com\\pay\\driver\\' . ucfirst(strtolower($driver));
$this->setDriver($class, $this->config);
}
/**
* 支付
* @return boolean
*/
public function pay(pay\Input $input){
return $this->payer->pay($input);
}
/**
* 获取配置
* @return array
*/
public function getConfig($driver){
$config = \think\Config::load(APP_PATH . 'pay.php');
$this->config = $config[$driver];
}
/**
* 设置支付驱动
* @param string $class 驱动类名称
*/
private function setDriver($class, $config) {
$this->payer = new $class($config);
if (!$this->payer) {
throw new \think\Exception("不存在支付驱动:{$class}");
}
}
public function __call($method, $arguments) {
if (method_exists($this, $method)) {
return call_user_func_array(array(&$this, $method), $arguments);
} elseif (!empty($this->payer) && $this->payer instanceof Pay\Pay && method_exists($this->payer, $method)) {
return call_user_func_array(array(&$this->payer, $method), $arguments);
}
}
}

164
core/extend/com/Sent.php Normal file
View File

@@ -0,0 +1,164 @@
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006-2015 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
namespace com;
use think\template\TagLib;
/**
* CX标签库解析类
* @category Think
* @package Think
* @subpackage Driver.Taglib
* @author liu21st <liu21st@gmail.com>
*/
class Sent extends Taglib{
// 标签定义
protected $tags = array(
// 标签定义: attr 属性列表 close 是否闭合0 或者1 默认1 alias 标签别名 level 嵌套层次
'nav' => array('attr' => 'field,name', 'close' => 1), //获取导航
'list' => array('attr' => 'table,where,order,limit,id,sql,field,key','level'=>3),//列表
'doc' => array('attr' => 'model,field,limit,id,field,key','level'=>3),
'recom' => array('attr' => 'doc_id,id'),
'link' => array('attr' => 'type,limit' , 'close' => 1),//友情链接
'prev' => array('attr' => 'id,cate' , 'close' => 1),//上一篇
'next' => array('attr' => 'id,cate' , 'close' => 1),//下一篇
);
public function tagnav($tag, $content){
$field = empty($tag['field']) ? 'true' : $tag['field'];
$tree = empty($tag['tree'])? true : false;
$parse = $parse = '<?php ';
$parse .= '$__NAV__ = db(\'Channel\')->field('.$field.')->where("status=1")->order("sort")->select();';
if($tree){
$parse .= '$__NAV__ = list_to_tree($__NAV__, "id", "pid");';
}
$parse .= 'foreach ($__NAV__ as $key => $'.$tag['name'].') {';
$parse .= '?>';
$parse .= $content;
$parse .= '<?php } ?>';
return $parse;
}
public function tagdoc($tag, $content){
$model = !empty($tag['model']) ? $tag['model']:'';
$cid = !empty($tag['cid']) ? $tag['cid']:'0';
$field = empty($tag['field']) ? '*' : $tag['field'];
$limit = empty($tag['limit']) ? 20 : $tag['limit'];
$order = empty($tag['order']) ? 'create_time desc' : $tag['order'];
//获得当前栏目的所有子栏目
$ids = get_category_child($cid);
$ids = implode(',', $ids);
$where = "category_id IN ({$ids})";
$where .= " and model_id = {$model} and status >= 1";
$parse = $parse = '<?php ';
$parse .= '$__LIST__ = model(\'Document\')->extend(\''.$model.'\')->where(\''.$where.'\')->field(\''.$field.'\')->limit(\''.$limit.'\')->order(\''.$order.'\')->select();';
$parse .= 'foreach ($__LIST__ as $key => $'.$tag['name'].') {';
$parse .= '?>';
$parse .= $content;
$parse .= '<?php } ?>';
return $parse;
}
public function taglist($tag, $content){
$name = !empty($tag['name']) ? $tag['name'] : '';
$map = !empty($tag['map']) ? $tag['map'] : '';
$field = empty($tag['field']) ? '*' : $tag['field'];
$limit = empty($tag['limit']) ? 20 : $tag['limit'];
$order = empty($tag['order']) ? 'id desc' : $tag['order'];
$where[] = "status > 0";
if ($map) {
$where[] = $map;
}
$map = implode(" and ", $where);
$parse = $parse = '<?php ';
$parse .= '$__LIST__ = model(\''.$name.'\')->where(\''.$map.'\')->field(\''.$field.'\')->limit(\''.$limit.'\')->order(\''.$order.'\')->select();';
$parse .= 'foreach ($__LIST__ as $key => $'.$tag['id'].') {';
$parse .= '?>';
$parse .= $content;
$parse .= '<?php } ?>';
return $parse;
}
public function tagrecom($tag, $content){
$doc_id = empty($tag['doc_id']) ? '' : $tag['doc_id'];
$field = empty($tag['field']) ? '*' : $tag['field'];
$limit = empty($tag['limit']) ? 20 : $tag['limit'];
$order = empty($tag['order']) ? 'id desc' : $tag['order'];
if (!$doc_id) {
return array();
}
$parse = $parse = '<?php ';
$parse .= '$__LIST__ = model(\'Document\')->recom('. $doc_id .',\'' .$field. '\',' .$limit. ',\'' .$order. '\');';
$parse .= 'foreach ($__LIST__ as $key => $'.$tag['id'].') {';
$parse .= '?>';
$parse .= $content;
$parse .= '<?php } ?>';
return $parse;
}
public function taglink($tag, $content){
$type = !empty($tag['type']) ? $tag['type'] : '';
$limit = !empty($tag['limit']) ? $tag['limit'] : '';
$field = empty($tag['field']) ? '*' : $tag['field'];
$limit = empty($tag['limit']) ? 20 : $tag['limit'];
$order = empty($tag['order']) ? "id desc" : $tag['order'];
$where[] = "status > 0";
if ($type) {
$where[] = "ftype = " . $type;
}
$map = implode(" and ", $where);
$parse = $parse = '<?php ';
$parse .= '$__LIST__ = model(\'Link\')->where(\''.$map.'\')->field(\''.$field.'\')->limit(\''.$limit.'\')->order(\''.$order.'\')->select();';
$parse .= 'foreach ($__LIST__ as $key => $'.$tag['name'].') {';
$parse .= '?>';
$parse .= $content;
$parse .= '<?php } ?>';
return $parse;
}
public function tagprev($tag, $content){
$id = !empty($tag['id']) ? $tag['id'] : '';
$cate = !empty($tag['cate']) ? $tag['cate'] : '';
$model_id = !empty($tag['model']) ? $tag['model'] : '';
$map = "category_id = ".$cate." and model_id=".$model_id." and id < ".$id;
$parse = '<?php ';
$parse .= '$__DATA__ = db(\'Document\')->where("' . $map . '")->order(\'id asc\')->find();';
$parse .= $content;
$parse .= '}?>';
return $parse;
}
public function tagnext($tag, $content){
$id = !empty($tag['id']) ? $tag['id'] : '';
$cate = !empty($tag['cate']) ? $tag['cate'] : '';
$model_id = !empty($tag['model']) ? $tag['model'] : '';
$map = "category_id = ".$cate." and model_id=".$model_id." and id < ".$id;
$parse = '<?php ';
$parse .= '$__DATA__ = db(\'Document\')->where("' . $map . '")->order(\'id asc\')->find();';
$parse .= $content;
$parse .= '}?>';
return $parse;
}
}

95
core/extend/com/Tree.php Normal file
View File

@@ -0,0 +1,95 @@
<?php
namespace com;
/**
* 通用的树型类,可以生成任何树型结构
*/
class Tree {
protected $formatTree;
/**
* 把返回的数据集转换成Tree
* @param array $list 要转换的数据集
* @param string $pid parent标记字段
* @param string $level level标记字段
* @return array
* @author 麦当苗儿 <zuojiazi@vip.qq.com>
*/
protected function list_to_tree($list, $pk='id', $pid = 'pid', $child = '_child', $root = 0) {
// 创建Tree
$tree = array();
if(is_array($list)) {
// 创建基于主键的数组引用
$refer = array();
foreach ($list as $key => $data) {
$refer[$data[$pk]] =& $list[$key];
}
foreach ($list as $key => $data) {
// 判断是否存在parent
$parentId = $data[$pid];
if ($root == $parentId) {
$tree[] =& $list[$key];
}else{
if (isset($refer[$parentId])) {
$parent =& $refer[$parentId];
$parent['childs'][] = $data['id'];
$parent[$child][] =& $list[$key];
}
}
}
}
return $tree;
}
/**
* 将树子节点加层级成列表
*/
protected function _toFormatTree($tree, $level = 1) {
foreach ($tree as $key => $value) {
$temp = $value;
if (isset($temp['_child'])) {
$temp['_child'] = true;
$temp['level'] = $level;
} else {
$temp['_child'] = false;
$temp['level'] = $level;
}
array_push($this->formatTree, $temp);
if (isset($value['_child'])) {
$this->_toFormatTree($value['_child'], ($level + 1));
}
}
}
protected function cat_empty_deal($cat, $next_parentid, $pid='pid', $empty = "&nbsp;&nbsp;&nbsp;&nbsp;") {
$str = "";
if ($cat[$pid]) {
for ($i=2; $i < $cat['level']; $i++) {
$str .= $empty."";
}
if ($cat[$pid] != $next_parentid && !$cat['_child']) {
$str .= $empty."└─&nbsp;";
} else {
$str .= $empty."├─&nbsp;";
}
}
return $str;
}
public function toFormatTree($list,$title = 'title',$pk='id',$pid = 'pid',$root = 0){
if (empty($list)) {
return false;
}
$list = $this->list_to_tree($list,$pk,$pid,'_child',$root);
$this->formatTree = array();
$this->_toFormatTree($list);
foreach ($this->formatTree as $key => $value) {
$index = ($key+1);
$next_parentid = isset($this->formatTree[$index][$pid]) ? $this->formatTree[$index][$pid] : '';
$value['level_show'] = $this->cat_empty_deal($value, $next_parentid);
$value['title_show'] = $value['level_show'].$value[$title];
$data[] = $value;
}
return $data;
}
}

356
core/extend/com/Ueditor.php Normal file
View File

@@ -0,0 +1,356 @@
<?php
/**
* Ueditor插件
* @author Nintendov
*/
namespace com;
class Ueditor{
public $uid;//要操作的用户id 如有登录需要则去掉注释
private $output;//要输出的数据
private $st;
private $rootpath = '/uploads';
private $config = '';
public function __construct($uid = ''){
//uid 为空则导入当前会话uid
if(''===$uid) $this->uid = session('user_auth.uid');
//导入设置
$this->config = json_decode(preg_replace("/\/\*[\s\S]+?\*\//", "", file_get_contents(APP_PATH."ueditor.json")), true);
$action = htmlspecialchars($_GET['action']);
switch($action){
case 'config':
$result = json_encode($this->config);
break;
case 'uploadimage':
$config = array(
"pathFormat" => $this->config['imagePathFormat'],
"maxSize" => $this->config['imageMaxSize'],
"allowFiles" => $this->config['imageAllowFiles']
);
$fieldName = $this->config['imageFieldName'];
$result = $this->uploadFile($config, $fieldName);
break;
case 'uploadscrawl':
$config = array(
"pathFormat" => $this->config['scrawlPathFormat'],
"maxSize" => $this->config['scrawlMaxSize'],
"allowFiles" => $this->config['scrawlAllowFiles'],
"oriName" => "scrawl.png"
);
$fieldName = $this->config['scrawlFieldName'];
$result=$this->uploadBase64($config,$fieldName);
break;
case 'uploadvideo':
$config = array(
"pathFormat" => $this->config['videoPathFormat'],
"maxSize" => $this->config['videoMaxSize'],
"allowFiles" => $this->config['videoAllowFiles']
);
$fieldName = $this->config['videoFieldName'];
$result=$this->uploadFile($config, $fieldName);
break;
case 'uploadfile':
// default:
$config = array(
"pathFormat" => $this->config['filePathFormat'],
"maxSize" => $this->config['fileMaxSize'],
"allowFiles" => $this->config['fileAllowFiles']
);
$fieldName = $this->config['fileFieldName'];
$result=$this->uploadFile($config, $fieldName);
break;
case 'listfile':
$config=array(
'allowFiles' => $this->config['fileManagerAllowFiles'],
'listSize' => $this->config['fileManagerListSize'],
'path' => $this->config['fileManagerListPath'],
);
$result = $this->listFile($config);
break;
case 'listimage':
$config=array(
'allowFiles' => $this->config['imageManagerAllowFiles'],
'listSize' => $this->config['imageManagerListSize'],
'path' => $this->config['imageManagerListPath'],
);
$result = $this->listFile($config);
break;
case 'catchimage':
$config = array(
"pathFormat" => $this->config['catcherPathFormat'],
"maxSize" => $this->config['catcherMaxSize'],
"allowFiles" => $this->config['catcherAllowFiles'],
"oriName" => "remote.png"
);
$fieldName = $this->config['catcherFieldName'];
$result = $this->saveRemote($config , $fieldName);
break;
default:
$result = json_encode(array(
'state'=> 'wrong require'
));
break;
}
if (isset($_GET["callback"])) {
if (preg_match("/^[\w_]+$/", $_GET["callback"])) {
$this->output = htmlspecialchars($_GET["callback"]) . '(' . $result . ')';
} else {
$this->output = json_encode(array(
'state'=> 'callback参数不合法'
));
}
} else {
$this->output = $result;
}
}
/**
*
* 输出结果
* @param data 数组数据
* @return 组合后json格式的结果
*/
public function output(){
return $this->output;
}
/**
* 上传文件方法
*
*/
private function uploadFile($config,$fieldName){
$upload = new \org\Upload();
$upload->maxSize = $config['maxSize'] ;// 设置附件上传大小
$upload->exts = $this->format_exts($config['allowFiles']);// 设置附件上传类型
$upload->rootPath = '.'.$this->rootpath; // 设置附件上传根目录
$upload->autoSub = false;
$upload->savePath = $this->getFullPath($config['pathFormat']); // 设置附件上传(子)目录
$info=$upload->uploadOne($_FILES[$fieldName]);
$rootpath = $this->rootpath;
if(!$info){
$data = array(
"state"=>$upload -> getError(),
);
}else{
$data = array(
'state' => "SUCCESS",
'url' => $rootpath . $info['savepath'] . $info['savename'],
'title' => $info['name'],
'original' => $info['name'],
'type' => '.' . $info['ext'],
'size' => $info['size'],
);
}
return json_encode($data);
}
/**
*
* Enter description here ...
*/
private function uploadBase64($config,$fieldName){
$data = array();
$base64Data = $_POST[$fieldName];
$img = base64_decode($base64Data);
$path = $this->getFullPath($config['pathFormat']);
if(strlen($img)>$config['maxSize']){
$data['states'] = 'too large';
return json_encode($data);
}
$rootpath = $this->rootpath;
//替换随机字符串
$imgname = uniqid().'.png';
$filename = $path.$imgname;
if(\Think\Storage::put($rootpath,$filename,$img)){
$data=array(
'state' =>'SUCCESS',
'url' => $rootpath . $filename,
'title' =>$imgname,
'original' =>'scrawl.png',
'type' => '.png',
'size' => strlen($img),
);
}else{
$data=array(
'state'=>'cant write',
);
}
return json_encode($data);
}
/**
* 列出文件夹下所有文件,如果是目录则向下
*/
private function listFile($config){
$allowFiles = substr(str_replace(".", "|", join("", $config['allowFiles'])), 1);
$size = isset($_GET['size']) ? htmlspecialchars($_GET['size']) : $config['listSize'];
$start = isset($_GET['start']) ? htmlspecialchars($_GET['start']) : 0;
$end = $start + $size;
$rootpath = $this->rootpath;
$path = $config['path'];
$files = \Think\Storage::listFile($rootpath,$path, $allowFiles);
//return $files;
if (!count($files)) {
return json_encode(array(
"state" => "no match file",
"list" => array(),
"start" => $start,
"total" => count($files)
));
}
/* 获取指定范围的列表 */
$len = count($files);
for ($i = min($end, $len) - 1, $list = array(); $i < $len && $i >= 0 && $i >= $start; $i--){
$list[] = $files[$i];
}
//倒序
//for ($i = $end, $list = array(); $i < $len && $i < $end; $i++){
// $list[] = $files[$i];
//}
/* 返回数据 */
$result = json_encode(array(
"state" => "SUCCESS",
"list" => $list,
"start" => $start,
"total" => count($files)
));
return $result;
}
/**
*
* Enter description here ...
*/
private function saveRemote($config , $fieldName){
$list = array();
if (isset($_POST[$fieldName])) {
$source = $_POST[$fieldName];
} else {
$source = $_GET[$fieldName];
}
foreach ($source as $imgUrl) {
$upload = new \org\Upload();
$imgUrl = htmlspecialchars($imgUrl);
$imgUrl = str_replace("&amp;", "&", $imgUrl);
//http开头验证
if (strpos($imgUrl, "http") !== 0) {
$data = array('state'=>'不是http链接');
return json_encode($data);
}
//格式验证(扩展名验证和Content-Type验证)
$fileType = strtolower(strrchr($imgUrl, '.'));
if (!in_array($fileType, $config['allowFiles']) || stristr($heads['Content-Type'], "image")) {
$data = array("state"=>"错误文件格式");
return json_encode($data);
}
//打开输出缓冲区并获取远程图片
ob_start();
$context = stream_context_create(
array('http' => array(
'follow_location' => false // don't follow redirects
))
);
readfile($imgUrl, false, $context);
$img = ob_get_contents();
ob_end_clean();
preg_match("/[\/]([^\/]*)[\.]?[^\.\/]*$/", $imgUrl, $m);
$path = $this->getFullPath($config['pathFormat']);
if(strlen($img)>$config['maxSize']){
$data['states'] = 'too large';
return json_encode($data);
}
$rootpath = $this->rootpath;
$imgname = uniqid().'.png';
$filename = $path.$imgname;
$oriName = $m ? $m[1]:"";
if(\Think\Storage::put($rootpath,$filename,$img)){
array_push($list, array(
"state" => 'SUCCESS',
"url" => \Think\Storage::getPath($rootpath,$filename),
"size" => strlen($img),
"title" => $imgname,
"original" => $oriName,
"source" => htmlspecialchars($imgUrl)
));
}else{
array_push($list,array('state'=>'文件写入失败'));
}
}
/* 返回抓取数据 */
return json_encode(array(
'state'=> count($list) ? 'SUCCESS':'ERROR',
'list'=> $list
));
}
/**
* 规则替换命名文件
* @param $path
* @return string
*/
private function getFullPath($path){
//替换日期事件
$t = time();
$d = explode('-', date("Y-y-m-d-H-i-s"));
$format = $path;
$format = str_replace("{yyyy}", $d[0], $format);
$format = str_replace("{yy}", $d[1], $format);
$format = str_replace("{mm}", $d[2], $format);
$format = str_replace("{dd}", $d[3], $format);
$format = str_replace("{hh}", $d[4], $format);
$format = str_replace("{ii}", $d[5], $format);
$format = str_replace("{ss}", $d[6], $format);
$format = str_replace("{uid}", $this->uid, $format);
return $format;
}
private function format_exts($exts){
$data=array();
foreach ($exts as $key => $value) {
$data[]=ltrim($value,'.');
}
return $data;
}
}

View File

@@ -0,0 +1,176 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2013 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace com\pay;
class Input{
protected $_orderNo;
protected $_fee;
protected $_title;
protected $_body;
protected $_callback;
protected $_url;
protected $_uid;
protected $_bank;
protected $_param;
/**
* 设置订单号
* @param type $order_no
* @return \Think\Pay\PayVo
*/
public function setOrderNo($order_no) {
$this->_orderNo = $order_no;
return $this;
}
/**
* 设置商品价格
* @param type $fee
* @return \Think\Pay\PayVo
*/
public function setFee($fee) {
$this->_fee = $fee;
return $this;
}
/**
* 设置商品名称
* @param type $title
* @return \Think\Pay\PayVo
*/
public function setTitle($title) {
$this->_title = $title;
return $this;
}
/**
* 设置商品描述
* @param type $body
* @return \Think\Pay\PayVo
*/
public function setBody($body) {
$this->_body = $body;
return $this;
}
/**
* 设置支付完成后的后续操作接口
* @param type $callback
* @return \Think\Pay\PayVo
*/
public function setCallback($callback) {
$this->_callback = $callback;
return $this;
}
/**
* 设置支付完成后的跳转地址
* @param type $url
* @return \Think\Pay\PayVo
*/
public function setUrl($url) {
$this->_url = $url;
return $this;
}
/**
* 设置订单的额外参数
* @param type $param
* @return \Think\Pay\PayVo
*/
public function setParam($param) {
$this->_param = $param;
return $this;
}
/**
* 设置订单的用户ID
* @param type $param
* @return \Think\Pay\PayVo
*/
public function setUid($uid) {
$this->_uid = $uid;
return $this;
}
public function setBank($bank){
$this->_bank = $bank;
return $this;
}
/**
* 获取订单号
* @return type
*/
public function getOrderNo() {
return $this->_orderNo;
}
/**
* 获取商品价格
* @return type
*/
public function getFee() {
return $this->_fee;
}
/**
* 获取商品名称
* @return type
*/
public function getTitle() {
return $this->_title;
}
/**
* 获取支付完成后的后续操作接口
* @return type
*/
public function getCallback() {
return $this->_callback;
}
/**
* 获取支付完成后的跳转地址
* @return type
*/
public function getUrl() {
return $this->_url;
}
/**
* 获取商品描述
* @return type
*/
public function getBody() {
return $this->_body;
}
/**
* 获取订单的额外参数
* @return type
*/
public function getParam() {
return $this->_param;
}
/**
* 获取用户UID
* @return type
*/
public function getUid() {
return $this->_uid;
}
public function getBank(){
return $this->_bank;
}
}

260
core/extend/com/pay/Pay.php Normal file
View File

@@ -0,0 +1,260 @@
<?php
// +----------------------------------------------------------------------
// | SentCMS [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2013 http://www.tensent.cn All rights reserved.
// +----------------------------------------------------------------------
// | Author: molong <molong@tensent.cn> <http://www.tensent.cn>
// +----------------------------------------------------------------------
namespace com\pay;
abstract class Pay extends \think\Controller{
protected $config;
protected $info;
public function __construct($config) {
parent::__construct();
$this->config = array_merge($this->config, $config);
}
/**
* 配置检查
* @return boolean
*/
public function check() {
return true;
}
/**
* 验证通过后获取订单信息
* @return type
*/
public function getInfo() {
return $this->info;
}
/**
* 生成订单号
* 可根据自身的业务需求更改
*/
public function createOrderNo() {
$year_code = array('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J');
return $year_code[intval(date('Y')) - 2010] .
strtoupper(dechex(date('m'))) . date('d') .
substr(time(), -5) . substr(microtime(), 2, 5) . sprintf('d', rand(0, 99));
}
/**
* 建立提交表单
*/
abstract public function pay(\com\pay\Input $input);
/**
* 构造表单
*/
protected function _buildForm($params, $gateway,$is_submit=true, $method = 'post') {
$sHtml = "<meta http-equiv='content-type' content='text/html; charset=utf-8'><form id='paysubmit' name='paysubmit' action='{$gateway}' method='{$method}' target='_blank'>";
foreach ($params as $k => $v) {
$sHtml.= "<input type=\"hidden\" name=\"{$k}\" value=\"{$v}\" />\n";
}
$sHtml = $sHtml . "</form>";
$data = array(
'sHtml' => $sHtml,
'is_submit' => $is_submit,
'params' => $params,
);
return $data;
}
/**
* 支付通知验证
*/
abstract public function verifyNotify($notify);
/**
* 异步通知验证成功返回信息
*/
public function notifySuccess() {
echo "success";
}
final protected function fsockOpen($url, $limit = 0, $post = '', $cookie = '', $bysocket = FALSE, $ip = '', $timeout = 15, $block = TRUE, $encodetype = 'URLENCODE', $allowcurl = TRUE, $position = 0, $files = array()) {
$return = '';
$matches = parse_url($url);
$scheme = $matches['scheme'];
$host = $matches['host'];
$path = $matches['path'] ? $matches['path'] . ($matches['query'] ? '?' . $matches['query'] : '') : '/';
$port = !empty($matches['port']) ? $matches['port'] : ($scheme == 'http' ? '80' : '');
$boundary = $encodetype == 'URLENCODE' ? '' : random(40);
if ($post) {
if (!is_array($post)) {
parse_str($post, $post);
}
$this->formatPostkey($post, $postnew);
$post = $postnew;
}
if (function_exists('curl_init') && function_exists('curl_exec') && $allowcurl) {
$ch = curl_init();
$httpheader = array();
if ($ip) {
$httpheader[] = "Host: " . $host;
}
if ($httpheader) {
curl_setopt($ch, CURLOPT_HTTPHEADER, $httpheader);
}
curl_setopt($ch, CURLOPT_URL, $scheme . '://' . ($ip ? $ip : $host) . ($port ? ':' . $port : '') . $path);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_HEADER, 1);
if ($post) {
curl_setopt($ch, CURLOPT_POST, 1);
if ($encodetype == 'URLENCODE') {
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
} else {
foreach ($post as $k => $v) {
if (isset($files[$k])) {
$post[$k] = '@' . $files[$k];
}
}
foreach ($files as $k => $file) {
if (!isset($post[$k]) && file_exists($file)) {
$post[$k] = '@' . $file;
}
}
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
}
}
if ($cookie) {
curl_setopt($ch, CURLOPT_COOKIE, $cookie);
}
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
$data = curl_exec($ch);
$status = curl_getinfo($ch);
$errno = curl_errno($ch);
curl_close($ch);
if ($errno || $status['http_code'] != 200) {
return;
} else {
$GLOBALS['filesockheader'] = substr($data, 0, $status['header_size']);
$data = substr($data, $status['header_size']);
return !$limit ? $data : substr($data, 0, $limit);
}
}
if ($post) {
if ($encodetype == 'URLENCODE') {
$data = http_build_query($post);
} else {
$data = '';
foreach ($post as $k => $v) {
$data .= "--$boundary\r\n";
$data .= 'Content-Disposition: form-data; name="' . $k . '"' . (isset($files[$k]) ? '; filename="' . basename($files[$k]) . '"; Content-Type: application/octet-stream' : '') . "\r\n\r\n";
$data .= $v . "\r\n";
}
foreach ($files as $k => $file) {
if (!isset($post[$k]) && file_exists($file)) {
if ($fp = @fopen($file, 'r')) {
$v = fread($fp, filesize($file));
fclose($fp);
$data .= "--$boundary\r\n";
$data .= 'Content-Disposition: form-data; name="' . $k . '"; filename="' . basename($file) . '"; Content-Type: application/octet-stream' . "\r\n\r\n";
$data .= $v . "\r\n";
}
}
}
$data .= "--$boundary\r\n";
}
$out = "POST $path HTTP/1.0\r\n";
$header = "Accept: */*\r\n";
$header .= "Accept-Language: zh-cn\r\n";
$header .= $encodetype == 'URLENCODE' ? "Content-Type: application/x-www-form-urlencoded\r\n" : "Content-Type: multipart/form-data; boundary=$boundary\r\n";
$header .= 'Content-Length: ' . strlen($data) . "\r\n";
$header .= "User-Agent: $_SERVER[HTTP_USER_AGENT]\r\n";
$header .= "Host: $host:$port\r\n";
$header .= "Connection: Close\r\n";
$header .= "Cache-Control: no-cache\r\n";
$header .= "Cookie: $cookie\r\n\r\n";
$out .= $header;
$out .= $data;
} else {
$out = "GET $path HTTP/1.0\r\n";
$header = "Accept: */*\r\n";
$header .= "Accept-Language: zh-cn\r\n";
$header .= "User-Agent: $_SERVER[HTTP_USER_AGENT]\r\n";
$header .= "Host: $host:$port\r\n";
$header .= "Connection: Close\r\n";
$header .= "Cookie: $cookie\r\n\r\n";
$out .= $header;
}
$fpflag = 0;
if (!$fp = @fsocketopen(($ip ? $ip : $host), $port, $errno, $errstr, $timeout)) {
$context = array(
'http' => array(
'method' => $post ? 'POST' : 'GET',
'header' => $header,
'content' => $post,
'timeout' => $timeout,
),
);
$context = stream_context_create($context);
$fp = @fopen($scheme . '://' . ($ip ? $ip : $host) . ':' . $port . $path, 'b', false, $context);
$fpflag = 1;
}
if (!$fp) {
return '';
} else {
stream_set_blocking($fp, $block);
stream_set_timeout($fp, $timeout);
@fwrite($fp, $out);
$status = stream_get_meta_data($fp);
if (!$status['timed_out']) {
while (!feof($fp) && !$fpflag) {
$header = @fgets($fp);
$headers .= $header;
if ($header && ($header == "\r\n" || $header == "\n")) {
break;
}
}
$GLOBALS['filesockheader'] = $headers;
if ($position) {
for ($i = 0; $i < $position; $i++) {
$char = fgetc($fp);
if ($char == "\n" && $oldchar != "\r") {
$i++;
}
$oldchar = $char;
}
}
if ($limit) {
$return = stream_get_contents($fp, $limit);
} else {
$return = stream_get_contents($fp);
}
}
@fclose($fp);
return $return;
}
}
final protected function formatPostkey($post, &$result, $key = '') {
foreach ($post as $k => $v) {
$_k = $key ? $key . '[' . $k . ']' : $k;
if (is_array($v)) {
$this->formatPostkey($v, $result, $_k);
} else {
$result[$_k] = $v;
}
}
}
}

View File

@@ -0,0 +1,140 @@
<?php
namespace com\pay\driver;
class Alipay extends \com\pay\Pay {
protected $gateway = 'https://mapi.alipay.com/gateway.do';
protected $verify_url = 'http://notify.alipay.com/trade/notify_query.do';
protected $config = array(
'email' => '',
'key' => '',
'partner' => '',
);
public function check() {
if (!$this->config['email'] || !$this->config['key'] || !$this->config['partner']) {
E("支付宝账号未开通!");
}
return true;
}
public function pay(\com\pay\Input $input) {
$param = array(
'service' => 'create_direct_pay_by_user',
'payment_type' => '1',
'_input_charset' => 'utf-8',
'seller_email' => $this->config['email'],
'partner' => $this->config['partner'],
'notify_url' => $this->config['notify_url'],
'return_url' => $this->config['return_url'],
'out_trade_no' => $input->getOrderNo(),
'subject' => $input->getTitle(),
'body' => $input->getBody(),
'total_fee' => $input->getFee()
);
ksort($param);
reset($param);
$arg = '';
foreach ($param as $key => $value) {
if ($value) {
$arg .= "$key=$value&";
}
}
//echo substr($arg, 0, -1) . $this->config['key'];exit();
$param['sign'] = md5(substr($arg, 0, -1) . $this->config['key']);
$param['sign_type'] = 'MD5';
$sHtml = $this->_buildForm($param, $this->gateway,true, 'get');
return $sHtml;
}
/**
* 获取返回时的签名验证结果
* @param $para_temp 通知返回来的参数数组
* @param $sign 返回的签名结果
* @return 签名验证结果
*/
protected function getSignVeryfy($param, $sign) {
//除去待签名参数数组中的空值和签名参数
$param_filter = array();
while (list ($key, $val) = each($param)) {
if ($key == "sign" || $key == "sign_type" || $val == "") {
continue;
} else {
$param_filter[$key] = $param[$key];
}
}
ksort($param_filter);
reset($param_filter);
//把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
$prestr = "";
while (list ($key, $val) = each($param_filter)) {
$prestr.=$key . "=" . $val . "&";
}
//去掉最后一个&字符
$prestr = substr($prestr, 0, -1);
$prestr = $prestr . $this->config['key'];
$mysgin = md5($prestr);
if ($mysgin == $sign) {
return true;
} else {
return false;
}
}
/**
* 针对notify_url验证消息是否是支付宝发出的合法消息
* @return 验证结果
*/
public function verifyNotify($notify) {
//生成签名结果
$isSign = $this->getSignVeryfy($notify, $notify["sign"]);
//获取支付宝远程服务器ATN结果验证是否是支付宝发来的消息
$responseTxt = 'true';
if (!empty($notify["notify_id"])) {
$responseTxt = $this->getResponse($notify["notify_id"]);
}
if (preg_match("/true$/i", $responseTxt) && $isSign) {
$this->setInfo($notify);
return $this->info;
} else {
return false;
}
}
protected function setInfo($notify) {
$info = array();
//支付状态
$info['status'] = ($notify['trade_status'] == 'TRADE_FINISHED' || $notify['trade_status'] == 'TRADE_SUCCESS') ? true : false;
$info['total_fee'] = $notify['total_fee'];
$info['out_trade_no'] = $notify['out_trade_no'];
$this->info = $info;
}
/**
* 获取远程服务器ATN结果,验证返回URL
* @param $notify_id 通知校验ID
* @return 服务器ATN结果
* 验证结果集:
* invalid命令参数不对 出现这个错误请检测返回处理中partner和key是否为空
* true 返回正确信息
* false 请检查防火墙或者是服务器阻止端口问题以及验证时间是否超过一分钟
*/
protected function getResponse($notify_id) {
$partner = $this->config['partner'];
$veryfy_url = $this->verify_url . "?partner=" . $partner . "&notify_id=" . $notify_id;
$responseTxt = $this->fsockOpen($veryfy_url);
return $responseTxt;
}
}