admin 发表于 2024-3-27 03:04:34

Discuz x3.5 核心文件 function_core.php 函数注释

<?php

/**
*       (C)2001-2099 Comsenz Inc.
*      This is NOT a freeware, use is subject to license terms
*
*      $Id: function_core.php 36342 2017-01-09 01:15:30Z nemohou $
*/

if(!defined('IN_DISCUZ')) {
      exit('Access Denied');
}

define('DISCUZ_CORE_FUNCTION', true);

function durlencode($url) {
      static $fix = array('%21', '%2A','%3B', '%3A', '%40', '%26', '%3D', '%2B', '%24', '%2C', '%2F', '%3F', '%25', '%23', '%5B', '%5D');
      static $replacements = array('!', '*', ';', ":", "@", "&", "=", "+", "$", ",", "/", "?", "%", "#", "[", "]");
      return str_replace($fix, $replacements, urlencode($url));
}

function system_error($message, $show = true, $save = true, $halt = true) {
      discuz_error::system_error($message, $show, $save, $halt);
}

function updatesession() {
      return C::app()->session->updatesession();
}
/**
* 设置全局变量
* @param string $key 变量的键名,如果提供了$group,则为$group下的键名
* @param mixed $value 要设置的变量的值
* @param string|null $group 可选,变量所属的组,如果不提供,则直接设置在全局变量中
* @return bool 总是返回true
*/
function setglobal($key , $value, $group = null) {
    global $_G;
    $key = explode('/', $group === null ? $key : $group.'/'.$key);
    $p = &$_G;
    foreach ($key as $k) {
      if(!isset($p[$k]) || !is_array($p[$k])) {
            $p[$k] = array();
      }
      $p = &$p[$k];
    }
    $p = $value;
    return true;
}

/**
* 获取全局变量的值
* @param string $key 变量的键名,如果提供了$group,则为$group下的键名
* @param string|null $group 可选,变量所属的组,如果不提供,则直接从全局变量中获取
* @return mixed 返回变量的值,如果未找到则返回null
*/
function getglobal($key, $group = null) {
    global $_G;
    $key = explode('/', $group === null ? $key : $group.'/'.$key);
    $v = &$_G;
    foreach ($key as $k) {
      if (!isset($v[$k])) {
            return null;
      }
      $v = &$v[$k];
    }
    return $v;
}

/**
* 获取GET、POST或COOKIE变量的值,或者根据优先级获取GET或POST变量的值
* @param string $k 变量名
* @param string $type 可选,变量来源类型,'G'代表GET,'P'代表POST,'C'代表COOKIE,默认为'GP',即先尝试GET再尝试POST
* @return mixed 返回变量的值,如果未找到则返回NULL
*/
function getgpc($k, $type='GP') {
    $type = strtoupper($type);
    switch($type) {
      case 'G': $var = &$_GET; break;
      case 'P': $var = &$_POST; break;
      case 'C': $var = &$_COOKIE; break;
      default:
            if(isset($_GET[$k])) {
                $var = &$_GET;
            } else {
                $var = &$_POST;
            }
            break;
    }

    return isset($var[$k]) ? $var[$k] : NULL;

}

/**
* 简单获取GET变量的值
* @param string $k 变量名
* @return mixed 返回GET变量的值,如果未找到则返回null
*/
function dget($k) {
    return isset($_GET[$k]) ? $_GET[$k] : null;
}

/**
* 简单获取POST变量的值
* @param string $k 变量名
* @return mixed 返回POST变量的值,如果未找到则返回null
*/
function dpost($k) {
    return isset($_POST[$k]) ? $_POST[$k] : null;
}

/**
* 根据用户ID获取用户信息
* @param int $uid 用户ID
* @param int $fetch_archive 可选,是否获取归档信息,0为不获取,1为仅获取归档信息,2为同时获取当前和归档信息
* @return array 包含用户信息的数组,如果用户不存在则返回空数组
*/
function getuserbyuid($uid, $fetch_archive = 0) {
    static $users = array();
    if(empty($users[$uid])) {
      $users[$uid] = C::t('common_member'.($fetch_archive === 2 ? '_archive' : ''))->fetch($uid);
      if($fetch_archive === 1 && empty($users[$uid])) {
            $users[$uid] = C::t('common_member_archive')->fetch($uid);
      }
    }
    if(!isset($users[$uid]['self']) && $uid == getglobal('uid') && getglobal('uid')) {
      $users[$uid]['self'] = 1;
    }
    return $users[$uid];
}

/**
* 获取用户的特定字段信息
* @param string $field 需要获取的字段名
* @return mixed 返回字段的值,如果未找到或者全局变量未设置则返回null
*/
function getuserprofile($field) {
    global $_G;
    if(isset($_G['member'][$field])) {
      return $_G['member'][$field];
    }
    static $tablefields = array(
      'count'                => array('extcredits1','extcredits2','extcredits3','extcredits4','extcredits5','extcredits6','extcredits7','extcredits8','friends','posts','threads','digestposts','doings','blogs','albums','sharings','attachsize','views','oltime','todayattachs','todayattachsize', 'follower', 'following', 'newfollower', 'blacklist'),
      'status'      => array('regip','lastip','lastvisit','lastactivity','lastpost','lastsendmail','invisible','buyercredit','sellercredit','favtimes','sharetimes','profileprogress'),
      'field_forum'      => array('publishfeed','customshow','customstatus','medals','sightml','groupterms','authstr','groups','attentiongroup'),
      'field_home'      => array('spacename','spacedescription','domain','addsize','addfriend','menunum','theme','spacecss','blockposition','recentnote','spacenote','privacy','feedfriend','acceptemail','magicgift','stickblogs'),
      'profile'      => array('realname','gender','birthyear','birthmonth','birthday','constellation','zodiac','telephone','mobile','idcardtype','idcard','address','zipcode','nationality','birthcountry','birthprovince','birthcity','residecountry','resideprovince','residecity','residedist','residecommunity','residesuite','graduateschool','company','education','occupation','position','revenue','affectivestatus','lookingfor','bloodtype','height','weight','alipay','icq','qq','yahoo','msn','taobao','site','bio','interest','field1','field2','field3','field4','field5','field6','field7','field8'),
      'verify'      => array('verify1', 'verify2', 'verify3', 'verify4', 'verify5', 'verify6'),
    );
    $profiletable = '';
    foreach($tablefields as $table => $fields) {
      if(in_array($field, $fields)) {
            $profiletable = $table;
            break;
      }
    }
    if($profiletable) {

      if(is_array($_G['member']) && $_G['member']['uid']) {
            space_merge($_G['member'], $profiletable);
      } else {
            foreach($tablefields[$profiletable] as $k) {
                $_G['member'][$k] = '';
            }
      }
      return $_G['member'][$field];
    }
    return null;
}

/**
* 对字符串进行添加反斜杠处理
*
* @param string $string 需要处理的字符串
* @param int $force 强制执行标志,默认为1
* @return string 添加反斜杠后的字符串
*/
function daddslashes($string, $force = 1) {
    // 如果输入的是数组,则递归处理数组中的每个元素
    if(is_array($string)) {
      $keys = array_keys($string);
      foreach($keys as $key) {
            $val = $string[$key];
            unset($string[$key]);
            $string = daddslashes($val, $force);
      }
    } else {
      // 对字符串添加反斜杠
      $string = addslashes($string);
    }
    return $string;
}

/**
* 对字符串进行编码或者解码
*
* @param string $string 需要编码或解码的字符串
* @param string $operation 操作类型,默认为'DECODE'解码
* @param string $key 加密解密使用的密钥
* @param int $expiry 过期时间,默认为0,表示不设置过期
* @return string 编码或解码后的字符串
*/
function authcode($string, $operation = 'DECODE', $key = '', $expiry = 0) {
    // 初始化变量和加密密钥
    $ckey_length = 4;
    $key = md5($key != '' ? $key : getglobal('authkey'));
    $keya = md5(substr($key, 0, 16));
    $keyb = md5(substr($key, 16, 16));
    $keyc = $ckey_length ? ($operation == 'DECODE' ? substr($string, 0, $ckey_length): substr(md5(microtime()), -$ckey_length)) : '';

    $cryptkey = $keya.md5($keya.$keyc);
    $key_length = strlen($cryptkey);

    // 根据操作类型进行编码或解码
    $string = $operation == 'DECODE' ? base64_decode(substr($string, $ckey_length)) : sprintf('%010d', $expiry ? $expiry + time() : 0).substr(md5($string.$keyb), 0, 16).$string;
    $string_length = strlen($string);

    $result = '';
    $box = range(0, 255);

    $rndkey = array();
    for($i = 0; $i <= 255; $i++) {
      $rndkey[$i] = ord($cryptkey[$i % $key_length]);
    }

    // 应用RC4加密算法
    for($j = $i = 0; $i < 256; $i++) {
      $j = ($j + $box[$i] + $rndkey[$i]) % 256;
      $tmp = $box[$i];
      $box[$i] = $box[$j];
      $box[$j] = $tmp;
    }

    for($a = $j = $i = 0; $i < $string_length; $i++) {
      $a = ($a + 1) % 256;
      $j = ($j + $box[$a]) % 256;
      $tmp = $box[$a];
      $box[$a] = $box[$j];
      $box[$j] = $tmp;
      $result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
    }

    // 根据操作类型返回解码后的字符串或编码后的字符串
    if($operation == 'DECODE') {
      if(((int)substr($result, 0, 10) == 0 || (int)substr($result, 0, 10) - time() > 0) && substr($result, 10, 16) === substr(md5(substr($result, 26).$keyb), 0, 16)) {
            return substr($result, 26);
      } else {
            return '';
      }
    } else {
      return $keyc.str_replace('=', '', base64_encode($result));
    }
}

/**
* 尝试使用多种方法打开与服务器的Socket连接
*
* @param string $hostname 目标主机名
* @param int $port 端口号,默认为80
* @param int &$errno 用于存储错误码的引用
* @param string &$errstr 用于存储错误信息的引用
* @param int $timeout 连接超时时间,默认为15秒
* @return resource 返回Socket连接的文件指针,失败返回false
*/
function fsocketopen($hostname, $port = 80, &$errno = null, &$errstr = null, $timeout = 15) {
    $fp = '';
    // 尝试使用多种函数打开Socket连接
    if(function_exists('fsockopen')) {
      $fp = @fsockopen($hostname, $port, $errno, $errstr, $timeout);
    } elseif(function_exists('pfsockopen')) {
      $fp = @pfsockopen($hostname, $port, $errno, $errstr, $timeout);
    } elseif(function_exists('stream_socket_client')) {
      $fp = @stream_socket_client($hostname.':'.$port, $errno, $errstr, $timeout);
    }
    return $fp;
}

/**
* 打开一个网络连接,功能与fsocketopen相似,但提供了更多的选项和灵活性
*
* @param string $url 请求的URL地址
* @param int $limit 下载限制,默认为0表示无限制
* @param string $post 提交的POST数据,默认为空
* @param string $cookie 携带的Cookie信息,默认为空
* @param bool $bysocket 是否通过Socket连接,默认为FALSE
* @param string $ip 目标IP地址,默认为空,用于指定连接的IP地址
* @param int $timeout 连接超时时间,默认为15秒
* @param bool $block 是否使用阻塞模式,默认为TRUE
* @param string $encodetype 提交数据的编码方式,默认为'URLENCODE'
* @param bool $allowcurl 是否允许使用cURL,默认为TRUE
* @param int $position 文件下载的起点位置,默认为0开始下载
* @param array $files 用于存储上传文件信息的数组,默认为空数组
* @return mixed 返回文件指针或者FALSE(在出错时)
*/
function dfsockopen($url, $limit = 0, $post = '', $cookie = '', $bysocket = FALSE, $ip = '', $timeout = 15, $block = TRUE, $encodetype= 'URLENCODE', $allowcurl = TRUE, $position = 0, $files = array()) {
    // 要求先引入filesock函数文件
    require_once libfile('function/filesock');
    return _dfsockopen($url, $limit, $post, $cookie, $bysocket, $ip, $timeout, $block, $encodetype, $allowcurl, $position, $files);
}
/**
* 将字符串中的特殊字符转为HTML实体
*
* @param string $string 需要转换的字符串
* @param int $flags HTML实体转换的标志位,默认为null
* @return string 转换后的字符串
*/
function dhtmlspecialchars($string, $flags = null) {
    // 如果输入是数组,则递归处理数组中的每个元素
    if(is_array($string)) {
      foreach($string as $key => $val) {
            $string[$key] = dhtmlspecialchars($val, $flags);
      }
    } else {
      // 如果没有指定标志位,则进行简单的字符替换
      if($flags === null) {
            $string = str_replace(array('&', '"', '<', '>'), array('&', '"', '<', '>'), $string);
      } else {
            // 根据PHP版本和字符集设置进行不同的HTML实体转换
            if(PHP_VERSION < '5.4.0') {
                $string = htmlspecialchars($string, $flags);
            } else {
                // 根据字符集确定使用的HTML实体转换字符集
                if(strtolower(CHARSET) == 'utf-8') {
                  $charset = 'UTF-8';
                } else {
                  $charset = 'ISO-8859-1';
                }
                $string = htmlspecialchars($string, $flags, $charset);
            }
      }
    }
    return $string;
}

/**
* 输出消息并退出
*
* @param string $message 要输出的消息,默认为空
*/
function dexit($message = '') {
    echo $message;
    output(); // 执行输出函数
    exit(); // 退出程序
}

/**
* 发送HTTP头信息
*
* @param string $string 要发送的头信息
* @param bool $replace 是否替换之前的同类头信息,默认为true
* @param int $http_response_code HTTP响应代码,默认为0
*/
function dheader($string, $replace = true, $http_response_code = 0) {
    // 检查是否是重定向,并且是否是在移动版中,如果是则添加移动参数
    $islocation = substr(strtolower(trim($string)), 0, 8) == 'location';
    if(defined('IN_MOBILE') && strpos($string, 'mobile') === false && $islocation) {
      if (strpos($string, '?') === false) {
            $string = $string.'?mobile='.IN_MOBILE;
      } else {
            if(strpos($string, '#') === false) {
                $string = $string.'&mobile='.IN_MOBILE;
            } else {
                $str_arr = explode('#', $string);
                $str_arr = $str_arr.'&mobile='.IN_MOBILE;
                $string = implode('#', $str_arr);
            }
      }
    }
    // 去除头信息中的换行和回车字符
    $string = str_replace(array("\r", "\n"), array('', ''), $string);
    // 根据PHP版本发送头信息
    if(empty($http_response_code) || PHP_VERSION < '4.3' ) {
      @header($string, $replace);
    } else {
      @header($string, $replace, $http_response_code);
    }
    // 如果是重定向,则退出程序
    if($islocation) {
      exit();
    }
}

/**
* 设置Cookie
*
* @param string $var Cookie的名称
* @param string $value Cookie的值,默认为空
* @param int $life Cookie的生命周期,默认为0
* @param int $prefix Cookie名称是否添加前缀,默认为1(添加前缀)
* @param bool $httponly 是否仅通过HTTP协议访问Cookie,默认为false
*/
function dsetcookie($var, $value = '', $life = 0, $prefix = 1, $httponly = false) {
    global $_G;
    $config = $_G['config']['cookie'];

    // 设置全局Cookie变量和$_COOKIE数组
    $_G['cookie'][$var] = $value;
    $var = ($prefix ? $config['cookiepre'] : '').$var;
    $_COOKIE[$var] = $value;

    // 处理Cookie值为空或生命周期为负的情况
    if($value === '' || $life < 0) {
      $value = '';
      $life = -1;
    }

    // 在移动版中强制不使用HttpOnly
    if(defined('IN_MOBILE')) {
      $httponly = false;
    }

    // 计算Cookie的过期时间
    $life = $life > 0 ? getglobal('timestamp') + $life : ($life < 0 ? getglobal('timestamp') - 31536000 : 0);
    // 根据PHP版本和是否使用HttpOnly设置Cookie路径
    $path = $httponly && PHP_VERSION < '5.2.0' ? $config['cookiepath'].'; HttpOnly' : $config['cookiepath'];

    $secure = $_G['isHTTPS'];
    // 根据PHP版本调用不同的setcookie方法
    if(PHP_VERSION < '5.2.0') {
      setcookie($var, $value, $life, $path, $config['cookiedomain'], $secure);
    } else {
      setcookie($var, $value, $life, $path, $config['cookiedomain'], $secure, $httponly);
    }
}

