From 11bc3c42f34a963b0186ade597eb99101b398d96 Mon Sep 17 00:00:00 2001 From: molong Date: Sun, 14 Jan 2018 09:42:27 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=94=B9=E7=9B=AE=E5=BD=95=E7=BB=93?= =?UTF-8?q?=E6=9E=84=EF=BC=8C=E5=A2=9E=E5=8A=A0composer=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- extend/com/Auth.php | 226 ++++++++++++++++++++++++++++ extend/com/Database.php | 212 ++++++++++++++++++++++++++ extend/com/Datatable.php | 273 ++++++++++++++++++++++++++++++++++ extend/com/Sent.php | 160 ++++++++++++++++++++ extend/com/Tree.php | 95 ++++++++++++ {extend => vendor}/.gitignore | 0 6 files changed, 966 insertions(+) create mode 100644 extend/com/Auth.php create mode 100644 extend/com/Database.php create mode 100644 extend/com/Datatable.php create mode 100644 extend/com/Sent.php create mode 100644 extend/com/Tree.php rename {extend => vendor}/.gitignore (100%) diff --git a/extend/com/Auth.php b/extend/com/Auth.php new file mode 100644 index 00000000..1e329a40 --- /dev/null +++ b/extend/com/Auth.php @@ -0,0 +1,226 @@ +  +// +---------------------------------------------------------------------- +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:用户id,group_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]; + } + +} diff --git a/extend/com/Database.php b/extend/com/Database.php new file mode 100644 index 00000000..2661ab4e --- /dev/null +++ b/extend/com/Database.php @@ -0,0 +1,212 @@ + +// +---------------------------------------------------------------------- + +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); + } +} \ No newline at end of file diff --git a/extend/com/Datatable.php b/extend/com/Datatable.php new file mode 100644 index 00000000..1b6b98a5 --- /dev/null +++ b/extend/com/Datatable.php @@ -0,0 +1,273 @@ + +// +---------------------------------------------------------------------- +namespace com; +use think\Db; + +/** + * 数据库管理类 + * @author colin + */ +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语句*/ + protected $typeAlist = array( + "text" => "VARCHAR", + "string" => "VARCHAR", + "password" => "VARCHAR", + "textarea" => "TEXT", + "bool" => "INT", + "select" => "INT", + "num" => "INT", + "decimal" => "DECIMAL", + "tags" => "VARCHAR", + "datetime" => "INT", + "date" => "INT", + "editor" => "TEXT", + "bind" => "INT", + "image" => "INT", + "images" => "VARCHAR", + "attach" => "VARCHAR", + ); + + /** + * 初始化数据库信息 + * @author colin + */ + public function __construct() { + //创建DB对象 + $this->prefix = config('database.prefix'); + $this->model_table_prefix = config('model_table_prefix'); + } + + /** + * @title 初始化表 + * @description 初始化创建表 + * @Author molong + * @DateTime 2017-06-11 + * @param string $table 表名 + * @return void 空 + */ + public function initTable($table = '', $comment = '', $pk = 'id') { + $this->table = $this->getTablename($table, true); + + $sql = $this->generateField($pk, 'int', 11, '', '主键', true); + + $primary = $pk ? "PRIMARY KEY (`" . $pk . "`)" : ''; + $generatesql = $sql . ','; + + $create = "CREATE TABLE IF NOT EXISTS `" . $this->table . "`(" + . $generatesql + . $primary + . ") ENGINE=" . $this->engine_type . " AUTO_INCREMENT=1 DEFAULT CHARSET=" . $this->charset . " ROW_FORMAT=DYNAMIC COMMENT='" . $comment . "';"; + $this->sql = $create; + return $this; + } + + /** + * 快速创建ID字段 + * @var length 字段的长度 + * @var comment 字段的描述 + * @author colin + */ + public function generateField($key = '', $type = '', $length = 11, $default = '', $comment = '主键', $is_auto_increment = false) { + if ($key && $type) { + $auto_increment = $is_auto_increment ? 'AUTO_INCREMENT' : ''; + $field_type = $length ? $type . '(' . $length . ')' : $type; + $signed = in_array($type, array('int', 'float', 'double')) ? 'signed' : ''; + $comment = $comment ? "COMMENT '" . $comment . "'" : ""; + $default = $default ? "DEFAULT '" . $default . "'" : ""; + $sql = "`{$key}` {$field_type} {$signed} NOT NULL {$default} $auto_increment {$comment}"; + } + return $sql; + } + + /** + * 追加字段 + * @var $table 追加字段的表名 + * @var $attr 属性列表 + * @var $is_more 是否为多条同时插入 + * @author colin + */ + public function columField($table, $attr = array()) { + $field_attr['table'] = $table ? $this->getTablename($table, true) : $this->table; + $field_attr['name'] = $attr['name']; + $field_attr['type'] = $attr['type'] ? $this->typeAlist[$attr['type']] : 'varchar'; + if (intval($attr['length']) && $attr['length']) { + $field_attr['length'] = "(" . $attr['length'] . ")"; + } else { + $field_attr['length'] = ""; + } + $field_attr['is_null'] = $attr['is_must'] ? 'NOT NULL' : 'NULL'; + $field_attr['default'] = $attr['value'] != '' ? 'DEFAULT "' . $attr['value'] . '"' : ''; + + $field_attr['comment'] = (isset($attr['remark']) && $attr['remark']) ? $attr['remark'] : $attr['title']; + $field_attr['after'] = (isset($attr['after']) && $attr['after']) ? ' AFTER `' . $attr['after'] . '`' : ' AFTER `id`'; + $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['name']}` {$field_attr['type']}{$field_attr['length']} {$field_attr['is_null']} {$field_attr['default']} COMMENT '{$field_attr['comment']}' {$field_attr['after']}"; + } elseif ($field_attr['action'] == 'CHANGE') { + $field_attr['oldname'] = (isset($attr['oldname']) && $attr['oldname']) ? $attr['oldname'] : ''; + + $this->sql = "ALTER TABLE `{$field_attr['table']}` CHANGE `{$field_attr['oldname']}` `{$field_attr['name']}` {$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 + */ + public function delField($table, $field) { + $table = $table ? $this->getTablename($table, true) : $this->table; + $this->sql = "ALTER TABLE `$table` DROP `$field`"; + return $this; + } + + /** + * 删除数据表 + * @var $table 追加字段的表名 + * @author colin + */ + public function delTable($table) { + $table = $table ? $this->getTablename($table, true) : $this->table; + $this->sql = "DROP TABLE `$table`"; + return $this; + } + + /** + * 结束表 + * @var $engine_type 数据库引擎 + * @var $comment 表注释 + * @var $charset 数据库编码 + * @author colin + */ + public function endTable($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 + */ + public function create() { + $res = Db::execute($this->sql); + return $res !== false; + } + + /** + * create的别名 + * @return int 0 + * @author colin + */ + public function query() { + return $this->create(); + } + + /** + * 获取最后生成的sql语句 + * @author colin + */ + public function getLastSql() { + return $this->sql; + } + + /** + * 获取指定的表名 + * @var $table 要获取名字的表名 + * @var $prefix 获取表前缀? 默认为不获取 false + * @author colin + */ + 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 + */ + 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 + * @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 + * @return boolen + */ + public function CheckField($table, $field) { + //检查字段是否存在 + $table = $this->getTablename($table, true); + if (!Db::query("Describe $table $field")) { + return false; + } else { + return true; + } + } +} \ No newline at end of file diff --git a/extend/com/Sent.php b/extend/com/Sent.php new file mode 100644 index 00000000..121b385d --- /dev/null +++ b/extend/com/Sent.php @@ -0,0 +1,160 @@ + +// +---------------------------------------------------------------------- + +namespace com; + +use think\template\TagLib; + +/** + * CX标签库解析类 + * @category Think + * @package Think + * @subpackage Driver.Taglib + * @author liu21st + */ +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 = '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 .= ''; + 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']) ? 'id desc' : $tag['order']; + + //获得当前栏目的所有子栏目 + $ids = get_category_child($cid); + $ids = implode(',', $ids); + $where = "category_id IN ({$ids})"; + $where .= " and status >= 1"; + + $parse = $parse = 'where(\''.$where.'\')->field(\''.$field.'\')->limit(\''.$limit.'\')->order(\''.$order.'\')->select();'; + $parse .= 'foreach ($__LIST__ as $key => $'.$tag['name'].') {'; + $parse .= '?>'; + $parse .= $content; + $parse .= ''; + 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 = 'where(\''.$map.'\')->field(\''.$field.'\')->limit(\''.$limit.'\')->order(\''.$order.'\')->select();'; + $parse .= 'foreach ($__LIST__ as $key => $'.$tag['id'].') {'; + $parse .= '?>'; + $parse .= $content; + $parse .= ''; + return $parse; + } + + public function tagrecom($tag, $content){ + $model = empty($tag['model']) ? '' : $tag['model']; + $field = empty($tag['field']) ? '*' : $tag['field']; + $limit = empty($tag['limit']) ? 20 : $tag['limit']; + $order = empty($tag['order']) ? 'id desc' : $tag['order']; + if (!$model) { + return ''; + } + $parse = $parse = 'recom(\'' .$field. '\',' .$limit. ',\'' .$order. '\');'; + $parse .= 'foreach ($__LIST__ as $key => $'.$tag['id'].') {'; + $parse .= '?>'; + $parse .= $content; + $parse .= ''; + 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 = 'where(\''.$map.'\')->field(\''.$field.'\')->limit(\''.$limit.'\')->order(\''.$order.'\')->select();'; + $parse .= 'foreach ($__LIST__ as $key => $'.$tag['name'].') {'; + $parse .= '?>'; + $parse .= $content; + $parse .= ''; + return $parse; + } + + public function tagprev($tag, $content){ + $id = !empty($tag['id']) ? $tag['id'] : ''; + $cate = !empty($tag['cate']) ? $tag['cate'] : ''; + $model = !empty($tag['model']) ? $tag['model'] : ''; + + $parse = '" . ' . $id . ';'; + $parse .= '$prev = db(\''.$model.'\')->where($map)->order(\'id asc\')->find();if(!empty($prev)){ ?>'; + $parse .= $content; + $parse .= ''; + return $parse; + } + + public function tagnext($tag, $content){ + $id = !empty($tag['id']) ? ($tag['id']) : ''; + $cate = !empty($tag['cate']) ? $tag['cate'] : ''; + $model = !empty($tag['model']) ? $tag['model'] : ''; + + $parse = 'where($map)->order(\'id desc\')->find();if(!empty($next)){ ?>'; + $parse .= $content; + $parse .= ''; + return $parse; + } +} \ No newline at end of file diff --git a/extend/com/Tree.php b/extend/com/Tree.php new file mode 100644 index 00000000..f73b43f1 --- /dev/null +++ b/extend/com/Tree.php @@ -0,0 +1,95 @@ + + */ + 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 = "    ") { + $str = ""; + if ($cat[$pid]) { + for ($i=2; $i < $cat['level']; $i++) { + $str .= $empty."│"; + } + if ($cat[$pid] != $next_parentid && !$cat['_child']) { + $str .= $empty."└─ "; + } else { + $str .= $empty."├─ "; + } + } + 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; + } +} \ No newline at end of file diff --git a/extend/.gitignore b/vendor/.gitignore similarity index 100% rename from extend/.gitignore rename to vendor/.gitignore