discuz_application.php 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  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 (function_exists('ini_get')) {
  62. $memorylimit = @ini_get('memory_limit');
  63. if ($memorylimit && return_bytes($memorylimit) < 33554432 && function_exists('ini_set')) {
  64. ini_set('memory_limit', '128m');
  65. }
  66. }
  67. define('IS_ROBOT', checkrobot());
  68. foreach ($GLOBALS as $key => $value) {
  69. if (!isset($this->superglobal[$key])) {
  70. $GLOBALS[$key] = null;
  71. unset($GLOBALS[$key]);
  72. }
  73. }
  74. global $_G;
  75. $_G = [
  76. 'uid' => 0,
  77. 'username' => '',
  78. 'adminid' => 0,
  79. 'groupid' => 1,
  80. 'sid' => '',
  81. 'formhash' => '',
  82. 'connectguest' => 0,
  83. 'timestamp' => TIMESTAMP,
  84. 'starttime' => microtime(true),
  85. 'clientip' => $this->_get_client_ip(),
  86. 'remoteport' => $_SERVER['REMOTE_PORT'],
  87. 'referer' => '',
  88. 'charset' => '',
  89. 'gzipcompress' => '',
  90. ];
  91. $_G['PHP_SELF'] = dhtmlspecialchars($this->_get_script_url());
  92. $_G['basefilename'] = basename($_G['PHP_SELF']);
  93. $_G['isHTTPS'] = !empty($_G['config']['output']['forcehttps']) || $this->_is_https();
  94. $_G['scheme'] = 'http' . ($_G['isHTTPS'] ? 's' : '');
  95. $_G['siteurl'] = dhtmlspecialchars($_G['scheme'] . '://' . $_SERVER['HTTP_HOST'] . $sitepath . '/');
  96. $url = parse_url($_G['siteurl']);
  97. $_G['siteroot'] = $url['path'] ?? '';
  98. $_G['siteport'] = empty($_SERVER['SERVER_PORT']) || $_SERVER['SERVER_PORT'] == '80' || $_SERVER['SERVER_PORT'] == '443' ? '' : ':' . $_SERVER['SERVER_PORT'];
  99. $this->var = &$_G;
  100. }
  101. private function _get_script_url() {
  102. if (!isset($this->var['PHP_SELF'])) {
  103. $scriptName = basename($_SERVER['SCRIPT_FILENAME']);
  104. if (basename($_SERVER['SCRIPT_NAME']) === $scriptName) {
  105. $this->var['PHP_SELF'] = $_SERVER['SCRIPT_NAME'];
  106. } else if (basename($_SERVER['PHP_SELF']) === $scriptName) {
  107. $this->var['PHP_SELF'] = $_SERVER['PHP_SELF'];
  108. } else if (isset($_SERVER['ORIG_SCRIPT_NAME']) && basename($_SERVER['ORIG_SCRIPT_NAME']) === $scriptName) {
  109. $this->var['PHP_SELF'] = $_SERVER['ORIG_SCRIPT_NAME'];
  110. } else if (($pos = strpos($_SERVER['PHP_SELF'], '/' . $scriptName)) !== false) {
  111. $this->var['PHP_SELF'] = substr($_SERVER['SCRIPT_NAME'], 0, $pos) . '/' . $scriptName;
  112. } else if (isset($_SERVER['DOCUMENT_ROOT']) && str_starts_with($_SERVER['SCRIPT_FILENAME'], $_SERVER['DOCUMENT_ROOT'])) {
  113. $this->var['PHP_SELF'] = str_replace('\\', '/', str_replace($_SERVER['DOCUMENT_ROOT'], '', $_SERVER['SCRIPT_FILENAME']));
  114. $this->var['PHP_SELF'][0] != '/' && $this->var['PHP_SELF'] = '/' . $this->var['PHP_SELF'];
  115. } else {
  116. system_error('request_tainting');
  117. }
  118. }
  119. return $this->var['PHP_SELF'];
  120. }
  121. private function _init_input() {
  122. if (isset($_GET['GLOBALS']) || isset($_POST['GLOBALS']) || isset($_COOKIE['GLOBALS']) || isset($_FILES['GLOBALS'])) {
  123. exit('request tainting');
  124. }
  125. $prelength = strlen($this->config['cookie']['cookiepre']);
  126. foreach ($_COOKIE as $key => $val) {
  127. if (substr($key, 0, $prelength) == $this->config['cookie']['cookiepre']) {
  128. $this->var['cookie'][substr($key, $prelength)] = $val;
  129. }
  130. }
  131. if ($_SERVER['REQUEST_METHOD'] == 'POST' && !empty($_POST)) {
  132. foreach ($_POST as $k => $v) {
  133. $_GET[$k] = $v;
  134. }
  135. }
  136. }
  137. private function _init_output() {
  138. if (!empty($_SERVER['HTTP_ACCEPT_ENCODING']) && !str_contains($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip')) {
  139. $this->config['output']['gzip'] = false;
  140. }
  141. $allowgzip = $this->config['output']['gzip'] && empty($this->var['inajax']) && $this->var['mod'] != 'attachment' && EXT_OBGZIP;
  142. setglobal('gzipcompress', $allowgzip);
  143. if (!ob_start($allowgzip ? 'ob_gzhandler' : null)) {
  144. ob_start();
  145. }
  146. setglobal('charset', $this->config['output']['charset']);
  147. define('CHARSET', $this->config['output']['charset']);
  148. if ($this->config['output']['forceheader']) {
  149. @header('Content-Type: text/html; charset=' . CHARSET);
  150. }
  151. if ($this->var['isHTTPS'] && isset($this->config['output']['upgradeinsecure']) && $this->config['output']['upgradeinsecure']) {
  152. @header('Content-Security-Policy: upgrade-insecure-requests');
  153. }
  154. }
  155. public function reject_robot() {
  156. if (IS_ROBOT) {
  157. exit(header('HTTP/1.1 403 Forbidden'));
  158. }
  159. }
  160. private function _is_https() {
  161. // PHP 标准服务器变量
  162. if (isset($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) != 'off') {
  163. return true;
  164. }
  165. // X-Forwarded-Proto 事实标准头部, 用于反代透传 HTTPS 状态
  166. if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) == 'https') {
  167. return true;
  168. }
  169. // 阿里云全站加速私有 HTTPS 状态头部
  170. // Git 意见反馈 https://gitee.com/Discuz/DiscuzX/issues/I3W5GP
  171. if (isset($_SERVER['HTTP_X_CLIENT_SCHEME']) && strtolower($_SERVER['HTTP_X_CLIENT_SCHEME']) == 'https') {
  172. return true;
  173. }
  174. // 西部数码建站助手私有 HTTPS 状态头部
  175. // 官网意见反馈 https://discuz.dismall.com/thread-3849819-1-1.html
  176. if (isset($_SERVER['HTTP_FROM_HTTPS']) && strtolower($_SERVER['HTTP_FROM_HTTPS']) != 'off') {
  177. return true;
  178. }
  179. // 服务器端口号兜底判断
  180. if (isset($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == 443) {
  181. return true;
  182. }
  183. return false;
  184. }
  185. private function _get_client_ip() {
  186. $ip = $_SERVER['REMOTE_ADDR'];
  187. if (!array_key_exists('security', $this->config) || !$this->config['security']['onlyremoteaddr']) {
  188. if (array_key_exists('ipgetter', $this->config) && !empty($this->config['ipgetter']['setting'])) {
  189. $s = empty($this->config['ipgetter'][$this->config['ipgetter']['setting']]) ? [] : $this->config['ipgetter'][$this->config['ipgetter']['setting']];
  190. $c = 'ip_getter_' . $this->config['ipgetter']['setting'];
  191. $r = $c::get($s);
  192. $ip = ip::validate_ip($r) ? $r : $ip;
  193. } elseif (isset($_SERVER['HTTP_CLIENT_IP']) && ip::validate_ip($_SERVER['HTTP_CLIENT_IP'])) {
  194. $ip = $_SERVER['HTTP_CLIENT_IP'];
  195. } elseif (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
  196. if (strpos($_SERVER['HTTP_X_FORWARDED_FOR'], ',') > 0) {
  197. $exp = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
  198. $ip = ip::validate_ip(trim($exp[0])) ? $exp[0] : $ip;
  199. } else {
  200. $ip = ip::validate_ip($_SERVER['HTTP_X_FORWARDED_FOR']) ? $_SERVER['HTTP_X_FORWARDED_FOR'] : $ip;
  201. }
  202. }
  203. }
  204. return $ip;
  205. }
  206. private function _init_db() {
  207. if ($this->init_db && $this->config) {
  208. if ($this->config['db']['driver'] == 'pdo' && class_exists('PDO')) {
  209. $driver = 'db_driver_pdo';
  210. if (getglobal('config/db/slave')) {
  211. $driver = 'db_driver_pdo_slave';
  212. }
  213. $this->var['db_driver'] = 'pdo';
  214. } else {
  215. $driver = 'db_driver_mysqli';
  216. if (getglobal('config/db/slave')) {
  217. $driver = 'db_driver_mysqli_slave';
  218. }
  219. $this->var['db_driver'] = 'mysqli';
  220. }
  221. $this->var['mysql_driver'] = $driver;
  222. DB::init($driver, $this->config['db']);
  223. }
  224. }
  225. }