/**
* 获取指定Cookie的值
*
* @param string $key Cookie的名称
* @return string 指定Cookie的值,如果未设置则返回空字符串
*/
function getcookie($key) {
    global $_G;
    return isset($_G['cookie'][$key]) ? $_G['cookie'][$key] : '';
}

/**
* 获取文件的扩展名
*
* @param string $filename 文件名称
* @return string 文件扩展名,带有点号(.)
*/
function fileext($filename) {
    return addslashes(strtolower(substr(strrchr($filename, '.'), 1, 10)));
}

/**
* 生成表单哈希值
* @param string $specialadd 特殊添加内容,默认为空,会加入到哈希值计算中
* @return string 返回8位的哈希值
*/
function formhash($specialadd = '') {
      global $_G;
      // 如果是在后台管理页面,添加特定字符串到哈希值中
      $hashadd = defined('IN_ADMINCP') ? 'Only For Discuz! Admin Control Panel' : '';
      return substr(md5(substr($_G['timestamp'], 0, -7).$_G['username'].$_G['uid'].$_G['authkey'].$hashadd.$specialadd), 8, 8);
}

/**
* 检查访问者是否为机器人
* @param string $useragent 用户代理字符串,默认为空,为空时使用服务器变量HTTP_USER_AGENT
* @return bool 返回true表示可能是机器人,返回false表示不是机器人
*/
function checkrobot($useragent = '') {
      static $kw_spiders = array('bot', 'crawl', 'spider' ,'slurp', 'sohu-search', 'lycos', 'robozilla'); // 机器人关键词
      static $kw_browsers = array('msie', 'netscape', 'opera', 'konqueror', 'mozilla'); // 浏览器关键词

      $useragent = strtolower(empty($useragent) ? $_SERVER['HTTP_USER_AGENT'] : $useragent);
      // 检查是否包含机器人关键词
      if(dstrpos($useragent, $kw_spiders)) return true;
      // 检查是否为纯浏览器访问(不包含http://)且是否为指定浏览器
      if(strpos($useragent, 'http://') === false && dstrpos($useragent, $kw_browsers)) return false;
      return false;
}

/**
* 检查是否为移动设备访问
* @return bool|mixed 返回false表示不是移动设备,返回'2'表示触摸屏设备,返回'3'表示WML版本设备,返回true表示未知移动设备
*/
function checkmobile() {
      global $_G;
      $mobile = array();
      static $touchbrowser_list =array('iphone', 'android', 'phone', 'mobile', 'wap', 'netfront', 'java', 'opera mobi', 'opera mini',
                              'ucweb', 'windows ce', 'symbian', 'series', 'webos', 'sony', 'blackberry', 'dopod', 'nokia', 'samsung',
                              'palmsource', 'xda', 'pieplus', 'meizu', 'midp', 'cldc', 'motorola', 'foma', 'docomo', 'up.browser',
                              'up.link', 'blazer', 'helio', 'hosin', 'huawei', 'novarra', 'coolpad', 'webos', 'techfaith', 'palmsource',
                              'alcatel', 'amoi', 'ktouch', 'nexian', 'ericsson', 'philips', 'sagem', 'wellcom', 'bunjalloo', 'maui', 'smartphone',
                              'iemobile', 'spice', 'bird', 'zte-', 'longcos', 'pantech', 'gionee', 'portalmmm', 'jig browser', 'hiptop',
                              'benq', 'haier', '^lct', '320x320', '240x320', '176x220', 'windows phone');
      static $wmlbrowser_list = array('cect', 'compal', 'ctl', 'lg', 'nec', 'tcl', 'alcatel', 'ericsson', 'bird', 'daxian', 'dbtel', 'eastcom',
                        'pantech', 'dopod', 'philips', 'haier', 'konka', 'kejian', 'lenovo', 'benq', 'mot', 'soutec', 'nokia', 'sagem', 'sgh',
                        'sed', 'capitel', 'panasonic', 'sonyericsson', 'sharp', 'amoi', 'panda', 'zte');

      static $pad_list = array('ipad');

      $useragent = strtolower($_SERVER['HTTP_USER_AGENT']);

      // 检查是否为平板设备
      if(dstrpos($useragent, $pad_list)) {
                return false;
      }
      // 检查是否为触摸屏设备
      if(($v = dstrpos($useragent, $touchbrowser_list, true))){
                $_G['mobile'] = $v;
                return '2';
      }
      // 检查是否为WML版本浏览器设备
      if(($v = dstrpos($useragent, $wmlbrowser_list))) {
                $_G['mobile'] = $v;
                return '3'; //wml版
      }
      // 检查是否为其他浏览器,若是则返回false
      $brower = array('mozilla', 'chrome', 'safari', 'opera', 'm3gate', 'winwap', 'openwave');
      if(dstrpos($useragent, $brower)) return false;

      $_G['mobile'] = 'unknown';
      // 检查是否启用了特定的移动模板
      if(isset($_G['mobiletpl'][$_GET['mobile']])) {
                return true;
      } else {
                return false;
      }
}

/**
* 检查字符串中是否包含数组中的任何一个子串,如果找到返回true或返回指定的值
* @param string $string 要搜索的字符串
* @param array $arr 包含要搜索的子串的数组
* @param bool $returnvalue 如果找到子串,是否返回该子串,默认为false,返回true
* @return bool|string 如果找到返回true或指定的值,未找到返回false
*/
function dstrpos($string, $arr, $returnvalue = false) {
      if(empty($string)) return false;
      foreach((array)$arr as $v) {
                if(strpos($string, $v) !== false) {
                        $return = $returnvalue ? $v : true;
                        return $return;
                }
      }
      return false;
}

/**
* 验证邮箱格式是否正确
* @param string $email 需要验证的邮箱地址
* @return bool 返回true表示邮箱格式正确,返回false表示邮箱格式错误
*/
function isemail($email) {
      return strlen($email) > 6 && strlen($email) <= 255 && preg_match("/^(+)@(+[.]+)$/", $email);
}

/**
* 生成指定长度的随机字符串
* @param int $length 随机字符串的长度
* @param int $numeric 是否仅生成数字,默认为0,如果为1则仅生成数字,为0则生成数字和字母的混合串
* @return string 返回生成的随机字符串
*/
function random($length, $numeric = 0) {
      $seed = base_convert(md5(microtime().$_SERVER['DOCUMENT_ROOT']), 16, $numeric ? 10 : 35);
      $seed = $numeric ? (str_replace('0', '', $seed).'012340567890') : ($seed.'zZ'.strtoupper($seed));
      if($numeric) {
                $hash = '';
      } else {
                $hash = chr(rand(1, 26) + rand(0, 1) * 32 + 64);
                $length--;
      }
      $max = strlen($seed) - 1;
      for($i = 0; $i < $length; $i++) {
                $hash .= $seed;
      }
      return $hash;
}


/**
* 生成指定长度的随机字符串
*
* @param int $length 需要生成的随机字符串的长度
* @param int $numeric 是否只生成数字,0为否,非0为是
* @param bool $strong 是否生成强随机数,true为强随机,false为普通随机
* @return string|bool 生成的随机字符串或在无法生成强随机数且$strong为true时返回false
*/
function secrandom($length, $numeric = 0, $strong = false) {
    // 初始化字符集
    $chars = $numeric ? array('A','B','+','/','=') : array('+','/','=');
    // 数字替代字符集
    $num_find = str_split('CDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz');
    $num_repl = str_split('01234567890123456789012345678901234567890123456789');
    // 判断是否支持强随机数生成
    $isstrong = false;
    if(function_exists('random_bytes')) {
      $isstrong = true;
      // 使用random_bytes生成随机数
      $random_bytes = function($length) {
            return random_bytes($length);
      };
    } elseif(extension_loaded('mcrypt') && function_exists('mcrypt_create_iv')) {
      $isstrong = true;
      // 使用mcrypt_create_iv生成随机数
      $random_bytes = function($length) {
            $rand = mcrypt_create_iv($length, MCRYPT_DEV_URANDOM);
            if ($rand !== false && strlen($rand) === $length) {
                return $rand;
            } else {
                return false;
            }
      };
    } elseif(extension_loaded('openssl') && function_exists('openssl_random_pseudo_bytes')) {
      $isstrong = true;
      // 使用openssl_random_pseudo_bytes生成随机数
      $random_bytes = function($length) {
            $rand = openssl_random_pseudo_bytes($length, $secure);
            if($secure === true) {
                return $rand;
            } else {
                return false;
            }
      };
    }
    if(!$isstrong) {
      // 不支持强随机数时的处理
      return $strong ? false : random($length, $numeric);
    }
    // 尝试生成随机字符串
    $retry_times = 0;
    $return = '';
    while($retry_times < 128) {
      $getlen = $length - strlen($return); // 为保证随机性,可能会多生成一些字节
      $bytes = $random_bytes(max($getlen, 12));
      if($bytes === false) {
            return false;
      }
      // 去除可能包含的特殊字符,避免解码问题
      $bytes = str_replace($chars, '', base64_encode($bytes));
      $return .= substr($bytes, 0, $getlen);
      if(strlen($return) == $length) {
            // 根据是否只生成数字返回相应的结果
            return $numeric ? str_replace($num_find, $num_repl, $return) : $return;
      }
      $retry_times++;
    }
}

/**
* 检查字符串中是否存在指定的子字符串
*
* @param string $string 主字符串
* @param string $find 待查找的子字符串
* @return bool 子字符串存在返回true,否则返回false
*/
function strexists($string, $find) {
    return !(strpos($string, $find) === FALSE);
}

/**
* 生成用户头像URL或HTML标签
*
* @param int $uid 用户ID
* @param string $size 头像大小,可选:'big', 'middle', 'small',默认为'middle'
* @param int|array $returnsrc 如果为1,则只返回URL;如果为数组,则允许通过数组设置额外参数
* @param bool $real 是否返回真实头像地址
* @param bool $static 是否使用静态地址
* @param string $ucenterurl UCenter的URL
* @param string $class 图片HTML标签的class属性
* @param string $extra 图片HTML标签的额外属性
* @param int $random 是否添加随机参数以强制刷新缓存
* @return string 返回头像的URL或HTML标签
*/
function avatar($uid, $size = 'middle', $returnsrc = 0, $real = FALSE, $static = FALSE, $ucenterurl = '', $class = '', $extra = '', $random = 0) {
    global $_G;
    // 检查插件中是否有自定义的头像函数
    if(!empty($_G['setting']['plugins']['func']['avatar']) && !defined('IN_ADMINCP')) {
      $_G['hookavatar'] = '';
      $param = func_get_args();
      hookscript('avatar', 'global', 'funcs', array('param' => $param), 'avatar');
      if($_G['hookavatar']) {
            return $_G['hookavatar'];
      }
    }
    // 解析传入的$returnsrc参数
    if(is_array($returnsrc)) {
      $random = isset($returnsrc['random']) ? $returnsrc['random'] : 0;
      $extra = isset($returnsrc['extra']) ? $returnsrc['extra'] : '';
      $class = isset($returnsrc['class']) ? $returnsrc['class'] : '';
      $ucenterurl = isset($returnsrc['ucenterurl']) ? $returnsrc['ucenterurl'] : '';
      $static = isset($returnsrc['static']) ? $returnsrc['static'] : FALSE;
      $real = isset($returnsrc['real']) ? $returnsrc['real'] : FALSE;
      $returnsrc = isset($returnsrc['returnsrc']) ? $returnsrc['returnsrc'] : 0;
    }
    // 静态头像开关
    static $staticavatar;
    if($staticavatar === null) {
      $staticavatar = $_G['setting']['avatarmethod'];
    }
    // 头像存在性缓存
    static $avtstatus;
    if($avtstatus === null) {
      $avtstatus = array();
    }
    // 动态头像配置
    $dynavt = intval($_G['setting']['dynavt']);

    // 处理UCenter URL
    $ucenterurl = empty($ucenterurl) ? $_G['setting']['ucenterurl'] : $ucenterurl;
    // 处理头像URL
    $avatarurl = empty($_G['setting']['avatarurl']) ? $ucenterurl.'/data/avatar' : $_G['setting']['avatarurl'];
    // 规范化头像大小参数
    $size = in_array($size, array('big', 'middle', 'small')) ? $size : 'middle';
    // 格式化用户ID
    $uid = abs(intval($uid));
    $rawuid = $uid;
    // 生成UCenter头像地址
    if(!$staticavatar && !$static && $ucenterurl != '.') {
      if($avatarurl != $ucenterurl.'/data/avatar') {
            $ucenterurl = $avatarurl;
      }
      $trandom = '';
      if($random == 1) {
            $trandom = '&random=1';
      } elseif($dynavt == 2 || ($dynavt == 1 && $uid == $_G['uid']) || $random == 2) {
            $trandom = '&ts=1';
      }
      if($returnsrc) {
            return $ucenterurl.'/avatar.php?uid='.$uid.'&size='.$size.($real ? '&type=real' : '').$trandom;
      } else {
            return '<img src="'.$ucenterurl.'/avatar.php?uid='.$uid.'&size='.$size.($real ? '&type=real' : '').$trandom.'"'.($class ? ' class="'.$class.'"' : '').($extra ? ' '.$extra : '').'>';
      }
    } else {
      // 生成本地头像地址
      $uid = sprintf("%09d", $uid);
      $dir1 = substr($uid, 0, 3);
      $dir2 = substr($uid, 3, 2);
      $dir3 = substr($uid, 5, 2);
      $filepath = $dir1.'/'.$dir2.'/'.$dir3.'/'.substr($uid, -2).($real ? '_real' : '').'_avatar_'.$size.'.jpg';
      $file = $avatarurl.'/'.$filepath;
      $noavt = $avatarurl.'/noavatar.svg';
      $trandom = '';
      $avtexist = -1;
      if(!$staticavatar && !$static) {
            $avatar_file = DISCUZ_ROOT.$_G['setting']['avatarpath'].$filepath;
            if(isset($avtstatus[$rawuid])) {
                $avtexist = $avtstatus[$rawuid];
            } else {
                $avtexist = file_exists($avatar_file) ? 1 : 0;
                $avtstatus[$rawuid] = $avtexist;
            }
            if($avtexist) {
                if($dynavt == 2 || ($dynavt == 1 && $rawuid && $rawuid == $_G['uid']) || $random == 2) {
                  if(empty($avtstatus[$rawuid])) {
                        $avtstatus[$rawuid] = filemtime($avatar_file);
                  }
                  $trandom = '?ts='.$avtstatus[$rawuid];
                }
            } else {
                $file = $noavt;
            }
      }
      if($random == 1 && $avtexist != 0) {
            $trandom = '?random='.rand(1000, 9999);
      }
      if($trandom) {
            $file = $file.$trandom;
      }
      if($returnsrc) {
            return $file;
      } else {
            return '<img src="'.$file.'"'.(($avtexist == -1) ? '' : '').($class ? ' class="'.$class.'"' : '').($extra ? ' '.$extra : '').'>';
      }
    }
}

