PHP解析Http协议&协议复习

àì夳堔傛蜴生んèń 2022-04-15 07:27 394阅读 0赞

PHP解析Http协议&协议复习

最近在整理自己的知识体系,发现很多基础已经忘得差不多了,所以重新学习一次。

Http协议

HTTP是一个应用层协议,由请求和响应构成,是一个标准的客户端服务器模型。HTTP是一个无状态的协议。

请求报文示例
在这里插入图片描述

  1. GET /public/api/index?id=1 HTTP/1.1
  2. Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
  3. Accept-Encoding: gzip, deflate
  4. Accept-Language: zh-CN,zh;q=0.9
  5. Cache-Control: max-age=0
  6. Connection: keep-alive
  7. Host: 192.168.10.10:8088
  8. Upgrade-Insecure-Requests: 1
  9. User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36

响应报文示例
在这里插入图片描述

  1. HTTP/1.1 200 OK
  2. Date: Sun, 25 Oct 2015 15:43:47 GMT
  3. Server: Apache
  4. Set-Cookie: PHPSESSID=4v2actjf96v614r2kh36380kq6; path=/
  5. Expires: Thu, 19 Nov 1981 08:52:00 GMT
  6. Cache-Control: private
  7. Pragma: no-cache
  8. Vary: Accept-Encoding
  9. Content-Length: 5105
  10. Connection: close
  11. Content-Type: text/html; charset=utf-8
  12. <html>
  13. ....
  14. </html>

