discuz_application.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. <?php
  2. /**
  3. * [Discuz!] (C)2001-2099 Discuz! Team
  4. * This is NOT a freeware, use is subject to license terms
  5. * https://license.discuz.vip
  6. */
  7. if (!defined('IN_DISCUZ')) {
  8. exit('Access Denied');
  9. }
  10. class discuz_application extends discuz_base {
  11. var $mem = null;
  12. var $session = null;
  13. var $config = [];
  14. var $var = [];
  15. var $cachelist = [];
  16. var $init_db = true;
  17. var $init_setting = true;
  18. var $init_user = true;
  19. var $init_session = true;
  20. var $init_cron = true;
  21. var $init_misc = true;
  22. var $init_mobile = true;
  23. var $initated = false;
  24. var $superglobal = [
  25. 'GLOBALS' => 1,
  26. '_GET' => 1,
  27. '_POST' => 1,
  28. '_REQUEST' => 1,
  29. '_COOKIE' => 1,
  30. '_SERVER' => 1,
  31. '_ENV' => 1,
  32. '_FILES' => 1,
  33. ];
  34. static function &instance() {
  35. static $object;
  36. if (empty($object)) {
  37. $object = new self();
  38. }
  39. return $object;
  40. }
  41. public function __construct() {
  42. $this->_init_env();
  43. $this->_init_input();
  44. $this->_init_output();
  45. }
  46. public function init() {
  47. if (!$this->initated) {
  48. $this->_init_db();
  49. }
  50. $this->initated = true;
  51. }
  52. private function _init_env() {
  53. error_reporting(E_ERROR);
  54. define('ICONV_ENABLE', function_exists('iconv'));
  55. define('MB_ENABLE', function_exists('mb_convert_encoding'));
  56. define('EXT_OBGZIP', function_exists('ob_gzhandler'));
  57. define('TIMESTAMP', time());
  58. if (!defined('DISCUZ_CORE_FUNCTION') && !@include(DISCUZ_ROOT . './source/function/function_core.php')) {
  59. exit('function_core.php is missing');
  60. }
  61. if (!defined('DISCUZ_LOG_FUNCTION') && !@include(DISCUZ_ROOT . './source/function/function_log.php')) {
  62. exit('function_log.php is missing');
  63. }
  64. if (function_exists('ini_get')) {
  65. $memorylimit = @ini_get('memory_limit');
  66. if ($memorylimit && return_bytes($memorylimit) < 33554432 && function_exists('ini_set')) {
  67. ini_set('memory_limit', '128m');
  68. }
  69. }
  70. define('IS_ROBOT', checkrobot());
  71. foreach ($GLOBALS as $key => $value) {
  72. if (!isset($this->superglobal[$key])) {
  73. $GLOBALS[$key] = null;
  74. unset($GLOBALS[$key]);
  75. }
  76. }
  77. if (!defined('APPTYPEID')) {
  78. define('APPTYPEID', 0);
  79. }
  80. if (!defined('DISCUZ_APP')) {
  81. define('DISCUZ_APP', '');
  82. }
  83. if (!defined('CURSCRIPT')) {
  84. define('CURSCRIPT', DISCUZ_APP);
  85. }
  86. global $_G;
  87. $_G = [
  88. 'uid' => 0,
  89. 'username' => '',
  90. 'adminid' => 0,
  91. 'groupid' => 1,
  92. 'sid' => '',
  93. 'formhash' => '',
  94. 'connectguest' => 0,
  95. 'timestamp' => TIMESTAMP,
  96. 'starttime' => microtime(true),
  97. 'clientip' => $this->_get_client_ip(),
  98. 'remoteport' => $_SERVER['REMOTE_PORT'],
  99. 'referer' => '',
  100. 'charset' => '',
  101. 'gzipcompress' => '',
  102. 'authkey' => '',
  103. 'timenow' => [],
  104. 'widthauto' => 0,
  105. 'disabledwidthauto' => 0,
  106. 'PHP_SELF' => '',
  107. 'siteurl' => '',
  108. 'siteroot' => '',
  109. 'siteport' => '',
  110. 'pluginrunlist' => !defined('PLUGINRUNLIST') ? [] : explode(',', PLUGINRUNLIST),
  111. 'config' => & $this->config,
  112. 'setting' => [],
  113. 'member' => [],
  114. 'group' => [],
  115. 'cookie' => [],
  116. 'style' => [],
  117. 'cache' => [],
  118. 'session' => [],
  119. 'lang' => [],
  120. 'fid' => 0,
  121. 'tid' => 0,
  122. 'forum' => [],
  123. 'thread' => [],
  124. 'rssauth' => '',
  125. 'home' => [],
  126. 'space' => [],
  127. 'block' => [],
  128. 'article' => [],
  129. 'action' => [
  130. 'action' => APPTYPEID,
  131. 'fid' => 0,
  132. 'tid' => 0,
  133. ],
  134. 'mobile' => '',
  135. 'notice_structure' => [
  136. 'mypost' => ['post', 'rate', 'pcomment', 'activity', 'reward', 'goods', 'at'],
  137. 'interactive' => ['poke', 'friend', 'wall', 'comment', 'click', 'sharenotice'],
  138. 'system' => ['system', 'credit', 'group', 'verify', 'magic', 'task', 'show', 'group', 'pusearticle', 'mod_member', 'blog', 'article'],
  139. 'manage' => ['mod_member', 'report', 'pmreport'],
  140. 'app' => [],
  141. ],
  142. 'mobiletpl' => ['1' => 'touch', '2' => 'touch', '3' => 'touch', 'yes' => 'touch'],
  143. ];
  144. $_G['PHP_SELF'] = dhtmlspecialchars($this->_get_script_url());
  145. $_G['basescript'] = CURSCRIPT;
  146. $_G['basefilename'] = basename($_G['PHP_SELF']);
  147. $sitepath = substr($_G['PHP_SELF'], 0, strrpos($_G['PHP_SELF'], '/'));
  148. if (defined('IN_API')) {
  149. $sitepath = preg_replace('/\/api\/?.*?$/i', '', $sitepath);
  150. } elseif (defined('IN_ARCHIVER')) {
  151. $sitepath = preg_replace('/\/archiver/i', '', $sitepath);
  152. }
  153. if (defined('IN_NEWMOBILE')) {
  154. $sitepath = preg_replace('/\/m/i', '', $sitepath);
  155. }
  156. $_G['isHTTPS'] = !empty($_G['config']['output']['forcehttps']) || $this->_is_https();
  157. $_G['scheme'] = 'http' . ($_G['isHTTPS'] ? 's' : '');
  158. $_G['siteurl'] = dhtmlspecialchars($_G['scheme'] . '://' . $_SERVER['HTTP_HOST'] . $sitepath . '/');
  159. $url = parse_url($_G['siteurl']);
  160. $_G['siteroot'] = $url['path'] ?? '';
  161. $_G['siteport'] = empty($_SERVER['SERVER_PORT']) || $_SERVER['SERVER_PORT'] == '80' || $_SERVER['SERVER_PORT'] == '443' ? '' : ':' . $_SERVER['SERVER_PORT'];
  162. if (defined('SUB_DIR')) {
  163. $_G['siteurl'] = str_replace(SUB_DIR, '/', $_G['siteurl']);
  164. $_G['siteroot'] = str_replace(SUB_DIR, '/', $_G['siteroot']);
  165. }
  166. $this->var = &$_G;
  167. }
  168. private function _get_script_url() {
  169. if (!isset($this->var['PHP_SELF'])) {
  170. $scriptName = basename($_SERVER['SCRIPT_FILENAME']);
  171. if (basename($_SERVER['SCRIPT_NAME']) === $scriptName) {
  172. $this->var['PHP_SELF'] = $_SERVER['SCRIPT_NAME'];
  173. } else if (basename($_SERVER['PHP_SELF']) === $scriptName) {
  174. $this->var['PHP_SELF'] = $_SERVER['PHP_SELF'];
  175. } else if (isset($_SERVER['ORIG_SCRIPT_NAME']) && basename($_SERVER['ORIG_SCRIPT_NAME']) === $scriptName) {
  176. $this->var['PHP_SELF'] = $_SERVER['ORIG_SCRIPT_NAME'];
  177. } else if (($pos = strpos($_SERVER['PHP_SELF'], '/' . $scriptName)) !== false) {
  178. $this->var['PHP_SELF'] = substr($_SERVER['SCRIPT_NAME'], 0, $pos) . '/' . $scriptName;
  179. } else if (isset($_SERVER['DOCUMENT_ROOT']) && str_starts_with($_SERVER['SCRIPT_FILENAME'], $_SERVER['DOCUMENT_ROOT'])) {
  180. $this->var['PHP_SELF'] = str_replace('\\', '/', str_replace($_SERVER['DOCUMENT_ROOT'], '', $_SERVER['SCRIPT_FILENAME']));
  181. $this->var['PHP_SELF'][0] != '/' && $this->var['PHP_SELF'] = '/' . $this->var['PHP_SELF'];
  182. } else {
  183. system_error('request_tainting');
  184. }
  185. }
  186. return $this->var['PHP_SELF'];
  187. }
  188. private function _init_input() {
  189. if (isset($_GET['GLOBALS']) || isset($_POST['GLOBALS']) || isset($_COOKIE['GLOBALS']) || isset($_FILES['GLOBALS'])) {
  190. system_error('request_tainting');
  191. }
  192. $prelength = strlen($this->config['cookie']['cookiepre']);
  193. foreach ($_COOKIE as $key => $val) {
  194. if (substr($key, 0, $prelength) == $this->config['cookie']['cookiepre']) {
  195. $this->var['cookie'][substr($key, $prelength)] = $val;
  196. }
  197. }
  198. if ($_SERVER['REQUEST_METHOD'] == 'POST' && !empty($_POST)) {
  199. foreach ($_POST as $k => $v) {
  200. $_GET[$k] = $v;
  201. }
  202. }
  203. }
  204. private function _init_output() {
  205. if (!empty($_SERVER['HTTP_ACCEPT_ENCODING']) && !str_contains($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip')) {
  206. $this->config['output']['gzip'] = false;
  207. }
  208. $allowgzip = $this->config['output']['gzip'] && empty($this->var['inajax']) && $this->var['mod'] != 'attachment' && EXT_OBGZIP;
  209. setglobal('gzipcompress', $allowgzip);
  210. if (!ob_start($allowgzip ? 'ob_gzhandler' : null)) {
  211. ob_start();
  212. }
  213. setglobal('charset', $this->config['output']['charset']);
  214. define('CHARSET', $this->config['output']['charset']);
  215. if ($this->config['output']['forceheader']) {
  216. @header('Content-Type: text/html; charset=' . CHARSET);
  217. }
  218. if ($this->var['isHTTPS'] && isset($this->config['output']['upgradeinsecure']) && $this->config['output']['upgradeinsecure']) {
  219. @header('Content-Security-Policy: upgrade-insecure-requests');
  220. }
  221. }
  222. public function reject_robot() {
  223. if (IS_ROBOT) {
  224. exit(header('HTTP/1.1 403 Forbidden'));
  225. }
  226. }
  227. private function _is_https() {
  228. // PHP 标准服务器变量
  229. if (isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) != 'off') {
  230. return true;
  231. }
  232. // X-Forwarded-Proto 事实标准头部, 用于反代透传 HTTPS 状态
  233. if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) == 'https') {
  234. return true;
  235. }
  236. // 阿里云全站加速私有 HTTPS 状态头部
  237. // Git 意见反馈 https://gitee.com/Discuz/DiscuzX/issues/I3W5GP
  238. if (isset($_SERVER['HTTP_X_CLIENT_SCHEME']) && strtolower($_SERVER['HTTP_X_CLIENT_SCHEME']) == 'https') {
  239. return true;
  240. }
  241. // 西部数码建站助手私有 HTTPS 状态头部
  242. // 官网意见反馈 https://discuz.dismall.com/thread-3849819-1-1.html
  243. if (isset($_SERVER['HTTP_FROM_HTTPS']) && strtolower($_SERVER['HTTP_FROM_HTTPS']) != 'off') {
  244. return true;
  245. }
  246. // 服务器端口号兜底判断
  247. if (isset($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == 443) {
  248. return true;
  249. }
  250. return false;
  251. }
  252. private function _get_client_ip() {
  253. $ip = $_SERVER['REMOTE_ADDR'];
  254. if (!array_key_exists('security', $this->config) || !$this->config['security']['onlyremoteaddr']) {
  255. if (array_key_exists('ipgetter', $this->config) && !empty($this->config['ipgetter']['setting'])) {
  256. $s = empty($this->config['ipgetter'][$this->config['ipgetter']['setting']]) ? [] : $this->config['ipgetter'][$this->config['ipgetter']['setting']];
  257. $c = 'ip_getter_' . $this->config['ipgetter']['setting'];
  258. $r = $c::get($s);
  259. $ip = ip::validate_ip($r) ? $r : $ip;
  260. } elseif (isset($_SERVER['HTTP_CLIENT_IP']) && ip::validate_ip($_SERVER['HTTP_CLIENT_IP'])) {
  261. $ip = $_SERVER['HTTP_CLIENT_IP'];
  262. } elseif (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
  263. if (strpos($_SERVER['HTTP_X_FORWARDED_FOR'], ',') > 0) {
  264. $exp = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
  265. $ip = ip::validate_ip(trim($exp[0])) ? $exp[0] : $ip;
  266. } else {
  267. $ip = ip::validate_ip($_SERVER['HTTP_X_FORWARDED_FOR']) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : $ip;
  268. }
  269. }
  270. }
  271. return $ip;
  272. }
  273. private function _init_db() {
  274. if ($this->init_db && $this->config) {
  275. if ($this->config['db']['driver'] == 'pdo' && class_exists('PDO')) {
  276. $driver = 'db_driver_pdo';
  277. if (getglobal('config/db/slave')) {
  278. $driver = 'db_driver_pdo_slave';
  279. }
  280. $this->var['db_driver'] = 'pdo';
  281. } else {
  282. $driver = 'db_driver_mysqli';
  283. if (getglobal('config/db/slave')) {
  284. $driver = 'db_driver_mysqli_slave';
  285. }
  286. $this->var['db_driver'] = 'mysqli';
  287. }
  288. $this->var['mysql_driver'] = $driver;
  289. DB::init($driver, $this->config['db']);
  290. }
  291. }
  292. }