/**
* 根据给定的语言文件和变量名获取本地化字符串
*
* @param string $file 语言文件名或插件语言标识
* @param string|null $langvar 要获取的具体语言变量名,如果为null则返回整个语言文件的内容
* @param array $vars 语言字符串中需要替换的变量数组,键为变量名,值为替换值
* @param mixed $default 如果指定的语言变量不存在时的默认返回值
* @return mixed 返回替换后的语言字符串或数组
*/
function lang($file, $langvar = null, $vars = array(), $default = null) {
    global $_G;
    $fileinput = $file;
    // 分解文件路径和名称
    $list = explode('/', $file);
    $path = $list;
    $file = isset($list) ? $list : false;
    // 如果没有文件名,则认为路径名即为文件名
    if(!$file) {
      $file = $path;
      $path = '';
    }
    // 处理插件语言文件特殊情况
    if(strpos($file, ':') !== false) {
      $path = 'plugin';
      list($file) = explode(':', $file);
    }

    // 加载并合并语言文件
    if($path != 'plugin') {
      $key = $path == '' ? $file : $path.'_'.$file;
      // 检查语言文件是否已加载,未加载则加载
      if(!isset($_G['lang'][$key])) {
            $loadfile = DISCUZ_ROOT.'./source/language/'.($path == '' ? '' : $path.'/').'lang_'.$file.'.php';
            if(file_exists($loadfile)) {
                include $loadfile;
            }
            $_G['lang'][$key] = (array)$lang;
      }
      // 手机版特殊处理
      if(defined('IN_MOBILE') && !defined('TPL_DEFAULT')) {
            include DISCUZ_ROOT.'./source/language/touch/lang_template.php';
            $_G['lang'][$key] = array_merge((array)$_G['lang'][$key], (array)$lang);
      }
      // 加载插件语言缓存
      if(!isset($_G['cache']['pluginlanguage_system'])) {
            loadcache('pluginlanguage_system');
      }
      if(!isset($_G['hooklang'][$fileinput])) {
            if(isset($_G['cache']['pluginlanguage_system'][$fileinput]) && is_array($_G['cache']['pluginlanguage_system'][$fileinput])) {
                $_G['lang'][$key] = array_merge((array)$_G['lang'][$key], (array)$_G['cache']['pluginlanguage_system'][$fileinput]);
            }
            $_G['hooklang'][$fileinput] = true;
      }
      $returnvalue = &$_G['lang'];
    } else {
      // 处理插件语言变量
      if(empty($_G['config']['plugindeveloper'])) {
            loadcache('pluginlanguage_script');
      } elseif(!isset($_G['cache']['pluginlanguage_script'][$file]) && preg_match("/^+*$/i", $file)) {
            if(@include(DISCUZ_ROOT.'./data/plugindata/'.$file.'.lang.php')) {
                $_G['cache']['pluginlanguage_script'][$file] = $scriptlang[$file];
            } else {
                loadcache('pluginlanguage_script');
            }
      }
      $returnvalue = & $_G['cache']['pluginlanguage_script'];
      !is_array($returnvalue) && $returnvalue = array();
      $key = &$file;
    }
    // 获取并处理指定的语言变量或整个语言文件
    $return = $langvar !== null ? (isset($returnvalue[$key][$langvar]) ? $returnvalue[$key][$langvar] : null) : (is_array($returnvalue[$key]) ? $returnvalue[$key] : array());
    $return = $return === null ? ($default !== null ? $default : ($path != 'plugin' ? '' : $file . ':') . $langvar) : $return;
    // 替换语言字符串中的变量
    $searchs = $replaces = array();
    if($vars && is_array($vars)) {
      foreach($vars as $k => $v) {
            $searchs[] = '{'.$k.'}';
            $replaces[] = $v;
      }
    }
    // 替换语言字符串中的全局变量
    if(is_string($return) && strpos($return, '{_G/') !== false) {
      preg_match_all('/\{_G\/(.+?)\}/', $return, $gvar);
      foreach($gvar as $k => $v) {
            $searchs[] = (string)$v;
            $replaces[] = getglobal($gvar[$k]);
      }
    }
    // 执行最后的替换
    if($searchs || $replaces) {
      $return = str_replace($searchs, $replaces, $return);
    }
    return $return;
}

/**
* 检查模板是否需要刷新
*
* @param string $maintpl 主模板文件名
* @param string $subtpl 子模板文件名
* @param int $timecompare 用于比较的最新修改时间
* @param int $templateid 模板ID
* @param string $cachefile 缓存文件名
* @param string $tpldir 模板目录
* @param string $file 检查的文件名
* @return bool 如果模板需要刷新返回true,否则返回false
*/
function checktplrefresh($maintpl, $subtpl, $timecompare, $templateid, $cachefile, $tpldir, $file) {
    static $tplrefresh, $timestamp, $targettplname;
    if($tplrefresh === null) {
      $tplrefresh = getglobal('config/output/tplrefresh');
      $timestamp = getglobal('timestamp');
    }

    // 检查是否满足模板刷新条件
    if(empty($timecompare) || $tplrefresh == 1 || ($tplrefresh > 1 && !($timestamp % $tplrefresh))) {
      if(!file_exists(DISCUZ_ROOT.$subtpl)){
            $subtpl = substr($subtpl, 0, -4).'.php';
      }
      // 检查子模板文件的修改时间
      if(empty($timecompare) || @filemtime(DISCUZ_ROOT.$subtpl) > $timecompare) {
            require_once DISCUZ_ROOT.'/source/class/class_template.php';
            $template = new template();
            $template->parse_template($maintpl, $templateid, $tpldir, $file, $cachefile);
            // 更新并检查目标模板文件名
            if($targettplname === null) {
                $targettplname = getglobal('style/tplfile');
                if(!empty($targettplname)) {
                  include_once libfile('function/block');
                  $targettplname = strtr($targettplname, ':', '_');
                  update_template_block($targettplname, getglobal('style/tpldirectory'), $template->blocks);
                }
                $targettplname = true;
            }
            return TRUE;
      }
    }
    return FALSE;
}
/**
* 加载模板文件
*
* @param string $file 模板文件名,可以包含路径和模板ID标识
* @param int $templateid 模板ID,默认为0,代表全局模板
* @param string $tpldir 指定的模板目录,默认为空,会根据模板ID自动确定
* @param int $gettplfile 是否仅获取模板文件路径而不生成缓存,1为是,默认为0
* @param string $primaltpl 默认模板文件名,用于指定原始模板,当$templateid为'diy'时有效
* @return string 返回模板文件的缓存路径
*/
function template($file, $templateid = 0, $tpldir = '', $gettplfile = 0, $primaltpl='') {
      global $_G;

      // 初始化模块和Hook
      if(!defined('CURMODULE')) {
                define('CURMODULE', '');
      }
      if(!defined('HOOKTYPE')) {
                define('HOOKTYPE', !defined('IN_MOBILE') ? 'hookscript' : 'hookscriptmobile');
      }
      // 执行插件的Hook
      if(!empty($_G['setting']['plugins']['func']['template'])) {
                $param = func_get_args();
                $hookreturn = hookscript('template', 'global', 'funcs', array('param' => $param, 'caller' => 'template'), 'template');
                if($hookreturn) {
                        return $hookreturn;
                }
      }

      // 初始化样式
      static $_init_style = false;
      if($_init_style === false) {
                C::app()->_init_style();
                $_init_style = true;
      }

      // 解析模板文件名,支持模板克隆和DIY模板
      $oldfile = $file;
      if(strpos($file, ':') !== false) {
                $clonefile = '';
                list($templateid, $file, $clonefile) = explode(':', $file.'::');
                $oldfile = $file;
                $file = empty($clonefile) ? $file : $file.'_'.$clonefile;
                if($templateid == 'diy') {
                        // 处理DIY模板逻辑
                        // ...
                } else {
                        $tpldir = './source/plugin/'.$templateid.'/template';
                }
      }

      // 处理Ajax请求下的模板文件名
      $file .= !empty($_G['inajax']) && ($file == 'common/header' || $file == 'common/footer') ? '_ajax' : '';
      $tpldir = $tpldir ? $tpldir : (defined('TPLDIR') ? TPLDIR : '');
      $templateid = $templateid ? $templateid : (defined('TEMPLATEID') ? TEMPLATEID : '');
      $filebak = $file;

      // 移动端模板处理
      if(constant('HOOKTYPE') == 'hookscriptmobile' && defined('IN_MOBILE') && !defined('TPL_DEFAULT') && strpos($file, $_G['mobiletpl'].'/') === false || (isset($_G['forcemobilemessage']) && $_G['forcemobilemessage'])) {
                // ...
      }

      if(!$tpldir) {
                $tpldir = './template/default';
      }
      $tplfile = $tpldir.'/'.$file.'.htm';

      // 生成或获取模板缓存文件
      if($gettplfile) {
                return $tplfile;
      }
      checktplrefresh($tplfile, $tplfile, @filemtime(DISCUZ_ROOT.$cachefile), $templateid, $cachefile, $tpldir, $file);
      return DISCUZ_ROOT.$cachefile;
}
/**
* 生成基于输入字符串和长度的安全签名
*
* @param string $str 输入字符串
* @param int $length 生成签名的长度,默认为16
* @return string 生成的签名字符串
*/
function dsign($str, $length = 16){
    return substr(md5($str.getglobal('config/security/authkey')), 0, ($length ? max(8, $length) : 16));
}

/**
* 生成模块认证密钥
*
* @param int $id 模块ID
* @return string 生成的模块认证密钥
*/
function modauthkey($id) {
    return md5(getglobal('username').getglobal('uid').getglobal('authkey').substr(TIMESTAMP, 0, -7).$id);
}

