Home >Backend Development >PHP Tutorial >PHP-CLI web server

PHP-CLI web server

WBOY
WBOYOriginal
2016-07-25 08:47:371200browse
Requires pthreads extension
php command line mode to run

I wrote it in a hurry and don’t have time to optimize it. I will take the time to optimize it when I have time

来自源地址: http://www.haowei.me/archives/1009.html
  1. ini_set('display_errors', false);
  2. error_reporting(0);
  3. if(!class_exists('thread')) {
  4. logs('PHP runtime environment not support multi thread');
  5. exit(0);
  6. }
  7. if(!function_exists('mime_content_type')) {
  8. logs('PHP runtime environment not support function mime_content_type()');
  9. exit(0);
  10. }
  11. class pthread extends thread {
  12. protected $socket = null;
  13. protected $arguments = null;
  14. protected $connections = 0;
  15. protected $octet_stream = false;
  16. public function __construct($socket, $arguments = array()) {
  17. $this->socket = $socket;
  18. $this->arguments = $arguments;
  19. if(!isset($this->arguments['ServerTokens']))
  20. $this->arguments['ServerTokens'] = 'off';
  21. }
  22. public function run() {
  23. date_default_timezone_set('UTC');
  24. $clients = 1;
  25. $maxRequests = !isset($this->arguments['MaxRequests'])?
  26. intval($this->arguments['MaxRequests']):
  27. 100;
  28. $timeout = 5;
  29. $connfd = socket_accept($this->socket);
  30. socket_set_option($connfd, SOL_SOCKET, SO_RCVTIMEO, array('sec' => $timeout, 'usec' => 0));
  31. $session = 1;
  32. while($session) {
  33. $buffer = '';
  34. while (( $buffer .= socket_read($connfd, 1024, PHP_BINARY_READ) ))
  35. if(strpos($buffer, "rnrn") !== false) break;
  36. if($buffer == '') {
  37. socket_close($connfd);
  38. $session = 0;
  39. }else{
  40. $availableRequests = $maxRequests - $clients;
  41. $clients++;
  42. $i = 0;
  43. $headers = array();
  44. array_push($headers, 'HTTP/1.1 200 OK');
  45. array_push($headers, 'Date: '. gmtdate());
  46. array_push($headers, 'Server: PHP-CLI/1.0');
  47. array_push($headers, 'Content-Type: text/html; charset=utf-8');
  48. array_push($headers, 'Connection: close');
  49. if($this->arguments['ServerTokens'] == 'on')
  50. $headers[2] = 'Server: PHP-CLI';
  51. $buffer = explode("rn", $buffer);
  52. $http_user_agent = '';
  53. $http_request_method = '';
  54. $http_request_file = '';
  55. $http_protocol = '';
  56. $extension = '';
  57. $mime_types = '';
  58. $this->octet_stream = false;
  59. foreach($buffer as $line) {
  60. $pattern = '/(GET|POST)s/(.*)s(HTTP/1.[0-1])$/';
  61. if(preg_match($pattern, $line)) {
  62. $http_request_method = preg_replace($pattern, '\1', $line);
  63. $http_request_file = preg_replace($pattern, '\2', $line);
  64. $http_protocol = preg_replace($pattern, '\3', $line);
  65. }
  66. $pattern = '/^User-Agent: (.+)$/';
  67. if(preg_match($pattern, $line)) {
  68. $http_user_agent = preg_replace($pattern, '\1', $line);
  69. }
  70. }
  71. $local_request_file = $this->arguments['DocumentRoot'].'/'. $http_request_file;
  72. if(file_exists($local_request_file) && is_file($local_request_file))
  73. $extension = pathinfo($local_request_file, PATHINFO_EXTENSION);
  74. if(file_exists($local_request_file)) {
  75. $array_key_exists = array_key_exists($extension, $this->arguments['MimeTypes']);
  76. if(is_file($local_request_file)) {
  77. if($array_key_exists) {
  78. $mime_types = $this->arguments['MimeTypes'][$extension];
  79. $headers[3] = sprintf('Content-Type: %s; charset=%s', $mime_types, 'utf-8');
  80. }else{
  81. $this->octet_stream = true;
  82. $headers[3] = sprintf('Content-Type: application/octet-stream');
  83. array_push($headers, 'Accept-Ranges: bytes');
  84. array_push($headers, 'Accept-Length: '.filesize($local_request_file));
  85. array_push($headers, 'Content-Disposition: attachment; filename='.basename($local_request_file));
  86. }
  87. }
  88. }
  89. $html = '';
  90. $code = '';
  91. $this->HttpStatusCode($local_request_file, $headers, $html, $code);
  92. if($availableRequests > 0) {
  93. $headers[4] = "Connection: keep-alive";
  94. $headers[5] = 'Keep-Alive: timeout='.$timeout.', max='.$maxRequests;
  95. }
  96. $headers[6] = 'Content-Length: '. strlen($html);
  97. $response = array(
  98. 'header'=> implode("rn", $headers) . "rn",
  99. 'html'=> $html);
  100. socket_write($connfd, implode("rn", $response));
  101. if($availableRequests <= 0) {
  102. socket_close($connfd);
  103. $session = 0;
  104. }
  105. $length = strlen($html);
  106. socket_getpeername($connfd, $address, $port);
  107. logs(sprintf('%s:%.0f -- "%s %s %s" %s %.0f "-" "%s"',
  108. $address,
  109. $port,
  110. $http_request_method,
  111. '/'.$http_request_file,
  112. $http_protocol,
  113. $code,
  114. $length,
  115. $http_user_agent));
  116. //logs('times '. intval($clients - 1), false);
  117. }
  118. }
  119. }
  120. public function error_page($statusCode, $ServerTokens) {
  121. $httpStatus = array('403'=> '403 Forbidden', '404'=> '404 Not Found');
  122. $string = "
  123. %s
  124. %s


  125. %s
  126. ";
  127. if(!in_array($ServerTokens, array('on', 'off')))
  128. $ServerTokens = 'off';
  129. return (string) sprintf($string,
  130. $httpStatus[$statusCode],
  131. $httpStatus[$statusCode],
  132. $ServerTokens == 'off' ? 'PHP-CLI/1.0' : 'PHP-CLI');
  133. }
  134. public function HttpStatusCode($file, &$headers, &$html, &$code) {
  135. $code = '200';
  136. if(!file_exists($file)) {
  137. $headers[0] = 'HTTP/1.1 404 Not Found';
  138. $html = $this->error_page('404', $this->arguments['ServerTokens']);
  139. $code = '404';
  140. return 0;
  141. }
  142. if(is_dir($file)){
  143. $find = false;
  144. $directoryIndex = $this->arguments['DirectoryIndex'];
  145. if(empty($directoryIndex)) {
  146. $headers[0] = 'HTTP/1.1 403 Forbidden';
  147. $code = '403';
  148. }else{
  149. $list = explode(' ', $directoryIndex);
  150. foreach($list as $index) {
  151. if(file_exists($file .'/'. $index)) {
  152. $file .= '/'. $index;
  153. if(file_exists($file) && is_file($file))
  154. $extension = pathinfo($file, PATHINFO_EXTENSION);
  155. $array_key_exists = array_key_exists($extension, $this->arguments['MimeTypes']);
  156. if($array_key_exists) {
  157. $mime_types = $this->arguments['MimeTypes'][$extension];
  158. }else{
  159. $this->otect_stream = true;
  160. $headers[3] = sprintf('Content-Type: application/octet-stream');
  161. array_push($headers, 'Accept-Ranges: bytes');
  162. array_push($headers, 'Accept-Length: '.filesize($local_request_file));
  163. array_push($headers, 'Content-Disposition: attachment; filename='.basename($local_request_file));
  164. }
  165. $find = true;
  166. break;
  167. }
  168. }
  169. }
  170. if(!$find) {
  171. $html = $this->error_page('403', $this->arguments['ServerTokens']);
  172. }else{
  173. if(!$this->octet_stream)
  174. $headers[3] = sprintf('Content-Type: %s; charset=%s', $mime_types, 'utf-8');
  175. $html = $this->get_local_handle_buffer($file);
  176. }
  177. return -1;
  178. }else{
  179. $html = $this->get_local_handle_buffer($file);
  180. }
  181. return 1;
  182. }
  183. public function get_local_handle_buffer($file) {
  184. $handle = fopen($file, 'rb');
  185. return $this->get_buffer($handle);
  186. }
  187. public function get_buffer($handle) {
  188. $buffer = '';
  189. if(!is_resource($handle)) return null;
  190. while(!feof($handle))
  191. $buffer .= fgets($handle, 1024);
  192. fclose($handle);
  193. return $buffer;
  194. }
  195. }
  196. function gmtdate() {
  197. return (string) date('D, d M Y H:i:s'). ' GMT';
  198. }
  199. function logs($string, $perfix = true) {
  200. ob_start();
  201. echo $perfix ?
  202. sprintf("[ %s ] %sn", date('d-M-Y H:i:s'), $string) :
  203. sprintf("
Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn