oneThink公共方法 Zane

1. 常用公共方法

   1 <?php
   2 // +----------------------------------------------------------------------
   3 // | OneThink [ WE CAN DO IT JUST THINK IT ]
   4 // +----------------------------------------------------------------------
   5 // | Copyright (c) 2013 http://www.onethink.cn All rights reserved.
   6 // +----------------------------------------------------------------------
   7 // | Author: 麦当苗儿 <zuojiazi@vip.qq.com> <http://www.zjzit.cn>
   8 // +----------------------------------------------------------------------
   9 
  10 // OneThink常量定义
  11 const ONETHINK_VERSION    = '1.1.141101';
  12 const ONETHINK_ADDON_PATH = './Addons/';
  13 
  14 /**
  15  * 系统公共库文件
  16  * 主要定义系统公共函数库
  17  */
  18 
  19 /**
  20  * 检测用户是否登录
  21  * @return integer 0-未登录,大于0-当前登录用户ID
  22  * @author 麦当苗儿 <zuojiazi@vip.qq.com>
  23  */
  24 function is_login(){
  25     $user = session('user_auth');
  26     if (empty($user)) {
  27         return 0;
  28     } else {
  29         return session('user_auth_sign') == data_auth_sign($user) ? $user['uid'] : 0;
  30     }
  31 }
  32 
  33 /**
  34  * 检测当前用户是否为管理员
  35  * @return boolean true-管理员,false-非管理员
  36  * @author 麦当苗儿 <zuojiazi@vip.qq.com>
  37  */
  38 function is_administrator($uid = null){
  39     $uid = is_null($uid) ? is_login() : $uid;
  40     return $uid && (intval($uid) === C('USER_ADMINISTRATOR'));
  41 }
  42 
  43 /**
  44  * 字符串转换为数组,主要用于把分隔符调整到第二个参数
  45  * @param  string $str  要分割的字符串
  46  * @param  string $glue 分割符
  47  * @return array
  48  * @author 麦当苗儿 <zuojiazi@vip.qq.com>
  49  */
  50 function str2arr($str, $glue = ','){
  51     return explode($glue, $str);
  52 }
  53 
  54 /**
  55  * 数组转换为字符串,主要用于把分隔符调整到第二个参数
  56  * @param  array  $arr  要连接的数组
  57  * @param  string $glue 分割符
  58  * @return string
  59  * @author 麦当苗儿 <zuojiazi@vip.qq.com>
  60  */
  61 function arr2str($arr, $glue = ','){
  62     return implode($glue, $arr);
  63 }
  64 
  65 /**
  66  * 字符串截取,支持中文和其他编码
  67  * @static
  68  * @access public
  69  * @param string $str 需要转换的字符串
  70  * @param string $start 开始位置
  71  * @param string $length 截取长度
  72  * @param string $charset 编码格式
  73  * @param string $suffix 截断显示字符
  74  * @return string
  75  */
  76 function msubstr($str, $start=0, $length, $charset="utf-8", $suffix=true) {
  77     if(function_exists("mb_substr"))
  78         $slice = mb_substr($str, $start, $length, $charset);
  79     elseif(function_exists('iconv_substr')) {
  80         $slice = iconv_substr($str,$start,$length,$charset);
  81         if(false === $slice) {
  82             $slice = '';
  83         }
  84     }else{
  85         $re['utf-8']   = "/[\x01-\x7f]|[\xc2-\xdf][\x80-\xbf]|[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xff][\x80-\xbf]{3}/";
  86         $re['gb2312'] = "/[\x01-\x7f]|[\xb0-\xf7][\xa0-\xfe]/";
  87         $re['gbk']    = "/[\x01-\x7f]|[\x81-\xfe][\x40-\xfe]/";
  88         $re['big5']   = "/[\x01-\x7f]|[\x81-\xfe]([\x40-\x7e]|\xa1-\xfe])/";
  89         preg_match_all($re[$charset], $str, $match);
  90         $slice = join("",array_slice($match[0], $start, $length));
  91     }
  92     return $suffix ? $slice.'...' : $slice;
  93 }
  94 
  95 /**
  96  * 系统加密方法
  97  * @param string $data 要加密的字符串
  98  * @param string $key  加密密钥
  99  * @param int $expire  过期时间 单位 秒
 100  * @return string
 101  * @author 麦当苗儿 <zuojiazi@vip.qq.com>
 102  */
 103 function think_encrypt($data, $key = '', $expire = 0) {
 104     $key  = md5(empty($key) ? C('DATA_AUTH_KEY') : $key);
 105     $data = base64_encode($data);
 106     $x    = 0;
 107     $len  = strlen($data);
 108     $l    = strlen($key);
 109     $char = '';
 110 
 111     for ($i = 0; $i < $len; $i++) {
 112         if ($x == $l) $x = 0;
 113         $char .= substr($key, $x, 1);
 114         $x++;
 115     }
 116 
 117     $str = sprintf('%010d', $expire ? $expire + time():0);
 118 
 119     for ($i = 0; $i < $len; $i++) {
 120         $str .= chr(ord(substr($data, $i, 1)) + (ord(substr($char, $i, 1)))%256);
 121     }
 122     return str_replace(array('+','/','='),array('-','_',''),base64_encode($str));
 123 }
 124 
 125 /**
 126  * 系统解密方法
 127  * @param  string $data 要解密的字符串 (必须是think_encrypt方法加密的字符串)
 128  * @param  string $key  加密密钥
 129  * @return string
 130  * @author 麦当苗儿 <zuojiazi@vip.qq.com>
 131  */
 132 function think_decrypt($data, $key = ''){
 133     $key    = md5(empty($key) ? C('DATA_AUTH_KEY') : $key);
 134     $data   = str_replace(array('-','_'),array('+','/'),$data);
 135     $mod4   = strlen($data) % 4;
 136     if ($mod4) {
 137        $data .= substr('====', $mod4);
 138     }
 139     $data   = base64_decode($data);
 140     $expire = substr($data,0,10);
 141     $data   = substr($data,10);
 142 
 143     if($expire > 0 && $expire < time()) {
 144         return '';
 145     }
 146     $x      = 0;
 147     $len    = strlen($data);
 148     $l      = strlen($key);
 149     $char   = $str = '';
 150 
 151     for ($i = 0; $i < $len; $i++) {
 152         if ($x == $l) $x = 0;
 153         $char .= substr($key, $x, 1);
 154         $x++;
 155     }
 156 
 157     for ($i = 0; $i < $len; $i++) {
 158         if (ord(substr($data, $i, 1))<ord(substr($char, $i, 1))) {
 159             $str .= chr((ord(substr($data, $i, 1)) + 256) - ord(substr($char, $i, 1)));
 160         }else{
 161             $str .= chr(ord(substr($data, $i, 1)) - ord(substr($char, $i, 1)));
 162         }
 163     }
 164     return base64_decode($str);
 165 }
 166 
 167 /**
 168  * 数据签名认证
 169  * @param  array  $data 被认证的数据
 170  * @return string       签名
 171  * @author 麦当苗儿 <zuojiazi@vip.qq.com>
 172  */
 173 function data_auth_sign($data) {
 174     //数据类型检测
 175     if(!is_array($data)){
 176         $data = (array)$data;
 177     }
 178     ksort($data); //排序
 179     $code = http_build_query($data); //url编码并生成query字符串
 180     $sign = sha1($code); //生成签名
 181     return $sign;
 182 }
 183 
 184 /**
 185 * 对查询结果集进行排序
 186 * @access public
 187 * @param array $list 查询结果
 188 * @param string $field 排序的字段名
 189 * @param array $sortby 排序类型
 190 * asc正向排序 desc逆向排序 nat自然排序
 191 * @return array
 192 */
 193 function list_sort_by($list,$field, $sortby='asc') {
 194    if(is_array($list)){
 195        $refer = $resultSet = array();
 196        foreach ($list as $i => $data)
 197            $refer[$i] = &$data[$field];
 198        switch ($sortby) {
 199            case 'asc': // 正向排序
 200                 asort($refer);
 201                 break;
 202            case 'desc':// 逆向排序
 203                 arsort($refer);
 204                 break;
 205            case 'nat': // 自然排序
 206                 natcasesort($refer);
 207                 break;
 208        }
 209        foreach ( $refer as $key=> $val)
 210            $resultSet[] = &$list[$key];
 211        return $resultSet;
 212    }
 213    return false;
 214 }
 215 
 216 /**
 217  * 把返回的数据集转换成Tree
 218  * @param array $list 要转换的数据集
 219  * @param string $pid parent标记字段
 220  * @param string $level level标记字段
 221  * @return array
 222  * @author 麦当苗儿 <zuojiazi@vip.qq.com>
 223  */
 224 function list_to_tree($list, $pk='id', $pid = 'pid', $child = '_child', $root = 0) {
 225     // 创建Tree
 226     $tree = array();
 227     if(is_array($list)) {
 228         // 创建基于主键的数组引用
 229         $refer = array();
 230         foreach ($list as $key => $data) {
 231             $refer[$data[$pk]] =& $list[$key];
 232         }
 233         foreach ($list as $key => $data) {
 234             // 判断是否存在parent
 235             $parentId =  $data[$pid];
 236             if ($root == $parentId) {
 237                 $tree[] =& $list[$key];
 238             }else{
 239                 if (isset($refer[$parentId])) {
 240                     $parent =& $refer[$parentId];
 241                     $parent[$child][] =& $list[$key];
 242                 }
 243             }
 244         }
 245     }
 246     return $tree;
 247 }
 248 
 249 /**
 250  * 将list_to_tree的树还原成列表
 251  * @param  array $tree  原来的树
 252  * @param  string $child 孩子节点的键
 253  * @param  string $order 排序显示的键,一般是主键 升序排列
 254  * @param  array  $list  过渡用的中间数组,
 255  * @return array        返回排过序的列表数组
 256  * @author yangweijie <yangweijiester@gmail.com>
 257  */
 258 function tree_to_list($tree, $child = '_child', $order='id', &$list = array()){
 259     if(is_array($tree)) {
 260         foreach ($tree as $key => $value) {
 261             $reffer = $value;
 262             if(isset($reffer[$child])){
 263                 unset($reffer[$child]);
 264                 tree_to_list($value[$child], $child, $order, $list);
 265             }
 266             $list[] = $reffer;
 267         }
 268         $list = list_sort_by($list, $order, $sortby='asc');
 269     }
 270     return $list;
 271 }
 272 
 273 /**
 274  * 格式化字节大小
 275  * @param  number $size      字节数
 276  * @param  string $delimiter 数字和单位分隔符
 277  * @return string            格式化后的带单位的大小
 278  * @author 麦当苗儿 <zuojiazi@vip.qq.com>
 279  */
 280 function format_bytes($size, $delimiter = '') {
 281     $units = array('B', 'KB', 'MB', 'GB', 'TB', 'PB');
 282     for ($i = 0; $size >= 1024 && $i < 5; $i++) $size /= 1024;
 283     return round($size, 2) . $delimiter . $units[$i];
 284 }
 285 
 286 /**
 287  * 设置跳转页面URL
 288  * 使用函数再次封装,方便以后选择不同的存储方式(目前使用cookie存储)
 289  * @author 麦当苗儿 <zuojiazi@vip.qq.com>
 290  */
 291 function set_redirect_url($url){
 292     cookie('redirect_url', $url);
 293 }
 294 
 295 /**
 296  * 获取跳转页面URL
 297  * @return string 跳转页URL
 298  * @author 麦当苗儿 <zuojiazi@vip.qq.com>
 299  */
 300 function get_redirect_url(){
 301     $url = cookie('redirect_url');
 302     return empty($url) ? __APP__ : $url;
 303 }
 304 
 305 /**
 306  * 处理插件钩子
 307  * @param string $hook   钩子名称
 308  * @param mixed $params 传入参数
 309  * @return void
 310  */
 311 function hook($hook,$params=array()){
 312     \Think\Hook::listen($hook,$params);
 313 }
 314 
 315 /**
 316  * 获取插件类的类名
 317  * @param strng $name 插件名
 318  */
 319 function get_addon_class($name){
 320     $class = "Addons\\{$name}\\{$name}Addon";
 321     return $class;
 322 }
 323 
 324 /**
 325  * 获取插件类的配置文件数组
 326  * @param string $name 插件名
 327  */
 328 function get_addon_config($name){
 329     $class = get_addon_class($name);
 330     if(class_exists($class)) {
 331         $addon = new $class();
 332         return $addon->getConfig();
 333     }else {
 334         return array();
 335     }
 336 }
 337 
 338 /**
 339  * 插件显示内容里生成访问插件的url
 340  * @param string $url url
 341  * @param array $param 参数
 342  * @author 麦当苗儿 <zuojiazi@vip.qq.com>
 343  */
 344 function addons_url($url, $param = array()){
 345     $url        = parse_url($url);
 346     $case       = C('URL_CASE_INSENSITIVE');
 347     $addons     = $case ? parse_name($url['scheme']) : $url['scheme'];
 348     $controller = $case ? parse_name($url['host']) : $url['host'];
 349     $action     = trim($case ? strtolower($url['path']) : $url['path'], '/');
 350 
 351     /* 解析URL带的参数 */
 352     if(isset($url['query'])){
 353         parse_str($url['query'], $query);
 354         $param = array_merge($query, $param);
 355     }
 356 
 357     /* 基础参数 */
 358     $params = array(
 359         '_addons'     => $addons,
 360         '_controller' => $controller,
 361         '_action'     => $action,
 362     );
 363     $params = array_merge($params, $param); //添加额外参数
 364 
 365     return U('Addons/execute', $params);
 366 }
 367 
 368 /**
 369  * 时间戳格式化
 370  * @param int $time
 371  * @return string 完整的时间显示
 372  * @author huajie <banhuajie@163.com>
 373  */
 374 function time_format($time = NULL,$format='Y-m-d H:i'){
 375     $time = $time === NULL ? NOW_TIME : intval($time);
 376     return date($format, $time);
 377 }
 378 
 379 /**
 380  * 根据用户ID获取用户名
 381  * @param  integer $uid 用户ID
 382  * @return string       用户名
 383  */
 384 function get_username($uid = 0){
 385     static $list;
 386     if(!($uid && is_numeric($uid))){ //获取当前登录用户名
 387         return session('user_auth.username');
 388     }
 389 
 390     /* 获取缓存数据 */
 391     if(empty($list)){
 392         $list = S('sys_active_user_list');
 393     }
 394 
 395     /* 查找用户信息 */
 396     $key = "u{$uid}";
 397     if(isset($list[$key])){ //已缓存,直接使用
 398         $name = $list[$key];
 399     } else { //调用接口获取用户信息
 400         $User = new User\Api\UserApi();
 401         $info = $User->info($uid);
 402         if($info && isset($info[1])){
 403             $name = $list[$key] = $info[1];
 404             /* 缓存用户 */
 405             $count = count($list);
 406             $max   = C('USER_MAX_CACHE');
 407             while ($count-- > $max) {
 408                 array_shift($list);
 409             }
 410             S('sys_active_user_list', $list);
 411         } else {
 412             $name = '';
 413         }
 414     }
 415     return $name;
 416 }
 417 
 418 /**
 419  * 根据用户ID获取用户昵称
 420  * @param  integer $uid 用户ID
 421  * @return string       用户昵称
 422  */
 423 function get_nickname($uid = 0){
 424     static $list;
 425     if(!($uid && is_numeric($uid))){ //获取当前登录用户名
 426         return session('user_auth.username');
 427     }
 428 
 429     /* 获取缓存数据 */
 430     if(empty($list)){
 431         $list = S('sys_user_nickname_list');
 432     }
 433 
 434     /* 查找用户信息 */
 435     $key = "u{$uid}";
 436     if(isset($list[$key])){ //已缓存,直接使用
 437         $name = $list[$key];
 438     } else { //调用接口获取用户信息
 439         $info = M('Member')->field('nickname')->find($uid);
 440         if($info !== false && $info['nickname'] ){
 441             $nickname = $info['nickname'];
 442             $name = $list[$key] = $nickname;
 443             /* 缓存用户 */
 444             $count = count($list);
 445             $max   = C('USER_MAX_CACHE');
 446             while ($count-- > $max) {
 447                 array_shift($list);
 448             }
 449             S('sys_user_nickname_list', $list);
 450         } else {
 451             $name = '';
 452         }
 453     }
 454     return $name;
 455 }
 456 
 457 /**
 458  * 获取分类信息并缓存分类
 459  * @param  integer $id    分类ID
 460  * @param  string  $field 要获取的字段名
 461  * @return string         分类信息
 462  */
 463 function get_category($id, $field = null){
 464     static $list;
 465 
 466     /* 非法分类ID */
 467     if(empty($id) || !is_numeric($id)){
 468         return '';
 469     }
 470 
 471     /* 读取缓存数据 */
 472     if(empty($list)){
 473         $list = S('sys_category_list');
 474     }
 475 
 476     /* 获取分类名称 */
 477     if(!isset($list[$id])){
 478         $cate = M('Category')->find($id);
 479         if(!$cate || 1 != $cate['status']){ //不存在分类,或分类被禁用
 480             return '';
 481         }
 482         $list[$id] = $cate;
 483         S('sys_category_list', $list); //更新缓存
 484     }
 485     return is_null($field) ? $list[$id] : $list[$id][$field];
 486 }
 487 
 488 /* 根据ID获取分类标识 */
 489 function get_category_name($id){
 490     return get_category($id, 'name');
 491 }
 492 
 493 /* 根据ID获取分类名称 */
 494 function get_category_title($id){
 495     return get_category($id, 'title');
 496 }
 497 
 498 /**
 499  * 获取顶级模型信息
 500  */
 501 function get_top_model($model_id=null){
 502     $map   = array('status' => 1, 'extend' => 0);
 503     if(!is_null($model_id)){
 504         $map['id']  =   array('neq',$model_id);
 505     }
 506     $model = M('Model')->where($map)->field(true)->select();
 507     foreach ($model as $value) {
 508         $list[$value['id']] = $value;
 509     }
 510     return $list;
 511 }
 512 
 513 /**
 514  * 获取文档模型信息
 515  * @param  integer $id    模型ID
 516  * @param  string  $field 模型字段
 517  * @return array
 518  */
 519 function get_document_model($id = null, $field = null){
 520     static $list;
 521 
 522     /* 非法分类ID */
 523     if(!(is_numeric($id) || is_null($id))){
 524         return '';
 525     }
 526 
 527     /* 读取缓存数据 */
 528     if(empty($list)){
 529         $list = S('DOCUMENT_MODEL_LIST');
 530     }
 531 
 532     /* 获取模型名称 */
 533     if(empty($list)){
 534         $map   = array('status' => 1, 'extend' => 1);
 535         $model = M('Model')->where($map)->field(true)->select();
 536         foreach ($model as $value) {
 537             $list[$value['id']] = $value;
 538         }
 539         S('DOCUMENT_MODEL_LIST', $list); //更新缓存
 540     }
 541 
 542     /* 根据条件返回数据 */
 543     if(is_null($id)){
 544         return $list;
 545     } elseif(is_null($field)){
 546         return $list[$id];
 547     } else {
 548         return $list[$id][$field];
 549     }
 550 }
 551 
 552 /**
 553  * 解析UBB数据
 554  * @param string $data UBB字符串
 555  * @return string 解析为HTML的数据
 556  * @author 麦当苗儿 <zuojiazi@vip.qq.com>
 557  */
 558 function ubb($data){
 559     //TODO: 待完善,目前返回原始数据
 560     return $data;
 561 }
 562 
 563 /**
 564  * 记录行为日志,并执行该行为的规则
 565  * @param string $action 行为标识
 566  * @param string $model 触发行为的模型名
 567  * @param int $record_id 触发行为的记录id
 568  * @param int $user_id 执行行为的用户id
 569  * @return boolean
 570  * @author huajie <banhuajie@163.com>
 571  */
 572 function action_log($action = null, $model = null, $record_id = null, $user_id = null){
 573 
 574     //参数检查
 575     if(empty($action) || empty($model) || empty($record_id)){
 576         return '参数不能为空';
 577     }
 578     if(empty($user_id)){
 579         $user_id = is_login();
 580     }
 581 
 582     //查询行为,判断是否执行
 583     $action_info = M('Action')->getByName($action);
 584     if($action_info['status'] != 1){
 585         return '该行为被禁用或删除';
 586     }
 587 
 588     //插入行为日志
 589     $data['action_id']      =   $action_info['id'];
 590     $data['user_id']        =   $user_id;
 591     $data['action_ip']      =   ip2long(get_client_ip());
 592     $data['model']          =   $model;
 593     $data['record_id']      =   $record_id;
 594     $data['create_time']    =   NOW_TIME;
 595 
 596     //解析日志规则,生成日志备注
 597     if(!empty($action_info['log'])){
 598         if(preg_match_all('/\[(\S+?)\]/', $action_info['log'], $match)){
 599             $log['user']    =   $user_id;
 600             $log['record']  =   $record_id;
 601             $log['model']   =   $model;
 602             $log['time']    =   NOW_TIME;
 603             $log['data']    =   array('user'=>$user_id,'model'=>$model,'record'=>$record_id,'time'=>NOW_TIME);
 604             foreach ($match[1] as $value){
 605                 $param = explode('|', $value);
 606                 if(isset($param[1])){
 607                     $replace[] = call_user_func($param[1],$log[$param[0]]);
 608                 }else{
 609                     $replace[] = $log[$param[0]];
 610                 }
 611             }
 612             $data['remark'] =   str_replace($match[0], $replace, $action_info['log']);
 613         }else{
 614             $data['remark'] =   $action_info['log'];
 615         }
 616     }else{
 617         //未定义日志规则,记录操作url
 618         $data['remark']     =   '操作url:'.$_SERVER['REQUEST_URI'];
 619     }
 620 
 621     M('ActionLog')->add($data);
 622 
 623     if(!empty($action_info['rule'])){
 624         //解析行为
 625         $rules = parse_action($action, $user_id);
 626 
 627         //执行行为
 628         $res = execute_action($rules, $action_info['id'], $user_id);
 629     }
 630 }
 631 
 632 /**
 633  * 解析行为规则
 634  * 规则定义  table:$table|field:$field|condition:$condition|rule:$rule[|cycle:$cycle|max:$max][;......]
 635  * 规则字段解释:table->要操作的数据表,不需要加表前缀;
 636  *              field->要操作的字段;
 637  *              condition->操作的条件,目前支持字符串,默认变量{$self}为执行行为的用户
 638  *              rule->对字段进行的具体操作,目前支持四则混合运算,如:1+score*2/2-3
 639  *              cycle->执行周期,单位(小时),表示$cycle小时内最多执行$max次
 640  *              max->单个周期内的最大执行次数($cycle和$max必须同时定义,否则无效)
 641  * 单个行为后可加 ; 连接其他规则
 642  * @param string $action 行为id或者name
 643  * @param int $self 替换规则里的变量为执行用户的id
 644  * @return boolean|array: false解析出错 , 成功返回规则数组
 645  * @author huajie <banhuajie@163.com>
 646  */
 647 function parse_action($action = null, $self){
 648     if(empty($action)){
 649         return false;
 650     }
 651 
 652     //参数支持id或者name
 653     if(is_numeric($action)){
 654         $map = array('id'=>$action);
 655     }else{
 656         $map = array('name'=>$action);
 657     }
 658 
 659     //查询行为信息
 660     $info = M('Action')->where($map)->find();
 661     if(!$info || $info['status'] != 1){
 662         return false;
 663     }
 664 
 665     //解析规则:table:$table|field:$field|condition:$condition|rule:$rule[|cycle:$cycle|max:$max][;......]
 666     $rules = $info['rule'];
 667     $rules = str_replace('{$self}', $self, $rules);
 668     $rules = explode(';', $rules);
 669     $return = array();
 670     foreach ($rules as $key=>&$rule){
 671         $rule = explode('|', $rule);
 672         foreach ($rule as $k=>$fields){
 673             $field = empty($fields) ? array() : explode(':', $fields);
 674             if(!empty($field)){
 675                 $return[$key][$field[0]] = $field[1];
 676             }
 677         }
 678         //cycle(检查周期)和max(周期内最大执行次数)必须同时存在,否则去掉这两个条件
 679         if(!array_key_exists('cycle', $return[$key]) || !array_key_exists('max', $return[$key])){
 680             unset($return[$key]['cycle'],$return[$key]['max']);
 681         }
 682     }
 683 
 684     return $return;
 685 }
 686 
 687 /**
 688  * 执行行为
 689  * @param array $rules 解析后的规则数组
 690  * @param int $action_id 行为id
 691  * @param array $user_id 执行的用户id
 692  * @return boolean false 失败 , true 成功
 693  * @author huajie <banhuajie@163.com>
 694  */
 695 function execute_action($rules = false, $action_id = null, $user_id = null){
 696     if(!$rules || empty($action_id) || empty($user_id)){
 697         return false;
 698     }
 699 
 700     $return = true;
 701     foreach ($rules as $rule){
 702 
 703         //检查执行周期
 704         $map = array('action_id'=>$action_id, 'user_id'=>$user_id);
 705         $map['create_time'] = array('gt', NOW_TIME - intval($rule['cycle']) * 3600);
 706         $exec_count = M('ActionLog')->where($map)->count();
 707         if($exec_count > $rule['max']){
 708             continue;
 709         }
 710 
 711         //执行数据库操作
 712         $Model = M(ucfirst($rule['table']));
 713         $field = $rule['field'];
 714         $res = $Model->where($rule['condition'])->setField($field, array('exp', $rule['rule']));
 715 
 716         if(!$res){
 717             $return = false;
 718         }
 719     }
 720     return $return;
 721 }
 722 
 723 //基于数组创建目录和文件
 724 function create_dir_or_files($files){
 725     foreach ($files as $key => $value) {
 726         if(substr($value, -1) == '/'){
 727             mkdir($value);
 728         }else{
 729             @file_put_contents($value, '');
 730         }
 731     }
 732 }
 733 
 734 if(!function_exists('array_column')){
 735     function array_column(array $input, $columnKey, $indexKey = null) {
 736         $result = array();
 737         if (null === $indexKey) {
 738             if (null === $columnKey) {
 739                 $result = array_values($input);
 740             } else {
 741                 foreach ($input as $row) {
 742                     $result[] = $row[$columnKey];
 743                 }
 744             }
 745         } else {
 746             if (null === $columnKey) {
 747                 foreach ($input as $row) {
 748                     $result[$row[$indexKey]] = $row;
 749                 }
 750             } else {
 751                 foreach ($input as $row) {
 752                     $result[$row[$indexKey]] = $row[$columnKey];
 753                 }
 754             }
 755         }
 756         return $result;
 757     }
 758 }
 759 
 760 /**
 761  * 获取表名(不含表前缀)
 762  * @param string $model_id
 763  * @return string 表名
 764  * @author huajie <banhuajie@163.com>
 765  */
 766 function get_table_name($model_id = null){
 767     if(empty($model_id)){
 768         return false;
 769     }
 770     $Model = M('Model');
 771     $name = '';
 772     $info = $Model->getById($model_id);
 773     if($info['extend'] != 0){
 774         $name = $Model->getFieldById($info['extend'], 'name').'_';
 775     }
 776     $name .= $info['name'];
 777     return $name;
 778 }
 779 
 780 /**
 781  * 获取属性信息并缓存
 782  * @param  integer $id    属性ID
 783  * @param  string  $field 要获取的字段名
 784  * @return string         属性信息
 785  */
 786 function get_model_attribute($model_id, $group = true,$fields=true){
 787     static $list;
 788 
 789     /* 非法ID */
 790     if(empty($model_id) || !is_numeric($model_id)){
 791         return '';
 792     }
 793 
 794     /* 获取属性 */
 795     if(!isset($list[$model_id])){
 796         $map = array('model_id'=>$model_id);
 797         $extend = M('Model')->getFieldById($model_id,'extend');
 798 
 799         if($extend){
 800             $map = array('model_id'=> array("in", array($model_id, $extend)));
 801         }
 802         $info = M('Attribute')->where($map)->field($fields)->select();
 803         $list[$model_id] = $info;
 804     }
 805 
 806     $attr = array();
 807     if($group){
 808         foreach ($list[$model_id] as $value) {
 809             $attr[$value['id']] = $value;
 810         }
 811         $model     = M("Model")->field("field_sort,attribute_list,attribute_alias")->find($model_id);
 812         $attribute = explode(",", $model['attribute_list']);
 813         if (empty($model['field_sort'])) { //未排序
 814             $group = array(1 => array_merge($attr));
 815         } else {
 816             $group = json_decode($model['field_sort'], true);
 817 
 818             $keys = array_keys($group);
 819             foreach ($group as &$value) {
 820                 foreach ($value as $key => $val) {
 821                     $value[$key] = $attr[$val];
 822                     unset($attr[$val]);
 823                 }
 824             }
 825 
 826             if (!empty($attr)) {
 827                 foreach ($attr as $key => $val) {
 828                     if (!in_array($val['id'], $attribute)) {
 829                         unset($attr[$key]);
 830                     }
 831                 }
 832                 $group[$keys[0]] = array_merge($group[$keys[0]], $attr);
 833             }
 834         }
 835         if (!empty($model['attribute_alias'])) {
 836             $alias  = preg_split('/[;\r\n]+/s', $model['attribute_alias']);
 837             $fields = array();
 838             foreach ($alias as &$value) {
 839                 $val             = explode(':', $value);
 840                 $fields[$val[0]] = $val[1];
 841             }
 842             foreach ($group as &$value) {
 843                 foreach ($value as $key => $val) {
 844                     if (!empty($fields[$val['name']])) {
 845                         $value[$key]['title'] = $fields[$val['name']];
 846                     }
 847                 }
 848             }
 849         }
 850         $attr = $group;
 851     }else{
 852         foreach ($list[$model_id] as $value) {
 853             $attr[$value['name']] = $value;
 854         }
 855     }
 856     return $attr;
 857 }
 858 
 859 /**
 860  * 调用系统的API接口方法(静态方法)
 861  * api('User/getName','id=5'); 调用公共模块的User接口的getName方法
 862  * api('Admin/User/getName','id=5');  调用Admin模块的User接口
 863  * @param  string  $name 格式 [模块名]/接口名/方法名
 864  * @param  array|string  $vars 参数
 865  */
 866 function api($name,$vars=array()){
 867     $array     = explode('/',$name);
 868     $method    = array_pop($array);
 869     $classname = array_pop($array);
 870     $module    = $array? array_pop($array) : 'Common';
 871     $callback  = $module.'\\Api\\'.$classname.'Api::'.$method;
 872     if(is_string($vars)) {
 873         parse_str($vars,$vars);
 874     }
 875     return call_user_func_array($callback,$vars);
 876 }
 877 
 878 /**
 879  * 根据条件字段获取指定表的数据
 880  * @param mixed $value 条件,可用常量或者数组
 881  * @param string $condition 条件字段
 882  * @param string $field 需要返回的字段,不传则返回整个数据
 883  * @param string $table 需要查询的表
 884  * @author huajie <banhuajie@163.com>
 885  */
 886 function get_table_field($value = null, $condition = 'id', $field = null, $table = null){
 887     if(empty($value) || empty($table)){
 888         return false;
 889     }
 890 
 891     //拼接参数
 892     $map[$condition] = $value;
 893     $info = M(ucfirst($table))->where($map);
 894     if(empty($field)){
 895         $info = $info->field(true)->find();
 896     }else{
 897         $info = $info->getField($field);
 898     }
 899     return $info;
 900 }
 901 
 902 /**
 903  * 获取链接信息
 904  * @param int $link_id
 905  * @param string $field
 906  * @return 完整的链接信息或者某一字段
 907  * @author huajie <banhuajie@163.com>
 908  */
 909 function get_link($link_id = null, $field = 'url'){
 910     $link = '';
 911     if(empty($link_id)){
 912         return $link;
 913     }
 914     $link = M('Url')->getById($link_id);
 915     if(empty($field)){
 916         return $link;
 917     }else{
 918         return $link[$field];
 919     }
 920 }
 921 
 922 /**
 923  * 获取文档封面图片
 924  * @param int $cover_id
 925  * @param string $field
 926  * @return 完整的数据  或者  指定的$field字段值
 927  * @author huajie <banhuajie@163.com>
 928  */
 929 function get_cover($cover_id, $field = null){
 930     if(empty($cover_id)){
 931         return false;
 932     }
 933     $picture = M('Picture')->where(array('status'=>1))->getById($cover_id);
 934     if($field == 'path'){
 935         if(!empty($picture['url'])){
 936             $picture['path'] = $picture['url'];
 937         }else{
 938             $picture['path'] = __ROOT__.$picture['path'];
 939         }
 940     }
 941     return empty($field) ? $picture : $picture[$field];
 942 }
 943 
 944 /**
 945  * 检查$pos(推荐位的值)是否包含指定推荐位$contain
 946  * @param number $pos 推荐位的值
 947  * @param number $contain 指定推荐位
 948  * @return boolean true 包含 , false 不包含
 949  * @author huajie <banhuajie@163.com>
 950  */
 951 function check_document_position($pos = 0, $contain = 0){
 952     if(empty($pos) || empty($contain)){
 953         return false;
 954     }
 955 
 956     //将两个参数进行按位与运算,不为0则表示$contain属于$pos
 957     $res = $pos & $contain;
 958     if($res !== 0){
 959         return true;
 960     }else{
 961         return false;
 962     }
 963 }
 964 
 965 /**
 966  * 获取数据的所有子孙数据的id值
 967  * @author 朱亚杰 <xcoolcc@gmail.com>
 968  */
 969 
 970 function get_stemma($pids,Model &$model, $field='id'){
 971     $collection = array();
 972 
 973     //非空判断
 974     if(empty($pids)){
 975         return $collection;
 976     }
 977 
 978     if( is_array($pids) ){
 979         $pids = trim(implode(',',$pids),',');
 980     }
 981     $result     = $model->field($field)->where(array('pid'=>array('IN',(string)$pids)))->select();
 982     $child_ids  = array_column ((array)$result,'id');
 983 
 984     while( !empty($child_ids) ){
 985         $collection = array_merge($collection,$result);
 986         $result     = $model->field($field)->where( array( 'pid'=>array( 'IN', $child_ids ) ) )->select();
 987         $child_ids  = array_column((array)$result,'id');
 988     }
 989     return $collection;
 990 }
 991 
 992 /**
 993  * 验证分类是否允许发布内容
 994  * @param  integer $id 分类ID
 995  * @return boolean     true-允许发布内容,false-不允许发布内容
 996  */
 997 function check_category($id){
 998     if (is_array($id)) {
 999         $id['type']    =    !empty($id['type'])?$id['type']:2;
1000         $type = get_category($id['category_id'], 'type');
1001         $type = explode(",", $type);
1002         return in_array($id['type'], $type);
1003     } else {
1004         $publish = get_category($id, 'allow_publish');
1005         return $publish ? true : false;
1006     }
1007 }
1008 
1009 /**
1010  * 检测分类是否绑定了指定模型
1011  * @param  array $info 模型ID和分类ID数组
1012  * @return boolean     true-绑定了模型,false-未绑定模型
1013  */
1014 function check_category_model($info){
1015     $cate   =   get_category($info['category_id']);
1016     $array  =   explode(',', $info['pid'] ? $cate['model_sub'] : $cate['model']);
1017     return in_array($info['model_id'], $array);
1018 }

