From 2d12aea936cb0ef0eae5bfde87c5cfe3e0a66cb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9C=B1=E9=87=91=E5=8B=87?= Date: Mon, 3 Jul 2023 08:09:26 +0000 Subject: [PATCH] * Wrapper header function for roadrunner. --- framework/base/control.class.php | 3 +- framework/base/helper.class.php | 74 +++++++++++++++++++++++++++++--- framework/base/model.class.php | 3 +- framework/base/router.class.php | 23 ++++++++-- module/common/model.php | 53 ++++++++++++++--------- 5 files changed, 123 insertions(+), 33 deletions(-) diff --git a/framework/base/control.class.php b/framework/base/control.class.php index bee2141f45..3e8423dd30 100644 --- a/framework/base/control.class.php +++ b/framework/base/control.class.php @@ -1,4 +1,5 @@ -framework->autoRepairTable) and $config->framework->autoRepairTable) { - header("location: " . $config->webRoot . 'checktable.php'); - throw EndResponseException::create(); + helper::header('location', $config->webRoot . 'checktable.php'); + helper::end(); } return $lang->repairTable; } return null; } + + /** + * 设置状态码。 + * Set status code. + * + * @param int $code + * @static + * @access public + * @return void + */ + static public function setStatus(int $code) + { + if(isset($app->worker)) + { + $app->worker->response->setStatus($code); + } + else + { + $PHRASES = array( + 100 => 'Continue', 101 => 'Switching Protocols', 102 => 'Processing', + 200 => 'OK', 201 => 'Created', 202 => 'Accepted', 203 => 'Non-Authoritative Information', 204 => 'No Content', 205 => 'Reset Content', 206 => 'Partial Content', 207 => 'Multi-status', 208 => 'Already Reported', + 300 => 'Multiple Choices', 301 => 'Moved Permanently', 302 => 'Found', 303 => 'See Other', 304 => 'Not Modified', 305 => 'Use Proxy', 306 => 'Switch Proxy', 307 => 'Temporary 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 Large', 415 => 'Unsupported Media Type', 416 => 'Requested range not satisfiable', 417 => 'Expectation Failed', 418 => 'I\'m a teapot', 422 => 'Unprocessable Entity', 423 => 'Locked', 424 => 'Failed Dependency', 425 => 'Unordered Collection', 426 => 'Upgrade Required', 428 => 'Precondition Required', 429 => 'Too Many Requests', 431 => 'Request Header Fields Too Large', 451 => 'Unavailable For Legal Reasons', + 500 => 'Internal Server Error', 501 => 'Not Implemented', 502 => 'Bad Gateway', 503 => 'Service Unavailable', 504 => 'Gateway Time-out', 505 => 'HTTP Version not supported', 506 => 'Variant Also Negotiates', 507 => 'Insufficient Storage', 508 => 'Loop Detected', 511 => 'Network Authentication Required', + ); + header('HTTP/1.1 ' . (string)$code . ' ' . $PHRASES[$code], true, $code); + } + } + + /** + * 发送HTTP头信息。 + * Send http header. + * + * @param string $key + * @param string $value + * @param bool $replace + * @param int $response_code + * @static + * @access public + * @return void + */ + static public function header(string $key, string $value, bool $replace = true, int $response_code = 0) + { + global $app; + + if(isset($app->worker)) + { + $key = trim(strtolower($key)); + $app->worker->response->setHeader($key, $value); + + if($key == 'location') + { + $app->worker->response->setStatus(302); + helper::end(); + } + } + else + { + header($key . ': ' . $value, $replace, $response_code); + } + } } //------------------------------- 常用函数。Some tool functions.-------------------------------// diff --git a/framework/base/model.class.php b/framework/base/model.class.php index c2e5557b5f..03f039133f 100644 --- a/framework/base/model.class.php +++ b/framework/base/model.class.php @@ -1,4 +1,5 @@ -setDebug(); $this->setErrorHandler(); $this->setTimezone(); - $this->startSession(); - if($this->config->framework->multiSite) $this->setSiteCode() && $this->loadExtraConfig(); if($this->config->framework->autoConnectDB) $this->connectDB(); - if($this->config->framework->multiLanguage) $this->setClientLang(); $this->setupProfiling(); $this->setupXhprof(); $this->setEdition(); + + $this->setClient(); + } + + /** + * 设置客户端信息 + * Set info of client: session, lang, device, theme... + * + * @access public + * @return void + */ + public function setClient(): void + { + $this->startSession(); + + if($this->config->framework->multiSite) $this->setSiteCode() && $this->loadExtraConfig(); + if($this->config->framework->multiLanguage) $this->setClientLang(); $this->setVision(); $needDetectDevice = zget($this->config->framework->detectDevice, $this->clientLang, false); diff --git a/module/common/model.php b/module/common/model.php index b14b9d04ad..7d2f7b09ae 100644 --- a/module/common/model.php +++ b/module/common/model.php @@ -25,18 +25,28 @@ class commonModel extends model if(!defined('FIRST_RUN')) { define('FIRST_RUN', true); - $this->sendHeader(); - $this->setCompany(); - $this->setUser(); - $this->setApproval(); - $this->loadConfigFromDB(); - $this->app->setTimezone(); - $this->loadCustomFromDB(); - if(!$this->checkIP()) return print($this->lang->ipLimited); $this->app->loadLang('company'); + $this->setUserConfig(); } } + /** + * Set config of user. + * + * @access public + * @return void + */ + public function setUserConfig() + { + $this->sendHeader(); + $this->setCompany(); + $this->setUser(); + $this->setApproval(); + $this->loadConfigFromDB(); + $this->loadCustomFromDB(); + if(!$this->checkIP()) return print($this->lang->ipLimited); + } + /** * Set the status of execution, project, and program to doing. * @@ -198,21 +208,21 @@ class commonModel extends model */ public function sendHeader() { - header("Content-Type: text/html; Language={$this->config->charset}"); - header("Cache-control: private"); + helper::header('Content-Type', "text/html; Language={$this->config->charset}"); + helper::header('Cache-Control', 'private'); /* Send HTTP header. */ - if($this->config->framework->sendXCTO) header("X-Content-Type-Options: nosniff"); - if($this->config->framework->sendXXP) header("X-XSS-Protection: 1; mode=block"); - if($this->config->framework->sendHSTS) header("Strict-Transport-Security: max-age=3600; includeSubDomains"); - if($this->config->framework->sendRP) header("Referrer-Policy: no-referrer-when-downgrade"); - if($this->config->framework->sendXPCDP) header("X-Permitted-Cross-Domain-Policies: master-only"); - if($this->config->framework->sendXDO) header("X-Download-Options: noopen"); + if($this->config->framework->sendXCTO) helper::header('X-Content-Type-Options', 'nosniff'); + if($this->config->framework->sendXXP) helper::header('X-XSS-Protection', '1; mode=block'); + if($this->config->framework->sendHSTS) helper::header('Strict-Transport-Security', 'max-age=3600; includeSubDomains'); + if($this->config->framework->sendRP) helper::header('Referrer-Policy', 'no-referrer-when-downgrade'); + if($this->config->framework->sendXPCDP) helper::header('X-Permitted-Cross-Domain-Policies', 'master-only'); + if($this->config->framework->sendXDO) helper::header('X-Download-Options', 'noopen'); /* Set Content-Security-Policy header. */ if($this->config->CSPs) { - foreach($this->config->CSPs as $CSP) header("Content-Security-Policy: $CSP;"); + foreach($this->config->CSPs as $CSP) helper::header('Content-Security-Policy', "$CSP;"); } if($this->loadModel('setting')->getItem('owner=system&module=sso&key=turnon')) @@ -220,12 +230,12 @@ class commonModel extends model if(isset($_SERVER["HTTPS"]) and $_SERVER["HTTPS"] == 'on') { $session = $this->config->sessionVar . '=' . session_id(); - header("Set-Cookie: $session; SameSite=None; Secure=true", false); + helper::header('Set-Cookie', "$session; SameSite=None; Secure=true", false); } } else { - if(!empty($this->config->xFrameOptions)) header("X-Frame-Options: {$this->config->xFrameOptions}"); + if(!empty($this->config->xFrameOptions)) helper::header('X-Frame-Options', $this->config->xFrameOptions); } } @@ -267,7 +277,7 @@ class commonModel extends model if(!defined('IN_UPGRADE')) $this->session->user->view = $this->loadModel('user')->grantUserView(); $this->app->user = $this->session->user; } - elseif($this->app->company->guest or PHP_SAPI == 'cli') + elseif($this->app->company->guest || (PHP_SAPI == 'cli' && !isset($_SERVER['RR_MODE']))) { $user = new stdClass(); $user->id = 0; @@ -2476,6 +2486,7 @@ EOF; 'my' => array('changepassword'), 'message' => array('ajaxgetmessage'), ); + if(!empty($this->app->user->modifyPassword) and (!isset($beforeValidMethods[$module]) or !in_array($method, $beforeValidMethods[$module]))) return print(js::locate(helper::createLink('my', 'changepassword'))); if(!$this->loadModel('user')->isLogon() and $this->server->php_auth_user) $this->user->identifyByPhpAuth(); if(!$this->loadModel('user')->isLogon() and $this->cookie->za) $this->user->identifyByCookie(); @@ -2572,7 +2583,7 @@ EOF; $url = helper::safe64Encode($_SERVER['REQUEST_URI']); $redirectUrl = helper::createLink('index', 'index'); $redirectUrl .= strpos($redirectUrl, '?') === false ? "?open=$url" : "&open=$url"; - header("location: $redirectUrl"); + helper::header('location', $redirectUrl); return false; }