/**
* 获取当前导航ID
*
* @return string 当前导航的ID
*/
function getcurrentnav() {
    global $_G;
    if(!empty($_G['mnid'])) {
      return $_G['mnid'];
    }
    $mnid = '';
    $_G['basefilename'] = $_G['basefilename'] == $_G['basescript'] ? $_G['basefilename'] : $_G['basescript'].'.php';
    // 根据当前脚本设置的导航进行匹配
    if(isset($_G['setting']['navmns'][$_G['basefilename']])) {
      // 对于特定的脚本和条件,调整导航匹配
      if($_G['basefilename'] == 'home.php' && $_GET['mod'] == 'space' && (empty($_GET['do']) || in_array($_GET['do'], array('follow', 'view')))) {
            $_GET['mod'] = 'follow';
      }
      // 遍历脚本设置的导航,匹配当前请求的导航
      foreach($_G['setting']['navmns'][$_G['basefilename']] as $navmn) {
            if($navmn == array_intersect_assoc($navmn, $_GET) || (isset($_GET['gid']) && $navmn['mod'] == 'forumdisplay' && $navmn['fid'] == $_GET['gid'])|| ($navmn['mod'] == 'space' && $_GET['mod'] == 'spacecp' && ($navmn['do'] == $_GET['ac'] || $navmn['do'] == 'album' && $_GET['ac'] == 'upload'))) {
                $mnid = $navmn;
            }
      }
    }
    // 若未匹配到导航,尝试根据请求的域名和URI匹配导航
    if(!$mnid && isset($_G['setting']['navdms'])) {
      foreach($_G['setting']['navdms'] as $navdm => $navid) {
            if(strpos(strtolower($_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']), $navdm) !== false && strpos(strtolower($_SERVER['HTTP_HOST']), $navdm) === false) {
                $mnid = $navid;
                break;
            }
      }
    }
    // 最后尝试直接获取当前脚本设置的默认导航
    if(!$mnid && isset($_G['setting']['navmn'][$_G['basefilename']])) {
      $mnid = $_G['setting']['navmn'][$_G['basefilename']];
    }
    return $mnid;
}

/**
* 加载UCenter配置和客户端库
*/
function loaducenter() {
    require_once DISCUZ_ROOT.'./config/config_ucenter.php';
    require_once DISCUZ_ROOT.'./uc_client/client.php';
}
/**
* 加载缓存函数。
* 该函数用于加载指定的缓存数据。如果缓存未被加载或强制加载标志为true,则会重新加载缓存。
*
* @param array|string $cachenames 要加载的缓存名称,可以是一个字符串或字符串数组。
* @param bool $force 是否强制重新加载缓存,默认为false。
* @return bool 函数总是返回true。
*/
function loadcache($cachenames, $force = false) {
      global $_G;
      static $loadedcache = array();

      // 确保$cachenames为数组
      $cachenames = is_array($cachenames) ? $cachenames : array($cachenames);
      $caches = array();

      // 遍历缓存名称,将未加载或需强制加载的缓存加入到加载列表中
      foreach ($cachenames as $k) {
                if(!isset($loadedcache[$k]) || $force) {
                        $caches[] = $k;
                        $loadedcache[$k] = true;
                }
      }

      // 当存在需要加载的缓存时,执行加载操作
      if(!empty($caches)) {
                $cachedata = C::t('common_syscache')->fetch_all_syscache($caches);
                foreach($cachedata as $cname => $data) {
                        // 根据缓存名称,将缓存数据存储到全局变量或$_G['cache']中
                        if($cname == 'setting') {
                              $_G['setting'] = $data;
                        } elseif($cname == 'usergroup_'.$_G['groupid']) {
                              $_G['cache'][$cname] = $_G['group'] = $data;
                        } elseif($cname == 'style_default') {
                              $_G['cache'][$cname] = $_G['style'] = $data;
                        } elseif($cname == 'grouplevels') {
                              $_G['grouplevels'] = $data;
                        } else {
                              $_G['cache'][$cname] = $data;
                        }
                }
      }
      return true;
}
/**
* 根据指定格式和时区偏移量格式化时间戳。
*
* @param int $timestamp 需要格式化的时间戳。
* @param string $format 格式化字符串,'dt'为日期和时间,默认,'d'为日期,'t'为时间,'u'为特殊时间格式。
* @param int $timeoffset 时区偏移量,单位为小时,默认为9999,表示使用全局设置。
* @param string $uformat 当$format为'u'时,使用的特定格式字符串。
* @return string 返回格式化后的时间字符串。
*/
function dgmdate($timestamp, $format = 'dt', $timeoffset = 9999, $uformat = '') {
      global $_G;
      // 当指定格式为'u'且全局设置禁用日期转换时,格式设为'dt'
      $format == 'u' && !$_G['setting']['dateconvert'] && $format = 'dt';
      // 静态变量初始化,用于缓存配置和语言变量
      static $dformat, $tformat, $dtformat, $offset, $lang;
      if($dformat === null) {
                $dformat = getglobal('setting/dateformat');
                $tformat = getglobal('setting/timeformat');
                $dtformat = $dformat.' '.$tformat;
                $offset = getglobal('member/timeoffset');
                $sysoffset = getglobal('setting/timeoffset');
                // 系统默认时区偏移量处理
                $offset = $offset == 9999 ? ($sysoffset ? $sysoffset : 0) : $offset;
                $lang = lang('core', 'date');
      }
      // 处理自定义时区偏移量
      $timeoffset = $timeoffset == 9999 ? $offset : $timeoffset;
      $timeoffset = intval($timeoffset);
      // 应用时区偏移量到时间戳
      $timestamp += $timeoffset * 3600;
      // 根据格式参数选择合适的格式字符串
      $format = empty($format) || $format == 'dt' ? $dtformat : ($format == 'd' ? $dformat : ($format == 't' ? $tformat : $format));
      if($format == 'u') {
                // 特殊时间格式处理
                $todaytimestamp = TIMESTAMP - (TIMESTAMP + $timeoffset * 3600) % 86400 + $timeoffset * 3600;
                $s = gmdate(!$uformat ? $dtformat : $uformat, $timestamp);
                $time = TIMESTAMP + $timeoffset * 3600 - $timestamp;
                if($timestamp >= $todaytimestamp) {
                        // 当天时间的特殊处理
                        if($time > 3600) {
                              $return = intval($time / 3600).' '.$lang['hour'].$lang['before'];
                        } elseif($time > 1800) {
                              $return = $lang['half'].$lang['hour'].$lang['before'];
                        } elseif($time > 60) {
                              $return = intval($time / 60).' '.$lang['min'].$lang['before'];
                        } elseif($time > 0) {
                              $return = $time.' '.$lang['sec'].$lang['before'];
                        } elseif($time == 0) {
                              $return = $lang['now'];
                        } else {
                              $return = $s;
                        }
                        // 非移动设备上添加时间标题
                        if($time >=0 && !defined('IN_MOBILE')) {
                              $return = '<span title="'.$s.'">'.$return.'</span>';
                        }
                } elseif(($days = intval(($todaytimestamp - $timestamp) / 86400)) >= 0 && $days < 7) {
                        // 本周内时间的特殊处理
                        if($days == 0) {
                              $return = $lang['yday'].' '.gmdate($tformat, $timestamp);
                        } elseif($days == 1) {
                              $return = $lang['byday'].' '.gmdate($tformat, $timestamp);
                        } else {
                              $return = ($days + 1).' '.$lang['day'].$lang['before'];
                        }
                        if(!defined('IN_MOBILE')) {
                              $return = '<span title="'.$s.'">'.$return.'</span>';
                        }
                } else {
                        // 其他情况直接返回格式化时间
                        $return = $s;
                }
                return $return;
      } else {
                // 对于非'u'格式,直接使用gmdate函数格式化
                return gmdate($format, $timestamp);
      }
}

/**
* 根据日期字符串计算时间戳。
*
* @param string $date 日期字符串,格式为'YYYY-MM-DD'。
* @return int 返回计算得到的时间戳,不合法则返回0。
*/
function dmktime($date) {
      if(strpos($date, '-')) {
                // 通过字符串分割获取年、月、日
                $time = explode('-', $date);
                return mktime(0, 0, 0, $time, $time, $time);
      }
      return 0;
}
/**
* 将数字格式化显示,如果超过1万,则以 '<span title="原数字">数字/10k</span>' 的形式显示
* @param int $number 需要格式化的数字
* @return string 格式化后的数字字符串
*/
function dnumber($number) {
    return abs((int)$number) > 10000 ? '<span title="'.$number.'">'.intval($number / 10000).lang('core', '10k').'</span>' : $number;
}

/**
* 保存缓存数据
* @param string $cachename 缓存名称
* @param mixed $data 缓存数据
*/
function savecache($cachename, $data) {
    C::t('common_syscache')->insert_syscache($cachename, $data);
}

/**
* 保存系统缓存数据,功能同savecache
* @param string $cachename 缓存名称
* @param mixed $data 缓存数据
*/
function save_syscache($cachename, $data) {
    savecache($cachename, $data);
}

/**
* 根据参数获取区块内容
* @param mixed $parameter 区块参数
*/
function block_get($parameter) {
    include_once libfile('function/block');
    block_get_batch($parameter);
}

/**
* 显示指定ID的区块
* @param int $bid 区块ID
*/
function block_display($bid) {
    include_once libfile('function/block');
    block_display_batch($bid);
}

/**
* 将数组中的每个元素转义并以逗号分隔拼接成一个SQL兼容的字符串
* @param array $array 需要处理的数组
* @return string 拼接后的字符串
*/
function dimplode($array) {
    if(!empty($array)) {
      $array = array_map('addslashes', $array);
      return "'".implode("','", is_array($array) ? $array : array($array))."'";
    } else {
      return 0;
    }
}

/**
* 获取库文件的文件路径
* @param string $libname 库名称
* @param string $folder 文件夹路径
* @return string|bool 返回库文件的绝对路径,如果路径不合法则返回false
*/
function libfile($libname, $folder = '') {
    $libpath = '/source/'.$folder;
    if(strstr($libname, '/')) {
      list($pre, $name) = explode('/', $libname);
      $path = "{$libpath}/{$pre}/{$pre}_{$name}";
    } else {
      $path = "{$libpath}/{$libname}";
    }
    return preg_match('/^[\w\d\/_]+$/i', $path) ? realpath(DISCUZ_ROOT.$path.'.php') : false;
}

/**
* 计算字符串的长度,针对UTF-8编码的字符串会按字符计算
* @param string $str 输入的字符串
* @return int 字符串的长度
*/
function dstrlen($str) {
    if(strtolower(CHARSET) != 'utf-8') {
      return strlen($str);
    }
    $count = 0;
    for($i = 0; $i < strlen($str); $i++){
      $value = ord($str[$i]);
      if($value > 127) {
            $count++;
            if($value >= 192 && $value <= 223) $i++;
            elseif($value >= 224 && $value <= 239) $i = $i + 2;
            elseif($value >= 240 && $value <= 247) $i = $i + 3;
      }
      $count++;
    }
    return $count;
}

/**
* 截取字符串,支持UTF-8编码。
* @param string $string 原始字符串
* @param int $length 截取的长度
* @param string $dot 截断后附加的字符串,默认为' ...'
* @return string 截取后的字符串
*/
function cutstr($string, $length, $dot = ' ...') {
    if(strlen($string) <= $length) {
      return $string;
    }

    $pre = chr(1);
    $end = chr(1);
    $string = str_replace(array('&', '"', '<', '>'), array($pre.'&'.$end, $pre.'"'.$end, $pre.'<'.$end, $pre.'>'.$end), $string);

    $strcut = '';
    if(strtolower(CHARSET) == 'utf-8') {

      $n = $tn = $noc = 0;
      while($n < strlen($string)) {

            $t = ord($string[$n]);
            if($t == 9 || $t == 10 || (32 <= $t && $t <= 126)) {
                $tn = 1; $n++; $noc++;
            } elseif(194 <= $t && $t <= 223) {
                $tn = 2; $n += 2; $noc += 2;
            } elseif(224 <= $t && $t <= 239) {
                $tn = 3; $n += 3; $noc += 2;
            } elseif(240 <= $t && $t <= 247) {
                $tn = 4; $n += 4; $noc += 2;
            } elseif(248 <= $t && $t <= 251) {
                $tn = 5; $n += 5; $noc += 2;
            } elseif($t == 252 || $t == 253) {
                $tn = 6; $n += 6; $noc += 2;
            } else {
                $n++;
            }

            if($noc >= $length) {
                break;
            }

      }
      if($noc > $length) {
            $n -= $tn;
      }

      $strcut = substr($string, 0, $n);

    } else {
      $_length = $length - 1;
      for($i = 0; $i < $length; $i++) {
            if(ord($string[$i]) <= 127) {
                $strcut .= $string[$i];
            } else if($i < $_length) {
                $strcut .= $string[$i].$string[++$i];
            }
      }
    }

    $strcut = str_replace(array($pre.'&'.$end, $pre.'"'.$end, $pre.'<'.$end, $pre.'>'.$end), array('&', '"', '<', '>'), $strcut);

    $pos = strrpos($strcut, chr(1));
    if($pos !== false) {
      $strcut = substr($strcut,0,$pos);
    }
    return $strcut.$dot;
}
/**
* 去除字符串中的反斜杠
*
* @param string $string 待处理的字符串
* @return string 处理后的字符串
*/
function dstripslashes($string) {
    if(empty($string)) return $string;
    if(is_array($string)) {
      foreach($string as $key => $val) {
            $string[$key] = dstripslashes($val); // 递归处理数组中的每个元素
      }
    } else {
      $string = stripslashes($string); // 去除字符串中的反斜杠
    }
    return $string;
}

/**
* 对给定的援助ID进行编码
*
* @param int $aid 援助ID
* @param int $type 编码类型,默认为0
* @param int $tid 附加ID,默认为0
* @return string 编码后的字符串
*/
function aidencode($aid, $type = 0, $tid = 0) {
    global $_G;
    $s = !$type ? $aid.'|'.substr(md5($aid.md5($_G['config']['security']['authkey']).TIMESTAMP.$_G['uid']), 0, 8).'|'.TIMESTAMP.'|'.$_G['uid'].'|'.$tid : $aid.'|'.md5($aid.md5($_G['config']['security']['authkey']).TIMESTAMP).'|'.TIMESTAMP;
    return rawurlencode(base64_encode($s)); // 对字符串进行编码
}

/**
* 获取论坛图片的URL
*
* @param int $aid 图片的援助ID
* @param int $nocache 是否启用缓存,默认为0
* @param int $w 图片宽度,默认为140
* @param int $h 图片高度,默认为140
* @param string $type 图片类型,默认为空
* @return string 图片的URL
*/
function getforumimg($aid, $nocache = 0, $w = 140, $h = 140, $type = '') {
    global $_G;
    $key = dsign($aid.'|'.$w.'|'.$h); // 生成签名
    return 'forum.php?mod=image&aid='.$aid.'&size='.$w.'x'.$h.'&key='.rawurlencode($key).($nocache ? '&nocache=yes' : '').($type ? '&type='.$type : '');
}

/**
* 重写输出URL
*
* @param string $type 输出类型
* @param string $returntype 返回类型
* @param string $host 主机名
* @return string 重写后的URL
*/
function rewriteoutput($type, $returntype, $host) {
    global $_G;
    $fextra = '';
    // 根据不同的类型处理参数并返回相应的URL
    if($type == 'forum_forumdisplay') {
      list(,,, $fid, $page, $extra) = func_get_args();
      $r = array(
            '{fid}' => empty($_G['setting']['forumkeys'][$fid]) ? $fid : $_G['setting']['forumkeys'][$fid],
            '{page}' => $page ? $page : 1,
      );
    } elseif($type == 'forum_viewthread') {
      // ...
      // 其他类型处理逻辑相似,省略...
      // ...
    }
    $href = str_replace(array_keys($r), $r, $_G['setting']['rewriterule'][$type]).$fextra;
    if(!$returntype) {
      return '<a href="'.$host.$href.'"'.(!empty($extra) ? stripslashes($extra) : '').'>'; // 返回HTML链接
    } else {
      return $host.$href; // 返回URL
    }
}

/**
* 手机端替换
*
* @param string $file 文件名
* @param array $replace 替换数组
* @return string 替换后的字符串
*/
function mobilereplace($file, $replace) {
    return helper_mobile::mobilereplace($file, $replace);
}

/**
* 手机端输出设置
*/
function mobileoutput() {
    helper_mobile::mobileoutput();
}
/**
* 输出处理函数
* 本函数负责处理全局输出,包括但不限于:
* 1. 判断是否已输出,防止重复输出。
* 2. 处理区块更新缓存。
* 3. 移动端输出处理。
* 4. 输出替换,如URL替换等。
* 5. HTML缓存生成。
* 6. 调试信息输出。
*
*/
function output() {

    global $_G;

    // 检查是否已定义输出标识,防止重复输出
    if(defined('DISCUZ_OUTPUTED')) {
      return;
    } else {
      define('DISCUZ_OUTPUTED', 1);
    }

    // 处理区块更新缓存
    if(!empty($_G['blockupdate'])) {
      block_updatecache($_G['blockupdate']['bid']);
    }

    // 移动端输出处理
    if(defined('IN_MOBILE')) {
      mobileoutput();
    }

    // 处理URL重写和域名配置,进行内容替换
    $havedomain = implode('', $_G['setting']['domain']['app']);
    if($_G['setting']['rewritestatus'] || !empty($havedomain)) {
      $content = ob_get_contents();
      $content = output_replace($content); // 对内容进行替换处理

      ob_end_clean();
      $_G['gzipcompress'] ? ob_start('ob_gzhandler') : ob_start(); // 启用gzip压缩

      echo $content; // 输出处理后的内容
    }

    // 生成HTML缓存
    if(isset($_G['makehtml'])) {
      helper_makehtml::make_html();
    }

    // 关闭FTP连接
    if($_G['setting']['ftp']['connid']) {
      @ftp_close($_G['setting']['ftp']['connid']);
    }
    $_G['setting']['ftp'] = array(); // 清空FTP配置

    // 生成缓存文件
    if(defined('CACHE_FILE') && CACHE_FILE && !defined('CACHE_FORBIDDEN') && !defined('IN_MOBILE') && !IS_ROBOT && !checkmobile()) {
      if(diskfreespace(DISCUZ_ROOT.'./'.$_G['setting']['cachethreaddir']) > 1000000) {
            $content = empty($content) ? ob_get_contents() : $content;
            // 生成临时变量替换formhash和siteurl,防止缓存被恶意修改
            $temp_md5 = md5(substr($_G['timestamp'], 0, -3).substr($_G['config']['security']['authkey'], 3, -3));
            $temp_formhash = substr($temp_md5, 8, 8);
            $content = preg_replace('/(name=[\'|\"]formhash[\'|\"] value=[\'\"]|formhash=)('.constant("FORMHASH").')/ismU', '${1}'.$temp_formhash, $content);
            $temp_siteurl = 'siteurl_'.substr($temp_md5, 16, 8);
            $content = preg_replace('/("|\')('.preg_quote($_G['siteurl'], '/').')/ismU', '${1}'.$temp_siteurl, $content);
            $content = empty($content) ? ob_get_contents() : $content;
            file_put_contents(CACHE_FILE, $content, LOCK_EX); // 写入缓存文件
            chmod(CACHE_FILE, 0777); // 修改缓存文件权限
      }
    }

    // 输出调试信息
    if(defined('DISCUZ_DEBUG') && DISCUZ_DEBUG && @include(libfile('function/debug'))) {
      function_exists('debugmessage') && debugmessage();
    }
}

/**
* 输出替换函数
* 本函数用于根据配置替换输出内容中的特定字符串或正则表达式。
*
* @param string $content 要处理的内容
* @return string 返回处理后的内容
*/
function output_replace($content) {
    global $_G;
    // 管理后台输出不进行替换
    if(defined('IN_MODCP') || defined('IN_ADMINCP')) return $content;

    // 字符串替换处理
    if(!empty($_G['setting']['output']['str']['search'])) {
      if(empty($_G['setting']['domain']['app']['default'])) {
            $_G['setting']['output']['str']['replace'] = str_replace('{CURHOST}', $_G['siteurl'], $_G['setting']['output']['str']['replace']);
      }
      $content = str_replace($_G['setting']['output']['str']['search'], $_G['setting']['output']['str']['replace'], $content);
    }

    // 正则表达式替换处理
    if(!empty($_G['setting']['output']['preg']['search']) && (empty($_G['setting']['rewriteguest']) || empty($_G['uid']))) {
      if(empty($_G['setting']['domain']['app']['default'])) {
            $_G['setting']['output']['preg']['search'] = str_replace('\{CURHOST\}', preg_quote($_G['siteurl'], '/'), $_G['setting']['output']['preg']['search']);
            $_G['setting']['output']['preg']['replace'] = str_replace('{CURHOST}', $_G['siteurl'], $_G['setting']['output']['preg']['replace']);
      }

      foreach($_G['setting']['output']['preg']['search'] as $key => $value) {
            $content = preg_replace_callback(
                $value,
                function ($matches) use ($_G, $key) {
                  return eval('return ' . $_G['setting']['output']['preg']['replace'][$key] . ';');
                },
                $content
            );
      }
    }

    return $content;
}
/**
* 输出AJAX内容
* 本函数获取当前输出内容,进行清理和替换,然后返回处理后的字符串。
*/
function output_ajax() {
    global $_G;
    // 获取当前输出缓冲区的内容
    $s = ob_get_contents();
    ob_end_clean(); // 清除输出缓冲区
    // 替换掉控制字符和特定字符
    $s = preg_replace("/([\\x01-\\x08\\x0b-\\x0c\\x0e-\\x1f])+/", ' ', $s);
    $s = str_replace(array(chr(0), ']]>'), array(' ', ']]>'), $s);
    // 如果处于调试模式,添加调试信息
    if(defined('DISCUZ_DEBUG') && DISCUZ_DEBUG && @include(libfile('function/debug'))) {
      function_exists('debugmessage') && $s .= debugmessage(1);
    }
    // 处理URL重写和域名设置
    $havedomain = implode('', $_G['setting']['domain']['app']);
    if($_G['setting']['rewritestatus'] || !empty($havedomain)) {
      $s = output_replace($s);
    }
    return $s; // 返回处理后的字符串
}

/**
* 执行插件钩子
* 本函数用于触发并执行插件钩子。
*
* @param string $scriptextra 额外的脚本参数
*/
function runhooks($scriptextra = '') {
    if(!defined('HOOKTYPE')) {
      define('HOOKTYPE', !defined('IN_MOBILE') ? 'hookscript' : 'hookscriptmobile');
    }
    // 触发全局插件钩子
    if(defined('CURMODULE')) {
      global $_G;
      if($_G['setting']['plugins']['func']['common']) {
            hookscript('common', 'global', 'funcs', array(), 'common');
      }
      hookscript(CURMODULE, $_G['basescript'], 'funcs', array(), '', $scriptextra);
    }
}

/**
* 执行具体的插件钩子脚本
* 本函数根据提供的参数,执行相应的插件钩子脚本。
*
* @param string $script 脚本名称
* @param string $hscript 执行环境脚本名称
* @param string $type 钩子类型
* @param array $param 传递给钩子函数的参数数组
* @param string $func 钩子函数名,为空则执行所有相关函数
* @param string $scriptextra 额外的脚本参数
*/
function hookscript($script, $hscript, $type = 'funcs', $param = array(), $func = '', $scriptextra = '') {
    global $_G;
    static $pluginclasses = array(); // 静态变量存储已加载的插件类
    // 处理特定脚本的额外逻辑
    if($hscript == 'home') {
      if($script == 'space') {
            $scriptextra = !$scriptextra ? getgpc('do') : $scriptextra;
            $script = 'space'.(!empty($scriptextra) ? '_'.$scriptextra : '');
      } elseif($script == 'spacecp') {
            $scriptextra = !$scriptextra ? getgpc('ac') : $scriptextra;
            $script .= !empty($scriptextra) ? '_'.$scriptextra : '';
      }
    }
    if(!defined('HOOKTYPE')) {
      define('HOOKTYPE', !defined('IN_MOBILE') ? 'hookscript' : 'hookscriptmobile');
    }
    // 检查是否存在该钩子的设置
    if(!isset($_G['setting'][$hscript][$script][$type])) {
      return;
    }
    // 加载插件设置
    if(!isset($_G['cache']['plugin'])) {
      loadcache('plugin');
    }
    // 循环遍历并加载所有相关插件
    foreach((array)$_G['setting'][$hscript][$script]['module'] as $identifier => $include) {
      if($_G['pluginrunlist'] && !in_array($identifier, $_G['pluginrunlist'])) {
            continue;
      }
      $hooksadminid[$identifier] = !$_G['setting'][$hscript][$script]['adminid'][$identifier] || ($_G['setting'][$hscript][$script]['adminid'][$identifier] && $_G['adminid'] > 0 && $_G['setting']['hookscript'][$hscript][$script]['adminid'][$identifier] >= $_G['adminid']);
      if($hooksadminid[$identifier]) {
            @include_once DISCUZ_ROOT.'./source/plugin/'.$include.'.class.php';
      }
    }
    // 执行钩子函数
    if(isset($_G['setting'][$hscript][$script][$type]) && is_array($_G['setting'][$hscript][$script][$type])) {
      $_G['inhookscript'] = true;
      $funcs = !$func ? $_G['setting'][$hscript][$script][$type] : array($func => $_G['setting'][$hscript][$script][$type][$func]);
      foreach($funcs as $hookkey => $hookfuncs) {
            foreach($hookfuncs as $hookfunc) {
                if($hooksadminid[$hookfunc]) {
                  $classkey = (HOOKTYPE != 'hookscriptmobile' ? '' : 'mobile').'plugin_'.($hookfunc.($hscript != 'global' ? '_'.$hscript : ''));
                  if(!class_exists($classkey, false)) {
                        continue;
                  }
                  if(!isset($pluginclasses[$classkey])) {
                        $pluginclasses[$classkey] = new $classkey;
                  }
                  if(!method_exists($pluginclasses[$classkey], $hookfunc)) {
                        continue;
                  }
                  // 调用插件方法
                  $return = call_user_func(array($pluginclasses[$classkey], $hookfunc), $param);

                  // 处理扩展钩子和更新插件钩子缓存
                  if(substr($hookkey, -7) == '_extend' && !empty($_G['setting']['pluginhooks'][$hookkey])) {
                        continue;
                  }

                  if(is_array($return)) {
                        // 更新插件钩子缓存
                        if(!isset($_G['setting']['pluginhooks'][$hookkey]) || is_array($_G['setting']['pluginhooks'][$hookkey])) {
                            foreach($return as $k => $v) {
                              $_G['setting']['pluginhooks'][$hookkey][$k] .= $v;
                            }
                        } else {
                            foreach($return as $k => $v) {
                              $_G['setting']['pluginhooks'][$hookkey][$k] = $v;
                            }
                        }
                  } else {
                        // 单个字符串返回的处理
                        if(!(isset($_G['setting']['pluginhooks'][$hookkey]) && is_array($_G['setting']['pluginhooks'][$hookkey]))) {
                            if(!isset($_G['setting']['pluginhooks'][$hookkey])) {
                              $_G['setting']['pluginhooks'][$hookkey] = '';
                            }
                            $_G['setting']['pluginhooks'][$hookkey] .= $return;
                        } else {
                            foreach($_G['setting']['pluginhooks'][$hookkey] as $k => $v) {
                              $_G['setting']['pluginhooks'][$hookkey][$k] .= $return;
                            }
                        }
                  }
                }
            }
      }
    }
    $_G['inhookscript'] = false; // 重置钩子执行标志
}
/**
* 执行全局钩子脚本输出
*
* @param string $tplfile 模板文件名
*/
function hookscriptoutput($tplfile) {
    global $_G;
    // 如果已经执行过钩子脚本输出,则不再执行
    if(!empty($_G['hookscriptoutput'])) {
      return;
    }
    // 加载全局钩子脚本
    hookscript('global', 'global');
    $_G['hookscriptoutput'] = true;
    // 如果定义了当前模块,执行模块输出钩子
    if(defined('CURMODULE')) {
      $param = array('template' => $tplfile, 'message' => getglobal('hookscriptmessage'), 'values' => getglobal('hookscriptmessage'));
      hookscript(CURMODULE, $_G['basescript'], 'outputfuncs', $param);
    }
}

/**
* 根据插件ID和类型获取插件模块文件路径
*
* @param string $pluginid 插件ID
* @param string $type 插件类型
* @return string 插件模块文件的完整路径
*/
function pluginmodule($pluginid, $type) {
    global $_G;
    $pluginid = $pluginid ? preg_replace("/[^A-Za-z0-9_:]/", '', $pluginid) : '';
    // 加载插件缓存
    if(!isset($_G['cache']['plugin'])) {
      loadcache('plugin');
    }
    list($identifier, $module) = explode(':', $pluginid);
    // 检查插件是否存在
    if(!is_array($_G['setting']['plugins'][$type]) || !array_key_exists($pluginid, $_G['setting']['plugins'][$type])) {
      showmessage('plugin_nonexistence');
    }
    // 处理插件URL跳转
    if(!empty($_G['setting']['plugins'][$type][$pluginid]['url'])) {
      dheader('location: '.$_G['setting']['plugins'][$type][$pluginid]['url']);
    }
    $directory = $_G['setting']['plugins'][$type][$pluginid]['directory'];
    // 检查插件目录和模块名称是否合法
    if(empty($identifier) || !preg_match("/^+*\/$/i", $directory) || !preg_match("/^+$/i", $module)) {
      showmessage('undefined_action');
    }
    // 检查插件模块文件是否存在
    if(@!file_exists(DISCUZ_ROOT.($modfile = './source/plugin/'.$directory.$module.'.inc.php'))) {
      showmessage('plugin_module_nonexistence', '', array('mod' => $modfile));
    }
    return DISCUZ_ROOT.$modfile;
}

/**
* 根据操作更新用户积分
*
* @param string $action 操作名称
* @param int $uid 用户ID,默认为0表示全局操作
* @param array $extrasql 额外的SQL语句数组
* @param string $needle 匹配规则中的关键字
* @param int $coef 积分规则的系数
* @param int $update 是否更新用户积分,默认为1表示更新
* @param int $fid 论坛ID,默认为0
* @return mixed 更新结果
*/
function updatecreditbyaction($action, $uid = 0, $extrasql = array(), $needle = '', $coef = 1, $update = 1, $fid = 0) {
    $credit = credit::instance();
    if($extrasql) {
      $credit->extrasql = $extrasql;
    }
    return $credit->execrule($action, $uid, $needle, $coef, $update, $fid);
}

/**
* 检查操作是否低于积分下限
*
* @param string $action 操作名称
* @param int $uid 用户ID,默认为0
* @param int $coef 积分规则的系数
* @param int $fid 论坛ID,默认为0
* @param int $returnonly 是否只返回不抛出异常,默认为0,表示抛出异常
* @return mixed 检查结果
*/
function checklowerlimit($action, $uid = 0, $coef = 1, $fid = 0, $returnonly = 0) {
    require_once libfile('function/credit');
    return _checklowerlimit($action, $uid, $coef, $fid, $returnonly);
}

/**
* 批量更新用户积分
*
* @param string $action 操作名称
* @param array $uids 用户ID数组
* @param array $extrasql 额外的SQL语句数组
* @param int $coef 积分规则的系数
* @param int $fid 论坛ID,默认为0
* @return mixed 更新结果
*/
function batchupdatecredit($action, $uids = 0, $extrasql = array(), $coef = 1, $fid = 0) {
    $credit = & credit::instance();
    if($extrasql) {
      $credit->extrasql = $extrasql;
    }
    return $credit->updatecreditbyrule($action, $uids, $coef, $fid);
}

/**
* 更新成员统计数字
*
* @param array $uids 用户ID数组
* @param array $dataarr 要更新的数据数组
* @param bool $checkgroup 是否检查用户组,默认为true
* @param string $operation 操作类型
* @param int $relatedid 关联ID
* @param string $ruletxt 规则文本
* @param string $customtitle 自定义标题
* @param string $custommemo 自定义备注
* @return bool 更新结果
*/
function updatemembercount($uids, $dataarr = array(), $checkgroup = true, $operation = '', $relatedid = 0, $ruletxt = '', $customtitle = '', $custommemo = '') {
    if(!empty($uids) && (is_array($dataarr) && $dataarr)) {
      require_once libfile('function/credit');
      return _updatemembercount($uids, $dataarr, $checkgroup, $operation, $relatedid, $ruletxt, $customtitle, $custommemo);
    }
    return true;
}

/**
* 检查用户组
*
* @param int $uid 用户ID,默认为0
*/
function checkusergroup($uid = 0) {
    $credit = & credit::instance();
    $credit->checkusergroup($uid);
}

/**
* 检查公式语法正确性
*
* @param string $formula 公式字符串
* @param array $operators 运算符数组
* @param array $tokens 变量令牌数组
* @param string $values 替换值,默认为空
* @param array $funcs 函数数组
* @return bool|mixed 正确返回true,错误返回错误信息
*/
function checkformulasyntax($formula, $operators, $tokens, $values = '', $funcs = array()) {
    $var = implode('|', $tokens);

    if(!empty($formula)) {
      $formula = preg_replace("/($var)/", "\$\\1", $formula);
      return formula_tokenize($formula, $operators, $tokens, $values, $funcs);
    }
    return true;
}
/**
* 对给定的公式进行分词处理
*
* @param string $formula 待分词的公式
* @param array $operators 运算符数组
* @param array $tokens 特殊令牌数组,如变量前缀等
* @param string|array $values 可接受的字符串或字符串数组值
* @param array $funcs 可接受的函数名数组
* @return bool 分词成功返回true,否则返回false
*/
function formula_tokenize($formula, $operators, $tokens, $values, $funcs) {
    // 将公式封装成PHP代码后进行token解析
    $fexp = token_get_all('<?php '.$formula);
    $prevseg = 1; // 上一个段落标记:1左括号, 2右括号, 3变量, 4运算符, 5函数
    $isclose = 0; // 括号是否匹配
    $tks = implode('|', $tokens); // 将令牌数组合并为一个正则表达式方便匹配
    $op1 = $op2 = array(); // 分别存储单字符和双字符运算符
    foreach($operators as $orts) {
      if(strlen($orts) === 1) {
            $op1[] = $orts;
      } else {
            $op2[] = $orts;
      }
    }
    foreach($fexp as $k => $val) {
      if(is_array($val)) {
            // 处理变量、字符串、数字等
            if(in_array($val, array(T_VARIABLE, T_CONSTANT_ENCAPSED_STRING, T_LNUMBER, T_DNUMBER))) {
                if(!in_array($prevseg, array(1, 4))) {
                  return false;
                }
                $prevseg = 3;
                // 检查变量是否符合要求
                if($val == T_VARIABLE && !preg_match('/^\$('.$tks.')$/', $val)) {
                  return false;
                }
                // 检查字符串是否符合给定的值
                if($val == T_CONSTANT_ENCAPSED_STRING && !($values && preg_match('/^'.$values.'$/', $val))) {
                  return false;
                }
            } elseif($val == T_STRING && in_array($val, $funcs)) {
                // 处理函数
                if(!in_array($prevseg, array(1, 4))) {
                  return false;
                }
                $prevseg = 5;
            } elseif($val == T_WHITESPACE || ($k == 0 && $val == T_OPEN_TAG)) {
                // 忽略空白字符和开头的T_OPEN_TAG
            } elseif(in_array($val, $op2)) {
                // 处理双字符运算符
                if(!in_array($prevseg, array(2, 3))) {
                  return false;
                }
                $prevseg = 4;
            } else {
                return false;
            }
      } else {
            // 处理括号和单字符运算符
            if($val === '(') {
                if(!in_array($prevseg, array(1, 4, 5))) {
                  return false;
                }
                $prevseg = 1;
                $isclose++;
            } elseif($val === ')') {
                if(!in_array($prevseg, array(2, 3))) {
                  return false;
                }
                $prevseg = 2;
                $isclose--;
                if($isclose < 0) {
                  return false;
                }
            } elseif(in_array($val, $op1)) {
                // 处理单字符运算符,特别处理负号情况
                if(!in_array($prevseg, array(2, 3)) && $val !== '-') {
                  return false;
                }
                $prevseg = 4;
            } else {
                return false;
            }
      }
    }
    // 检查括号是否匹配,上一个段落标记是否正确
    return (in_array($prevseg, array(2, 3)) && $isclose === 0);
}

/**
* 检查公式的语法信用
*
* @param string $formula 待检查的公式
* @return bool 语法检查通过返回true,否则返回false
*/
function checkformulacredits($formula) {
    return checkformulasyntax(
      $formula,
      array('+', '-', '*', '/'),
      array('extcredits', 'digestposts', 'posts', 'threads', 'oltime', 'friends', 'doings', 'polls', 'blogs', 'albums', 'sharings')
    );
}

/**
* 页面调试信息输出
*
* @param mixed $var 要调试的变量,默认为null,如果为null则输出整个页面变量
* @param bool $vardump 是否使用var_dump输出,默认为false,使用var_dump需要设置为true
*/
function debug($var = null, $vardump = false) {
    echo '<pre>';
    $vardump = empty($var) ? true : $vardump;
    if($vardump) {
      var_dump($var);
    } else {
      print_r($var);
    }
    exit();
}

/**
* 获取调试信息
*
* @global array $_G 全局变量数组
* @return bool 如果启用了调试模式返回调试信息,否则返回false
*/
function debuginfo() {
    global $_G;
    if(getglobal('setting/debug')) {
      $_G['debuginfo'] = array(
            'time' => number_format((microtime(true) - $_G['starttime']), 6),
            'queries' => DB::object()->querynum,
            'memory' => ucwords(C::memory()->type)
      );
      if(DB::object()->slaveid) {
            $_G['debuginfo']['queries'] = 'Total '.DB::object()->querynum.', Slave '.DB::object()->slavequery;
      }
      return TRUE;
    } else {
      return FALSE;
    }
}
/**
* 获取指定模块的随机焦点图片ID
*
* @param string $module 模块名称
* @return null|mixed 返回随机焦点图片的ID,若未设置或不存在则返回null
*/
function getfocus_rand($module) {
      global $_G;

      // 检查焦点设置是否存在且指定模块有效,以及用户是否关闭了焦点图片显示
      if(empty($_G['setting']['focus']) || !array_key_exists($module, $_G['setting']['focus']) || !empty($_G['cookie']['nofocus_'.$module]) || !$_G['setting']['focus'][$module]) {
                return null;
      }
      loadcache('focus'); // 加载焦点缓存
      if(empty($_G['cache']['focus']['data']) || !is_array($_G['cache']['focus']['data'])) {
                return null;
      }
      // 随机获取一个焦点图片ID
      $focusid = $_G['setting']['focus'][$module]['focus'][$module])];
      return $focusid;
}

