Http.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  1. <?php
  2. namespace App\Common\Protocols;
  3. /**
  4. * 判断http协议的数据包是否完整
  5. * @param string $http_string
  6. * @return integer 0表示完整 否则还需要integer长度的数据
  7. */
  8. function http_input($http_string)
  9. {
  10. // 查找\r\n\r\n
  11. $data_length = strlen($http_string);
  12. if(!strpos($http_string, "\r\n\r\n"))
  13. {
  14. return 1;
  15. }
  16. // POST请求还要读包体
  17. if(strpos($http_string, "POST"))
  18. {
  19. // 找Content-Length
  20. $match = array();
  21. if(preg_match("/\r\nContent-Length: ?(\d?)\r\n/", $http_string, $match))
  22. {
  23. $content_lenght = $match[1];
  24. }
  25. else
  26. {
  27. return 0;
  28. }
  29. // 看包体长度是否符合
  30. $tmp = explode("\r\n\r\n", $http_string, 2);
  31. $remain_length = $content_lenght - strlen($tmp[1]);
  32. return $remain_length >= 0 ? $remain_length : 0;
  33. }
  34. return 0;
  35. }
  36. /**
  37. * 解析http协议,设置$_POST $_GET $_COOKIE $_REQUEST
  38. * @param string $http_string
  39. */
  40. function http_start($http_string, $SERVER = array())
  41. {
  42. // 初始化
  43. $_POST = $_GET = $_COOKIE = $_REQUEST = $_SESSION = array();
  44. $GLOBALS['HTTP_RAW_POST_DATA'] = '';
  45. // 清空上次的数据
  46. HttpCache::$header = array();
  47. HttpCache::$instance = new HttpCache();
  48. // 需要设置的变量名
  49. $_SERVER = array (
  50. 'QUERY_STRING' => '',
  51. 'REQUEST_METHOD' => '',
  52. 'REQUEST_URI' => '',
  53. 'SERVER_PROTOCOL' => 'HTTP/1.1',
  54. 'GATEWAY_INTERFACE' => 'CGI/1.1',
  55. 'SERVER_SOFTWARE' => 'workerman/2.1',
  56. 'SERVER_NAME' => '',
  57. 'HTTP_HOST' => '',
  58. 'HTTP_USER_AGENT' => '',
  59. 'HTTP_ACCEPT' => '',
  60. 'HTTP_ACCEPT_LANGUAGE' => '',
  61. 'HTTP_ACCEPT_ENCODING' => '',
  62. 'HTTP_COOKIE' => '',
  63. 'HTTP_CONNECTION' => '',
  64. 'REQUEST_TIME' => 0,
  65. 'SCRIPT_NAME' => '',//$SERVER传递
  66. 'REMOTE_ADDR' => '',// $SERVER传递
  67. 'REMOTE_PORT' => '0',// $SERVER传递
  68. 'SERVER_ADDR' => '', // $SERVER传递
  69. 'DOCUMENT_ROOT' => '',//$SERVER传递
  70. 'SCRIPT_FILENAME' => '',// $SERVER传递
  71. 'SERVER_PORT' => '80',
  72. 'PHP_SELF' => '', // 设置成SCRIPT_NAME
  73. );
  74. // 将header分割成数组
  75. $header_data = explode("\r\n", $http_string);
  76. list($_SERVER['REQUEST_METHOD'], $_SERVER['REQUEST_URI'], $_SERVER['SERVER_PROTOCOL']) = explode(' ', $header_data[0]);
  77. // 需要解析$_POST
  78. if($_SERVER['REQUEST_METHOD'] == 'POST')
  79. {
  80. $tmp = explode("\r\n\r\n", $http_string, 2);
  81. parse_str($tmp[1], $_POST);
  82. // $GLOBALS['HTTP_RAW_POST_DATA']
  83. $GLOBALS['HTTP_RAW_POST_DATA'] = $tmp[1];
  84. unset($header_data[count($header_data) - 1]);
  85. }
  86. unset($header_data[0]);
  87. foreach($header_data as $content)
  88. {
  89. // \r\n\r\n
  90. if(empty($content))
  91. {
  92. continue;
  93. }
  94. list($key, $value) = explode(':', $content, 2);
  95. $key = strtolower($key);
  96. $value = trim($value);
  97. switch($key)
  98. {
  99. // HTTP_HOST
  100. case 'host':
  101. $_SERVER['HTTP_HOST'] = $value;
  102. $tmp = explode(':', $value);
  103. $_SERVER['SERVER_NAME'] = $tmp[0];
  104. if(isset($tmp[1]))
  105. {
  106. $_SERVER['SERVER_PORT'] = $tmp[1];
  107. }
  108. break;
  109. // cookie
  110. case 'cookie':
  111. {
  112. $_SERVER['HTTP_COOKIE'] = $value;
  113. parse_str(str_replace('; ', '&', $_SERVER['HTTP_COOKIE']), $_COOKIE);
  114. }
  115. break;
  116. // user-agent
  117. case 'user-agent':
  118. $_SERVER['HTTP_USER_AGENT'] = $value;
  119. break;
  120. // accept
  121. case 'accept':
  122. $_SERVER['HTTP_ACCEPT'] = $value;
  123. break;
  124. // accept-language
  125. case 'accept-language':
  126. $_SERVER['HTTP_ACCEPT_LANGUAGE'] = $value;
  127. break;
  128. // accept-encoding
  129. case 'accept-encoding':
  130. $_SERVER['HTTP_ACCEPT_ENCODING'] = $value;
  131. break;
  132. // connection
  133. case 'connection':
  134. $_SERVER['HTTP_CONNECTION'] = $value;
  135. break;
  136. case 'referer':
  137. $_SERVER['HTTP_REFERER'] = $value;
  138. break;
  139. }
  140. }
  141. // 'REQUEST_TIME_FLOAT' => 1375774613.237,
  142. $_SERVER['REQUEST_TIME_FLOAT'] = microtime(true);
  143. $_SERVER['REQUEST_TIME'] = intval($_SERVER['REQUEST_TIME_FLOAT']);
  144. // QUERY_STRING
  145. $_SERVER['QUERY_STRING'] = parse_url($_SERVER['REQUEST_URI'], PHP_URL_QUERY);
  146. // GET
  147. parse_str($_SERVER['QUERY_STRING'], $_GET);
  148. // REQUEST
  149. $_REQUEST = array_merge($_GET, $_POST);
  150. // 合并传递的值
  151. $_SERVER = array_merge($_SERVER, $SERVER);
  152. // PHP_SELF
  153. if($_SERVER['SCRIPT_NAME'] && !$_SERVER['PHP_SELF'])
  154. {
  155. $_SERVER['PHP_SELF'] = $_SERVER['SCRIPT_NAME'];
  156. }
  157. }
  158. function http_end($content)
  159. {
  160. // 没有http-code默认给个
  161. if(!isset(HttpCache::$header['Http-Code']))
  162. {
  163. $header = "HTTP/1.1 200 OK\r\n";
  164. }
  165. else
  166. {
  167. $header = HttpCache::$header['Http-Code']."\r\n";
  168. unset(HttpCache::$header['Http-Code']);
  169. }
  170. // 没有Content-Type默认给个
  171. if(!isset(HttpCache::$header['Content-Type']))
  172. {
  173. $header .= "Content-Type: text/html;charset=utf-8\r\n";
  174. }
  175. // 其它header
  176. foreach(HttpCache::$header as $key=>$item)
  177. {
  178. if('Set-Cookie' == $key && is_array($item))
  179. {
  180. foreach($item as $it)
  181. {
  182. $header .= $it."\r\n";
  183. }
  184. }
  185. else
  186. {
  187. $header .= $item."\r\n";
  188. }
  189. }
  190. // header
  191. $header .= "Server: WorkerMan/2.1\r\nContent-Length: ".strlen($content)."\r\n";
  192. $header .= "\r\n";
  193. HttpCache::$header = array();
  194. // 保存cookie
  195. session_write_close();
  196. $_POST = $_GET = $_COOKIE = $_REQUEST = $_SESSION = array();
  197. $GLOBALS['HTTP_RAW_POST_DATA'] = '';
  198. HttpCache::$instance = null;
  199. // 整个http包
  200. return $header.$content;
  201. }
  202. /**
  203. * 设置http头
  204. * @return bool
  205. */
  206. function header($content, $replace = true, $http_response_code = 0)
  207. {
  208. if(!defined('WORKERMAN_ROOT_DIR'))
  209. {
  210. if($http_response_code != 0)
  211. {
  212. return \header($content, $replace, $http_response_code);
  213. }
  214. else
  215. {
  216. return \header($content, $replace);
  217. }
  218. }
  219. if(strpos($content, 'HTTP') === 0)
  220. {
  221. $key = 'Http-Code';
  222. }
  223. else
  224. {
  225. $key = strstr($content, ":", true);
  226. if(empty($key))
  227. {
  228. return false;
  229. }
  230. }
  231. if($key == 'Set-Cookie')
  232. {
  233. HttpCache::$header[$key][] = $content;
  234. }
  235. else
  236. {
  237. HttpCache::$header[$key] = $content;
  238. }
  239. if('location' == strtolower($key))
  240. {
  241. header("HTTP/1.1 302 Moved Temporarily");
  242. }
  243. return true;
  244. }
  245. /**
  246. * 删除一个header
  247. * @param string $name
  248. * @return void
  249. */
  250. function header_remove($name)
  251. {
  252. if(!defined('WORKERMAN_ROOT_DIR'))
  253. {
  254. return \header_remove($name);
  255. }
  256. unset( HttpCache::$header[$name]);
  257. }
  258. /**
  259. * 设置cookie
  260. * @param string $name
  261. * @param string $value
  262. * @param integer $maxage
  263. * @param string $path
  264. * @param string $domain
  265. * @param bool $secure
  266. * @param bool $HTTPOnly
  267. */
  268. function setcookie($name, $value = '', $maxage = 0, $path = '', $domain = '', $secure = false, $HTTPOnly = false) {
  269. if(!defined('WORKERMAN_ROOT_DIR'))
  270. {
  271. return \setcookie($name, $value, $maxage, $path, $domain, $secure, $HTTPOnly);
  272. }
  273. header(
  274. 'Set-Cookie: ' . $name . '=' . rawurlencode($value)
  275. . (empty($domain) ? '' : '; Domain=' . $domain)
  276. . (empty($maxage) ? '' : '; Max-Age=' . $maxage)
  277. . (empty($path) ? '' : '; Path=' . $path)
  278. . (!$secure ? '' : '; Secure')
  279. . (!$HTTPOnly ? '' : '; HttpOnly'), false);
  280. }
  281. /**
  282. * session_start
  283. *
  284. */
  285. function session_start()
  286. {
  287. if(!defined('WORKERMAN_ROOT_DIR'))
  288. {
  289. return \session_start();
  290. }
  291. if(HttpCache::$instance->sessionStarted)
  292. {
  293. echo "already sessionStarted\nn";
  294. return true;
  295. }
  296. HttpCache::$instance->sessionStarted = true;
  297. // 没有sid,则创建一个session文件,生成一个sid
  298. if(!isset($_COOKIE[HttpCache::$sessionName]) || !is_file(HttpCache::$sessionPath . '/sess_' . $_COOKIE[HttpCache::$sessionName]))
  299. {
  300. $file_name = tempnam(HttpCache::$sessionPath, 'sess_');
  301. if(!$file_name)
  302. {
  303. return false;
  304. }
  305. HttpCache::$instance->sessionFile = $file_name;
  306. $session_id = substr(basename($file_name), strlen('sess_'));
  307. return setcookie(
  308. HttpCache::$sessionName
  309. , $session_id
  310. , ini_get('session.cookie_lifetime')
  311. , ini_get('session.cookie_path')
  312. , ini_get('session.cookie_domain')
  313. , ini_get('session.cookie_secure')
  314. , ini_get('session.cookie_httponly')
  315. );
  316. }
  317. if(!HttpCache::$instance->sessionFile)
  318. {
  319. HttpCache::$instance->sessionFile = HttpCache::$sessionPath . '/sess_' . $_COOKIE[HttpCache::$sessionName];
  320. }
  321. // 有sid则打开文件,读取session值
  322. if(HttpCache::$instance->sessionFile)
  323. {
  324. $raw = file_get_contents(HttpCache::$instance->sessionFile);
  325. if($raw)
  326. {
  327. session_decode($raw);
  328. }
  329. }
  330. }
  331. /**
  332. * 保存session
  333. */
  334. function session_write_close()
  335. {
  336. if(!defined('WORKERMAN_ROOT_DIR'))
  337. {
  338. return \session_write_close();
  339. }
  340. if(HttpCache::$instance->sessionStarted && !empty($_SESSION))
  341. {
  342. $session_str = session_encode();
  343. if($session_str && HttpCache::$instance->sessionFile)
  344. {
  345. return file_put_contents(HttpCache::$instance->sessionFile, $session_str);
  346. }
  347. }
  348. return empty($_SESSION);
  349. }
  350. /**
  351. * 退出
  352. * @param string $msg
  353. * @throws \Exception
  354. */
  355. function jump_exit($msg = '')
  356. {
  357. if(!defined('WORKERMAN_ROOT_DIR'))
  358. {
  359. return exit($msg);
  360. }
  361. if($msg)
  362. {
  363. echo $msg;
  364. }
  365. throw new \Exception('jump_exit');
  366. }
  367. /**
  368. * 解析http协议数据包 缓存先关
  369. * @author walkor
  370. */
  371. class HttpCache
  372. {
  373. public static $instance = null;
  374. public static $header = array();
  375. public static $sessionPath = '';
  376. public static $sessionName = '';
  377. public $sessionStarted = false;
  378. public $sessionFile = '';
  379. public static function init()
  380. {
  381. self::$sessionName = ini_get('session.name');
  382. self::$sessionPath = session_save_path();
  383. if(!self::$sessionPath)
  384. {
  385. self::$sessionPath = sys_get_temp_dir();
  386. }
  387. @\session_start();
  388. }
  389. }