仓库初始化
This commit is contained in:
265
extend/fast/Auth.php
Normal file
265
extend/fast/Auth.php
Normal file
@@ -0,0 +1,265 @@
|
||||
<?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>
|
||||
// +----------------------------------------------------------------------
|
||||
// | 修改者: anuo (本权限类在原3.2.3的基础上修改过来的)
|
||||
// +----------------------------------------------------------------------
|
||||
|
||||
namespace fast;
|
||||
|
||||
use think\Db;
|
||||
use think\Config;
|
||||
use think\Session;
|
||||
use think\Request;
|
||||
|
||||
/**
|
||||
* 权限认证类
|
||||
* 功能特性:
|
||||
* 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 表中定义一条规则,condition字段就可以定义规则表达式。 如定义{score}>5 and {score}<100
|
||||
* 表示用户的分数在5-100之间时这条规则才会通过。
|
||||
*/
|
||||
class Auth
|
||||
{
|
||||
|
||||
/**
|
||||
* @var object 对象实例
|
||||
*/
|
||||
protected static $instance;
|
||||
protected $rules = [];
|
||||
|
||||
/**
|
||||
* 当前请求实例
|
||||
* @var Request
|
||||
*/
|
||||
protected $request;
|
||||
//默认配置
|
||||
protected $config = [
|
||||
'auth_on' => 1, // 权限开关
|
||||
'auth_type' => 1, // 认证方式,1为实时认证;2为登录认证。
|
||||
'auth_group' => 'auth_group', // 用户组数据表名
|
||||
'auth_group_access' => 'auth_group_access', // 用户-用户组关系表
|
||||
'auth_rule' => 'auth_rule', // 权限规则表
|
||||
'auth_user' => 'user', // 用户信息表
|
||||
];
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
if ($auth = Config::get('auth')) {
|
||||
$this->config = array_merge($this->config, $auth);
|
||||
}
|
||||
// 初始化request
|
||||
$this->request = Request::instance();
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
* @access public
|
||||
* @param array $options 参数
|
||||
* @return Auth
|
||||
*/
|
||||
public static function instance($options = [])
|
||||
{
|
||||
if (is_null(self::$instance)) {
|
||||
self::$instance = new static($options);
|
||||
}
|
||||
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查权限
|
||||
* @param string|array $name 需要验证的规则列表,支持逗号分隔的权限规则或索引数组
|
||||
* @param int $uid 认证用户的id
|
||||
* @param string $relation 如果为 'or' 表示满足任一条规则即通过验证;如果为 'and'则表示需满足所有规则才能通过验证
|
||||
* @param string $mode 执行验证的模式,可分为url,normal
|
||||
* @return bool 通过验证返回true;失败返回false
|
||||
*/
|
||||
public function check($name, $uid, $relation = 'or', $mode = 'url')
|
||||
{
|
||||
if (!$this->config['auth_on']) {
|
||||
return true;
|
||||
}
|
||||
// 获取用户需要验证的所有有效规则列表
|
||||
$rulelist = $this->getRuleList($uid);
|
||||
if (in_array('*', $rulelist)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (is_string($name)) {
|
||||
$name = strtolower($name);
|
||||
if (strpos($name, ',') !== false) {
|
||||
$name = explode(',', $name);
|
||||
} else {
|
||||
$name = [$name];
|
||||
}
|
||||
}
|
||||
$list = []; //保存验证通过的规则名
|
||||
if ('url' == $mode) {
|
||||
$REQUEST = unserialize(strtolower(serialize($this->request->param())));
|
||||
}
|
||||
foreach ($rulelist as $rule) {
|
||||
$query = preg_replace('/^.+\?/U', '', $rule);
|
||||
if ('url' == $mode && $query != $rule) {
|
||||
parse_str($query, $param); //解析规则中的param
|
||||
$intersect = array_intersect_assoc($REQUEST, $param);
|
||||
$rule = preg_replace('/\?.*$/U', '', $rule);
|
||||
if (in_array($rule, $name) && $intersect == $param) {
|
||||
//如果节点相符且url参数满足
|
||||
$list[] = $rule;
|
||||
}
|
||||
} else {
|
||||
if (in_array($rule, $name)) {
|
||||
$list[] = $rule;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ('or' == $relation && !empty($list)) {
|
||||
return true;
|
||||
}
|
||||
$diff = array_diff($name, $list);
|
||||
if ('and' == $relation && empty($diff)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据用户id获取用户组,返回值为数组
|
||||
* @param int $uid 用户id
|
||||
* @return array 用户所属的用户组 array(
|
||||
* array('uid'=>'用户id','group_id'=>'用户组id','name'=>'用户组名称','rules'=>'用户组拥有的规则id,多个,号隔开'),
|
||||
* ...)
|
||||
*/
|
||||
public function getGroups($uid)
|
||||
{
|
||||
static $groups = [];
|
||||
if (isset($groups[$uid])) {
|
||||
return $groups[$uid];
|
||||
}
|
||||
|
||||
// 执行查询
|
||||
$user_groups = Db::name($this->config['auth_group_access'])
|
||||
->alias('aga')
|
||||
->join('__' . strtoupper($this->config['auth_group']) . '__ ag', 'aga.group_id = ag.id', 'LEFT')
|
||||
->field('aga.uid,aga.group_id,ag.id,ag.pid,ag.name,ag.rules')
|
||||
->where("aga.uid='{$uid}' and ag.status='normal'")
|
||||
->select();
|
||||
$groups[$uid] = $user_groups ?: [];
|
||||
return $groups[$uid];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得权限规则列表
|
||||
* @param int $uid 用户id
|
||||
* @return array
|
||||
*/
|
||||
public function getRuleList($uid)
|
||||
{
|
||||
static $_rulelist = []; //保存用户验证通过的权限列表
|
||||
if (isset($_rulelist[$uid])) {
|
||||
return $_rulelist[$uid];
|
||||
}
|
||||
if (2 == $this->config['auth_type'] && Session::has('_rule_list_' . $uid)) {
|
||||
return Session::get('_rule_list_' . $uid);
|
||||
}
|
||||
|
||||
// 读取用户规则节点
|
||||
$ids = $this->getRuleIds($uid);
|
||||
if (empty($ids)) {
|
||||
$_rulelist[$uid] = [];
|
||||
return [];
|
||||
}
|
||||
|
||||
// 筛选条件
|
||||
$where = [
|
||||
'status' => 'normal'
|
||||
];
|
||||
if (!in_array('*', $ids)) {
|
||||
$where['id'] = ['in', $ids];
|
||||
}
|
||||
//读取用户组所有权限规则
|
||||
$this->rules = Db::name($this->config['auth_rule'])->where($where)->field('id,pid,condition,icon,name,title,ismenu')->select();
|
||||
|
||||
//循环规则,判断结果。
|
||||
$rulelist = []; //
|
||||
if (in_array('*', $ids)) {
|
||||
$rulelist[] = "*";
|
||||
}
|
||||
foreach ($this->rules as $rule) {
|
||||
//超级管理员无需验证condition
|
||||
if (!empty($rule['condition']) && !in_array('*', $ids)) {
|
||||
//根据condition进行验证
|
||||
$user = $this->getUserInfo($uid); //获取用户信息,一维数组
|
||||
$nums = 0;
|
||||
$condition = str_replace(['&&', '||'], "\r\n", $rule['condition']);
|
||||
$condition = preg_replace('/\{(\w*?)\}/', '\\1', $condition);
|
||||
$conditionArr = explode("\r\n", $condition);
|
||||
foreach ($conditionArr as $index => $item) {
|
||||
preg_match("/^(\w+)\s?([\>\<\=]+)\s?(.*)$/", trim($item), $matches);
|
||||
if ($matches && isset($user[$matches[1]]) && version_compare($user[$matches[1]], $matches[3], $matches[2])) {
|
||||
$nums++;
|
||||
}
|
||||
}
|
||||
if ($conditionArr && ((stripos($rule['condition'], "||") !== false && $nums > 0) || count($conditionArr) == $nums)) {
|
||||
$rulelist[$rule['id']] = strtolower($rule['name']);
|
||||
}
|
||||
} else {
|
||||
//只要存在就记录
|
||||
$rulelist[$rule['id']] = strtolower($rule['name']);
|
||||
}
|
||||
}
|
||||
$_rulelist[$uid] = $rulelist;
|
||||
//登录验证则需要保存规则列表
|
||||
if (2 == $this->config['auth_type']) {
|
||||
//规则列表结果保存到session
|
||||
Session::set('_rule_list_' . $uid, $rulelist);
|
||||
}
|
||||
return array_unique($rulelist);
|
||||
}
|
||||
|
||||
public function getRuleIds($uid)
|
||||
{
|
||||
//读取用户所属用户组
|
||||
$groups = $this->getGroups($uid);
|
||||
$ids = []; //保存用户所属用户组设置的所有权限规则id
|
||||
foreach ($groups as $g) {
|
||||
$ids = array_merge($ids, explode(',', trim($g['rules'], ',')));
|
||||
}
|
||||
$ids = array_unique($ids);
|
||||
return $ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得用户资料
|
||||
* @param int $uid 用户id
|
||||
* @return mixed
|
||||
*/
|
||||
protected function getUserInfo($uid)
|
||||
{
|
||||
static $user_info = [];
|
||||
|
||||
$user = Db::name($this->config['auth_user']);
|
||||
// 获取用户表主键
|
||||
$_pk = is_string($user->getPk()) ? $user->getPk() : 'uid';
|
||||
if (!isset($user_info[$uid])) {
|
||||
$user_info[$uid] = $user->where($_pk, $uid)->find();
|
||||
}
|
||||
|
||||
return $user_info[$uid];
|
||||
}
|
||||
}
|
||||
230
extend/fast/Date.php
Normal file
230
extend/fast/Date.php
Normal file
@@ -0,0 +1,230 @@
|
||||
<?php
|
||||
|
||||
namespace fast;
|
||||
|
||||
use DateTime;
|
||||
use DateTimeZone;
|
||||
|
||||
/**
|
||||
* 日期时间处理类
|
||||
*/
|
||||
class Date
|
||||
{
|
||||
const YEAR = 31536000;
|
||||
const MONTH = 2592000;
|
||||
const WEEK = 604800;
|
||||
const DAY = 86400;
|
||||
const HOUR = 3600;
|
||||
const MINUTE = 60;
|
||||
|
||||
/**
|
||||
* 计算两个时区间相差的时长,单位为秒
|
||||
*
|
||||
* $seconds = self::offset('America/Chicago', 'GMT');
|
||||
*
|
||||
* [!!] A list of time zones that PHP supports can be found at
|
||||
* <http://php.net/timezones>.
|
||||
*
|
||||
* @param string $remote timezone that to find the offset of
|
||||
* @param string $local timezone used as the baseline
|
||||
* @param mixed $now UNIX timestamp or date string
|
||||
* @return integer
|
||||
*/
|
||||
public static function offset($remote, $local = null, $now = null)
|
||||
{
|
||||
if ($local === null) {
|
||||
// Use the default timezone
|
||||
$local = date_default_timezone_get();
|
||||
}
|
||||
if (is_int($now)) {
|
||||
// Convert the timestamp into a string
|
||||
$now = date(DateTime::RFC2822, $now);
|
||||
}
|
||||
// Create timezone objects
|
||||
$zone_remote = new DateTimeZone($remote);
|
||||
$zone_local = new DateTimeZone($local);
|
||||
// Create date objects from timezones
|
||||
$time_remote = new DateTime($now, $zone_remote);
|
||||
$time_local = new DateTime($now, $zone_local);
|
||||
// Find the offset
|
||||
$offset = $zone_remote->getOffset($time_remote) - $zone_local->getOffset($time_local);
|
||||
return $offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算两个时间戳之间相差的时间
|
||||
*
|
||||
* $span = self::span(60, 182, 'minutes,seconds'); // array('minutes' => 2, 'seconds' => 2)
|
||||
* $span = self::span(60, 182, 'minutes'); // 2
|
||||
*
|
||||
* @param int $remote timestamp to find the span of
|
||||
* @param int $local timestamp to use as the baseline
|
||||
* @param string $output formatting string
|
||||
* @return string when only a single output is requested
|
||||
* @return array associative list of all outputs requested
|
||||
* @from https://github.com/kohana/ohanzee-helpers/blob/master/src/Date.php
|
||||
*/
|
||||
public static function span($remote, $local = null, $output = 'years,months,weeks,days,hours,minutes,seconds')
|
||||
{
|
||||
// Normalize output
|
||||
$output = trim(strtolower((string)$output));
|
||||
if (!$output) {
|
||||
// Invalid output
|
||||
return false;
|
||||
}
|
||||
// Array with the output formats
|
||||
$output = preg_split('/[^a-z]+/', $output);
|
||||
// Convert the list of outputs to an associative array
|
||||
$output = array_combine($output, array_fill(0, count($output), 0));
|
||||
// Make the output values into keys
|
||||
extract(array_flip($output), EXTR_SKIP);
|
||||
if ($local === null) {
|
||||
// Calculate the span from the current time
|
||||
$local = time();
|
||||
}
|
||||
// Calculate timespan (seconds)
|
||||
$timespan = abs($remote - $local);
|
||||
if (isset($output['years'])) {
|
||||
$timespan -= self::YEAR * ($output['years'] = (int)floor($timespan / self::YEAR));
|
||||
}
|
||||
if (isset($output['months'])) {
|
||||
$timespan -= self::MONTH * ($output['months'] = (int)floor($timespan / self::MONTH));
|
||||
}
|
||||
if (isset($output['weeks'])) {
|
||||
$timespan -= self::WEEK * ($output['weeks'] = (int)floor($timespan / self::WEEK));
|
||||
}
|
||||
if (isset($output['days'])) {
|
||||
$timespan -= self::DAY * ($output['days'] = (int)floor($timespan / self::DAY));
|
||||
}
|
||||
if (isset($output['hours'])) {
|
||||
$timespan -= self::HOUR * ($output['hours'] = (int)floor($timespan / self::HOUR));
|
||||
}
|
||||
if (isset($output['minutes'])) {
|
||||
$timespan -= self::MINUTE * ($output['minutes'] = (int)floor($timespan / self::MINUTE));
|
||||
}
|
||||
// Seconds ago, 1
|
||||
if (isset($output['seconds'])) {
|
||||
$output['seconds'] = $timespan;
|
||||
}
|
||||
if (count($output) === 1) {
|
||||
// Only a single output was requested, return it
|
||||
return array_pop($output);
|
||||
}
|
||||
// Return array
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化 UNIX 时间戳为人易读的字符串
|
||||
*
|
||||
* @param int Unix 时间戳
|
||||
* @param mixed $local 本地时间
|
||||
*
|
||||
* @return string 格式化的日期字符串
|
||||
*/
|
||||
public static function human($remote, $local = null)
|
||||
{
|
||||
$time_diff = (is_null($local) ? time() : $local) - $remote;
|
||||
$tense = $time_diff < 0 ? 'after' : 'ago';
|
||||
$time_diff = abs($time_diff);
|
||||
$chunks = [
|
||||
[60 * 60 * 24 * 365, 'year'],
|
||||
[60 * 60 * 24 * 30, 'month'],
|
||||
[60 * 60 * 24 * 7, 'week'],
|
||||
[60 * 60 * 24, 'day'],
|
||||
[60 * 60, 'hour'],
|
||||
[60, 'minute'],
|
||||
[1, 'second']
|
||||
];
|
||||
$name = 'second';
|
||||
$count = 0;
|
||||
|
||||
for ($i = 0, $j = count($chunks); $i < $j; $i++) {
|
||||
$seconds = $chunks[$i][0];
|
||||
$name = $chunks[$i][1];
|
||||
if (($count = floor($time_diff / $seconds)) != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return __("%d $name%s $tense", [$count, ($count > 1 ? 's' : '')]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取一个基于时间偏移的Unix时间戳
|
||||
*
|
||||
* @param string $type 时间类型,默认为day,可选minute,hour,day,week,month,quarter,year
|
||||
* @param int $offset 时间偏移量 默认为0,正数表示当前type之后,负数表示当前type之前
|
||||
* @param string $position 时间的开始或结束,默认为begin,可选前(begin,start,first,front),end
|
||||
* @param int $year 基准年,默认为null,即以当前年为基准
|
||||
* @param int $month 基准月,默认为null,即以当前月为基准
|
||||
* @param int $day 基准天,默认为null,即以当前天为基准
|
||||
* @param int $hour 基准小时,默认为null,即以当前年小时基准
|
||||
* @param int $minute 基准分钟,默认为null,即以当前分钟为基准
|
||||
* @return int 处理后的Unix时间戳
|
||||
*/
|
||||
public static function unixtime($type = 'day', $offset = 0, $position = 'begin', $year = null, $month = null, $day = null, $hour = null, $minute = null)
|
||||
{
|
||||
$year = is_null($year) ? date('Y') : $year;
|
||||
$month = is_null($month) ? date('m') : $month;
|
||||
$day = is_null($day) ? date('d') : $day;
|
||||
$hour = is_null($hour) ? date('H') : $hour;
|
||||
$minute = is_null($minute) ? date('i') : $minute;
|
||||
$position = in_array($position, array('begin', 'start', 'first', 'front'));
|
||||
|
||||
$baseTime = mktime(0, 0, 0, $month, $day, $year);
|
||||
|
||||
switch ($type) {
|
||||
case 'minute':
|
||||
$time = $position ? mktime($hour, $minute + $offset, 0, $month, $day, $year) : mktime($hour, $minute + $offset, 59, $month, $day, $year);
|
||||
break;
|
||||
case 'hour':
|
||||
$time = $position ? mktime($hour + $offset, 0, 0, $month, $day, $year) : mktime($hour + $offset, 59, 59, $month, $day, $year);
|
||||
break;
|
||||
case 'day':
|
||||
$time = $position ? mktime(0, 0, 0, $month, $day + $offset, $year) : mktime(23, 59, 59, $month, $day + $offset, $year);
|
||||
break;
|
||||
case 'week':
|
||||
$weekIndex = date("w", $baseTime);
|
||||
$time = $position ?
|
||||
strtotime($offset . " weeks", strtotime(date('Y-m-d', strtotime("-" . ($weekIndex ? $weekIndex - 1 : 6) . " days", $baseTime)))) :
|
||||
strtotime($offset . " weeks", strtotime(date('Y-m-d 23:59:59', strtotime("+" . (6 - ($weekIndex ? $weekIndex - 1 : 6)) . " days", $baseTime))));
|
||||
break;
|
||||
case 'month':
|
||||
$_timestamp = mktime(0, 0, 0, $month + $offset, 1, $year);
|
||||
$time = $position ? $_timestamp : mktime(23, 59, 59, $month + $offset, self::days_in_month(date("m", $_timestamp), date("Y", $_timestamp)), $year);
|
||||
break;
|
||||
case 'quarter':
|
||||
$quarter = ceil(date('n', $baseTime) / 3) + $offset;
|
||||
$month = $quarter * 3;
|
||||
$offset_year = ceil($month/12) - 1;
|
||||
$year = $year + $offset_year;
|
||||
$month = $month - ($offset_year * 12);
|
||||
$time = $position ?
|
||||
mktime(0, 0, 0, $month-2, 1, $year) :
|
||||
mktime(23, 59, 59, $month, self::days_in_month($month, $year), $year);
|
||||
break;
|
||||
case 'year':
|
||||
$time = $position ? mktime(0, 0, 0, 1, 1, $year + $offset) : mktime(23, 59, 59, 12, 31, $year + $offset);
|
||||
break;
|
||||
default:
|
||||
$time = mktime($hour, $minute, 0, $month, $day, $year);
|
||||
break;
|
||||
}
|
||||
return $time;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定年月拥有的天数
|
||||
* @param int $month
|
||||
* @param int $year
|
||||
* @return false|int|string
|
||||
*/
|
||||
public static function days_in_month($month, $year)
|
||||
{
|
||||
if (function_exists("cal_days_in_month")) {
|
||||
return cal_days_in_month(CAL_GREGORIAN, $month, $year);
|
||||
} else {
|
||||
return date('t', mktime(0, 0, 0, $month, 1, $year));
|
||||
}
|
||||
}
|
||||
}
|
||||
1289
extend/fast/Form.php
Normal file
1289
extend/fast/Form.php
Normal file
File diff suppressed because it is too large
Load Diff
185
extend/fast/Http.php
Normal file
185
extend/fast/Http.php
Normal file
@@ -0,0 +1,185 @@
|
||||
<?php
|
||||
|
||||
namespace fast;
|
||||
|
||||
/**
|
||||
* Http 请求类
|
||||
*/
|
||||
class Http
|
||||
{
|
||||
|
||||
/**
|
||||
* 发送一个POST请求
|
||||
* @param string $url 请求URL
|
||||
* @param array $params 请求参数
|
||||
* @param array $options 扩展参数
|
||||
* @return mixed|string
|
||||
*/
|
||||
public static function post($url, $params = [], $options = [])
|
||||
{
|
||||
$req = self::sendRequest($url, $params, 'POST', $options);
|
||||
return $req['ret'] ? $req['msg'] : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送一个GET请求
|
||||
* @param string $url 请求URL
|
||||
* @param array $params 请求参数
|
||||
* @param array $options 扩展参数
|
||||
* @return mixed|string
|
||||
*/
|
||||
public static function get($url, $params = [], $options = [])
|
||||
{
|
||||
$req = self::sendRequest($url, $params, 'GET', $options);
|
||||
return $req['ret'] ? $req['msg'] : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* CURL发送Request请求,含POST和REQUEST
|
||||
* @param string $url 请求的链接
|
||||
* @param mixed $params 传递的参数
|
||||
* @param string $method 请求的方法
|
||||
* @param mixed $options CURL的参数
|
||||
* @return array
|
||||
*/
|
||||
public static function sendRequest($url, $params = [], $method = 'POST', $options = [])
|
||||
{
|
||||
$method = strtoupper($method);
|
||||
$protocol = substr($url, 0, 5);
|
||||
$query_string = is_array($params) ? http_build_query($params) : $params;
|
||||
|
||||
$ch = curl_init();
|
||||
$defaults = [];
|
||||
if ('GET' == $method) {
|
||||
$geturl = $query_string ? $url . (stripos($url, "?") !== false ? "&" : "?") . $query_string : $url;
|
||||
$defaults[CURLOPT_URL] = $geturl;
|
||||
} else {
|
||||
$defaults[CURLOPT_URL] = $url;
|
||||
if ($method == 'POST') {
|
||||
$defaults[CURLOPT_POST] = 1;
|
||||
} else {
|
||||
$defaults[CURLOPT_CUSTOMREQUEST] = $method;
|
||||
}
|
||||
$defaults[CURLOPT_POSTFIELDS] = is_array($params) && count(array_filter($params, 'is_array')) > 0 ? $query_string : $params;
|
||||
}
|
||||
|
||||
$defaults[CURLOPT_HEADER] = false;
|
||||
$defaults[CURLOPT_USERAGENT] = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.98 Safari/537.36";
|
||||
$defaults[CURLOPT_FOLLOWLOCATION] = true;
|
||||
$defaults[CURLOPT_RETURNTRANSFER] = true;
|
||||
$defaults[CURLOPT_CONNECTTIMEOUT] = 10;
|
||||
$defaults[CURLOPT_TIMEOUT] = 10;
|
||||
|
||||
// disable 100-continue
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Expect:'));
|
||||
|
||||
if ('https' == $protocol) {
|
||||
$defaults[CURLOPT_SSL_VERIFYPEER] = false;
|
||||
$defaults[CURLOPT_SSL_VERIFYHOST] = false;
|
||||
}
|
||||
|
||||
curl_setopt_array($ch, (array)$options + $defaults);
|
||||
|
||||
$ret = curl_exec($ch);
|
||||
$err = curl_error($ch);
|
||||
|
||||
if (false === $ret || !empty($err)) {
|
||||
$errno = curl_errno($ch);
|
||||
$info = curl_getinfo($ch);
|
||||
curl_close($ch);
|
||||
return [
|
||||
'ret' => false,
|
||||
'errno' => $errno,
|
||||
'msg' => $err,
|
||||
'info' => $info,
|
||||
];
|
||||
}
|
||||
curl_close($ch);
|
||||
return [
|
||||
'ret' => true,
|
||||
'msg' => $ret,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 异步发送一个请求
|
||||
* @param string $url 请求的链接
|
||||
* @param mixed $params 请求的参数
|
||||
* @param string $method 请求的方法
|
||||
* @return boolean TRUE
|
||||
*/
|
||||
public static function sendAsyncRequest($url, $params = [], $method = 'POST')
|
||||
{
|
||||
$method = strtoupper($method);
|
||||
$method = $method == 'POST' ? 'POST' : 'GET';
|
||||
//构造传递的参数
|
||||
if (is_array($params)) {
|
||||
$post_params = [];
|
||||
foreach ($params as $k => &$v) {
|
||||
if (is_array($v)) {
|
||||
$v = implode(',', $v);
|
||||
}
|
||||
$post_params[] = $k . '=' . urlencode($v);
|
||||
}
|
||||
$post_string = implode('&', $post_params);
|
||||
} else {
|
||||
$post_string = $params;
|
||||
}
|
||||
$parts = parse_url($url);
|
||||
//构造查询的参数
|
||||
if ($method == 'GET' && $post_string) {
|
||||
$parts['query'] = isset($parts['query']) ? $parts['query'] . '&' . $post_string : $post_string;
|
||||
$post_string = '';
|
||||
}
|
||||
$parts['query'] = isset($parts['query']) && $parts['query'] ? '?' . $parts['query'] : '';
|
||||
//发送socket请求,获得连接句柄
|
||||
$fp = fsockopen($parts['host'], $parts['port'] ?? 80, $errno, $errstr, 10);
|
||||
if (!$fp) {
|
||||
return false;
|
||||
}
|
||||
//设置超时时间
|
||||
stream_set_timeout($fp, 10);
|
||||
$out = "{$method} {$parts['path']}{$parts['query']} HTTP/1.1\r\n";
|
||||
$out .= "Host: {$parts['host']}\r\n";
|
||||
$out .= "Content-Type: application/x-www-form-urlencoded\r\n";
|
||||
$out .= "Content-Length: " . strlen($post_string) . "\r\n";
|
||||
$out .= "Connection: Close\r\n\r\n";
|
||||
if ($post_string !== '') {
|
||||
$out .= $post_string;
|
||||
}
|
||||
fwrite($fp, $out);
|
||||
//不用关心服务器返回结果
|
||||
//echo fread($fp, 1024);
|
||||
fclose($fp);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送文件到客户端
|
||||
* @param string $file
|
||||
* @param bool $delaftersend
|
||||
* @param bool $exitaftersend
|
||||
*/
|
||||
public static function sendToBrowser($file, $delaftersend = true, $exitaftersend = true)
|
||||
{
|
||||
if (file_exists($file) && is_readable($file)) {
|
||||
header('Content-Description: File Transfer');
|
||||
header('Content-Type: application/octet-stream');
|
||||
header('Content-Disposition: attachment;filename = ' . basename($file));
|
||||
header('Content-Transfer-Encoding: binary');
|
||||
header('Expires: 0');
|
||||
header('Cache-Control: must-revalidate, post-check = 0, pre-check = 0');
|
||||
header('Pragma: public');
|
||||
header('Content-Length: ' . filesize($file));
|
||||
ob_clean();
|
||||
flush();
|
||||
readfile($file);
|
||||
if ($delaftersend) {
|
||||
unlink($file);
|
||||
}
|
||||
if ($exitaftersend) {
|
||||
exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
36
extend/fast/Pinyin.php
Normal file
36
extend/fast/Pinyin.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace fast;
|
||||
|
||||
/**
|
||||
* 中文转拼音类
|
||||
*/
|
||||
class Pinyin
|
||||
{
|
||||
|
||||
/**
|
||||
* 获取文字的拼音
|
||||
* @param string $chinese 中文汉字
|
||||
* @param boolean $onlyfirst 是否只返回拼音首字母
|
||||
* @param string $delimiter 分隔符
|
||||
* @param bool $ucfirst 是否首字母大写
|
||||
* @return string
|
||||
*/
|
||||
public static function get($chinese, $onlyfirst = false, $delimiter = '', $ucfirst = false)
|
||||
{
|
||||
|
||||
$pinyin = new \Overtrue\Pinyin\Pinyin();
|
||||
if ($onlyfirst) {
|
||||
$result = $pinyin->abbr($chinese, $delimiter);
|
||||
} else {
|
||||
$result = $pinyin->permalink($chinese, $delimiter);
|
||||
}
|
||||
if ($ucfirst) {
|
||||
$pinyinArr = explode($delimiter, $result);
|
||||
$result = implode($delimiter, array_map('ucfirst', $pinyinArr));
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
||||
110
extend/fast/Random.php
Normal file
110
extend/fast/Random.php
Normal file
@@ -0,0 +1,110 @@
|
||||
<?php
|
||||
|
||||
namespace fast;
|
||||
|
||||
/**
|
||||
* 随机生成类
|
||||
*/
|
||||
class Random
|
||||
{
|
||||
|
||||
/**
|
||||
* 生成数字和字母
|
||||
*
|
||||
* @param int $len 长度
|
||||
* @return string
|
||||
*/
|
||||
public static function alnum(int $len = 6): string
|
||||
{
|
||||
return self::build('alnum', $len);
|
||||
}
|
||||
|
||||
/**
|
||||
* 仅生成字符
|
||||
*
|
||||
* @param int $len 长度
|
||||
* @return string
|
||||
*/
|
||||
public static function alpha(int $len = 6): string
|
||||
{
|
||||
return self::build('alpha', $len);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成指定长度的随机数字
|
||||
*
|
||||
* @param int $len 长度
|
||||
* @return string
|
||||
*/
|
||||
public static function numeric(int $len = 4): string
|
||||
{
|
||||
return self::build('numeric', $len);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成指定长度的无0随机数字
|
||||
*
|
||||
* @param int $len 长度
|
||||
* @return string
|
||||
*/
|
||||
public static function nozero(int $len = 4): string
|
||||
{
|
||||
return self::build('nozero', $len);
|
||||
}
|
||||
|
||||
/**
|
||||
* 能用的随机数生成
|
||||
* @param string $type 类型 alpha/alnum/numeric/nozero/unique/md5/encrypt/sha1
|
||||
* @param int $len 长度
|
||||
* @return string
|
||||
*/
|
||||
public static function build(string $type = 'alnum', int $len = 8): string
|
||||
{
|
||||
switch ($type) {
|
||||
case 'alpha':
|
||||
case 'alnum':
|
||||
case 'numeric':
|
||||
case 'nozero':
|
||||
switch ($type) {
|
||||
case 'alpha':
|
||||
$pool = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||
break;
|
||||
case 'alnum':
|
||||
$pool = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
|
||||
break;
|
||||
case 'numeric':
|
||||
$pool = '0123456789';
|
||||
break;
|
||||
case 'nozero':
|
||||
$pool = '123456789';
|
||||
break;
|
||||
}
|
||||
return substr(str_shuffle(str_repeat($pool, ceil($len / strlen($pool)))), 0, $len);
|
||||
case 'unique':
|
||||
case 'md5':
|
||||
return md5(uniqid(mt_rand()));
|
||||
case 'encrypt':
|
||||
case 'sha1':
|
||||
return sha1(uniqid(mt_rand(), true));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取全球唯一标识
|
||||
* @return string
|
||||
*/
|
||||
public static function uuid(): string
|
||||
{
|
||||
return sprintf(
|
||||
'%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
|
||||
mt_rand(0, 0xffff),
|
||||
mt_rand(0, 0xffff),
|
||||
mt_rand(0, 0xffff),
|
||||
mt_rand(0, 0x0fff) | 0x4000,
|
||||
mt_rand(0, 0x3fff) | 0x8000,
|
||||
mt_rand(0, 0xffff),
|
||||
mt_rand(0, 0xffff),
|
||||
mt_rand(0, 0xffff)
|
||||
);
|
||||
}
|
||||
}
|
||||
179
extend/fast/Rsa.php
Normal file
179
extend/fast/Rsa.php
Normal file
@@ -0,0 +1,179 @@
|
||||
<?php
|
||||
|
||||
namespace fast;
|
||||
|
||||
/**
|
||||
* RSA签名类
|
||||
*/
|
||||
class Rsa
|
||||
{
|
||||
public $publicKey = '';
|
||||
public $privateKey = '';
|
||||
private $_privKey;
|
||||
|
||||
/**
|
||||
* * private key
|
||||
*/
|
||||
private $_pubKey;
|
||||
|
||||
/**
|
||||
* * public key
|
||||
*/
|
||||
private $_keyPath;
|
||||
|
||||
/**
|
||||
* * the keys saving path
|
||||
*/
|
||||
|
||||
/**
|
||||
* * the construtor,the param $path is the keys saving path
|
||||
* @param string $publicKey 公钥
|
||||
* @param string $privateKey 私钥
|
||||
*/
|
||||
public function __construct($publicKey = null, $privateKey = null)
|
||||
{
|
||||
$this->setKey($publicKey, $privateKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置公钥和私钥
|
||||
* @param string $publicKey 公钥
|
||||
* @param string $privateKey 私钥
|
||||
*/
|
||||
public function setKey($publicKey = null, $privateKey = null)
|
||||
{
|
||||
if (!is_null($publicKey)) {
|
||||
$this->publicKey = $publicKey;
|
||||
}
|
||||
if (!is_null($privateKey)) {
|
||||
$this->privateKey = $privateKey;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* * setup the private key
|
||||
*/
|
||||
private function setupPrivKey()
|
||||
{
|
||||
if (is_resource($this->_privKey)) {
|
||||
return true;
|
||||
}
|
||||
$pem = chunk_split($this->privateKey, 64, "\n");
|
||||
$pem = "-----BEGIN PRIVATE KEY-----\n" . $pem . "-----END PRIVATE KEY-----\n";
|
||||
$this->_privKey = openssl_pkey_get_private($pem);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* * setup the public key
|
||||
*/
|
||||
private function setupPubKey()
|
||||
{
|
||||
if (is_resource($this->_pubKey)) {
|
||||
return true;
|
||||
}
|
||||
$pem = chunk_split($this->publicKey, 64, "\n");
|
||||
$pem = "-----BEGIN PUBLIC KEY-----\n" . $pem . "-----END PUBLIC KEY-----\n";
|
||||
$this->_pubKey = openssl_pkey_get_public($pem);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* * encrypt with the private key
|
||||
*/
|
||||
public function privEncrypt($data)
|
||||
{
|
||||
if (!is_string($data)) {
|
||||
return null;
|
||||
}
|
||||
$this->setupPrivKey();
|
||||
$r = openssl_private_encrypt($data, $encrypted, $this->_privKey);
|
||||
if ($r) {
|
||||
return base64_encode($encrypted);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* * decrypt with the private key
|
||||
*/
|
||||
public function privDecrypt($encrypted)
|
||||
{
|
||||
if (!is_string($encrypted)) {
|
||||
return null;
|
||||
}
|
||||
$this->setupPrivKey();
|
||||
$encrypted = base64_decode($encrypted);
|
||||
$r = openssl_private_decrypt($encrypted, $decrypted, $this->_privKey);
|
||||
if ($r) {
|
||||
return $decrypted;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* * encrypt with public key
|
||||
*/
|
||||
public function pubEncrypt($data)
|
||||
{
|
||||
if (!is_string($data)) {
|
||||
return null;
|
||||
}
|
||||
$this->setupPubKey();
|
||||
$r = openssl_public_encrypt($data, $encrypted, $this->_pubKey);
|
||||
if ($r) {
|
||||
return base64_encode($encrypted);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* * decrypt with the public key
|
||||
*/
|
||||
public function pubDecrypt($crypted)
|
||||
{
|
||||
if (!is_string($crypted)) {
|
||||
return null;
|
||||
}
|
||||
$this->setupPubKey();
|
||||
$crypted = base64_decode($crypted);
|
||||
$r = openssl_public_decrypt($crypted, $decrypted, $this->_pubKey);
|
||||
if ($r) {
|
||||
return $decrypted;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造签名
|
||||
* @param string $dataString 被签名数据
|
||||
* @return string
|
||||
*/
|
||||
public function sign($dataString)
|
||||
{
|
||||
$this->setupPrivKey();
|
||||
$signature = false;
|
||||
openssl_sign($dataString, $signature, $this->_privKey);
|
||||
return base64_encode($signature);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证签名
|
||||
* @param string $dataString 被签名数据
|
||||
* @param string $signString 已经签名的字符串
|
||||
* @return number 1签名正确 0签名错误
|
||||
*/
|
||||
public function verify($dataString, $signString)
|
||||
{
|
||||
$this->setupPubKey();
|
||||
$signature = base64_decode($signString);
|
||||
$flg = openssl_verify($dataString, $signature, $this->_pubKey);
|
||||
return $flg;
|
||||
}
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
is_resource($this->_privKey) && @openssl_free_key($this->_privKey);
|
||||
is_resource($this->_pubKey) && @openssl_free_key($this->_pubKey);
|
||||
}
|
||||
}
|
||||
334
extend/fast/Tencentst.php
Normal file
334
extend/fast/Tencentst.php
Normal file
@@ -0,0 +1,334 @@
|
||||
<?php
|
||||
|
||||
namespace fast;
|
||||
|
||||
if ( version_compare( PHP_VERSION, '5.1.2' ) < 0 ) {
|
||||
trigger_error( 'need php 5.1.2 or newer', E_USER_ERROR );
|
||||
}
|
||||
|
||||
class Tencentst
|
||||
{
|
||||
private $key = false;
|
||||
private $sdkappid = 0;
|
||||
|
||||
/**
|
||||
*【功能说明】用于签发 TRTC 和 IM 服务中必须要使用的 UserSig 鉴权票据
|
||||
*
|
||||
*【参数说明】
|
||||
* @param string userid - 用户id,限制长度为32字节,只允许包含大小写英文字母(a-zA-Z)、数字(0-9)及下划线和连词符。
|
||||
* @param string expire - UserSig 票据的过期时间,单位是秒,比如 86400 代表生成的 UserSig 票据在一天后就无法再使用了。
|
||||
* @return string 签名字符串
|
||||
* @throws \Exception
|
||||
*/
|
||||
|
||||
public function genUserSig( $userid, $expire = 86400*180 ) {
|
||||
return $this->__genSig( $userid, $expire, '', false );
|
||||
}
|
||||
|
||||
/**
|
||||
*【功能说明】
|
||||
* 用于签发 TRTC 进房参数中可选的 PrivateMapKey 权限票据。
|
||||
* PrivateMapKey 需要跟 UserSig 一起使用,但 PrivateMapKey 比 UserSig 有更强的权限控制能力:
|
||||
* - UserSig 只能控制某个 UserID 有无使用 TRTC 服务的权限,只要 UserSig 正确,其对应的 UserID 可以进出任意房间。
|
||||
* - PrivateMapKey 则是将 UserID 的权限控制的更加严格,包括能不能进入某个房间,能不能在该房间里上行音视频等等。
|
||||
* 如果要开启 PrivateMapKey 严格权限位校验,需要在【实时音视频控制台】=>【应用管理】=>【应用信息】中打开“启动权限密钥”开关。
|
||||
*
|
||||
*【参数说明】
|
||||
* @param userid - 用户id,限制长度为32字节,只允许包含大小写英文字母(a-zA-Z)、数字(0-9)及下划线和连词符。
|
||||
* @param expire - PrivateMapKey 票据的过期时间,单位是秒,比如 86400 生成的 PrivateMapKey 票据在一天后就无法再使用了。
|
||||
* @param roomid - 房间号,用于指定该 userid 可以进入的房间号
|
||||
* @param privilegeMap - 权限位,使用了一个字节中的 8 个比特位,分别代表八个具体的功能权限开关:
|
||||
* - 第 1 位:0000 0001 = 1,创建房间的权限
|
||||
* - 第 2 位:0000 0010 = 2,加入房间的权限
|
||||
* - 第 3 位:0000 0100 = 4,发送语音的权限
|
||||
* - 第 4 位:0000 1000 = 8,接收语音的权限
|
||||
* - 第 5 位:0001 0000 = 16,发送视频的权限
|
||||
* - 第 6 位:0010 0000 = 32,接收视频的权限
|
||||
* - 第 7 位:0100 0000 = 64,发送辅路(也就是屏幕分享)视频的权限
|
||||
* - 第 8 位:1000 0000 = 200,接收辅路(也就是屏幕分享)视频的权限
|
||||
* - privilegeMap == 1111 1111 == 255 代表该 userid 在该 roomid 房间内的所有功能权限。
|
||||
* - privilegeMap == 0010 1010 == 42 代表该 userid 拥有加入房间和接收音视频数据的权限,但不具备其他权限。
|
||||
*/
|
||||
|
||||
public function genPrivateMapKey( $userid, $expire, $roomid, $privilegeMap ) {
|
||||
$userbuf = $this->__genUserBuf( $userid, $roomid, $expire, $privilegeMap, 0, '' );
|
||||
return $this->__genSig( $userid, $expire, $userbuf, true );
|
||||
}
|
||||
/**
|
||||
*【功能说明】
|
||||
* 用于签发 TRTC 进房参数中可选的 PrivateMapKey 权限票据。
|
||||
* PrivateMapKey 需要跟 UserSig 一起使用,但 PrivateMapKey 比 UserSig 有更强的权限控制能力:
|
||||
* - UserSig 只能控制某个 UserID 有无使用 TRTC 服务的权限,只要 UserSig 正确,其对应的 UserID 可以进出任意房间。
|
||||
* - PrivateMapKey 则是将 UserID 的权限控制的更加严格,包括能不能进入某个房间,能不能在该房间里上行音视频等等。
|
||||
* 如果要开启 PrivateMapKey 严格权限位校验,需要在【实时音视频控制台】=>【应用管理】=>【应用信息】中打开“启动权限密钥”开关。
|
||||
*
|
||||
*【参数说明】
|
||||
* @param userid - 用户id,限制长度为32字节,只允许包含大小写英文字母(a-zA-Z)、数字(0-9)及下划线和连词符。
|
||||
* @param expire - PrivateMapKey 票据的过期时间,单位是秒,比如 86400 生成的 PrivateMapKey 票据在一天后就无法再使用了。
|
||||
* @param roomstr - 房间号,用于指定该 userid 可以进入的房间号
|
||||
* @param privilegeMap - 权限位,使用了一个字节中的 8 个比特位,分别代表八个具体的功能权限开关:
|
||||
* - 第 1 位:0000 0001 = 1,创建房间的权限
|
||||
* - 第 2 位:0000 0010 = 2,加入房间的权限
|
||||
* - 第 3 位:0000 0100 = 4,发送语音的权限
|
||||
* - 第 4 位:0000 1000 = 8,接收语音的权限
|
||||
* - 第 5 位:0001 0000 = 16,发送视频的权限
|
||||
* - 第 6 位:0010 0000 = 32,接收视频的权限
|
||||
* - 第 7 位:0100 0000 = 64,发送辅路(也就是屏幕分享)视频的权限
|
||||
* - 第 8 位:1000 0000 = 200,接收辅路(也就是屏幕分享)视频的权限
|
||||
* - privilegeMap == 1111 1111 == 255 代表该 userid 在该 roomid 房间内的所有功能权限。
|
||||
* - privilegeMap == 0010 1010 == 42 代表该 userid 拥有加入房间和接收音视频数据的权限,但不具备其他权限。
|
||||
*/
|
||||
|
||||
public function genPrivateMapKeyWithStringRoomID( $userid, $expire, $roomstr, $privilegeMap ) {
|
||||
$userbuf = $this->__genUserBuf( $userid, 0, $expire, $privilegeMap, 0, $roomstr );
|
||||
return $this->__genSig( $userid, $expire, $userbuf, true );
|
||||
}
|
||||
|
||||
public function __construct( $sdkappid, $key ) {
|
||||
$this->sdkappid = $sdkappid;
|
||||
$this->key = $key;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于 url 的 base64 encode
|
||||
* '+' => '*', '/' => '-', '=' => '_'
|
||||
* @param string $string 需要编码的数据
|
||||
* @return string 编码后的base64串,失败返回false
|
||||
* @throws \Exception
|
||||
*/
|
||||
|
||||
private function base64_url_encode( $string ) {
|
||||
static $replace = Array( '+' => '*', '/' => '-', '=' => '_' );
|
||||
$base64 = base64_encode( $string );
|
||||
if ( $base64 === false ) {
|
||||
throw new \Exception( 'base64_encode error' );
|
||||
}
|
||||
return str_replace( array_keys( $replace ), array_values( $replace ), $base64 );
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于 url 的 base64 decode
|
||||
* '+' => '*', '/' => '-', '=' => '_'
|
||||
* @param string $base64 需要解码的base64串
|
||||
* @return string 解码后的数据,失败返回false
|
||||
* @throws \Exception
|
||||
*/
|
||||
|
||||
private function base64_url_decode( $base64 ) {
|
||||
static $replace = Array( '+' => '*', '/' => '-', '=' => '_' );
|
||||
$string = str_replace( array_values( $replace ), array_keys( $replace ), $base64 );
|
||||
$result = base64_decode( $string );
|
||||
if ( $result == false ) {
|
||||
throw new \Exception( 'base64_url_decode error' );
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
/**
|
||||
* TRTC业务进房权限加密串使用用户定义的userbuf
|
||||
* @brief 生成 userbuf
|
||||
* @param account 用户名
|
||||
* @param dwSdkappid sdkappid
|
||||
* @param dwAuthID 数字房间号
|
||||
* @param dwExpTime 过期时间:该权限加密串的过期时间. 过期时间 = now+dwExpTime
|
||||
* @param dwPrivilegeMap 用户权限,255表示所有权限
|
||||
* @param dwAccountType 用户类型, 默认为0
|
||||
* @param roomStr 字符串房间号
|
||||
* @return userbuf string 返回的userbuf
|
||||
*/
|
||||
|
||||
private function __genUserBuf( $account, $dwAuthID, $dwExpTime, $dwPrivilegeMap, $dwAccountType,$roomStr ) {
|
||||
|
||||
//cVer unsigned char/1 版本号,填0
|
||||
if($roomStr == '')
|
||||
$userbuf = pack( 'C1', '0' );
|
||||
else
|
||||
$userbuf = pack( 'C1', '1' );
|
||||
|
||||
$userbuf .= pack( 'n', strlen( $account ) );
|
||||
//wAccountLen unsigned short /2 第三方自己的帐号长度
|
||||
$userbuf .= pack( 'a'.strlen( $account ), $account );
|
||||
//buffAccount wAccountLen 第三方自己的帐号字符
|
||||
$userbuf .= pack( 'N', $this->sdkappid );
|
||||
//dwSdkAppid unsigned int/4 sdkappid
|
||||
$userbuf .= pack( 'N', $dwAuthID );
|
||||
//dwAuthId unsigned int/4 群组号码/音视频房间号
|
||||
$expire = $dwExpTime + time();
|
||||
$userbuf .= pack( 'N', $expire );
|
||||
//dwExpTime unsigned int/4 过期时间 (当前时间 + 有效期(单位:秒,建议300秒))
|
||||
$userbuf .= pack( 'N', $dwPrivilegeMap );
|
||||
//dwPrivilegeMap unsigned int/4 权限位
|
||||
$userbuf .= pack( 'N', $dwAccountType );
|
||||
//dwAccountType unsigned int/4
|
||||
if($roomStr != '')
|
||||
{
|
||||
$userbuf .= pack( 'n', strlen( $roomStr ) );
|
||||
//roomStrLen unsigned short /2 字符串房间号长度
|
||||
$userbuf .= pack( 'a'.strlen( $roomStr ), $roomStr );
|
||||
//roomStr roomStrLen 字符串房间号
|
||||
}
|
||||
return $userbuf;
|
||||
}
|
||||
/**
|
||||
* 使用 hmac sha256 生成 sig 字段内容,经过 base64 编码
|
||||
* @param $identifier 用户名,utf-8 编码
|
||||
* @param $curr_time 当前生成 sig 的 unix 时间戳
|
||||
* @param $expire 有效期,单位秒
|
||||
* @param $base64_userbuf base64 编码后的 userbuf
|
||||
* @param $userbuf_enabled 是否开启 userbuf
|
||||
* @return string base64 后的 sig
|
||||
*/
|
||||
|
||||
private function hmacsha256( $identifier, $curr_time, $expire, $base64_userbuf, $userbuf_enabled ) {
|
||||
$content_to_be_signed = 'TLS.identifier:' . $identifier . "\n"
|
||||
. 'TLS.sdkappid:' . $this->sdkappid . "\n"
|
||||
. 'TLS.time:' . $curr_time . "\n"
|
||||
. 'TLS.expire:' . $expire . "\n";
|
||||
if ( true == $userbuf_enabled ) {
|
||||
$content_to_be_signed .= 'TLS.userbuf:' . $base64_userbuf . "\n";
|
||||
}
|
||||
return base64_encode( hash_hmac( 'sha256', $content_to_be_signed, $this->key, true ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成签名。
|
||||
*
|
||||
* @param $identifier 用户账号
|
||||
* @param int $expire 过期时间,单位秒,默认 180 天
|
||||
* @param $userbuf base64 编码后的 userbuf
|
||||
* @param $userbuf_enabled 是否开启 userbuf
|
||||
* @return string 签名字符串
|
||||
* @throws \Exception
|
||||
*/
|
||||
|
||||
private function __genSig( $identifier, $expire, $userbuf, $userbuf_enabled ) {
|
||||
$curr_time = time();
|
||||
$sig_array = Array(
|
||||
'TLS.ver' => '2.0',
|
||||
'TLS.identifier' => strval( $identifier ),
|
||||
'TLS.sdkappid' => intval( $this->sdkappid ),
|
||||
'TLS.expire' => intval( $expire ),
|
||||
'TLS.time' => intval( $curr_time )
|
||||
);
|
||||
|
||||
$base64_userbuf = '';
|
||||
if ( true == $userbuf_enabled ) {
|
||||
$base64_userbuf = base64_encode( $userbuf );
|
||||
$sig_array['TLS.userbuf'] = strval( $base64_userbuf );
|
||||
}
|
||||
|
||||
$sig_array['TLS.sig'] = $this->hmacsha256( $identifier, $curr_time, $expire, $base64_userbuf, $userbuf_enabled );
|
||||
if ( $sig_array['TLS.sig'] === false ) {
|
||||
throw new \Exception( 'base64_encode error' );
|
||||
}
|
||||
$json_str_sig = json_encode( $sig_array );
|
||||
if ( $json_str_sig === false ) {
|
||||
throw new \Exception( 'json_encode error' );
|
||||
}
|
||||
$compressed = gzcompress( $json_str_sig );
|
||||
if ( $compressed === false ) {
|
||||
throw new \Exception( 'gzcompress error' );
|
||||
}
|
||||
return $this->base64_url_encode( $compressed );
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证签名。
|
||||
*
|
||||
* @param string $sig 签名内容
|
||||
* @param string $identifier 需要验证用户名,utf-8 编码
|
||||
* @param int $init_time 返回的生成时间,unix 时间戳
|
||||
* @param int $expire_time 返回的有效期,单位秒
|
||||
* @param string $userbuf 返回的用户数据
|
||||
* @param string $error_msg 失败时的错误信息
|
||||
* @return boolean 验证是否成功
|
||||
* @throws \Exception
|
||||
*/
|
||||
|
||||
private function __verifySig( $sig, $identifier, &$init_time, &$expire_time, &$userbuf, &$error_msg ) {
|
||||
try {
|
||||
$error_msg = '';
|
||||
$compressed_sig = $this->base64_url_decode( $sig );
|
||||
$pre_level = error_reporting( E_ERROR );
|
||||
$uncompressed_sig = gzuncompress( $compressed_sig );
|
||||
error_reporting( $pre_level );
|
||||
if ( $uncompressed_sig === false ) {
|
||||
throw new \Exception( 'gzuncompress error' );
|
||||
}
|
||||
$sig_doc = json_decode( $uncompressed_sig );
|
||||
if ( $sig_doc == false ) {
|
||||
throw new \Exception( 'json_decode error' );
|
||||
}
|
||||
$sig_doc = ( array )$sig_doc;
|
||||
if ( $sig_doc['TLS.identifier'] !== $identifier ) {
|
||||
throw new \Exception( "identifier dosen't match" );
|
||||
}
|
||||
if ( $sig_doc['TLS.sdkappid'] != $this->sdkappid ) {
|
||||
throw new \Exception( "sdkappid dosen't match" );
|
||||
}
|
||||
$sig = $sig_doc['TLS.sig'];
|
||||
if ( $sig == false ) {
|
||||
throw new \Exception( 'sig field is missing' );
|
||||
}
|
||||
|
||||
$init_time = $sig_doc['TLS.time'];
|
||||
$expire_time = $sig_doc['TLS.expire'];
|
||||
|
||||
$curr_time = time();
|
||||
if ( $curr_time > $init_time+$expire_time ) {
|
||||
throw new \Exception( 'sig expired' );
|
||||
}
|
||||
|
||||
$userbuf_enabled = false;
|
||||
$base64_userbuf = '';
|
||||
if ( isset( $sig_doc['TLS.userbuf'] ) ) {
|
||||
$base64_userbuf = $sig_doc['TLS.userbuf'];
|
||||
$userbuf = base64_decode( $base64_userbuf );
|
||||
$userbuf_enabled = true;
|
||||
}
|
||||
$sigCalculated = $this->hmacsha256( $identifier, $init_time, $expire_time, $base64_userbuf, $userbuf_enabled );
|
||||
|
||||
if ( $sig != $sigCalculated ) {
|
||||
throw new \Exception( 'verify failed' );
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch ( \Exception $ex ) {
|
||||
$error_msg = $ex->getMessage();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 带 userbuf 验证签名。
|
||||
*
|
||||
* @param string $sig 签名内容
|
||||
* @param string $identifier 需要验证用户名,utf-8 编码
|
||||
* @param int $init_time 返回的生成时间,unix 时间戳
|
||||
* @param int $expire_time 返回的有效期,单位秒
|
||||
* @param string $error_msg 失败时的错误信息
|
||||
* @return boolean 验证是否成功
|
||||
* @throws \Exception
|
||||
*/
|
||||
|
||||
public function verifySig( $sig, $identifier, &$init_time, &$expire_time, &$error_msg ) {
|
||||
$userbuf = '';
|
||||
return $this->__verifySig( $sig, $identifier, $init_time, $expire_time, $userbuf, $error_msg );
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证签名
|
||||
* @param string $sig 签名内容
|
||||
* @param string $identifier 需要验证用户名,utf-8 编码
|
||||
* @param int $init_time 返回的生成时间,unix 时间戳
|
||||
* @param int $expire_time 返回的有效期,单位秒
|
||||
* @param string $userbuf 返回的用户数据
|
||||
* @param string $error_msg 失败时的错误信息
|
||||
* @return boolean 验证是否成功
|
||||
* @throws \Exception
|
||||
*/
|
||||
|
||||
public function verifySigWithUserBuf( $sig, $identifier, &$init_time, &$expire_time, &$userbuf, &$error_msg ) {
|
||||
return $this->__verifySig( $sig, $identifier, $init_time, $expire_time, $userbuf, $error_msg );
|
||||
}
|
||||
|
||||
}
|
||||
438
extend/fast/Tree.php
Normal file
438
extend/fast/Tree.php
Normal file
@@ -0,0 +1,438 @@
|
||||
<?php
|
||||
|
||||
namespace fast;
|
||||
|
||||
use think\Config;
|
||||
|
||||
/**
|
||||
* 通用的树型类
|
||||
* @author XiaoYao <476552238li@gmail.com>
|
||||
*/
|
||||
class Tree
|
||||
{
|
||||
protected static $instance;
|
||||
//默认配置
|
||||
protected $config = [];
|
||||
public $options = [];
|
||||
|
||||
/**
|
||||
* 生成树型结构所需要的2维数组
|
||||
* @var array
|
||||
*/
|
||||
public $arr = [];
|
||||
|
||||
/**
|
||||
* 生成树型结构所需修饰符号,可以换成图片
|
||||
* @var array
|
||||
*/
|
||||
public $icon = array('│', '├', '└');
|
||||
public $nbsp = " ";
|
||||
public $pidname = 'pid';
|
||||
|
||||
public function __construct($options = [])
|
||||
{
|
||||
if ($config = Config::get('tree')) {
|
||||
$this->options = array_merge($this->config, $config);
|
||||
}
|
||||
$this->options = array_merge($this->config, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
* @access public
|
||||
* @param array $options 参数
|
||||
* @return Tree
|
||||
*/
|
||||
public static function instance($options = [])
|
||||
{
|
||||
if (is_null(self::$instance)) {
|
||||
self::$instance = new static($options);
|
||||
}
|
||||
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化方法
|
||||
* @param array $arr 2维数组,例如:
|
||||
* array(
|
||||
* 1 => array('id'=>'1','pid'=>0,'name'=>'一级栏目一'),
|
||||
* 2 => array('id'=>'2','pid'=>0,'name'=>'一级栏目二'),
|
||||
* 3 => array('id'=>'3','pid'=>1,'name'=>'二级栏目一'),
|
||||
* 4 => array('id'=>'4','pid'=>1,'name'=>'二级栏目二'),
|
||||
* 5 => array('id'=>'5','pid'=>2,'name'=>'二级栏目三'),
|
||||
* 6 => array('id'=>'6','pid'=>3,'name'=>'三级栏目一'),
|
||||
* 7 => array('id'=>'7','pid'=>3,'name'=>'三级栏目二')
|
||||
* )
|
||||
* @param string $pidname 父字段名称
|
||||
* @param string $nbsp 空格占位符
|
||||
* @return Tree
|
||||
*/
|
||||
public function init($arr = [], $pidname = null, $nbsp = null)
|
||||
{
|
||||
$this->arr = $arr;
|
||||
if (!is_null($pidname)) {
|
||||
$this->pidname = $pidname;
|
||||
}
|
||||
if (!is_null($nbsp)) {
|
||||
$this->nbsp = $nbsp;
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 得到子级数组
|
||||
* @param int
|
||||
* @return array
|
||||
*/
|
||||
public function getChild($myid)
|
||||
{
|
||||
$newarr = [];
|
||||
foreach ($this->arr as $value) {
|
||||
if (!isset($value['id'])) {
|
||||
continue;
|
||||
}
|
||||
if ($value[$this->pidname] == $myid) {
|
||||
$newarr[$value['id']] = $value;
|
||||
}
|
||||
}
|
||||
return $newarr;
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取指定节点的所有孩子节点
|
||||
* @param int $myid 节点ID
|
||||
* @param boolean $withself 是否包含自身
|
||||
* @return array
|
||||
*/
|
||||
public function getChildren($myid, $withself = false)
|
||||
{
|
||||
$newarr = [];
|
||||
foreach ($this->arr as $value) {
|
||||
if (!isset($value['id'])) {
|
||||
continue;
|
||||
}
|
||||
if ((string)$value[$this->pidname] == (string)$myid) {
|
||||
$newarr[] = $value;
|
||||
$newarr = array_merge($newarr, $this->getChildren($value['id']));
|
||||
} elseif ($withself && (string)$value['id'] == (string)$myid) {
|
||||
$newarr[] = $value;
|
||||
}
|
||||
}
|
||||
return $newarr;
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取指定节点的所有孩子节点ID
|
||||
* @param int $myid 节点ID
|
||||
* @param boolean $withself 是否包含自身
|
||||
* @return array
|
||||
*/
|
||||
public function getChildrenIds($myid, $withself = false)
|
||||
{
|
||||
$childrenlist = $this->getChildren($myid, $withself);
|
||||
$childrenids = [];
|
||||
foreach ($childrenlist as $k => $v) {
|
||||
$childrenids[] = $v['id'];
|
||||
}
|
||||
return $childrenids;
|
||||
}
|
||||
|
||||
/**
|
||||
* 得到当前位置父辈数组
|
||||
* @param int
|
||||
* @return array
|
||||
*/
|
||||
public function getParent($myid)
|
||||
{
|
||||
$pid = 0;
|
||||
$newarr = [];
|
||||
foreach ($this->arr as $value) {
|
||||
if (!isset($value['id'])) {
|
||||
continue;
|
||||
}
|
||||
if ($value['id'] == $myid) {
|
||||
$pid = $value[$this->pidname];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($pid) {
|
||||
foreach ($this->arr as $value) {
|
||||
if ($value['id'] == $pid) {
|
||||
$newarr[] = $value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $newarr;
|
||||
}
|
||||
|
||||
/**
|
||||
* 得到当前位置所有父辈数组
|
||||
* @param int
|
||||
* @param bool $withself 是否包含自己
|
||||
* @return array
|
||||
*/
|
||||
public function getParents($myid, $withself = false)
|
||||
{
|
||||
$pid = 0;
|
||||
$newarr = [];
|
||||
foreach ($this->arr as $value) {
|
||||
if (!isset($value['id'])) {
|
||||
continue;
|
||||
}
|
||||
if ($value['id'] == $myid) {
|
||||
if ($withself) {
|
||||
$newarr[] = $value;
|
||||
}
|
||||
$pid = $value[$this->pidname];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($pid) {
|
||||
$arr = $this->getParents($pid, true);
|
||||
$newarr = array_merge($arr, $newarr);
|
||||
}
|
||||
return $newarr;
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取指定节点所有父类节点ID
|
||||
* @param int $myid
|
||||
* @param boolean $withself
|
||||
* @return array
|
||||
*/
|
||||
public function getParentsIds($myid, $withself = false)
|
||||
{
|
||||
$parentlist = $this->getParents($myid, $withself);
|
||||
$parentsids = [];
|
||||
foreach ($parentlist as $k => $v) {
|
||||
$parentsids[] = $v['id'];
|
||||
}
|
||||
return $parentsids;
|
||||
}
|
||||
|
||||
/**
|
||||
* 树型结构Option
|
||||
* @param int $myid 表示获得这个ID下的所有子级
|
||||
* @param string $itemtpl 条目模板 如:"<option value=@id @selected @disabled>@spacer@name</option>"
|
||||
* @param mixed $selectedids 被选中的ID,比如在做树型下拉框的时候需要用到
|
||||
* @param mixed $disabledids 被禁用的ID,比如在做树型下拉框的时候需要用到
|
||||
* @param string $itemprefix 每一项前缀
|
||||
* @param string $toptpl 顶级栏目的模板
|
||||
* @return string
|
||||
*/
|
||||
public function getTree($myid, $itemtpl = "<option value=@id @selected @disabled>@spacer@name</option>", $selectedids = '', $disabledids = '', $itemprefix = '', $toptpl = '')
|
||||
{
|
||||
$ret = '';
|
||||
$number = 1;
|
||||
$childs = $this->getChild($myid);
|
||||
if ($childs) {
|
||||
$total = count($childs);
|
||||
foreach ($childs as $value) {
|
||||
$id = $value['id'];
|
||||
$j = $k = '';
|
||||
if ($number == $total) {
|
||||
$j .= $this->icon[2];
|
||||
$k = $itemprefix ? $this->nbsp : '';
|
||||
} else {
|
||||
$j .= $this->icon[1];
|
||||
$k = $itemprefix ? $this->icon[0] : '';
|
||||
}
|
||||
$spacer = $itemprefix ? $itemprefix . $j : '';
|
||||
$selected = $selectedids && in_array($id, (is_array($selectedids) ? $selectedids : explode(',', $selectedids))) ? 'selected' : '';
|
||||
$disabled = $disabledids && in_array($id, (is_array($disabledids) ? $disabledids : explode(',', $disabledids))) ? 'disabled' : '';
|
||||
$value = array_merge($value, array('selected' => $selected, 'disabled' => $disabled, 'spacer' => $spacer));
|
||||
$value = array_combine(array_map(function ($k) {
|
||||
return '@' . $k;
|
||||
}, array_keys($value)), $value);
|
||||
$nstr = strtr((($value["@{$this->pidname}"] == 0 || $this->getChild($id)) && $toptpl ? $toptpl : $itemtpl), $value);
|
||||
$ret .= $nstr;
|
||||
$ret .= $this->getTree($id, $itemtpl, $selectedids, $disabledids, $itemprefix . $k . $this->nbsp, $toptpl);
|
||||
$number++;
|
||||
}
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* 树型结构UL
|
||||
* @param int $myid 表示获得这个ID下的所有子级
|
||||
* @param string $itemtpl 条目模板 如:"<li value=@id @selected @disabled>@name @childlist</li>"
|
||||
* @param string $selectedids 选中的ID
|
||||
* @param string $disabledids 禁用的ID
|
||||
* @param string $wraptag 子列表包裹标签
|
||||
* @param string $wrapattr 子列表包裹属性
|
||||
* @return string
|
||||
*/
|
||||
public function getTreeUl($myid, $itemtpl, $selectedids = '', $disabledids = '', $wraptag = 'ul', $wrapattr = '')
|
||||
{
|
||||
$str = '';
|
||||
$childs = $this->getChild($myid);
|
||||
if ($childs) {
|
||||
foreach ($childs as $value) {
|
||||
$id = $value['id'];
|
||||
unset($value['child']);
|
||||
$selected = $selectedids && in_array($id, (is_array($selectedids) ? $selectedids : explode(',', $selectedids))) ? 'selected' : '';
|
||||
$disabled = $disabledids && in_array($id, (is_array($disabledids) ? $disabledids : explode(',', $disabledids))) ? 'disabled' : '';
|
||||
$value = array_merge($value, array('selected' => $selected, 'disabled' => $disabled));
|
||||
$value = array_combine(array_map(function ($k) {
|
||||
return '@' . $k;
|
||||
}, array_keys($value)), $value);
|
||||
$nstr = strtr($itemtpl, $value);
|
||||
$childdata = $this->getTreeUl($id, $itemtpl, $selectedids, $disabledids, $wraptag, $wrapattr);
|
||||
$childlist = $childdata ? "<{$wraptag} {$wrapattr}>" . $childdata . "</{$wraptag}>" : "";
|
||||
$str .= strtr($nstr, array('@childlist' => $childlist));
|
||||
}
|
||||
}
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* 菜单数据
|
||||
* @param int $myid
|
||||
* @param string $itemtpl
|
||||
* @param mixed $selectedids
|
||||
* @param mixed $disabledids
|
||||
* @param string $wraptag
|
||||
* @param string $wrapattr
|
||||
* @param int $deeplevel
|
||||
* @return string
|
||||
*/
|
||||
public function getTreeMenu($myid, $itemtpl, $selectedids = '', $disabledids = '', $wraptag = 'ul', $wrapattr = '', $deeplevel = 0)
|
||||
{
|
||||
$str = '';
|
||||
$childs = $this->getChild($myid);
|
||||
if ($childs) {
|
||||
foreach ($childs as $value) {
|
||||
$id = $value['id'];
|
||||
unset($value['child']);
|
||||
$selected = in_array($id, (is_array($selectedids) ? $selectedids : explode(',', $selectedids))) ? 'selected' : '';
|
||||
$disabled = in_array($id, (is_array($disabledids) ? $disabledids : explode(',', $disabledids))) ? 'disabled' : '';
|
||||
$value = array_merge($value, array('selected' => $selected, 'disabled' => $disabled));
|
||||
$value = array_combine(array_map(function ($k) {
|
||||
return '@' . $k;
|
||||
}, array_keys($value)), $value);
|
||||
$bakvalue = array_intersect_key($value, array_flip(['@url', '@caret', '@class']));
|
||||
$value = array_diff_key($value, $bakvalue);
|
||||
$nstr = strtr($itemtpl, $value);
|
||||
$value = array_merge($value, $bakvalue);
|
||||
$childdata = $this->getTreeMenu($id, $itemtpl, $selectedids, $disabledids, $wraptag, $wrapattr, $deeplevel + 1);
|
||||
$childlist = $childdata ? "<{$wraptag} {$wrapattr}>" . $childdata . "</{$wraptag}>" : "";
|
||||
$childlist = strtr($childlist, array('@class' => $childdata ? 'last' : ''));
|
||||
$value = array(
|
||||
'@childlist' => $childlist,
|
||||
'@url' => $childdata || !isset($value['@url']) ? "javascript:;" : $value['@url'],
|
||||
'@addtabs' => $childdata || !isset($value['@url']) ? "" : (stripos($value['@url'], "?") !== false ? "&" : "?") . "ref=addtabs",
|
||||
'@caret' => ($childdata && (!isset($value['@badge']) || !$value['@badge']) ? '<i class="fa fa-angle-left"></i>' : ''),
|
||||
'@badge' => $value['@badge'] ?? '',
|
||||
'@class' => ($selected ? ' active' : '') . ($disabled ? ' disabled' : '') . ($childdata ? ' treeview' . (config('fastadmin.show_submenu') ? ' treeview-open' : '') : ''),
|
||||
);
|
||||
$str .= strtr($nstr, $value);
|
||||
}
|
||||
}
|
||||
return $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* 特殊
|
||||
* @param integer $myid 要查询的ID
|
||||
* @param string $itemtpl1 第一种HTML代码方式
|
||||
* @param string $itemtpl2 第二种HTML代码方式
|
||||
* @param mixed $selectedids 默认选中
|
||||
* @param mixed $disabledids 禁用
|
||||
* @param string $itemprefix 前缀
|
||||
* @return string
|
||||
*/
|
||||
public function getTreeSpecial($myid, $itemtpl1, $itemtpl2, $selectedids = 0, $disabledids = 0, $itemprefix = '')
|
||||
{
|
||||
$ret = '';
|
||||
$number = 1;
|
||||
$childs = $this->getChild($myid);
|
||||
if ($childs) {
|
||||
$total = count($childs);
|
||||
foreach ($childs as $id => $value) {
|
||||
$j = $k = '';
|
||||
if ($number == $total) {
|
||||
$j .= $this->icon[2];
|
||||
$k = $itemprefix ? $this->nbsp : '';
|
||||
} else {
|
||||
$j .= $this->icon[1];
|
||||
$k = $itemprefix ? $this->icon[0] : '';
|
||||
}
|
||||
$spacer = $itemprefix ? $itemprefix . $j : '';
|
||||
$selected = $selectedids && in_array($id, (is_array($selectedids) ? $selectedids : explode(',', $selectedids))) ? 'selected' : '';
|
||||
$disabled = $disabledids && in_array($id, (is_array($disabledids) ? $disabledids : explode(',', $disabledids))) ? 'disabled' : '';
|
||||
$value = array_merge($value, array('selected' => $selected, 'disabled' => $disabled, 'spacer' => $spacer));
|
||||
$value = array_combine(array_map(function ($k) {
|
||||
return '@' . $k;
|
||||
}, array_keys($value)), $value);
|
||||
$nstr = strtr(!isset($value['@disabled']) || !$value['@disabled'] ? $itemtpl1 : $itemtpl2, $value);
|
||||
|
||||
$ret .= $nstr;
|
||||
$ret .= $this->getTreeSpecial($id, $itemtpl1, $itemtpl2, $selectedids, $disabledids, $itemprefix . $k . $this->nbsp);
|
||||
$number++;
|
||||
}
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* 获取树状数组
|
||||
* @param string $myid 要查询的ID
|
||||
* @param string $itemprefix 前缀
|
||||
* @return array
|
||||
*/
|
||||
public function getTreeArray($myid, $itemprefix = '')
|
||||
{
|
||||
$childs = $this->getChild($myid);
|
||||
$n = 0;
|
||||
$data = [];
|
||||
$number = 1;
|
||||
if ($childs) {
|
||||
$total = count($childs);
|
||||
foreach ($childs as $id => $value) {
|
||||
$j = $k = '';
|
||||
if ($number == $total) {
|
||||
$j .= $this->icon[2];
|
||||
$k = $itemprefix ? $this->nbsp : '';
|
||||
} else {
|
||||
$j .= $this->icon[1];
|
||||
$k = $itemprefix ? $this->icon[0] : '';
|
||||
}
|
||||
$spacer = $itemprefix ? $itemprefix . $j : '';
|
||||
$value['spacer'] = $spacer;
|
||||
$data[$n] = $value;
|
||||
$data[$n]['childlist'] = $this->getTreeArray($id, $itemprefix . $k . $this->nbsp);
|
||||
$n++;
|
||||
$number++;
|
||||
}
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将getTreeArray的结果返回为二维数组
|
||||
* @param array $data
|
||||
* @param string $field
|
||||
* @return array
|
||||
*/
|
||||
public function getTreeList($data = [], $field = 'name')
|
||||
{
|
||||
$arr = [];
|
||||
foreach ($data as $k => $v) {
|
||||
$childlist = $v['childlist'] ?? [];
|
||||
unset($v['childlist']);
|
||||
$v[$field] = $v['spacer'] . ' ' . $v[$field];
|
||||
$v['haschild'] = $childlist ? 1 : 0;
|
||||
if ($v['id']) {
|
||||
$arr[] = $v;
|
||||
}
|
||||
if ($childlist) {
|
||||
$arr = array_merge($arr, $this->getTreeList($childlist, $field));
|
||||
}
|
||||
}
|
||||
return $arr;
|
||||
}
|
||||
}
|
||||
79
extend/fast/Version.php
Normal file
79
extend/fast/Version.php
Normal file
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
namespace fast;
|
||||
|
||||
/**
|
||||
* 版本检测和对比
|
||||
*/
|
||||
class Version
|
||||
{
|
||||
|
||||
/**
|
||||
* 检测版本是否的版本要求的数据中
|
||||
*
|
||||
* @param string $version
|
||||
* @param array $data
|
||||
* @return bool
|
||||
*/
|
||||
public static function check($version, $data = [])
|
||||
{
|
||||
//版本号以.分隔
|
||||
$data = is_array($data) ? $data : [$data];
|
||||
if ($data) {
|
||||
if (in_array("*", $data) || in_array($version, $data)) {
|
||||
return true;
|
||||
}
|
||||
$ver = explode('.', $version);
|
||||
if ($ver) {
|
||||
$versize = count($ver);
|
||||
//验证允许的版本
|
||||
foreach ($data as $m) {
|
||||
$c = explode('.', $m);
|
||||
if (!$c || $versize != count($c)) {
|
||||
continue;
|
||||
}
|
||||
$i = 0;
|
||||
foreach ($c as $a => $k) {
|
||||
if (!self::compare($ver[$a], $k)) {
|
||||
continue 2;
|
||||
} else {
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
if ($i == $versize) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 比较两个版本号
|
||||
*
|
||||
* @param string $v1
|
||||
* @param string $v2
|
||||
* @return boolean
|
||||
*/
|
||||
public static function compare($v1, $v2)
|
||||
{
|
||||
if ($v2 == "*" || $v1 == $v2) {
|
||||
return true;
|
||||
} else {
|
||||
$values = [];
|
||||
$k = explode(',', $v2);
|
||||
foreach ($k as $v) {
|
||||
if (strpos($v, '-') !== false) {
|
||||
list($start, $stop) = explode('-', $v);
|
||||
for ($i = $start; $i <= $stop; $i++) {
|
||||
$values[] = $i;
|
||||
}
|
||||
} else {
|
||||
$values[] = $v;
|
||||
}
|
||||
}
|
||||
return in_array($v1, $values) ? true : false;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user