/**
* 校验验证码
*
* @param string $value 用户输入的验证码值
* @param string $idhash 验证码ID哈希值
* @param int $fromjs 是否来自JS提交,默认为0(非JS)
* @param string $modid 模块ID,默认为空
* @param bool $verifyonly 是否只进行验证码校验,默认为false
* @return mixed 返回校验结果
*/
function check_seccode($value, $idhash, $fromjs = 0, $modid = '', $verifyonly = false) {
      return helper_seccheck::check_seccode($value, $idhash, $fromjs, $modid, $verifyonly);
}

/**
* 校验QAA安全问题
*
* @param string $value 用户输入的安全问题答案
* @param string $idhash 安全问题ID哈希值
* @param bool $verifyonly 是否只进行安全问题校验,默认为false
* @return mixed 返回校验结果
*/
function check_secqaa($value, $idhash, $verifyonly = false) {
      return helper_seccheck::check_secqaa($value, $idhash, $verifyonly);
}

/**
* 执行安全检查
*
* @param string $rule 安全检查规则
* @param array $param 传递给规则的参数,默认为空数组
* @return mixed 返回安全检查结果
*/
function seccheck($rule, $param = array()) {
      return helper_seccheck::seccheck($rule, $param);
}

/**
* 生成验证码
*
* @param string $seccode 验证码内容,默认为空
* @return string 返回生成的验证码
*/
function make_seccode($seccode = '') {
      return helper_seccheck::make_seccode($seccode);
}

/**
* 生成QAA安全问题
*
* @return string 返回生成的安全问题
*/
function make_secqaa() {
      return helper_seccheck::make_secqaa();
}

