qcminecraft/Carbon-Forum-F

View on GitHub
common.php

Summary

Maintainability
F
4 days
Test Coverage
<?php
/*
 * Carbon-Forum-F
 * https://github.com/lincanbin/Carbon-Forum
 *
 * Copyright 2006-2017 Canbin Lin (lincanbin@hotmail.com)
 * http://www.94cb.com/
 *
 * Licensed under the Apache License, Version 2.0:
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * A high performance open-source forum software written in PHP. 
 */
/*
逐渐替换为帕斯卡命名法
数据库从设计上避免使用Join多表联查
*/
define('CARBON_FORUM_VERSION', '5.9.0');

//Initialize timer
$StartTime = microtime(true);
$TimeStamp = intval($_SERVER['REQUEST_TIME']);
if ((@include __DIR__ . '/config.php') != 1) {
    //Bring user to installation
    header("Location: install/");
    exit(); //No errors
}
require(LanguagePath . 'common.php');
//Initialize PHP Data Object(Database)
require(LibraryPath . 'PDO.class.php');
require(LibraryPath . 'WhiteHTMLFilterConfig.php');
require(LibraryPath . 'WhiteHTMLFilter.php');

$DB = new Db(DBHost, DBPort, DBName, DBUser, DBPassword);
//Initialize MemCache(d) / Redis
$MCache = false;
if (EnableMemcache) {
    if (extension_loaded('memcached')) {
        //MemCached
        $MCache = new Memcached(MemCachePrefix . 'Cache');
        //Using persistent memcached connection
        if (!count($MCache->getServerList())) {
            $MCache->addServer(MemCacheHost, MemCachePort);
        }
    } elseif (extension_loaded('memcache')) {
        //MemCache
        require(LibraryPath . "MemcacheMod.class.php");
        $MCache = new MemcacheMod(MemCacheHost, MemCachePort);
    } elseif (extension_loaded('redis')) {
        //Redis
        //https://github.com/phpredis/phpredis
        $MCache = new Redis();
        $MCache->pconnect(MemCacheHost, MemCachePort);
    } elseif (extension_loaded('xcache')) {
        // XCache
        require(LibraryPath . "XCache.class.php");
        $MCache = new XCache();
    }
}

//Load configuration
$Config = array();
if ($MCache) {
    $Config = $MCache->get(MemCachePrefix . 'Config');
}
if (!$Config) {
    foreach ($DB->query('SELECT ConfigName,ConfigValue FROM ' . PREFIX . 'config') as $ConfigArray) {
        $Config[$ConfigArray['ConfigName']] = $ConfigArray['ConfigValue'];
    }
    // Update
    if ($Config['Version'] != CARBON_FORUM_VERSION) {
        header("Location: update/"); // Bring user to installation
        exit(); //No errors
    }
    if ($MCache) {
        $MCache->set(MemCachePrefix . 'Config', $Config, 86400);
    }
}
// 热门标签列表
$HotTagsArray = json_decode($Config['CacheHotTags'], true);
$HotTagsArray = $HotTagsArray ? $HotTagsArray : array();

$PHPSelf = addslashes(htmlspecialchars($_SERVER['PHP_SELF'] ? $_SERVER['PHP_SELF'] : $_SERVER['SCRIPT_NAME']));
$UrlPath = '';
//For IIS ISAPI_Rewrite
$RequestURI = str_ireplace('?' . (isset($_SERVER['QUERY_STRING']) ? $_SERVER['QUERY_STRING'] : ''), '', (isset($_SERVER['HTTP_X_REWRITE_URL']) ? $_SERVER['HTTP_X_REWRITE_URL'] : $_SERVER['REQUEST_URI']));
$IsAjax = isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) === 'xmlhttprequest';
$CurProtocol = IsSSL() ? 'https://' : 'http://';

$_HEAD = array();
$_PUT = array();
$_DELETE = array();
$_OPTIONS = array();

