index.php 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. <?php
  2. namespace loyalsoft;
  3. /**
  4. * 服务端程序入口(单一入口)
  5. * method: post/get 皆可
  6. * params: 一个经过(压缩)转码的json串.
  7. * @author gwang (mail@wanggangzero.cn)
  8. * @version 2018.11.08
  9. * @modifys
  10. * 2018.11.08 将index.php原来的代码整理到Index类中,使用到的全局变量用类的静态变量打理起来。
  11. * 给$req的全局静态变量增加req()访问方式。
  12. * 对于逻辑中的ErrResp, 添加Err方法,直接截断逻辑,返回响应结果。 -- gwang
  13. * 2018.04.05 去掉返回值中的content-encoding信息,开发了配套的fiddler插件,不需要自动识别机制了. --gwang
  14. * 2017.11.15 调整传输层协议, get的返回值也采用deflate编码.
  15. * 2017.07.19 代码优化, 格式整理
  16. * 2016.4.26 引入客户端检查机制,来源为模拟客户端时输出调试信息.
  17. * 2016.4.25 echo 中的连字符改为逗号表达式.
  18. */
  19. class Index {
  20. /**
  21. * @var boolean 请求方式是否为Post
  22. */
  23. static $isPost = false;
  24. /**
  25. * @var string 调试信息
  26. */
  27. static $debugMsg = "";
  28. /**
  29. * @var string user-agent
  30. */
  31. static $ua = "";
  32. /**
  33. * @var boolean 调试模式
  34. */
  35. static $isDebugging = false;
  36. /**
  37. * @var int 超大响应的判断标准50kb
  38. */
  39. static $bigRespInKbs = 50;
  40. static function Init() {
  41. ob_start(); # 开启一重output_buffer截获意外输出.
  42. self::$isPost = (isset($_SERVER['REQUEST_METHOD']) ? ($_SERVER['REQUEST_METHOD'] == 'PUT' || $_SERVER['REQUEST_METHOD'] == 'POST' ) : FALSE); # 判断是否为Post方式
  43. self::$debugMsg = ""; # 记录调试信息
  44. self::$ua = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : ""; # 客户端标志
  45. self::$isDebugging = isset(self::$ua) && \strncmp(self::$ua, "WebRequest", 10) == 0; # 是否将ob_buff的输出信息附加到返回值
  46. self::$bigRespInKbs = self::$isDebugging ? 1 : 50; # 记录超大返回值,测试模式1k,正式50k.
  47. include_once __DIR__ . '/Services/AppServer.php'; # 引入主程序
  48. $data = query_string(); # 取参数
  49. if (self::$isDebugging) { # 调试模式=>性能记录
  50. $rt = new RenderTime(); # 计时器, 默认开始计时
  51. }
  52. # 传输层解码(压缩、去除控制字符)
  53. # 目前规则: Post发送数据时使用deflate编码, GET方式发送数据时使用base64编码
  54. $data = self::$isPost ? gzinflate($data) : base64_decode($data);
  55. //$data = base64_decode($data);
  56. # 加密层解码, 加密传输, 保障数据安全
  57. # ....
  58. $req = JsonUtil::decode($data); # 请求数据, 数据层协议JSON
  59. if (self::$isDebugging) { # 刷调试信息
  60. $rt->end(); # 计时器结束
  61. self::$debugMsg .= '<br/>解压耗时:' . $rt->getRenderTime(); # 解码耗时
  62. # 计时器开始
  63. }
  64. new Req($req); # 初始化req()
  65. }
  66. static function Run() {
  67. if (self::$isDebugging) { # 调试模式=>性能记录
  68. $rt = new RenderTime(); # 计时器, 默认开始计时
  69. $rt->start();
  70. }
  71. $app = new AppServer(); # 初始化业务框架
  72. $resp = $app->api(); # 分发处理逻辑
  73. if (self::$isDebugging) { # 组织调试信息
  74. $rt->end(); # 计时器结束
  75. $ms = round($rt->getRenderTime(false) / 1000, 2); # 耗时换算成毫秒
  76. $msi = $ms > 50 ? "<font color='red'>$ms</font>" : $ms; # 超过50ms用红色显示
  77. self::$debugMsg .= "<br/>逻辑耗时: $msi 毫秒"; # 逻辑耗时
  78. self::$debugMsg .= '<br/>内存分配:' . number_format(memory_get_peak_usage() / 1024) . 'kb,';
  79. self::$debugMsg .= '内存占用:' . number_format(memory_get_usage() / 1024) . 'kb'; # 内存使用数量(kb)
  80. }
  81. return $resp;
  82. }
  83. static function OverPass($resp) {
  84. $ret = JsonUtil::encode($resp); # 返回值, 数据层协议:JSON
  85. $errinfo = ob_get_clean(); # 检查并截获异常输出
  86. if (self::$isDebugging) { # 附加调试信息和异常输出
  87. $ret .= '<br/><hr/><font color=\'#6666FF\'>' . self::$debugMsg; # 附加调试信息,
  88. if (strlen($errinfo) > 0) { # 将捕获的异常输出附加到返回值
  89. $ret .= '<br/><br/>Unexpected output:<br/>' . $errinfo;
  90. }
  91. $ret .= '</font>';
  92. } else {
  93. if (!empty(self::$debugMsg)) {
  94. CLog::err(self::$debugMsg);
  95. }
  96. }
  97. # 返回数据, 加密层编码, 加密传输, 保障数据安全
  98. # ....
  99. # 返回数据, 传输层编码(一律deflate压缩)
  100. if (php_sapi_name() === 'cli') {
  101. # 命令行的就算了, 要不肉眼看不懂了
  102. } else {
  103. $ret = gzdeflate($ret); # 不管请求时使用的是什么方法, 返回时一律使用deflate压缩
  104. }
  105. $retLen = strlen($ret); # 计算下返回值长度.
  106. if ($retLen > (1024 * self::$bigRespInKbs)) { # 长度大于50k时记录超大返回值日志.
  107. CLog::warn("Big Response(" . req()->cmd . "):\n" # 带有\n转义符的时候, 必须用双引号
  108. . "\t" . substr(JsonUtil::encode($resp), 0, 30) # 返回串(截断为30bytes)
  109. . "..., about " . CommUtil::floatToInt($retLen / 1024) . "kbs.", "Index"); # 返回串长度
  110. }
  111. return $ret;
  112. }
  113. /**
  114. * 直接返回错误resp并结束运行
  115. * @param int $err
  116. * @param string $msg
  117. */
  118. static function Err($err, $msg = "") {
  119. if (ErrCode::ok === $err) {
  120. CLog::err("Err()方法的参数err==ok, 那你还调个蛋的Err()!!!");
  121. }
  122. if (Index::$isDebugging) { # 组织调试信息
  123. Index::$debugMsg .= "<br/><font color='red'>发生错误逻辑中断($err):$msg</font>"; # 错误信息用红色显示
  124. Index::$debugMsg .= '<br/>内存分配:' . number_format(memory_get_peak_usage() / 1024) . 'kb,';
  125. Index::$debugMsg .= '内存占用:' . number_format(memory_get_usage() / 1024) . 'kb'; # 内存使用数量(kb)
  126. }
  127. if (is_string($err)) { # 防御Err中直接输入字符串的货
  128. $msg = "发生错误($err)直接中断逻辑执行." . $msg;
  129. CLog::err($msg);
  130. $err = ErrCode::err_innerfault;
  131. }
  132. $resp = Resp::err($err, $msg);
  133. $resp->AfterProc();
  134. exit(Index::OverPass($resp)); # 直接返回错误信息
  135. }
  136. }
  137. Index::Init();
  138. $resp = Index::Run();
  139. exit(Index::OverPass($resp));