/**
* 显示广告
*
* @param string $parameter 广告参数
* @return string 返回广告内容或空字符串
*/
function adshow($parameter) {
      global $_G;
      // 判断是否在AJAX请求中或用户组关闭了广告显示
      if(getgpc('inajax') || $_G['group']['closead']) {
                return;
      }
      $return = (isset($_G['config']['plugindeveloper']) && $_G['config']['plugindeveloper'] == 2) ? '<hook></hook>' : '';
      $params = explode('/', $parameter);
      $customid = 0;
      $customc = explode('_', $params);
      // 处理自定义广告
      if($customc == 'custom') {
                $params = $customc;
                $customid = $customc;
      }
      $adcontent = null;
      // 检查广告类型是否设置
      if(empty($_G['setting']['advtype']) || !in_array($params, $_G['setting']['advtype'])) {
                $adcontent = '';
      }
      if($adcontent === null) {
                loadcache('advs'); // 加载广告缓存
                $adids = array();
                $evalcode = &$_G['cache']['advs']['evalcode'][$params];
                $parameters = &$_G['cache']['advs']['parameters'][$params];
                $codes = &$_G['cache']['advs']['code'][$_G['basescript']][$params];
                // 评估并选择合适的广告进行显示
                if(!empty($codes)) {
                        foreach($codes as $adid => $code) {
                              $parameter = &$parameters[$adid];
                              $checked = true;
                              @eval($evalcode['check']);
                              if($checked) {
                                        $adids[] = $adid;
                              }
                        }
                        if(!empty($adids)) {
                              $adcode = $extra = '';
                              @eval($evalcode['create']);
                              if(empty($notag)) {
                                        $adcontent = '<div'.($params != '' ? ' class="'.$params.'"' : '').$extra.'>'.$adcode.'</div>';
                              } else {
                                        $adcontent = $adcode;
                              }
                        }
                }
      }
      $adfunc = 'ad_'.$params;
      $_G['setting']['pluginhooks'][$adfunc] = null;
      // 执行插件钩子
      hookscript('ad', 'global', 'funcs', array('params' => $params, 'content' => $adcontent, 'customid' => $customid), $adfunc);
      if(empty($_G['setting']['hookscript']['global']['ad']['funcs'][$adfunc])) {
                hookscript('ad', $_G['basescript'], 'funcs', array('params' => $params, 'content' => $adcontent, 'customid' => $customid), $adfunc);
      }
      return $return.($_G['setting']['pluginhooks'][$adfunc] === null ? $adcontent : $_G['setting']['pluginhooks'][$adfunc]);
}

/**
* 显示消息并跳转
*
* @param string $message 要显示的消息
* @param string $url_forward 跳转的URL
* @param array $values 传递给消息页面的变量
* @param array $extraparam 额外的参数
* @param int $custom 自定义参数
* @return string 返回消息显示和跳转的HTML代码
*/
function showmessage($message, $url_forward = '', $values = array(), $extraparam = array(), $custom = 0) {
      require_once libfile('function/message');
      return dshowmessage($message, $url_forward, $values, $extraparam, $custom);
}

/**
* 检查提交的变量是否合法
*
* @param string $var 要检查的变量名
* @param int $allowget 是否允许通过GET方式提交
* @param int $seccodecheck 是否检查验证码
* @param int $secqaacheck 是否检查安全问题
* @return bool 如果检查通过返回TRUE,否则返回FALSE
*/
function submitcheck($var, $allowget = 0, $seccodecheck = 0, $secqaacheck = 0) {
      if(!getgpc($var)) {
                return FALSE;
      } else {
                return helper_form::submitcheck($var, $allowget, $seccodecheck, $secqaacheck);
      }
}

/**
* 生成分页链接
*
* @param int $num 总数量
* @param int $perpage 每页数量
* @param int $curpage 当前页码
* @param string $mpurl 分页跳转的URL
* @param int $maxpages 最大显示页数
* @param int $page 显示的页码数
* @param bool $autogoto 是否自动跳转到当前页
* @param bool $simple 是否为简单分页模式
* @param bool $jsfunc 是否通过JS函数处理分页
* @return string 返回分页HTML代码
*/
function multi($num, $perpage, $curpage, $mpurl, $maxpages = 0, $page = 10, $autogoto = FALSE, $simple = FALSE, $jsfunc = FALSE) {
      return $num > $perpage ? helper_page::multi($num, $perpage, $curpage, $mpurl, $maxpages, $page, $autogoto, $simple, $jsfunc) : '';
}

/**
* 生成简单分页链接
*
* @param int $num 总数量
* @param int $perpage 每页数量
* @param int $curpage 当前页码
* @param string $mpurl 分页跳转的URL
* @return string 返回分页HTML代码
*/
function simplepage($num, $perpage, $curpage, $mpurl) {
      return helper_page::simplepage($num, $perpage, $curpage, $mpurl);
}

/**
* 检查并过滤敏感词
*
* @param string $message 要检查的消息
* @param string $modword 指定的敏感词列表
* @param bool $return 是否返回过滤后的消息
* @param bool $modasban 是否将含有敏感词的帖子默认禁言
* @return mixed 根据$return参数返回过滤后的消息或TRUE/FALSE
*/
function censor($message, $modword = NULL, $return = FALSE, $modasban = TRUE) {
      return helper_form::censor($message, $modword, $return, $modasban);
}

/**
* 检测消息是否包含敏感词
*
* @param string $message 要检查的消息
* @return bool 如果消息包含敏感词返回FALSE,否则返回TRUE
*/
function censormod($message) {
      return getglobal('group/ignorecensor') || !$message ? false :helper_form::censormod($message);
}

/**
* 合并用户空间数据
*
* @param array &$values 要合并的数据数组
* @param string $tablename 数据表名
* @param bool $isarchive 是否为归档数据
* @global array $_G 全局变量数组
* @return void
*/
function space_merge(&$values, $tablename, $isarchive = false) {
      global $_G;

      $uid = empty($values['uid'])?$_G['uid']:$values['uid'];
      $var = "member_{$uid}_{$tablename}";
      if($uid) {
                if(!isset($_G[$var])) {
                        $ext = $isarchive ? '_archive' : '';
                        if(($_G[$var] = C::t('common_member_'.$tablename.$ext)->fetch($uid)) !== false) {
                              if($tablename == 'field_home') {
                                        // 处理个人空间字段的特殊逻辑
                                        $_G['setting']['privacy'] = empty($_G['setting']['privacy']) ? array() : (is_array($_G['setting']['privacy']) ? $_G['setting']['privacy'] : dunserialize($_G['setting']['privacy']));
                                        $_G[$var]['privacy'] = empty($_G[$var]['privacy']) ? array() : (is_array($_G[$var]['privacy']) ? $_G[$var]['privacy'] : dunserialize($_G[$var]['privacy']));
                                        foreach (array('feed','view','profile') as $pkey) {
                                                if(empty($_G[$var]['privacy'][$pkey]) && !isset($_G[$var]['privacy'][$pkey])) {
                                                      $_G[$var]['privacy'][$pkey] = isset($_G['setting']['privacy'][$pkey]) ? $_G['setting']['privacy'][$pkey] : array();
                                                }
                                        }
                                        $_G[$var]['acceptemail'] = empty($_G[$var]['acceptemail'])? array() : dunserialize($_G[$var]['acceptemail']);
                                        if(empty($_G[$var]['acceptemail'])) {
                                                $_G[$var]['acceptemail'] = empty($_G['setting']['acceptemail'])?array():dunserialize($_G['setting']['acceptemail']);
                                        }
                              }
                        } else {
                              C::t('common_member_'.$tablename.$ext)->insert(array('uid'=>$uid));
                              $_G[$var] = array();
                        }
                }
                $values = array_merge($values, $_G[$var]);
      }
}

/**
* 记录运行日志
*
* @param string $file 日志文件名
* @param string $message 要记录的消息
* @param int $halt 是否停止执行
* @return void
*/
function runlog($file, $message, $halt=0) {
      helper_log::runlog($file, $message, $halt);
}

/**
* 去除搜索关键词中的特殊字符
*
* @param string $string 搜索关键词
* @return string 处理后的关键词
*/
function stripsearchkey($string) {
      $string = trim($string);
      $string = str_replace('*', '%', addcslashes($string, '%_'));
      return $string;
}

/**
* 创建目录及其子目录
*
* @param string $dir 要创建的目录路径
* @param int $mode 目录权限
* @param bool $makeindex 是否创建index文件
* @return bool 创建成功返回true,否则返回false
*/
function dmkdir($dir, $mode = 0777, $makeindex = TRUE){
      if(!is_dir($dir)) {
                dmkdir(dirname($dir), $mode, $makeindex);
                @mkdir($dir, $mode);
                if(!empty($makeindex)) {
                        @touch($dir.'/index.html'); @chmod($dir.'/index.html', 0777);
                }
      }
      return true;
}
/**
* 获取并处理引用地址
*
* 本函数用于获取并处理当前的引用地址(即来源地址)。如果引用地址不符合特定条件,
* 则会返回一个默认地址。处理过程包括去除查询字符串、检查是否为登录页面、验证域名等。
*
* @param string $default 默认的引用地址,若为空且当前应用环境定义了'curapp'则默认为'curapp.php'
* @return string 处理后的引用地址
*/
function dreferer($default = '') {
      global $_G;

      // 初始化默认值
      $default = empty($default) && $_ENV['curapp'] ? $_ENV['curapp'].'.php' : '';
      // 获取并处理GET参数中的引用地址或HTTP头部中的引用地址
      $_G['referer'] = !empty($_GET['referer']) ? $_GET['referer'] : $_SERVER['HTTP_REFERER'];
      // 去除引用地址中的查询字符串
      $_G['referer'] = substr($_G['referer'], -1) == '?' ? substr($_G['referer'], 0, -1) : $_G['referer'];

      // 如果引用地址是登录页面,则使用默认地址
      if(strpos($_G['referer'], 'member.php?mod=logging')) {
                $_G['referer'] = $default;
      }

      // 解析引用地址的URL
      $reurl = parse_url($_G['referer']);
      // 构造带有端口的主机地址
      $hostwithport = $reurl['host'] . (isset($reurl['port']) ? ':' . $reurl['port'] : '');

      // 验证引用地址的有效性
      if(!$reurl || (isset($reurl['scheme']) && !in_array(strtolower($reurl['scheme']), array('http', 'https')))) {
                $_G['referer'] = '';
      }

      // 处理跨域引用的情况
      if(!empty($hostwithport) && !in_array($hostwithport, array($_SERVER['HTTP_HOST'], 'www.'.$_SERVER['HTTP_HOST'])) && !in_array($_SERVER['HTTP_HOST'], array($hostwithport, 'www.'.$hostwithport))) {
                if(!in_array($hostwithport, $_G['setting']['domain']['app']) && !isset($_G['setting']['domain']['list'][$hostwithport])) {
                        $domainroot = substr($hostwithport, strpos($hostwithport, '.')+1);
                        if(empty($_G['setting']['domain']['root']) || (is_array($_G['setting']['domain']['root']) && !in_array($domainroot, $_G['setting']['domain']['root']))) {
                              $_G['referer'] = $_G['setting']['domain']['defaultindex'] ? $_G['setting']['domain']['defaultindex'] : 'index.php';
                        }
                }
      } elseif(empty($hostwithport)) {
                // 修正不带域名的引用地址
                $_G['referer'] = $_G['siteurl'].'./'.$_G['referer'];
      }

      // 对处理后的引用地址进行URL编码
      $_G['referer'] = durlencode($_G['referer']);
      return $_G['referer'];
}

/**
* 执行FTP命令
*
* 本函数用于通过FTP客户端执行指定的FTP命令。支持的命令包括上传、删除文件以及连接关闭等。
*
* @param string $cmd 要执行的FTP命令
* @param string $arg1 传递给FTP命令的参数,具体取决于命令类型
* @return mixed 执行结果,具体取决于FTP命令
*/
function ftpcmd($cmd, $arg1 = '') {
      static $ftp;
      $ftpconfig = getglobal('setting/ftp');
      // 判断FTP配置是否启用以及FTP客户端是否已初始化
      if(empty($ftpconfig['on']) || empty($ftpconfig['host'])) {
                // FTP未启用或未配置返回错误码或0
                return $cmd == 'error' ? -101 : 0;
      } elseif($ftp == null) {
                // FTP客户端初始化
                $ftp = & discuz_ftp::instance();
      }
      if(!$ftp->enabled) {
                // FTP客户端未启用返回错误信息
                return $ftp->error();
      } elseif($ftp->enabled && !$ftp->connectid) {
                // FTP连接未建立则建立连接
                $ftp->connect();
      }
      switch ($cmd) {
                // 根据命令类型执行相应的操作
                case 'upload' : return $ftp->upload(getglobal('setting/attachdir').'/'.$arg1, $arg1); break;
                case 'delete' : return $ftp->ftp_delete($arg1); break;
                case 'close': return $ftp->ftp_close(); break;
                case 'error': return $ftp->error(); break;
                case 'object' : return $ftp; break;
                default       : return false;
      }

}

/**
* 检查文件上传权限
*
* 本函数用于检查特定文件扩展名和文件大小是否符合FTP上传的规则设置。
*
* @param string $fileext 文件扩展名
* @param int $filesize 文件大小(以字节为单位)
* @return bool 文件是否具有上传权限
*/
function ftpperm($fileext, $filesize) {
      global $_G;
      $return = false;
      if($_G['setting']['ftp']['on']) {
                // 检查文件扩展名和文件大小是否符合设置要求
                if(((!$_G['setting']['ftp']['allowedexts'] && !$_G['setting']['ftp']['disallowedexts']) || ($_G['setting']['ftp']['allowedexts'] && in_array($fileext, $_G['setting']['ftp']['allowedexts'])) || ($_G['setting']['ftp']['disallowedexts'] && !in_array($fileext, $_G['setting']['ftp']['disallowedexts']) && (!$_G['setting']['ftp']['allowedexts'] || $_G['setting']['ftp']['allowedexts'] && in_array($fileext, $_G['setting']['ftp']['allowedexts'])))) && (!$_G['setting']['ftp']['minsize'] || $filesize >= $_G['setting']['ftp']['minsize'] * 1024)) {
                        $return = true;
                }
      }
      return $return;
}
/**
* 将字符串从一个字符集转换到另一个字符集。
*
* @param string $str 需要转换的字符串。
* @param string $in_charset 输入字符串的字符集。
* @param string $out_charset 输出字符串的字符集,默认为全局字符集。
* @param bool $ForceTable 是否强制使用转换表,默认为不强制。
* @return string 转换后的字符串。
*/
function diconv($str, $in_charset, $out_charset = CHARSET, $ForceTable = FALSE) {
      global $_G;

      $in_charset = strtoupper($in_charset); // 将输入字符集转换为大写
      $out_charset = strtoupper($out_charset); // 将输出字符集转换为大写

      // 如果输入字符串为空或字符集相同,则直接返回原字符串
      if(empty($str) || $in_charset == $out_charset) {
                return $str;
      }

      $out = ''; // 初始化输出字符串

      // 如果不强制使用转换表,则尝试使用iconv或mb_convert_encoding进行转换
      if(!$ForceTable) {
                if(function_exists('iconv')) {
                        $out = iconv($in_charset, $out_charset.'//IGNORE', $str);
                } elseif(function_exists('mb_convert_encoding')) {
                        $out = mb_convert_encoding($str, $out_charset, $in_charset);
                }
      }

      // 如果上述方法都未能成功转换,则使用Chinese类进行转换
      if($out == '') {
                $chinese = new Chinese($in_charset, $out_charset, true);
                $out = $chinese->Convert($str);
      }

      return $out; // 返回转换后的字符串
}

/**
* 自动调整宽度的开关状态判定。
*
* @return int 返回宽度自动调整的状态:0-关闭,1-开启。
*/
function widthauto() {
      global $_G;
      // 若已明确禁用宽度自动调整,则直接返回0
      if($_G['disabledwidthauto']) {
                return 0;
      }
      // 检查是否已有宽度自动调整的设置
      if(!empty($_G['widthauto'])) {
                return $_G['widthauto'] > 0 ? 1 : 0;
      }
      // 检查cookie中是否有宽度自动调整的设置
      if($_G['setting']['switchwidthauto'] && !empty($_G['cookie']['widthauto'])) {
                return $_G['cookie']['widthauto'] > 0 ? 1 : 0;
      } else {
                // 默认返回宽度自动调整的配置状态
                return $_G['setting']['allowwidthauto'] ? 0 : 1;
      }
}