//消除低版本中魔术引号的影响
if (version_compare(PHP_VERSION, '5.4.0') < 0 && get_magic_quotes_gpc()) {
    function StripslashesDeep($var)
    {
        return is_array($var) ? array_map('StripslashesDeep', $var) : stripslashes($var);
    }

    $_GET = StripslashesDeep($_GET);
    $_POST = StripslashesDeep($_POST);
    $_COOKIE = StripslashesDeep($_COOKIE);
    $_REQUEST = StripslashesDeep($_REQUEST);
}


// At某人并提醒他,使用时常在其前后加空格或回车,如 “@admin ”
function AddingNotifications($Content, $TopicID, $PostID, $FilterUser = '')
{
    /*
    Type:
    1:新回复
    2:@ 到我的
    */
    global $DB, $MCache, $TimeStamp, $CurUserName;
    $InTransaction = $DB->inTransaction();//是否处于其他事务之中
    //例外列表
    $ExceptionUser = array(
        $CurUserName
    );
    if ($FilterUser != $CurUserName) {
        $ExceptionUser[] = $FilterUser;
    }
    // 正则跟用户注册、登录保持一致
    preg_match_all('/\B\@([a-zA-Z0-9\x80-\xff\-_]{4,20})/', strip_tags($Content, '<br><p>'), $out, PREG_PATTERN_ORDER);
    $TemporaryUserList = array_unique($out[1]); //排重
    $TemporaryUserList = array_diff($TemporaryUserList, $ExceptionUser);
    //对数组重新分配下标
    sort($TemporaryUserList);
    if ($TemporaryUserList) {
        try {
            if (!$InTransaction) {
                $DB->beginTransaction();
            }
            $UserList = $DB->row('SELECT ID FROM `' . PREFIX . 'users` WHERE `UserName` IN (?)', $TemporaryUserList);
            if ($UserList && count($UserList) <= 20) {
                //最多@ 20人,防止骚扰
                foreach ($UserList as $UserID) {
                    $DB->query('INSERT INTO `' . PREFIX . 'notifications`(`ID`,`UserID`, `UserName`, `Type`, `TopicID`, `PostID`, `Time`, `IsRead`) VALUES (NULL,?,?,?,?,?,?,?)', array(
                        $UserID,
                        $CurUserName,
                        2,
                        $TopicID,
                        $PostID,
                        $TimeStamp,
                        0
                    ));
                    $DB->query('UPDATE `' . PREFIX . 'users` SET `NewMention` = NewMention+1 WHERE ID = :UserID', array(
                        'UserID' => $UserID
                    ));
                    //清理内存缓存
                    if ($MCache) {
                        $MCache->delete(MemCachePrefix . 'UserInfo_' . $UserID);
                    }
                }
            }
            if (!$InTransaction) {
                $DB->commit();
            }
        } catch (Exception $ex) {
            if (!$InTransaction) {
                $DB->rollBack();
            } else {
                throw $ex;
            }
            return false;
        }
    }
    return true;
}