2. 安装公共方法

  1 <?php
  2 // +----------------------------------------------------------------------
  3 // | OneThink [ WE CAN DO IT JUST THINK IT ]
  4 // +----------------------------------------------------------------------
  5 // | Copyright (c) 2013 http://www.onethink.cn All rights reserved.
  6 // +----------------------------------------------------------------------
  7 // | Author: 麦当苗儿 <zuojiazi@vip.qq.com> <http://www.zjzit.cn>
  8 // +----------------------------------------------------------------------
  9 
 10 // 检测环境是否支持可写
 11 define('IS_WRITE',APP_MODE !== 'sae');
 12 
 13 /**
 14  * 系统环境检测
 15  * @return array 系统环境数据
 16  */
 17 function check_env(){
 18     $items = array(
 19         'os'      => array('操作系统', '不限制', '类Unix', PHP_OS, 'success'),
 20         'php'     => array('PHP版本', '5.3', '5.3+', PHP_VERSION, 'success'),
 21         'upload'  => array('附件上传', '不限制', '2M+', '未知', 'success'),
 22         'gd'      => array('GD库', '2.0', '2.0+', '未知', 'success'),
 23         'disk'    => array('磁盘空间', '5M', '不限制', '未知', 'success'),
 24     );
 25 
 26     //PHP环境检测
 27     if($items['php'][3] < $items['php'][1]){
 28         $items['php'][4] = 'error';
 29         session('error', true);
 30     }
 31 
 32     //附件上传检测
 33     if(@ini_get('file_uploads'))
 34         $items['upload'][3] = ini_get('upload_max_filesize');
 35 
 36     //GD库检测
 37     $tmp = function_exists('gd_info') ? gd_info() : array();
 38     if(empty($tmp['GD Version'])){
 39         $items['gd'][3] = '未安装';
 40         $items['gd'][4] = 'error';
 41         session('error', true);
 42     } else {
 43         $items['gd'][3] = $tmp['GD Version'];
 44     }
 45     unset($tmp);
 46 
 47     //磁盘空间检测
 48     if(function_exists('disk_free_space')) {
 49         $items['disk'][3] = floor(disk_free_space(INSTALL_APP_PATH) / (1024*1024)).'M';
 50     }
 51 
 52     return $items;
 53 }
 54 
 55 /**
 56  * 目录,文件读写检测
 57  * @return array 检测数据
 58  */
 59 function check_dirfile(){
 60     $items = array(
 61         array('dir',  '可写', 'success', './Uploads/Download'),
 62         array('dir',  '可写', 'success', './Uploads/Picture'),
 63         array('dir',  '可写', 'success', './Uploads/Editor'),
 64         array('dir',  '可写', 'success', './Runtime'),
 65         array('dir',  '可写', 'success', './Data'),
 66         array('dir', '可写', 'success', './Application/User/Conf'),
 67         array('file', '可写', 'success', './Application/Common/Conf'),
 68 
 69     );
 70 
 71     foreach ($items as &$val) {
 72         $item =    INSTALL_APP_PATH . $val[3];
 73         if('dir' == $val[0]){
 74             if(!is_writable($item)) {
 75                 if(is_dir($items)) {
 76                     $val[1] = '可读';
 77                     $val[2] = 'error';
 78                     session('error', true);
 79                 } else {
 80                     $val[1] = '不存在';
 81                     $val[2] = 'error';
 82                     session('error', true);
 83                 }
 84             }
 85         } else {
 86             if(file_exists($item)) {
 87                 if(!is_writable($item)) {
 88                     $val[1] = '不可写';
 89                     $val[2] = 'error';
 90                     session('error', true);
 91                 }
 92             } else {
 93                 if(!is_writable(dirname($item))) {
 94                     $val[1] = '不存在';
 95                     $val[2] = 'error';
 96                     session('error', true);
 97                 }
 98             }
 99         }
100     }
101 
102     return $items;
103 }
104 
105 /**
106  * 函数检测
107  * @return array 检测数据
108  */
109 function check_func(){
110     $items = array(
111         array('pdo','支持','success','类'),
112         array('pdo_mysql','支持','success','模块'),
113         array('file_get_contents', '支持', 'success','函数'),
114         array('mb_strlen',           '支持', 'success','函数'),
115     );
116 
117     foreach ($items as &$val) {
118         if(('类'==$val[3] && !class_exists($val[0]))
119             || ('模块'==$val[3] && !extension_loaded($val[0]))
120             || ('函数'==$val[3] && !function_exists($val[0]))
121             ){
122             $val[1] = '不支持';
123             $val[2] = 'error';
124             session('error', true);
125         }
126     }
127 
128     return $items;
129 }
130 
131 /**
132  * 写入配置文件
133  * @param  array $config 配置信息
134  */
135 function write_config($config, $auth){
136     if(is_array($config)){
137         //读取配置内容
138         $conf = file_get_contents(MODULE_PATH . 'Data/conf.tpl');
139         $user = file_get_contents(MODULE_PATH . 'Data/user.tpl');
140         //替换配置项
141         foreach ($config as $name => $value) {
142             $conf = str_replace("[{$name}]", $value, $conf);
143             $user = str_replace("[{$name}]", $value, $user);
144         }
145 
146         $conf = str_replace('[AUTH_KEY]', $auth, $conf);
147         $user = str_replace('[AUTH_KEY]', $auth, $user);
148 
149         //写入应用配置文件
150         if(!IS_WRITE){
151             return '由于您的环境不可写,请复制下面的配置文件内容覆盖到相关的配置文件,然后再登录后台。<p>'.realpath(APP_PATH).'/Common/Conf/config.php</p>
152             <textarea name="" style="650px;height:185px">'.$conf.'</textarea>
153             <p>'.realpath(APP_PATH).'/User/Conf/config.php</p>
154             <textarea name="" style="650px;height:125px">'.$user.'</textarea>';
155         }else{
156             if(file_put_contents(APP_PATH . 'Common/Conf/config.php', $conf) &&
157                file_put_contents(APP_PATH . 'User/Conf/config.php', $user)){
158                 show_msg('配置文件写入成功');
159             } else {
160                 show_msg('配置文件写入失败!', 'error');
161                 session('error', true);
162             }
163             return '';
164         }
165 
166     }
167 }
168 
169 /**
170  * 创建数据表
171  * @param  resource $db 数据库连接资源
172  */
173 function create_tables($db, $prefix = ''){
174     //读取SQL文件
175     $sql = file_get_contents(MODULE_PATH . 'Data/install.sql');
176     $sql = str_replace("\r", "\n", $sql);
177     $sql = explode(";\n", $sql);
178 
179     //替换表前缀
180     $orginal = C('ORIGINAL_TABLE_PREFIX');
181     $sql = str_replace(" `{$orginal}", " `{$prefix}", $sql);
182 
183     //开始安装
184     show_msg('开始安装数据库...');
185     foreach ($sql as $value) {
186         $value = trim($value);
187         if(empty($value)) continue;
188         if(substr($value, 0, 12) == 'CREATE TABLE') {
189             $name = preg_replace("/^CREATE TABLE `(\w+)` .*/s", "\\1", $value);
190             $msg  = "创建数据表{$name}";
191             if(false !== $db->execute($value)){
192                 show_msg($msg . '...成功');
193             } else {
194                 show_msg($msg . '...失败!', 'error');
195                 session('error', true);
196             }
197         } else {
198             $db->execute($value);
199         }
200 
201     }
202 }
203 
204 function register_administrator($db, $prefix, $admin, $auth){
205     show_msg('开始注册创始人帐号...');
206     $sql = "INSERT INTO `[PREFIX]ucenter_member` VALUES " .
207            "('1', '[NAME]', '[PASS]', '[EMAIL]', '', '[TIME]', '[IP]', 0, 0, '[TIME]', '1')";
208 
209     $password = user_md5($admin['password'], $auth);
210     $sql = str_replace(
211         array('[PREFIX]', '[NAME]', '[PASS]', '[EMAIL]', '[TIME]', '[IP]'),
212         array($prefix, $admin['username'], $password, $admin['email'], NOW_TIME, get_client_ip(1)),
213         $sql);
214     //执行sql
215     $db->execute($sql);
216 
217     $sql = "INSERT INTO `[PREFIX]member` VALUES ".
218            "('1', '[NAME]', '0', '0000-00-00', '', '0', '1', '0', '[TIME]', '0', '[TIME]', '1');";
219     $sql = str_replace(
220         array('[PREFIX]', '[NAME]', '[TIME]'),
221         array($prefix, $admin['username'], NOW_TIME),
222         $sql);
223     $db->execute($sql);
224     show_msg('创始人帐号注册完成!');
225 }
226 
227 /**
228  * 更新数据表
229  * @param  resource $db 数据库连接资源
230  * @author lyq <605415184@qq.com>
231  */
232 function update_tables($db, $prefix = ''){
233     //读取SQL文件
234     $sql = file_get_contents(MODULE_PATH . 'Data/update.sql');
235     $sql = str_replace("\r", "\n", $sql);
236     $sql = explode(";\n", $sql);
237 
238     //替换表前缀
239     $sql = str_replace(" `onethink_", " `{$prefix}", $sql);
240 
241     //开始安装
242     show_msg('开始升级数据库...');
243     foreach ($sql as $value) {
244         $value = trim($value);
245         if(empty($value)) continue;
246         if(substr($value, 0, 12) == 'CREATE TABLE') {
247             $name = preg_replace("/^CREATE TABLE `(\w+)` .*/s", "\\1", $value);
248             $msg  = "创建数据表{$name}";
249             if(false !== $db->execute($value)){
250                 show_msg($msg . '...成功');
251             } else {
252                 show_msg($msg . '...失败!', 'error');
253                 session('error', true);
254             }
255         } else {
256             if(substr($value, 0, 8) == 'UPDATE `') {
257                 $name = preg_replace("/^UPDATE `(\w+)` .*/s", "\\1", $value);
258                 $msg  = "更新数据表{$name}";
259             } else if(substr($value, 0, 11) == 'ALTER TABLE'){
260                 $name = preg_replace("/^ALTER TABLE `(\w+)` .*/s", "\\1", $value);
261                 $msg  = "修改数据表{$name}";
262             } else if(substr($value, 0, 11) == 'INSERT INTO'){
263                 $name = preg_replace("/^INSERT INTO `(\w+)` .*/s", "\\1", $value);
264                 $msg  = "写入数据表{$name}";
265             }
266             if(($db->execute($value)) !== false){
267                 show_msg($msg . '...成功');
268             } else{
269                 show_msg($msg . '...失败!', 'error');
270                 session('error', true);
271             }
272         }
273     }
274 }
275 
276 /**
277  * 及时显示提示信息
278  * @param  string $msg 提示信息
279  */
280 function show_msg($msg, $class = ''){
281     echo "<script type=\"text/javascript\">showmsg(\"{$msg}\", \"{$class}\")</script>";
282     flush();
283     ob_flush();
284 }
285 
286 /**
287  * 生成系统AUTH_KEY
288  * @author 麦当苗儿 <zuojiazi@vip.qq.com>
289  */
290 function build_auth_key(){
291     $chars  = 'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ';
292     $chars .= '`~!@#$%^&*()_+-=[]{};:"|,.<>/?';
293     $chars  = str_shuffle($chars);
294     return substr($chars, 0, 40);
295 }
296 
297 /**
298  * 系统非常规MD5加密方法
299  * @param  string $str 要加密的字符串
300  * @return string
301  */
302 function user_md5($str, $key = ''){
303     return '' === $str ? '' : md5(sha1($str) . $key);
304 }