/**
* 对数组中的数值进行重新分配和归类。
*
* @param array $array 需要处理的数组,其值为数字。
* @return array 返回一个包含两个数组的数组:第一个数组为数值数组,第二个数组为数值对应的键名数组。
*/
function renum($array) {
      $newnums = $nums = array();
      foreach ($array as $id => $num) { // 遍历数组,重新组织数据
                $newnums[$num][] = $id;
                $nums[$num] = $num;
      }
      return array($nums, $newnums);
}

/**
* 根据文件大小返回带单位的可读大小。
*
* @param int $size 文件大小,单位为字节。
* @return string 返回格式化后的文件大小字符串,单位为GB、MB、KB或Bytes。
*/
function sizecount($size) {
      // 分别对应GB、MB、KB,如果小于1KB则显示为Bytes
      if($size >= 1073741824) {
                $size = round($size / 1073741824 * 100) / 100 . ' GB';
      } elseif($size >= 1048576) {
                $size = round($size / 1048576 * 100) / 100 . ' MB';
      } elseif($size >= 1024) {
                $size = round($size / 1024 * 100) / 100 . ' KB';
      } else {
                $size = intval($size) . ' Bytes';
      }
      return $size;
}
/**
* 交换两个类的静态变量存储
*
* @param string $class1 第一个类名
* @param string $class2 第二个类名,默认为空字符串
* @return string 交换后的类名存储
*/
function swapclass($class1, $class2 = '') {
    static $swapc = null;// 静态变量存储,用于记录上一次交换的类名
    // 判断并进行类名交换
    $swapc = isset($swapc) && $swapc != $class1 ? $class1 : $class2;
    return $swapc;
}

/**
* 写入日志
*
* @param string $file 日志文件名
* @param string $log 日志内容
*/
function writelog($file, $log) {
    // 调用helper_log类的writelog方法,进行日志写入
    helper_log::writelog($file, $log);
}

/**
* 获取状态值中某一位的状态
*
* @param int $status 总的状态值
* @param int $position 指定的状态位
* @return int 指定状态位的状态(1或0)
*/
function getstatus($status, $position) {
    $t = (int)$status & pow(2, (int)$position - 1) ? 1 : 0; // 通过位运算获取指定状态位的值
    return $t;
}

/**
* 设置状态值中某一位的状态
*
* @param int $position 指定的状态位
* @param int $value 指定状态位的新值
* @param int $baseon 基础状态值,默认为null
* @return int 更新后的状态值
*/
function setstatus($position, $value, $baseon = null) {
    $t = pow(2, $position - 1); // 计算指定状态位的掩码
    if($value) {
      $t = $baseon | $t; // 设置指定状态位为1
    } elseif ($baseon !== null) {
      $t = $baseon & ~$t; // 清除指定状态位为0
    } else {
      $t = ~$t; // 取反以设置所有位,除了指定状态位
    }
    return $t & 0xFFFF; // 保证返回的状态值在16位范围内
}

/**
* 添加通知
*
* @param int $touid 接收通知的用户ID
* @param string $type 通知类型
* @param string $note 通知内容
* @param array $notevars 通知内容中的变量数组,默认为空数组
* @param int $system 是否为系统通知,默认为0
* @return mixed 添加结果,通常为布尔值或特定的标识符
*/
function notification_add($touid, $type, $note, $notevars = array(), $system = 0) {
    return helper_notification::notification_add($touid, $type, $note, $notevars, $system);
}

/**
* 添加管理通知
*
* @param string $type 通知类型
* @param int $from_num 发送方数量
* @param array $langvar 语言变量数组
*/
function manage_addnotify($type, $from_num = 0, $langvar = array()) {
    helper_notification::manage_addnotify($type, $from_num, $langvar);
}

/**
* 发送私信
*
* @param int $toid 接收私信的用户ID
* @param string $subject 私信主题
* @param string $message 私信内容
* @param string $fromid 发送私信的用户ID,默认为空字符串
* @param int $replypmid 回复的私信ID,默认为0
* @param int $isusername 是否使用用户名作为发送者,默认为0
* @param int $type 私信类型,默认为0
* @return mixed 发送结果,通常为布尔值或特定的标识符
*/
function sendpm($toid, $subject, $message, $fromid = '', $replypmid = 0, $isusername = 0, $type = 0) {
    return helper_pm::sendpm($toid, $subject, $message, $fromid, $replypmid, $isusername, $type);
}

/**
* 获取用户组图标
*
* @param string $groupid 用户组ID
* @param int $return 是否返回图标HTML,默认为0(即直接输出)
*/
function g_icon($groupid, $return = 0) {
    global $_G;
    // 判断用户组图标是否存在
    if(empty($_G['cache']['usergroups'][$groupid]['icon'])) {
      $s ='';
    } else {
      // 根据图标地址生成完整的HTML标签
      if(preg_match('/^https?:\/\//is', $_G['cache']['usergroups'][$groupid]['icon'])) {
            $s = '<img src="'.$_G['cache']['usergroups'][$groupid]['icon'].'" alt="" class="vm" />';
      } else {
            $s = '<img src="'.$_G['setting']['attachurl'].'common/'.$_G['cache']['usergroups'][$groupid]['icon'].'" alt="" class="vm" />';
      }
    }
    // 根据$return参数决定是返回还是输出图标HTML
    if($return) {
      return $s;
    } else {
      echo $s;
    }
}
/**
* 更新DIY模板
* @param string $targettplname 目标模板名称
* @param string $tpldirectory 模板目录
* @return boolean 更新结果,成功返回true,失败返回false
*/
function updatediytemplate($targettplname = '', $tpldirectory = '') {
    $r = false;
    $alldata = !empty($targettplname) ? array( C::t('common_diy_data')->fetch_diy($targettplname, $tpldirectory)) : C::t('common_diy_data')->range();
    require_once libfile('function/portalcp');
    foreach($alldata as $value) {
      $r = save_diy_data($value['tpldirectory'], $value['primaltplname'], $value['targettplname'], dunserialize($value['diycontent']));
    }
    return $r;
}

/**
* 根据主题ID获取帖子表
* @param array $tids 主题ID数组
* @param int $primary 主表标识,默认为0
* @return string 帖子表名称
*/
function getposttablebytid($tids, $primary = 0) {
    return table_forum_post::getposttablebytid($tids, $primary);
}

/**
* 获取帖子表
* @param int $tableid 表ID,默认为0
* @param bool $prefix 表前缀,默认为false
* @return string 帖子表名称
*/
function getposttable($tableid = 0, $prefix = false) {
    return table_forum_post::getposttable($tableid, $prefix);
}

/**
* 操作缓存内存
* @param string $cmd 操作命令
* @param string|array $key 键名,对于某些命令可以是键名数组
* @param string|array $value 对于设置、添加等操作的值
* @param int $ttl 时间生存期,默认为0
* @param string $prefix 键的前缀
* @return mixed 操作结果,具体取决于执行的命令
*/
function memory($cmd, $key='', $value='', $ttl = 0, $prefix = '') {
    static $supported_command = array(
      'set', 'add', 'get', 'rm', 'inc', 'dec', 'exists',
      'incex', /* 存在时才inc */
      'sadd', 'srem', 'scard', 'smembers', 'sismember',
      'hmset', 'hgetall', 'hexists', 'hget',
      'eval',
      'zadd', 'zcard', 'zrem', 'zscore', 'zrevrange', 'zincrby', 'zrevrangewithscore' /* 带score返回 */,
      'pipeline', 'commit', 'discard'
    );

    if($cmd == 'check') {
      returnC::memory()->enable ? C::memory()->type : '';
    } elseif(C::memory()->enable && in_array($cmd, $supported_command)) {
      if(defined('DISCUZ_DEBUG') && DISCUZ_DEBUG) {
            if(is_array($key)) {
                foreach($key as $k) {
                  C::memory()->debug[$cmd][] = ($cmd == 'get' || $cmd == 'rm' || $cmd == 'add' ? $value : '').$prefix.$k;
                }
            } else {
                if ($cmd === 'hget') {
                  C::memory()->debug[$cmd][] = $prefix . $key . "->" . $value;
                } elseif ($cmd === 'eval') {
                  C::memory()->debug[$cmd][] = $key . "->" . $ttl;
                } else {
                  C::memory()->debug[$cmd][] = ($cmd == 'get' || $cmd == 'rm' || $cmd == 'add' ? $value : '').$prefix.$key;
                }
            }
      }
      switch ($cmd) {
            // 执行具体的缓存操作
            case 'set': return C::memory()->set($key, $value, $ttl, $prefix); break;
            case 'add': return C::memory()->add($key, $value, $ttl, $prefix); break;
            case 'get': return C::memory()->get($key, $value/*prefix*/); break;
            case 'rm': return C::memory()->rm($key, $value/*prefix*/); break;
            case 'exists': return C::memory()->exists($key, $value/*prefix*/); break;
            case 'inc': return C::memory()->inc($key, $value ? $value : 1, $prefix); break;
            case 'incex': return C::memory()->incex($key, $value ? $value : 1, $prefix); break;
            case 'dec': return C::memory()->dec($key, $value ? $value : 1, $prefix); break;
            case 'sadd': return C::memory()->sadd($key, $value, $prefix); break;
            case 'srem': return C::memory()->srem($key, $value, $prefix); break;
            case 'scard': return C::memory()->scard($key, $value/*prefix*/); break;
            case 'smembers': return C::memory()->smembers($key, $value/*prefix*/); break;
            case 'sismember': return C::memory()->sismember($key, $value, $prefix); break;
            case 'hmset': return C::memory()->hmset($key, $value, $prefix); break;
            case 'hgetall': return C::memory()->hgetall($key, $value/*prefix*/); break;
            case 'hexists': return C::memory()->hexists($key, $value/*field*/, $prefix); break;
            case 'hget': return C::memory()->hget($key, $value/*field*/, $prefix); break;
            case 'eval': return C::memory()->evalscript($key/*script*/, $value/*args*/, $ttl/*sha key*/, $prefix); break;
            case 'zadd': return C::memory()->zadd($key, $value, $ttl/*score*/, $prefix); break;
            case 'zrem': return C::memory()->zrem($key, $value, $prefix); break;
            case 'zscore': return C::memory()->zscore($key, $value, $prefix); break;
            case 'zcard': return C::memory()->zcard($key, $value/*prefix*/); break;
            case 'zrevrange': return C::memory()->zrevrange($key, $value/*start*/, $ttl/*end*/, $prefix); break;
            case 'zrevrangewithscore': return C::memory()->zrevrange($key, $value/*start*/, $ttl/*end*/, $prefix, true); break;
            case 'zincrby': return C::memory()->zincrby($key, $value/*member*/, $ttl ? $ttl : 1/*to increase*/, $prefix); break;
            case 'pipeline': return C::memory()->pipeline(); break;
            case 'commit': return C::memory()->commit(); break;
            case 'discard': return C::memory()->discard(); break;
      }
    }
    return null;
}
/**
* 检查IP是否在访问列表中
* @param string $ip 要检查的IP地址
* @param array $accesslist 访问列表,包含允许或禁止的IP范围
* @return bool 返回IP是否被允许访问
*/
function ipaccess($ip, $accesslist) {
    return ip::checkaccess($ip, $accesslist);
}

/**
* 检查IP是否被禁止
* @param string $ip 要检查的IP地址
* @return bool 返回IP是否被禁止
*/
function ipbanned($ip) {
    return ip::checkbanned($ip);
}

/**
* 根据条件获取记录数
* @param string $tablename 表名
* @param string|array $condition 查询条件,可以是字符串或条件数组
* @return int 返回符合条件的记录数
*/
function getcount($tablename, $condition) {
    // 根据条件构建SQL WHERE子句
    if(empty($condition)) {
      $where = '1';
    } elseif(is_array($condition)) {
      $where = DB::implode_field_value($condition, ' AND ');
    } else {
      $where = $condition;
    }
    // 执行SQL查询并返回记录数
    $ret = intval(DB::result_first("SELECT COUNT(*) AS num FROM ".DB::table($tablename)." WHERE $where"));
    return $ret;
}

/**
* 显示系统消息
* @param string $message 要显示的消息内容
*/
function sysmessage($message) {
    helper_sysmessage::show($message);
}

/**
* 检查用户组权限
* @param string $permstr 权限字符串
* @param int $groupid 用户组ID,默认为0
* @return bool 返回用户组是否有对应的权限
*/
function forumperm($permstr, $groupid = 0) {
    global $_G;
    $groupidarray = array($_G['groupid']);
    // 如果指定用户组ID,检查该用户组是否有权限
    if($groupid) {
      return preg_match("/(^|\t)(".$groupid.")(\t|$)/", $permstr);
    }
    // 构建用户所属用户组ID数组
    $groupterms = dunserialize(getuserprofile('groupterms'));
    foreach(explode("\t", $_G['member']['extgroupids']) as $extgroupid) {
      if($extgroupid = intval(trim($extgroupid))) {
            if($groupterms['ext'][$extgroupid] && $groupterms['ext'][$extgroupid] < TIMESTAMP){
                continue;
            }
            $groupidarray[] = $extgroupid;
      }
    }
    // 检查验证组权限
    if($_G['setting']['verify']['enabled']) {
      getuserprofile('verify1');
      foreach($_G['setting']['verify'] as $vid => $verify) {
            if($verify['available'] && $_G['member']['verify'.$vid] == 1) {
                $groupidarray[] = 'v'.$vid;
            }
      }
    }
    return preg_match("/(^|\t)(".implode('|', $groupidarray).")(\t|$)/", $permstr);
}

/**
* 检查用户权限
* @param string $perm 权限标识
* @return bool 返回用户是否具有该权限
*/
function checkperm($perm) {
    global $_G;
    // 在后台则直接返回true,否则检查用户组权限设置
    return defined('IN_ADMINCP') ? true : (empty($_G['group'][$perm])?'':$_G['group'][$perm]);
}
/**
* 检查特定时间段内用户是否有权限发帖或执行某些操作
*
* @param string $periods 指定的时期类型,如 'postmodperiods' 或 'postbanperiods'
* @param int $showmessage 当检查失败时,是否显示错误消息。1为显示,其他为不显示。
* @return bool 返回检查结果,如果通过检查返回false,否则返回true。
*/
function periodscheck($periods, $showmessage = 1) {
      global $_G;
      // 检查是否忽略特定IP或地区发帖限制
      if(($periods == 'postmodperiods' || $periods == 'postbanperiods') && (getglobal('setting/postignorearea') || getglobal('setting/postignoreip'))) {
                // 检查IP是否在忽略列表中
                if($_G['setting']['postignoreip']) {
                        foreach(explode("\n", $_G['setting']['postignoreip']) as $ctrlip) {
                              if(preg_match("/^(".preg_quote(($ctrlip = trim($ctrlip)), '/').")/", $_G['clientip'])) {
                                        return false;
                                        break;
                              }
                        }
                }
                // 检查地区是否在忽略列表中
                if($_G['setting']['postignorearea']) {
                        $location = $whitearea = '';
                        require_once libfile('function/misc');
                        $location = trim(convertip($_G['clientip']));
                        if($location) {
                              $whitearea = preg_quote(trim($_G['setting']['postignorearea']), '/');
                              $whitearea = str_replace(array("\\*"), array('.*'), $whitearea);
                              $whitearea = '.*'.$whitearea.'.*';
                              $whitearea = '/^('.str_replace(array("\r\n", ' '), array('.*|.*', ''), $whitearea).')$/i';
                              if(@preg_match($whitearea, $location)) {
                                        return false;
                              }
                        }
                }
      }
      // 检查用户组是否受时间段控制以及是否在受控时间段内
      if(!$_G['group']['disableperiodctrl'] && $_G['setting'][$periods]) {
                $now = dgmdate(TIMESTAMP, 'G.i', $_G['setting']['timeoffset']);
                foreach(explode("\r\n", str_replace(':', '.', $_G['setting'][$periods])) as $period) {
                        list($periodbegin, $periodend) = explode('-', $period);
                        if(($periodbegin > $periodend && ($now >= $periodbegin || $now < $periodend)) || ($periodbegin < $periodend && $now >= $periodbegin && $now < $periodend)) {
                              $banperiods = str_replace("\r\n", ', ', $_G['setting'][$periods]);
                              if($showmessage) {
                                        showmessage('period_nopermission', NULL, array('banperiods' => $banperiods), array('login' => 1));
                              } else {
                                        return TRUE;
                              }
                        }
                }
      }
      return FALSE;
}