//提示信息
function AlertMsg($PageTitle, $Error, $StatusCode = 200)
{
    global $Lang, $CurProtocol, $RequestURI, $UrlPath, $IsAjax, $IsMobile, $IsApp, $DB, $Config, $HotTagsArray, $CurUserID, $CurUserName, $CurUserCode, $CurUserRole, $CurUserInfo, $FormHash, $StartTime, $PageMetaKeyword, $TemplatePath;
    $HttpStatuses = [
        100 => 'Continue',
        101 => 'Switching Protocols',
        102 => 'Processing',
        118 => 'Connection timed out',
        200 => 'OK',
        201 => 'Created',
        202 => 'Accepted',
        203 => 'Non-Authoritative',
        204 => 'No Content',
        205 => 'Reset Content',
        206 => 'Partial Content',
        207 => 'Multi-Status',
        208 => 'Already Reported',
        210 => 'Content Different',
        226 => 'IM Used',
        300 => 'Multiple Choices',
        301 => 'Moved Permanently',
        302 => 'Found',
        303 => 'See Other',
        304 => 'Not Modified',
        305 => 'Use Proxy',
        306 => 'Reserved',
        307 => 'Temporary Redirect',
        308 => 'Permanent Redirect',
        310 => 'Too many Redirect',
        400 => 'Bad Request',
        401 => 'Unauthorized',
        402 => 'Payment Required',
        403 => 'Forbidden',
        404 => 'Not Found',
        405 => 'Method Not Allowed',
        406 => 'Not Acceptable',
        407 => 'Proxy Authentication Required',
        408 => 'Request Time-out',
        409 => 'Conflict',
        410 => 'Gone',
        411 => 'Length Required',
        412 => 'Precondition Failed',
        413 => 'Request Entity Too Large',
        414 => 'Request-URI Too Long',
        415 => 'Unsupported Media Type',
        416 => 'Requested range unsatisfiable',
        417 => 'Expectation failed',
        418 => 'I\'m a teapot',
        422 => 'Unprocessable entity',
        423 => 'Locked',
        424 => 'Method failure',
        425 => 'Unordered Collection',
        426 => 'Upgrade Required',
        428 => 'Precondition Required',
        429 => 'Too Many Requests',
        431 => 'Request Header Fields Too Large',
        449 => 'Retry With',
        450 => 'Blocked by Windows Parental Controls',
        500 => 'Internal Server Error',
        501 => 'Not Implemented',
        502 => 'Bad Gateway or Proxy Error',
        503 => 'Service Unavailable',
        504 => 'Gateway Time-out',
        505 => 'HTTP Version not supported',
        507 => 'Insufficient storage',
        508 => 'Loop Detected',
        509 => 'Bandwidth Limit Exceeded',
        510 => 'Not Extended',
        511 => 'Network Authentication Required',
    ];
    $Protocol = (isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.1');
    if (!$IsAjax && !empty($HttpStatuses[$StatusCode])) {
        // http_response_code($StatusCode);
        header($Protocol . ' ' . $StatusCode . ' ' . $HttpStatuses[$StatusCode]);
    }
    $ContentFile = $TemplatePath . 'alert.php';
    include($TemplatePath . 'layout.php');
    exit;
}


//获取数组中的某一列
function ArrayColumn($Input, $ColumnKey)
{
    if (version_compare(PHP_VERSION, '5.5.0') < 0) {
        $Result = array();
        if ($Input) {
            foreach ($Input as $Value) {
                $Result[] = $Value[$ColumnKey];
            }
        }
        return $Result;
    } else {
        return array_column($Input, $ColumnKey);
    }
}


//鉴权
function Auth($MinRoleRequire, $AuthorizedUserID = 0, $StatusRequire = false)
{
    global $CurUserRole, $CurUserID, $CurUserInfo, $Lang, $RequestURI;
    $error = '';
    if ($CurUserRole < $MinRoleRequire) {
        $error = str_replace('{{RoleDict}}', $Lang['RolesDict'][$MinRoleRequire], $Lang['Error_Insufficient_Permissions']);
    }
    if ($CurUserID && $StatusRequire == true && $CurUserInfo['UserAccountStatus'] == 0) {
        $error = $Lang['Error_Account_navailable'];
    }
    if ($AuthorizedUserID && $CurUserID && $CurUserID == $AuthorizedUserID) {
        $error = false;
    }
    if ($error) {
        AlertMsg($Lang['Error_Message'], $error, 401);
    }
}


//转换字符
function CharCV($string)
{
    $string = htmlspecialchars(trim($string));
    return $string;
}


// 过滤掉一些非法字符
function CharsFilter($String)
{
    $String = str_replace("<", "", $String);
    $String = str_replace(">", "", $String);
    return trim($String);
}


// 获得IP地址
function CurIP()
{
    $IsCDN = false; //未使用CDN时,应直接使用 $_SERVER['REMOTE_ADDR'] 以防止客户端伪造IP
    $IP = false;
    if (!empty($_SERVER["HTTP_CLIENT_IP"])) {
        $IP = trim($_SERVER["HTTP_CLIENT_IP"]);
    }
    if ($IsCDN && !empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
        $IPs = array_map("trim", explode(",", $_SERVER['HTTP_X_FORWARDED_FOR']));
        if ($IP) {
            array_unshift($IPs, $IP);//插入头部而不是尾部,提升性能
            $IP = FALSE;
        }
        //支持使用CDN后获取IP,理论上令 $IP = $IPs[0]; 即可,安全起见遍历过滤一次
        foreach ($IPs as $Key => $Value) {
            /*
            Fails validation for the following private IPv4 ranges: 10.0.0.0/8, 172.16.0.0/12 and 192.168.0.0/16.
            Fails validation for the IPv6 addresses starting with FD or FC.
            */
            if (filter_var($Value, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE)) {
                $IP = $Value;
                break;
            }
        }
    }
    return htmlspecialchars($IP ? $IP : $_SERVER['REMOTE_ADDR']);
}


//关键词过滤
function Filter($Content)
{
    if (is_file(LibraryPath . 'Filtering.words.config.json')) {
        $FilteringWords = JsonDecode(file_get_contents(LibraryPath . 'Filtering.words.config.json'));
    } else {
        $FilteringWords = JsonDecode(file_get_contents(LibraryPath . 'Filtering.words.config.template.json'));
    }
    $Prohibited = false;
    $GagTime = 0;
    foreach ($FilteringWords as $SearchRegEx => $Rule) {

        if (preg_match_all("/" . $SearchRegEx . "/i", $Content, $SearchWordsList)) {
            //var_dump($SearchWordsList);
            foreach ($SearchWordsList as $SearchWord) {
                if (is_array($Rule)) {
                    $Content = str_ireplace($SearchWord, $Rule[0], $Content);
                    $Prohibited |= ($Rule[0] === false);
                    $GagTime = ($Rule[1] > $GagTime) ? $Rule[1] : $GagTime; //将规则中封禁时间最长的一个赏给用户
                } else {
                    $Content = str_ireplace($SearchWord, $Rule, $Content);
                    //$Prohibited |= false;
                    //$GagTime = 0;
                }
            }
        }
    }
    return array(
        'Content' => $Content, //过滤后的内容
        'Prohibited' => $Prohibited, //是否包含有禁止发布的词
        'GagTime' => $GagTime //赏赐给用户的禁言时间(秒)
    );
}

// 获得表单校验散列
function FormHash()
{
    global $Config;
    if (GetCookie('UserCode'))
        return substr(md5($Config['SiteName'] . GetCookie('UserCode') . SALT), 8, 8);
    else
        return substr(md5($Config['SiteName'] . SALT), 8, 8);
}


//格式化文件大小
function FormatBytes($size, $precision = 2)
{
    // https://www.zhihu.com/question/21578998/answer/86401223
    // According to Metric prefix, IEEE 1541-2002.
    $units = array(
        ' Bytes',
        ' KiB',
        ' MiB',
        ' GiB',
        ' TiB'
    );
    for ($i = 0; $size >= 1024 && $i < 4; $i++)
        $size /= 1024;
    return round($size, $precision) . $units[$i];
}


// 格式化时间
function FormatTime($UnixTimeStamp)
{
    global $Lang;
    $Seconds = $_SERVER['REQUEST_TIME'] - $UnixTimeStamp;
    if ($Seconds < 2592000) {
        // 小于30天如下显示
        if ($Seconds >= 86400) {
            return round($Seconds / 86400, 0) . '&nbsp;' . $Lang['Time_Days_Ago'];
        } else if ($Seconds >= 3600) {
            return round($Seconds / 3600, 0) . '&nbsp;' . $Lang['Time_Hours_Ago'];
        } else if ($Seconds >= 60) {
            return round($Seconds / 60, 0) . '&nbsp;' . $Lang['Time_Minutes_Ago'];
        } else if ($Seconds < 0) {
            return $Lang['Time_Just_Now'];
        } else {
            return ($Seconds + 1) . '&nbsp;' . $Lang['Time_Seconds_Ago'];
        }
    } else {
        // 大于一月
        return date("Y-m-d", $UnixTimeStamp);
        //gmdate()可以返回格林威治标准时,date()则为当地时
    }
}


//获取头像
function GetAvatar($UserID, $UserName, $Size = 'middle')
{
    global $Config;
    return '<img src="' . $Config['WebsitePath'] . '/upload/avatar/' . $Size . '/' . $UserID . '.png" alt="' . $UserName . '"/>';
}


//获取Tag标签
function GetTagIcon($TagID, $Icon, $TagName, $Size = 'middle')
{
    global $Config;
    return '<img src="' . $Config['WebsitePath'] . '/upload/tag/' . $Size . '/' . ($Icon ? $TagID : '0') . '.png" alt="' . $TagName . '"/>';
}

//获取Cookie
function GetCookie($Key, $DefaultValue = false)
{
    global $Config, $IsApp;
    if (!$IsApp) {
        if (!empty($_COOKIE[$Config['CookiePrefix'] . $Key])) {
            return $_COOKIE[$Config['CookiePrefix'] . $Key];
        } else if ($DefaultValue) {
            SetCookies(array(
                $Key => $DefaultValue
            ));
            return $DefaultValue;
        }
    } else {
        return Request("Request", "Auth" . $Key, $DefaultValue);
    }
    return false;
}


//Hash值校验,防止时序攻击法
function HashEquals($KnownString, $UserString)
{
    if (version_compare(PHP_VERSION, '5.6.0') < 0) {
        return ($KnownString === $UserString);
    } else {
        return hash_equals($KnownString, $UserString);
    }
}

//长整数intval,防止溢出,目前暂未用到
function Int($s)
{
    return ($a = preg_replace('/[^\-\d]*(\-?\d*).*/', '$1', $s)) ? $a : '0';
}


//判断是否为邮件地址
function IsEmail($email)
{
    return strlen($email) > 6 && preg_match("/^[\w\-\.]+@[\w\-\.]+(\.\w+)+$/", $email);
}

function IsJson($String)
{
    JsonDecode($String);
    return (json_last_error() === JSON_ERROR_NONE);
}

//判断是否为合法用户名
function IsName($string)
{
    return !preg_match('/^[0-9]{4,20}$/', $string) && preg_match('/^[a-zA-Z0-9\x{4e00}-\x{9fa5}\-_]{4,20}$/ui', $string);
}


//判断当前协议
function IsSSL()
{
    if (!isset($_SERVER['HTTPS']))
        return false;
    if ($_SERVER['HTTPS'] === 1) { //Apache
        return true;
    } elseif ($_SERVER['HTTPS'] === 'on') { //IIS
        return true;
    } elseif ($_SERVER['SERVER_PORT'] == 443) { //其他
        return true;
    }
    return false;
}

// 去除注释的JsonDecode
function JsonDecode($Json)
{
    return json_decode(preg_replace("/\/\*[\s\S]+?\*\//", "", $Json), true);
}

//登出
function LogOut()
{
    global $CurUserID;
    SetCookies(array(
        'UserID' => '',
        'UserExpirationTime' => '',
        'UserCode' => ''
    ), 1);
    $CurUserID = 0;
}


//跳转
function Redirect($URI = '', $ExitCode = 0)
{
    global $Config;
    header('location: ' . $Config['WebsitePath'] . '/' . $URI);
    exit($ExitCode);
}

//来源检查
function ReferCheck($UserHash)
{
    global $IsApp;
    if (!$IsApp && (empty($_SERVER['HTTP_REFERER']) || $UserHash != FormHash() || preg_replace("/https?:\/\/([^\:\/]+).*/i", "\\1", $_SERVER['HTTP_REFERER']) !== preg_replace("/([^\:]+).*/", "\\1", $_SERVER['HTTP_HOST'])))
        return false;
    else
        return true;
}

//表单获取
function Request($Type, $Key, $DefaultValue = '')
{
    global $_PUT, $_DELETE, $_OPTIONS;
    switch ($Type) {
        case 'Get':
            return isset($_GET[$Key]) ? trim($_GET[$Key]) : $DefaultValue;
            break;
        case 'Post':
            return isset($_POST[$Key]) ? trim($_POST[$Key]) : $DefaultValue;
            break;
        case 'Put':
            return isset($_PUT[$Key]) ? trim($_PUT[$Key]) : $DefaultValue;
            break;
        case 'Delete':
            return isset($_DELETE[$Key]) ? trim($_DELETE[$Key]) : $DefaultValue;
            break;
        case 'Options':
            return isset($_OPTIONS[$Key]) ? trim($_OPTIONS[$Key]) : $DefaultValue;
            break;
        default:
            return isset($_REQUEST[$Key]) ? trim($_REQUEST[$Key]) : $DefaultValue;
            break;
    }
}


//设置工作模式为API模式(返回Json格式数据)
//SetStyle('api','API');
function SetStyle($PathName, $StyleName)
{
    global $IsApp, $TemplatePath, $Style;
    if ($StyleName = 'API') {
        $IsApp = true;
        header('Access-Control-Allow-Origin: *');
        header('Content-Type: application/json; charset=utf-8');
    }
    $TemplatePath = __DIR__ . '/view/' . $PathName . '/';
    $Style = $StyleName;
}


//批量设置Cookie
function SetCookies($CookiesArray, $Expires = 0)
{
    global $TimeStamp, $Config;
    foreach ($CookiesArray as $key => $value) {
        if (!$Expires)
            setcookie($Config['CookiePrefix'] . $key, $value, 0, $Config['WebsitePath'] . '/', null, false, true);
        else
            setcookie($Config['CookiePrefix'] . $key, $value, $TimeStamp + 86400 * $Expires, $Config['WebsitePath'] . '/', null, false, true);
    }
}


//大小写不敏感的array_diff
function TagsDiff($Arr1, $Arr2)
{
    global $Config;
    $Arr2 = array_change_key_case(array_flip($Arr2), CASE_LOWER); //flip,排重,Key有Hash索引,速度更快
    foreach ($Arr1 as $Key => $Item) {
        if (mb_strlen($Item, "UTF-8") > $Config["MaxTagChars"] || isset($Arr2[strtolower(trim($Item))]) || strpos("|", $Item) || !preg_match('/^[a-zA-Z0-9\x80-\xff\-_\s]{1,' . $Config['MaxTagChars'] . '}$/i', $Item) || $Item != Filter($Item)['Content']) {
            unset($Arr1[$Key]);
        } else {
            $Arr1[$Key] = htmlspecialchars(trim($Arr1[$Key])); //XSS
        }
    }
    sort($Arr1);
    return $Arr1;
}


//修改系统设置
function UpdateConfig($NewConfig)
{
    global $DB, $Config, $MCache;
    if ($NewConfig) {
        foreach ($NewConfig as $Key => $Value) {
            $DB->query("UPDATE `" . PREFIX . "config` SET ConfigValue=? WHERE ConfigName=?", array(
                $Value,
                $Key
            ));
            $Config[$Key] = $Value;
        }
        if ($MCache) {
            $MCache->set(MemCachePrefix . 'Config', $Config, 86400);
        }
        return true;
    } else {
        return false;
    }

}


//修改用户资料
function UpdateUserInfo($NewUserInfo, $UserID = 0)
{
    global $DB, $CurUserID, $CurUserInfo, $MCache;
    if ($UserID == 0) {
        $UserID = $CurUserID;
    }
    if ($NewUserInfo) {
        $StringBindParam = '';
        foreach ($NewUserInfo as $Key => $Value) {
            $StringBindParam .= $Key . ' = :' . $Key . ',';
        }
        $StringBindParam = substr($StringBindParam, 0, -1);
        $Result = $DB->query('UPDATE `' . PREFIX . 'users` SET ' . $StringBindParam . ' WHERE ID = :UserID', array_merge($NewUserInfo, array(
            'UserID' => $UserID
        )));
        if ($MCache) {
            $MCache->set(MemCachePrefix . 'UserInfo_' . $UserID, $DB->row("SELECT *, (NewReply + NewMention + NewMessage) as NewNotification FROM " . PREFIX . "users WHERE ID = :UserID", array(
                "UserID" => $UserID
            )), 86400);
        }
        return $Result;
    } else {
        return false;
    }

}

//跨站脚本白名单过滤
function XssEscape($html)
{
    $filter = new WhiteHTMLFilter();
    $urlFilter = function($url) {
        $token = parse_url($url);
        if (empty($token['scheme']) || in_array($token['scheme'], array('http', 'https')) === false) {
            return '';
        }
        $hostWhiteList = array(
            'www.youtube.com', 'youtube.com', 'www.youtu.be', 'youtu.be',
            'player.youku.com', 'v.youku.com',
            'video.tudou.com', 'www.tudou.com',
            'player.video.qiyi.com', 'open.iqiyi.com',
            'imgcache.qq.com', 'v.qq.com',
            'static.hdslb.com',
            //'www.le.com',
            'share.vrs.sohu.com', 'tv.sohu.com',
            'player.pptv.com',
            'cdn.aixifan.com',
            'v.ifeng.com',
            'video.sina.com.cn',
            'galaxy.bjcathay.com'//CNTV
        );
        if (empty($token['host']) || in_array($token['host'], $hostWhiteList) === false) {
            return '';
        }
        return $url;
    };

    $iframeRule = array(
        'iframe' => array(
            'src' => $urlFilter,
            'width',
            'height',
            'frameborder',
            'allowfullscreen'
        )
    );
    $filter->config->modifyTagWhiteList($iframeRule);
    $filter->loadHTML($html);
    $filter->clean();
    return $filter->outputHtml();
}

$UserAgent = isset($_SERVER['HTTP_USER_AGENT']) ? strtolower($_SERVER['HTTP_USER_AGENT']) : '';
if ($UserAgent) {
    $IsSpider = preg_match('/(bot|crawl|spider|slurp|sohu-search|lycos|robozilla|google)/i', $UserAgent);
    $IsMobile = preg_match('/(iPod|iPhone|Android|Opera Mini|BlackBerry|webOS|UCWEB|Blazer|PSP)/i', $UserAgent);
} else {
    //exit('error: 400 no agent');
    $IsSpider = false;
    $IsMobile = false;
}
$IsApp = $_SERVER['HTTP_HOST'] == $Config['AppDomainName'] ? true : false;
/* Set current template
 * default: PC Version
 * mobile: Mobile Version
 * api: API
 */
if ($IsApp) {
    $TemplatePath = __DIR__ . '/view/api/';
    $Style = 'API';
    header('Access-Control-Allow-Origin: *');
    header('Content-Type: application/json');
    //API鉴权
    $SignatureKey = Request("Request", "SKey");
    $SignatureValue = Request("Request", "SValue");
    $SignatureTime = intval(Request("Request", "STime"));
    if (!$SignatureTime || !$SignatureKey || !$SignatureValue || empty($APISignature[$SignatureKey]) || abs($SignatureTime - $TimeStamp) > 600 || !HashEquals($SignatureValue, md5($SignatureKey . $APISignature[$SignatureKey] . $SignatureTime))) {
        AlertMsg('403', 'Forbidden', 403);
    }
} elseif ($_SERVER['HTTP_HOST'] == $Config['MobileDomainName'] || (!$Config['MobileDomainName'] && $IsMobile)) {
    $TemplatePath = __DIR__ . '/view/mobile/';
    $Style = 'Mobile';
    header('X-Frame-Options: SAMEORIGIN');
} else {
    $TemplatePath = __DIR__ . '/view/default/';
    $Style = 'Default';
    header('X-Frame-Options: SAMEORIGIN');
    //header('X-XSS-Protection: 1; mode=block');
    //X-XSS-Protection may cause some issues in dashboard
}

$CurView = GetCookie('View', $IsMobile ? 'mobile' : 'desktop');
$CurIP = CurIP();
$FormHash = FormHash();
// 限制不能打开.php的网址
if (strpos($RequestURI, '.php')) {
    AlertMsg('403', 'Forbidden', 403);
}


$CurrentDate = date('Y-m-d');
if ($Config['DaysDate'] != $CurrentDate) {
    if (!strtotime($Config['DaysDate'])) {
        $Config['DaysDate'] = $CurrentDate;
    }
    $DB->query('INSERT INTO `' . PREFIX . 'statistics` 
        (`DaysUsers`, `DaysPosts`, `DaysTopics`, `TotalUsers`, `TotalPosts`, `TotalTopics`, `DaysDate`, `DateCreated`) 
        SELECT 
        :DaysUsers, :DaysPosts, :DaysTopics, :TotalUsers, :TotalPosts, :TotalTopics, :DaysDate, :DateCreated 
        FROM dual  
        WHERE NOT EXISTS(  
            SELECT *  FROM `' . PREFIX . 'statistics`  
            WHERE DaysDate = :DaysDate2
        )
        ', array(
        'DaysUsers' => $Config['DaysUsers'],
        'DaysPosts' => $Config['DaysPosts'],
        'DaysTopics' => $Config['DaysTopics'],
        'TotalUsers' => $Config['NumUsers'],
        'TotalPosts' => $Config['NumPosts'],
        'TotalTopics' => $Config['NumTopics'],
        'DaysDate' => $Config['DaysDate'],
        'DateCreated' => $TimeStamp,
        'DaysDate2' => $Config['DaysDate']
    ));
    UpdateConfig(array(
        'DaysDate' => $CurrentDate,
        'DaysTopics' => 0,
        'DaysPosts' => 0,
        'DaysUsers' => 0,
        'CacheHotTags' => json_encode($DB->query('SELECT ID,Name,Icon,TotalPosts,Followers FROM ' . PREFIX . 'tags 
            WHERE IsEnabled=1 AND TotalPosts>0
            ORDER BY TotalPosts DESC 
            LIMIT ' . $Config['TopicsPerPage']))
    ));
}
// Get the infomation of current user
$CurUserInfo = null; //当前用户信息,Array,以后判断是否登陆使用if($CurUserID)
$CurUserRole = 0;
$CurUserID = intval(GetCookie('UserID'));
$CurUserName = '';
$CurUserExpirationTime = intval(GetCookie('UserExpirationTime'));
$CurUserCode = GetCookie('UserCode');

if ($CurUserExpirationTime > $TimeStamp && $CurUserExpirationTime < ($TimeStamp + 2678400) && $CurUserID && $CurUserCode) {
    $TempUserInfo = array();
    if ($MCache) {
        $TempUserInfo = $MCache->get(MemCachePrefix . 'UserInfo_' . $CurUserID);
    }
    if (empty($TempUserInfo)) {
        $TempUserInfo = $DB->row("SELECT *, (NewReply + NewMention + NewMessage) as NewNotification FROM " . PREFIX . "users WHERE ID = :UserID", array(
            "UserID" => $CurUserID
        ));
        if ($MCache && $TempUserInfo) {
            $MCache->set(MemCachePrefix . 'UserInfo_' . $CurUserID, $TempUserInfo, 86400);
        }
    }
    if ($TempUserInfo && HashEquals(md5($TempUserInfo['Password'] . $TempUserInfo['Salt'] . $CurUserExpirationTime . SALT), $CurUserCode)) {
        $CurUserName = $TempUserInfo['UserName'];
        $CurUserRole = $TempUserInfo['UserRoleID'];
        $CurUserInfo = $TempUserInfo;
    } else {
        LogOut();
    }
    unset($TempUserInfo);
} elseif ($CurUserExpirationTime || $CurUserID || $CurUserCode) {
    LogOut();
}