3. 加密公共方法

 1 <?php
 2 // +----------------------------------------------------------------------
 3 // | OneThink [ WE CAN DO IT JUST THINK IT ]
 4 // +----------------------------------------------------------------------
 5 // | Copyright (c) 2013 http://www.onethink.cn All rights reserved.
 6 // +----------------------------------------------------------------------
 7 // | Author: 麦当苗儿 <zuojiazi@vip.qq.com> <http://www.zjzit.cn>
 8 // +----------------------------------------------------------------------
 9 
10 /**
11  * 系统非常规MD5加密方法
12  * @param  string $str 要加密的字符串
13  * @return string 
14  */
15 function think_ucenter_md5($str, $key = 'ThinkUCenter'){
16     return '' === $str ? '' : md5(sha1($str) . $key);
17 }
18 
19 /**
20  * 系统加密方法
21  * @param string $data 要加密的字符串
22  * @param string $key  加密密钥
23  * @param int $expire  过期时间 (单位:秒)
24  * @return string 
25  */
26 function think_ucenter_encrypt($data, $key, $expire = 0) {
27     $key  = md5($key);
28     $data = base64_encode($data);
29     $x    = 0;
30     $len  = strlen($data);
31     $l    = strlen($key);
32     $char =  '';
33     for ($i = 0; $i < $len; $i++) {
34         if ($x == $l) $x=0;
35         $char  .= substr($key, $x, 1);
36         $x++;
37     }
38     $str = sprintf('%010d', $expire ? $expire + time() : 0);
39     for ($i = 0; $i < $len; $i++) {
40         $str .= chr(ord(substr($data,$i,1)) + (ord(substr($char,$i,1)))%256);
41     }
42     return str_replace('=', '', base64_encode($str));
43 }
44 
45 /**
46  * 系统解密方法
47  * @param string $data 要解密的字符串 (必须是think_encrypt方法加密的字符串)
48  * @param string $key  加密密钥
49  * @return string 
50  */
51 function think_ucenter_decrypt($data, $key){
52     $key    = md5($key);
53     $x      = 0;
54     $data   = base64_decode($data);
55     $expire = substr($data, 0, 10);
56     $data   = substr($data, 10);
57     if($expire > 0 && $expire < time()) {
58         return '';
59     }
60     $len  = strlen($data);
61     $l    = strlen($key);
62     $char = $str = '';
63     for ($i = 0; $i < $len; $i++) {
64         if ($x == $l) $x = 0;
65         $char  .= substr($key, $x, 1);
66         $x++;
67     }
68     for ($i = 0; $i < $len; $i++) {
69         if (ord(substr($data, $i, 1)) < ord(substr($char, $i, 1))) {
70             $str .= chr((ord(substr($data, $i, 1)) + 256) - ord(substr($char, $i, 1)));
71         }else{
72             $str .= chr(ord(substr($data, $i, 1)) - ord(substr($char, $i, 1)));
73         }
74     }
75     return base64_decode($str);
76 }
原文地址:https://www.cnblogs.com/zhien/p/5274147.html