/**
* 检查新用户是否满足发帖条件
*
* @param int $return 是否返回检查结果,0为不返回,其他为返回结果。
* @return bool 如果检查通过返回true,否则根据$return参数决定是否显示错误信息并返回false。
*/
function cknewuser($return=0) {
      global $_G;

      $result = true;

      if(!$_G['uid']) return true;

      if(checkperm('disablepostctrl')) {
                return $result;
      }
      $ckuser = $_G['member'];

      // 检查新用户发帖限制
      if($_G['setting']['newbiespan'] && $_G['timestamp']-$ckuser['regdate']<$_G['setting']['newbiespan']*60) {
                if(empty($return)) showmessage('no_privilege_newbiespan', '', array('newbiespan' => $_G['setting']['newbiespan']), array());
                $result = false;
      }
      // 检查是否设置了需要验证头像的条件
      if($_G['setting']['need_avatar'] && empty($ckuser['avatarstatus'])) {
                if(empty($return)) showmessage('no_privilege_avatar', '', array(), array());
                $result = false;
      }
      // 检查是否设置了需要验证手机的条件
      if($_G['setting']['need_secmobile'] && empty($ckuser['secmobilestatus'])) {
                if(empty($return)) showmessage('no_privilege_secmobile', '', array(), array());
                $result = false;
      }
      // 检查是否设置了需要验证邮箱的条件
      if($_G['setting']['need_email'] && empty($ckuser['emailstatus'])) {
                if(empty($return)) showmessage('no_privilege_email', '', array(), array());
                $result = false;
      }
      // 检查是否设置了需要达到一定好友数的条件
      if($_G['setting']['need_friendnum']) {
                space_merge($ckuser, 'count');
                if($ckuser['friends'] < $_G['setting']['need_friendnum']) {
                        if(empty($return)) showmessage('no_privilege_friendnum', '', array('friendnum' => $_G['setting']['need_friendnum']), array());
                        $result = false;
                }
      }
      return $result;
}

/**
* 记录用户行为日志
*
* @param int $uid 用户ID
* @param string $action 用户行为描述
* @return mixed 执行结果
*/
function useractionlog($uid, $action) {
      return helper_log::useractionlog($uid, $action);
}

/**
* 获取用户行为日志
*
* @param mixed $var 变量,用于获取特定的日志信息
* @return mixed 返回用户行为日志信息
*/
function getuseraction($var) {
      return helper_log::getuseraction($var);
}

/**
* 获取用户应用信息
*
* @param int $panel 应用面板ID,默认为0
* @return string 返回用户应用信息
*/
function getuserapp($panel = 0) {
      return '';
}

/**
* 获取我的应用图标路径
*
* @param int $appid 应用ID
* @param int $iconstatus 图标状态,默认为0
* @return string 返回应用图标路径
*/
function getmyappiconpath($appid, $iconstatus=0) {
      return '';
}

/**
* 获取过期时间
*
* @return int 返回过期时间戳
*/
function getexpiration() {
      global $_G;
      $date = getdate($_G['timestamp']);
      return mktime(0, 0, 0, $date['mon'], $date['mday'], $date['year']) + 86400;
}

/**
* 将带单位的字节值转换为纯数字字节值。
* 支持的单位有:B, KB, MB, GB。
*
* @param string $val 待转换的字节值,可以带单位。
* @return int 转换后的纯数字字节值。
*/
function return_bytes($val) {
    $last = strtolower($val); // 获取并转换单位字符为小写
    if (!is_numeric($val)) {
      $val = substr(trim($val), 0, -1); // 移除单位字符,准备计算
    }
    switch($last) { // 根据单位进行转换
      case 'g': $val *= 1024;
      case 'm': $val *= 1024;
      case 'k': $val *= 1024;
    }
    return $val; // 返回转换后的字节值
}

/**
* 检查给定的主机名是否在白名单中。
*
* @param string $host 待检查的主机名。
* @return bool 如果主机名在白名单中,则返回true;否则返回false。
*/
function iswhitelist($host) {
    global $_G;
    static $iswhitelist = array(); // 静态数组用于缓存已检查的主机名结果

    if(isset($iswhitelist[$host])) {
      return $iswhitelist[$host]; // 如果已检查过该主机名,直接返回之前的结果
    }
    $hostlen = strlen($host); // 计算主机名长度
    $iswhitelist[$host] = false; // 默认设置为不在白名单中
    if(!$_G['cache']['domainwhitelist']) {
      loadcache('domainwhitelist'); // 加载白名单缓存
    }
    if(is_array($_G['cache']['domainwhitelist'])) foreach($_G['cache']['domainwhitelist'] as $val) { // 遍历白名单检查是否匹配
      $domainlen = strlen($val);
      if($domainlen > $hostlen) {
            continue; // 如果白名单中的域名长度大于待检查的主机名长度,跳过检查
      }
      if(substr($host, -$domainlen) == $val) {
            $iswhitelist[$host] = true; // 如果匹配成功,设置结果为在白名单中,并结束循环
            break;
      }
    }
    if($iswhitelist[$host] == false) {
      $iswhitelist[$host] = $host == $_SERVER['HTTP_HOST']; // 如果未在白名单中找到,检查是否与当前HTTP_HOST匹配
    }
    return $iswhitelist[$host]; // 返回检查结果
}

/**
* 根据附件ID获取附件表名称。
*
* @param int $aid 附件ID。
* @return string 返回附件存储的表名。
*/
function getattachtablebyaid($aid) {
    $attach = C::t('forum_attachment')->fetch($aid); // 通过附件ID获取附件信息
    $tableid = $attach['tableid']; // 获取附件存储的表ID
    return 'forum_attachment_'.($tableid >= 0 && $tableid < 10 ? intval($tableid) : 'unused'); // 返回附件表名称,对于无效的表ID返回'unused'
}

/**
* 根据主题ID获取附件表ID。
*
* @param string $tid 主题ID。
* @return int 返回附件存储的表ID。
*/
function getattachtableid($tid) {
    $tid = (string)$tid; // 确保主题ID为字符串类型
    return intval($tid); // 返回最后一位字符作为表ID
}

/**
* 根据主题ID获取附件表名称。
*
* @param string $tid 主题ID。
* @return string 返回附件存储的表名。
*/
function getattachtablebytid($tid) {
    return 'forum_attachment_'.getattachtableid($tid); // 调用getattachtableid函数获取表ID,并拼接成表名
}

/**
* 根据帖子ID获取附件表名称。
*
* @param int $pid 帖子ID。
* @return string 返回附件存储的表名。
*/
function getattachtablebypid($pid) {
    $tableid = DB::result_first("SELECT tableid FROM ".DB::table('forum_attachment')." WHERE pid='$pid' LIMIT 1"); // 通过帖子ID查询附件表ID
    return 'forum_attachment_'.($tableid >= 0 && $tableid < 10 ? intval($tableid) : 'unused'); // 返回附件表名称,对于无效的表ID返回'unused'
}

/**
* 为指定用户(默认为当前用户)生成一个新的附件ID。
*
* @param int $uid 用户ID,默认为0,表示当前用户。
* @return int 返回新生成的附件ID。
*/
function getattachnewaid($uid = 0) {
    global $_G;
    $uid = !$uid ? $_G['uid'] : $uid; // 如果未指定用户ID,则使用当前用户ID
    return C::t('forum_attachment')->insert(array('tid' => 0, 'pid' => 0, 'uid' => $uid, 'tableid' => 127), true); // 插入新附件记录,并返回新附件ID
}
/**
* 获取SEO设置
* @param string $page 页面名称
* @param array $data 附加数据数组
* @param array $defset 默认设置数组
* @return mixed 返回SEO设置
*/
function get_seosetting($page, $data = array(), $defset = array()) {
    return helper_seo::get_seosetting($page, $data, $defset);
}

/**
* 生成图片缩略图名称
* @param string $fileStr 原始文件名
* @param string $extend 缩略图文件扩展名,默认为'.thumb.jpg'
* @param bool $holdOldExt 是否保留原文件扩展名,默认为true
* @return string 返回缩略图文件名
*/
function getimgthumbname($fileStr, $extend='.thumb.jpg', $holdOldExt=true) {
    if(empty($fileStr)) {
      return '';
    }
    if(!$holdOldExt) {
      $fileStr = substr($fileStr, 0, strrpos($fileStr, '.'));
    }
    $extend = strstr($extend, '.') ? $extend : '.'.$extend;
    return $fileStr.$extend;
}

/**
* 更新审核状态
* @param string $idtype ID类型
* @param array/int $ids 需要更新审核状态的ID或ID数组
* @param int $status 新的审核状态,默认为0
*/
function updatemoderate($idtype, $ids, $status = 0) {
    helper_form::updatemoderate($idtype, $ids, $status);
}

/**
* 用户应用提示函数
*/
function userappprompt() {
}

/**
* 转换整数,支持处理数组
* @param mixed $int 需要转换的整数或数组
* @param bool $allowarray 是否允许输入数组,默认为false
* @return mixed 返回转换后的整数或数组
*/
function dintval($int, $allowarray = false) {
    $ret = intval($int);
    if($int == '' || $int == $ret || !$allowarray && is_array($int)) return $ret;
    if($allowarray && is_array($int)) {
      foreach($int as &$v) {
            $v = dintval($v, true);
      }
      return $int;
    } elseif($int <= 0xffffffff) {
      $l = strlen($int);
      $m = substr($int, 0, 1) == '-' ? 1 : 0;
      if(($l - $m) === strspn($int,'0987654321', $m)) {
            return $int;
      }
    }
    return $ret;
}

/**
* 生成搜索签名URL
* @return array 返回生成的URL数组
*/
function makeSearchSignUrl() {
    return array();
}

/**
* 获取相关链接
* @param string $extent 扩展参数
* @return mixed 返回相关链接
*/
function get_related_link($extent) {
    return helper_seo::get_related_link($extent);
}

/**
* 解析相关链接
* @param string $content 待解析的内容
* @param string $extent 扩展参数
* @return mixed 返回解析后的内容
*/
function parse_related_link($content, $extent) {
    return helper_seo::parse_related_link($content, $extent);
}

/**
* 检查DIY权限
* @param array $topic 主题信息数组
* @param string $flag 指定检查的权限类型
* @return bool 返回权限检查结果
*/
function check_diy_perm($topic = array(), $flag = '') {
    static $ret = array();
    if(empty($ret)) {
      global $_G;
      $common = !empty($_G['style']['tplfile']) || getgpc('inajax');
      $blockallow = getstatus(getglobal('member/allowadmincp'), 4) || getstatus(getglobal('member/allowadmincp'), 5) || getstatus(getglobal('member/allowadmincp'), 6);
      $ret['data'] = $common && $blockallow;
      $ret['layout'] = $common && (!empty($_G['group']['allowdiy']) || (
                CURMODULE === 'topic' && ($_G['group']['allowmanagetopic'] || $_G['group']['allowaddtopic'] && $topic && $topic['uid'] == $_G['uid'])
                ));
    }
    return empty($flag) ? $ret['data'] || $ret['layout'] : $ret[$flag];
}
/**
* 对字符串进行加密或解密操作
*
* @param string $string 需要进行加密或解密的字符串
* @param string $operation 操作类型,'DECODE'为解密,其他为加密,默认为'DECODE'
* @param string $key 加密解密使用的密钥,默认使用全局authkey
* @return string 返回解密后的字符串或加密后的字符串
*/
function strhash($string, $operation = 'DECODE', $key = '') {
    // 根据提供的密钥生成实际使用的密钥
    $key = md5($key != '' ? $key : getglobal('authkey'));
    if($operation == 'DECODE') {
      // 对加密字符串进行解密操作
      $hashcode = gzuncompress(base64_decode($string));
      $string = substr($hashcode, 0, -16);
      $hash = substr($hashcode, -16);
      unset($hashcode);
    }

    // 生成验证字符串的密钥
    $vkey = substr(md5($string.substr($key, 0, 16)), 4, 8).substr(md5($string.substr($key, 16, 16)), 18, 8);

    if($operation == 'DECODE') {
      // 解密操作时,验证密钥是否正确,正确则返回解密字符串,否则返回空
      return $hash == $vkey ? $string : '';
    }

    // 加密操作时,返回加密后的字符串
    return base64_encode(gzcompress($string.$vkey));
}

/**
* 尝试反序列化一个字符串,支持处理被转义的字符串
*
* @param string $data 需要反序列化的字符串
* @return mixed 反序列化后的数据,失败时返回原字符串或空数组
*/
function dunserialize($data) {
    // 如果输入就是数组,直接返回
    if(is_array($data)) {
      $ret = $data;
    } elseif(($ret = unserialize($data)) === false) {
      // 如果常规反序列化失败,尝试去除反斜杠后再次反序列化
      $ret = unserialize(stripslashes($data));
    }
    return $ret;
}

/**
* 获取浏览器版本信息
*
* @param string $type 需要获取的浏览器类型,若不指定则返回所有浏览器类型及其版本的数组
* @return mixed 返回指定浏览器类型的版本号,若未指定则返回所有浏览器类型及其版本的数组
*/
function browserversion($type = '') {
    static $return = array();
    static $types = array('ie' => 'msie', 'firefox' => '', 'chrome' => '', 'opera' => '', 'safari' => '', 'mozilla' => '', 'webkit' => '', 'maxthon' => '', 'qq' => 'qqbrowser');
    if(!$return) {
      // 初始化浏览器版本信息
      $useragent = strtolower($_SERVER['HTTP_USER_AGENT']);
      $other = 1;
      foreach($types as $i => $v) {
            $v = $v ? $v : $i;
            if(strpos($useragent, $v) !== false) {
                // 检测并记录浏览器版本
                preg_match('/'.$v.'(\/|\s)([\d\.]+)/i', $useragent, $matches);
                $ver = $matches;
                $other = $ver !== 0 && $v != 'mozilla' ? 0 : $other;
            } else {
                $ver = 0;
            }
            $return[$i] = $ver;
      }
      $return['other'] = $other;
    }
    return isset($return[$type]) ? $return[$type] : $return;
}

/**
* 获取当前语言环境
*
* @return string 返回当前语言环境的标识符
*/
function currentlang() {
    $charset = strtoupper(CHARSET);
    if($charset == 'GBK') {
      return 'SC_GBK';
    } elseif($charset == 'BIG5') {
      return 'TC_BIG5';
    } elseif($charset == 'UTF-8') {
      global $_G;
      // 根据配置确定是简体还是繁体中文环境
      if($_G['config']['output']['language'] == 'zh_cn') {
            return 'SC_UTF8';
      } elseif ($_G['config']['output']['language'] == 'zh_tw') {
            return 'TC_UTF8';
      }
    } else {
      return '';
    }
}

/**
* 根据给定的模式替换字符串。
*
* 这个函数是为了处理PHP版本兼容性问题而设计的。如果PHP版本小于7.0.0,它会使用
* PHP内置的preg_replace函数进行模式替换;如果PHP版本大于等于7.0.0,则会调用
* 自定义的_dpreg_replace函数以处理可能的preg_replace行为变化。
*
* @param string $pattern 需要匹配的模式。
* @param string $replacement 用于替换匹配到模式的字符串。
* @param string $subject 待处理的源字符串。
* @param int $limit 替换的次数限制,默认为-1,表示不限制替换次数。
* @param int &$count 替换操作执行的次数,如果提供,会在此函数执行后被设置为实际替换的次数。
* @return string 替换后的字符串。
*/
function dpreg_replace($pattern, $replacement, $subject, $limit = -1, &$count = null) {
    // 检查PHP版本,以决定使用哪个函数进行模式替换
      if(PHP_VERSION < '7.0.0') {
                return preg_replace($pattern, $replacement, $subject, $limit, $count);
      } else {
                // PHP版本大于等于7.0.0时,使用自定义的替换函数
                require_once libfile('function/preg');
                return _dpreg_replace($pattern, $replacement, $subject, $limit, $count);
      }
}


?>
页: [1]
查看完整版本: Discuz x3.5 核心文件 function_core.php 函数注释