Não pode escolher mais do que 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 
 

366 linhas
10 KiB

  1. <?php
  2. namespace Kuxin;
  3. /**
  4. * Class Response
  5. *
  6. * @package Kuxin
  7. * @author Pakey <pakey@qq.com>
  8. */
  9. class Response
  10. {
  11. /**
  12. * @var
  13. */
  14. protected static $type;
  15. /**
  16. * @var array
  17. */
  18. protected static $types = ['html', 'json', 'xml', 'jsonp', 'png', 'gif', 'jpg', 'jpeg'];
  19. /**
  20. * @var bool
  21. */
  22. protected static $autoRender = true;
  23. /**
  24. * @return string
  25. */
  26. public static function getType(): string
  27. {
  28. if (self::$type) {
  29. return self::$type;
  30. } elseif (Request::isAjax()) {
  31. return 'json';
  32. } else {
  33. return 'html';
  34. }
  35. }
  36. /**
  37. * @param $type
  38. * @return bool
  39. */
  40. public static function setType(string $type)
  41. {
  42. if (in_array($type, self::$types)) {
  43. return self::$type = $type;
  44. } else {
  45. return false;
  46. }
  47. }
  48. /**
  49. * @return string
  50. */
  51. protected static function getMime(): string
  52. {
  53. switch (self::$type) {
  54. case 'json':
  55. return 'application/json';
  56. case 'xml':
  57. return 'text/xml';
  58. case 'html':
  59. return 'text/html';
  60. case 'png':
  61. return 'image/png';
  62. case 'jpg':
  63. case 'jpeg':
  64. return 'image/jpg';
  65. case 'gif':
  66. return 'image/gif';
  67. default:
  68. return 'text/html';
  69. }
  70. }
  71. /**
  72. *
  73. */
  74. public static function setHeader(): void
  75. {
  76. if (!headers_sent()) {
  77. //设置系统的输出字符
  78. $charset = in_array(self::getType(), ['json', 'jsonp', 'xml']) ? 'utf-8' : (Config::get('template.output_charset', 'utf-8') == 'big5' ? 'utf-8' : Config::get('template.output_charset'));
  79. header("Content-Type: " . self::getMime() . "; charset={$charset}");
  80. if (self::getType() == 'html') {
  81. // 支持页面回跳
  82. header("Cache-control: private");
  83. // 防止被框架引用
  84. header('X-Frame-Options: sameorigin');
  85. }
  86. //版权标识
  87. header("X-Powered-By: PTcms Studio (www.ptcms.com)");
  88. // 跨域 暂时不做统一处理
  89. // if (self::$type == 'json') {
  90. // header('Access-Control-Allow-Origin:*');
  91. // header('Access-Control-Allow-Headers:accept, content-type');
  92. // }
  93. }
  94. }
  95. /**
  96. * @param string $content
  97. */
  98. public static function setBody($content = ''): void
  99. {
  100. if (!headers_sent()) {
  101. self::setHeader();
  102. }
  103. echo $content;
  104. }
  105. /**
  106. * 终止相应
  107. */
  108. public static function finish()
  109. {
  110. exit();
  111. }
  112. /**
  113. *
  114. */
  115. public static function disableRender(): void
  116. {
  117. self::$autoRender = false;
  118. }
  119. /**
  120. *
  121. */
  122. public static function enableRender(): void
  123. {
  124. self::$autoRender = true;
  125. }
  126. /**
  127. * @return bool
  128. */
  129. public static function isAutoRender(): bool
  130. {
  131. return self::$autoRender;
  132. }
  133. /**
  134. * @param $url
  135. * @param int $code
  136. */
  137. public static function redirect(string $url, $code = 302): void
  138. {
  139. if (!headers_sent()) {
  140. if ($code == 302) {
  141. header('HTTP/1.1 302 Moved Temporarily');
  142. header('Status:302 Moved Temporarily'); // 确保FastCGI模式下正常
  143. } else {
  144. header('HTTP/1.1 301 Moved Permanently');
  145. header('Status:301 Moved Permanently');
  146. }
  147. header('Location: ' . $url);
  148. exit;
  149. } else {
  150. echo '<script>window.location.href="' . $url . '"</script>';
  151. }
  152. }
  153. /**
  154. * @return mixed|string
  155. */
  156. public static function runInfo()
  157. {
  158. if (Config::get('is_gen_html')) {
  159. return '';
  160. }
  161. $tpl = Config::get('runinfo', 'Power by PTCMS, Processed in {time}(s), Memory usage: {mem}MB.');
  162. $from[] = '{time}';
  163. $to[] = number_format(microtime(true) - Registry::get('_startTime'), 3);
  164. $from[] = '{mem}';
  165. $to[] = number_format((memory_get_usage() - Registry::get('_startUseMems')) / 1024 / 1024, 3);
  166. if (strpos($tpl, '{net}')) {
  167. $from[] = '{net}';
  168. $to[] = Registry::get('_apinum', 0);
  169. }
  170. if (strpos($tpl, '{file}')) {
  171. $from[] = '{file}';
  172. $to[] = count(get_included_files());
  173. }
  174. if (strpos($tpl, '{sql}')) {
  175. $from[] = '{sql}';
  176. $to[] = Registry::get('_sqlnum', 0);
  177. }
  178. if (strpos($tpl, '{cacheread}')) {
  179. $from[] = '{cacheread}';
  180. $to[] = Registry::get('_cacheRead', 0);
  181. }
  182. if (strpos($tpl, '{cachewrite}')) {
  183. $from[] = '{cachewrite}';
  184. $to[] = Registry::get('_cacheWrite', 0);
  185. }
  186. if (strpos($tpl, '{cachehit}')) {
  187. $from[] = '{cachehit}';
  188. $to[] = Registry::get('_cacheHit', 0);
  189. }
  190. $runtimeinfo = str_replace($from, $to, $tpl);
  191. return $runtimeinfo;
  192. }
  193. /**
  194. * 下载文件
  195. *
  196. * @param $con
  197. * @param $name
  198. * @param string $type
  199. */
  200. public static function download(string $con, string $name, $type = 'str')
  201. {
  202. $length = ($type == 'file') ? filesize($con) : strlen($con);
  203. header("Content-type: application/octet-stream");
  204. header("Accept-Ranges: bytes");
  205. header("Content-Length: " . $length);
  206. header('Pragma: cache');
  207. header('Cache-Control: public, must-revalidate, max-age=0');
  208. header('Content-Disposition: attachment; filename="' . urlencode($name) . '"; charset=utf-8'); //下载显示的名字,注意格式
  209. header("Content-Transfer-Encoding: binary ");
  210. if ($type == 'file') {
  211. readfile($con);
  212. } else {
  213. echo $con;
  214. }
  215. }
  216. /**
  217. * 屏幕输出
  218. *
  219. * @param $text
  220. * @param $type
  221. * @param $line
  222. * @return mixed
  223. */
  224. public static function screen(string $text, string $type, bool $line = true)
  225. {
  226. switch ($type) {
  227. case 'success':
  228. $color = 'green';
  229. break;
  230. case 'error':
  231. $color = 'red';
  232. break;
  233. case 'warning':
  234. $color = "orangered";
  235. break;
  236. case 'info':
  237. $color = 'darkblue';
  238. break;
  239. default:
  240. $color = $type;
  241. }
  242. $line = $line ? '<br/>' . PHP_EOL : '';
  243. $text = nl2br($text);
  244. if ($color) {
  245. echo "<span style='color:{$color}'>{$text}</span>{$line}";
  246. } else {
  247. echo "<span>{$text}</span>{$line}";
  248. }
  249. if (Config::get('app.fastcgi_buffer_fill')) {
  250. echo str_repeat(' ', 1024 * Config::get('app.fastcgi_buffer_size', 128));
  251. }
  252. ob_flush();
  253. flush();
  254. }
  255. /**
  256. * 终端输出
  257. *
  258. * @param string $text
  259. * @param string $type
  260. * @param bool $line
  261. * @return mixed
  262. */
  263. public static function terminal(string $text, string $type = '', $line = true)
  264. {
  265. $end = chr(27) . "[0m";
  266. switch (strtolower($type)) {
  267. case "success":
  268. $pre = chr(27) . "[32m"; //Green
  269. break;
  270. case "error":
  271. $pre = chr(27) . "[31m"; //Red
  272. break;
  273. case "warning":
  274. $pre = chr(27) . "[33m"; //Yellow
  275. break;
  276. case 'info':
  277. $pre = chr(27) . '[36m'; //蓝色
  278. break;
  279. default:
  280. $pre = "";
  281. $end = '';
  282. }
  283. $line = $line ? PHP_EOL : '';
  284. if (stripos($text, '<br')) {
  285. $text = str_ireplace(['<br /><br />', '<br/><br/>', '<br/>', '<br />'], PHP_EOL, $text);
  286. }
  287. $text = strip_tags($text);
  288. $text = preg_replace("#" . PHP_EOL . "+?#", PHP_EOL, $text);
  289. return $pre . $text . $end . $line;
  290. }
  291. public static function error(string $message, string $file, int $line)
  292. {
  293. if (PHP_SAPI == 'cli') {
  294. debug_print_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
  295. echo PHP_EOL;
  296. $debug = debug_backtrace();
  297. $traces = end($debug);
  298. if (isset($traces['args']['0']->xdebug_message)) {
  299. exit(PHP_EOL . trim($traces['args']['0']->xdebug_message) . PHP_EOL);
  300. } else {
  301. exit($message . '[' . $file . ':' . $line . ']' . PHP_EOL);
  302. }
  303. } else {
  304. if (Config::get('app.debug')) {
  305. $e['message'] = $message;
  306. $e['file'] = $file;
  307. $e['line'] = $line;
  308. include KX_ROOT . '/kuxin/tpl/error.php';
  309. } else {
  310. header('HTTP/1.1 404 Not Found');
  311. header("status: 404 Not Found");
  312. Log::record(sprintf("%s [%s:%s]", $message, $file, $line));
  313. $file = KX_ROOT . (Config::get('system.spider_error_page') && Request::isSpider() ? '/spider.html' : '/error.html');
  314. if (is_file($file)) {
  315. $content = file_get_contents($file);
  316. $content = str_replace(['{$sitename}', '{$siteurl}', '{$msg}', '{$tongji}'], [Config::get('sitename'), Config::get('siteurl'), $message, Config::get('tongji.pc')], $content);
  317. } else {
  318. $content = '页面出现错误';
  319. }
  320. self::setBody($content);
  321. }
  322. self::finish();
  323. }
  324. }
  325. /**
  326. * @param $arr
  327. */
  328. public static function debug($arr)
  329. {
  330. echo '<pre>';
  331. print_r($arr);
  332. echo '</pre>', PHP_EOL;
  333. }
  334. public static function nocache()
  335. {
  336. header('Expires: Thu, 01 Jan 1970 00:00:01 GMT');
  337. header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
  338. header('Cache-Control: no-cache, must-revalidate, max-age=0');
  339. header('Pragma: no-cache');
  340. }
  341. }