代码

  1. <?php
  2. /*php实现监听socket并实时解析Http后返回信息*/
  3. $_POST = $_GET = $_COOKIE = $_REQUEST = $_SESSION = $_FILES = array();
  4. //创建一个tcp套接字,并监听8088端口
  5. if($web = stream_socket_server('tcp://0.0.0.0:8088',$errno,$errstr)){
  6. while(true){
  7. //阻塞式读取
  8. $conn = @stream_socket_accept($web);
  9. if($conn){
  10. //这里简单点只读取最多2048数据
  11. //定长传输可以加入Content-Length判断body的长度
  12. //如果是对数据进行分块传输,则判断Transfer-Encoding: chunked,按照truncked协议分批读取数据
  13. $string = fread($conn,2048);
  14. // var_dump(json_encode($string));
  15. list($_GET, $_POST, $_COOKIE, $_SERVER, $_FILES) = parse_http($string);
  16. fwrite($conn,response(json_encode(array('get'=>$_GET, 'post'=>$_POST, 'cookie'=>$_COOKIE, 'server'=>$_SERVER, 'files'=>$_FILES))));
  17. fclose($conn);
  18. }
  19. }
  20. }else{
  21. die($errstr);
  22. }
  23. //响应
  24. function response($str){
  25. $content = "HTTP/1.1 200 OK\r\nServer: vruan_web/1.0.0\r\nContent-Length: " . strlen($str)."\r\nContent-type: application/json;charset=UTF-8"."\r\n\r\n{$str}";
  26. return $content;
  27. }
  28. /*
  29. * 函数:parse_http
  30. * 描述:解析http协议
  31. */
  32. function parse_http($http)
  33. {
  34. // 初始化
  35. $_POST = $_GET = $_COOKIE = $_REQUEST = $_SESSION = $_FILES = array();
  36. $GLOBALS['HTTP_RAW_POST_DATA'] = '';
  37. // 需要设置的变量名
  38. $_SERVER = array (
  39. 'QUERY_STRING' => '',
  40. 'REQUEST_METHOD' => '',
  41. 'REQUEST_URI' => '',
  42. 'SERVER_PROTOCOL' => '',
  43. 'SERVER_SOFTWARE' => '',
  44. 'SERVER_NAME' => '',
  45. 'HTTP_HOST' => '',
  46. 'HTTP_USER_AGENT' => '',
  47. 'HTTP_ACCEPT' => '',
  48. 'HTTP_ACCEPT_LANGUAGE' => '',
  49. 'HTTP_ACCEPT_ENCODING' => '',
  50. 'HTTP_COOKIE' => '',
  51. 'HTTP_CONNECTION' => '',
  52. 'REMOTE_ADDR' => '',
  53. 'REMOTE_PORT' => '0',
  54. );
  55. // 将header分割成数组
  56. list($http_header, $http_body) = explode("\r\n\r\n", $http, 2);
  57. $header_data = explode("\r\n", $http_header);
  58. list($_SERVER['REQUEST_METHOD'], $_SERVER['REQUEST_URI'], $_SERVER['SERVER_PROTOCOL']) = explode(' ', $header_data[0]);
  59. unset($header_data[0]);
  60. foreach($header_data as $content)
  61. {
  62. // \r\n\r\n
  63. if(empty($content))
  64. {
  65. continue;
  66. }
  67. list($key, $value) = explode(':', $content, 2);
  68. $key = strtolower($key);
  69. $value = trim($value);
  70. switch($key)
  71. {
  72. // HTTP_HOST
  73. case 'host':
  74. $_SERVER['HTTP_HOST'] = $value;
  75. $tmp = explode(':', $value);
  76. $_SERVER['SERVER_NAME'] = $tmp[0];
  77. if(isset($tmp[1]))
  78. {
  79. $_SERVER['SERVER_PORT'] = $tmp[1];
  80. }
  81. break;
  82. // cookie
  83. case 'cookie':
  84. $_SERVER['HTTP_COOKIE'] = $value;
  85. //将字符串解析成多个变量
  86. parse_str(str_replace('; ', '&', $_SERVER['HTTP_COOKIE']), $_COOKIE);
  87. break;
  88. // user-agent
  89. case 'user-agent':
  90. $_SERVER['HTTP_USER_AGENT'] = $value;
  91. break;
  92. // accept
  93. case 'accept':
  94. $_SERVER['HTTP_ACCEPT'] = $value;
  95. break;
  96. // accept-language
  97. case 'accept-language':
  98. $_SERVER['HTTP_ACCEPT_LANGUAGE'] = $value;
  99. break;
  100. // accept-encoding
  101. case 'accept-encoding':
  102. $_SERVER['HTTP_ACCEPT_ENCODING'] = $value;
  103. break;
  104. // connection
  105. case 'connection':
  106. $_SERVER['HTTP_CONNECTION'] = $value;
  107. break;
  108. case 'referer':
  109. $_SERVER['HTTP_REFERER'] = $value;
  110. break;
  111. case 'if-modified-since':
  112. $_SERVER['HTTP_IF_MODIFIED_SINCE'] = $value;
  113. break;
  114. case 'if-none-match':
  115. $_SERVER['HTTP_IF_NONE_MATCH'] = $value;
  116. break;
  117. case 'content-type':
  118. // 不同的请求类型:application/x-www-form-urlencoded application/json multipart/form-data text/xml
  119. //demo: Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryrGKCBY7qhFd3TrwA
  120. if(!preg_match('/boundary="?(\S+)"?/', $value, $match))
  121. {
  122. $_SERVER['CONTENT_TYPE'] = $value;
  123. }
  124. else
  125. {
  126. $_SERVER['CONTENT_TYPE'] = 'multipart/form-data';
  127. $http_post_boundary = '--'.$match[1];
  128. }
  129. break;
  130. }
  131. }
  132. // 需要解析$_POST
  133. if($_SERVER['REQUEST_METHOD'] === 'POST')
  134. {
  135. //上传文件处理
  136. if(isset($_SERVER['CONTENT_TYPE']) && $_SERVER['CONTENT_TYPE'] === 'multipart/form-data')
  137. {
  138. parse_upload_files($http_body, $http_post_boundary);
  139. }
  140. else
  141. {
  142. parse_str($http_body, $_POST);
  143. // $GLOBALS['HTTP_RAW_POST_DATA']
  144. $GLOBALS['HTTP_RAW_POST_DATA'] = $http_body;
  145. }
  146. }
  147. // QUERY_STRING
  148. $_SERVER['QUERY_STRING'] = parse_url($_SERVER['REQUEST_URI'], PHP_URL_QUERY);
  149. if($_SERVER['QUERY_STRING'])
  150. {
  151. // $GET
  152. parse_str($_SERVER['QUERY_STRING'], $_GET);
  153. }
  154. else
  155. {
  156. $_SERVER['QUERY_STRING'] = '';
  157. }
  158. // REQUEST
  159. // $_REQUEST = array_merge($_GET, $_POST);
  160. return array($_GET, $_POST, $_COOKIE, $_SERVER, $_FILES);
  161. }
  162. /*
  163. * 函数:parse_upload_files
  164. * 描述:解析上传的文件
  165. */
  166. function parse_upload_files($http_body, $http_post_boundary)
  167. {
  168. //去除最后一行boundary
  169. $http_body = substr($http_body, 0, strlen($http_body) - (strlen($http_post_boundary) + 4));
  170. $boundary_data_array = explode($http_post_boundary."\r\n", $http_body);
  171. if($boundary_data_array[0] === '')
  172. {
  173. unset($boundary_data_array[0]);
  174. }
  175. foreach($boundary_data_array as $boundary_data_buffer)
  176. {
  177. /**
  178. Content-Disposition: form-data; name="text"
  179. title
  180. ------WebKitFormBoundaryrGKCBY7qhFd3TrwA
  181. Content-Disposition: form-data; name="file"; filename="chrome.png"
  182. Content-Type: image/png
  183. PNG ... content of chrome.png ...
  184. */
  185. list($boundary_header_buffer, $boundary_value) = explode("\r\n\r\n", $boundary_data_buffer, 2);
  186. // 去掉末尾\r\n
  187. $boundary_value = substr($boundary_value, 0, -2);
  188. foreach (explode("\r\n", $boundary_header_buffer) as $item)
  189. {
  190. list($header_key, $header_value) = explode(": ", $item);
  191. $header_key = strtolower($header_key);
  192. switch ($header_key)
  193. {
  194. case "content-disposition":
  195. // 是文件
  196. if(preg_match('/name=".*?"; filename="(.*?)"$/', $header_value, $match))
  197. {
  198. $_FILES[] = array(
  199. 'file_name' => $match[1],
  200. 'file_data' => $boundary_value,
  201. 'file_size' => strlen($boundary_value),
  202. );
  203. continue;
  204. }
  205. // 是post field
  206. else
  207. {
  208. // 收集post
  209. if(preg_match('/name="(.*?)"$/', $header_value, $match))
  210. {
  211. $_POST[$match[1]] = $boundary_value;
  212. }
  213. }
  214. break;
  215. }
  216. }
  217. }
  218. }

定义及参考资料

https://www.cnblogs.com/guguli/p/4758937.html
http://caibaojian.com/http-protocol.html

发表评论

表情:
评论列表 (有 0 条评论,394人围观)

还没有评论,来说两句吧...

相关阅读

    相关 HTTP协议HTTPS协议详解

    HTTP是一个属于应用层的面向对象的协议,由于其简捷、快速的方式,适用于分布式超媒体信息系统。它于1990年提出,经过几年的使用与发展,得到不断地完善和扩展。目前在WWW中使用