/standard/tags/release-0.6.0/incubator/tools/http_server/src/Server.php

https://github.com/bhaumik25/zend-framework · PHP · 211 lines · 135 code · 36 blank · 40 comment · 18 complexity · 280afd45f4c3bb0c76e8039e82df506e MD5 · raw file

  1. <?php
  2. /**
  3. * Zend Framework
  4. *
  5. * LICENSE
  6. *
  7. * This source file is subject to the new BSD license that is bundled
  8. * with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://framework.zend.com/license/new-bsd
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@zend.com so we can send you a copy immediately.
  14. *
  15. * @category Zend
  16. * @package Zend_Http
  17. * @subpackage Server
  18. * @copyright Copyright (c) 2006 Zend Technologies USA Inc. (http://www.zend.com)
  19. * @license http://framework.zend.com/license/new-bsd New BSD License
  20. */
  21. require_once( "DefaultHandler.php" );
  22. require_once( "Exception.php" );
  23. require_once( "Request.php" );
  24. require_once( "Zend/Http/Response.php" );
  25. /**
  26. * @category Zend
  27. * @package Zend_Http
  28. * @subpackage Server
  29. * @copyright Copyright (c) 2006 Zend Technologies USA Inc. (http://www.zend.com)
  30. * @license http://framework.zend.com/license/new-bsd New BSD License
  31. */
  32. class Server
  33. {
  34. private $socket;
  35. private $connections = array();
  36. public $handler = "DefaultHandler";
  37. public $document_root = "";
  38. public function __construct( $address = '127.0.0.1', $port = 8000 )
  39. {
  40. if( !function_exists( "socket_create" ) )
  41. {
  42. throw new Zend_Http_Server_Exception( "Socket extension not found" );
  43. }
  44. // Make sure pcntl functions are available
  45. if (! function_exists('pcntl_fork')) {
  46. throw new Zend_Http_Server_Exception('PCNTL exntension not found');
  47. }
  48. if( ( $this->socket = socket_create( AF_INET, SOCK_STREAM, SOL_TCP ) ) < 0 )
  49. {
  50. throw new Zend_Http_Server_Exception( "socket_create() failed: Reason: " . socket_strerror( $this->socket ) );
  51. }
  52. socket_set_option( $this->socket, SOL_SOCKET, SO_REUSEADDR, 1 );
  53. if( ( $bind_result = socket_bind( $this->socket, $address, $port ) ) < 0 )
  54. {
  55. throw new Zend_Http_Server_Exception( "socket_bind() failed: Reason: " . socket_strerror( $bind_result ) );
  56. }
  57. if( !( $nonblock_result = socket_set_nonblock( $this->socket ) ) )
  58. {
  59. throw new Zend_Http_Server_Exception( "socket_set_nonblock() failed: Reason: " .
  60. socket_strerror( $nonblock_result ) );
  61. }
  62. }
  63. public function __destruct()
  64. {
  65. socket_close( $this->socket );
  66. foreach( $this->connections as $connection )
  67. {
  68. socket_close( $connection );
  69. }
  70. }
  71. public function setHandler( $handler_class )
  72. {
  73. $this->handler = $handler_class;
  74. }
  75. public function getHandler()
  76. {
  77. return $this->handler;
  78. }
  79. public function listen()
  80. {
  81. if( ( $ret = socket_listen( $this->socket, 5 ) ) < 0 )
  82. {
  83. throw new Zend_Http_Server_Exception( "socket_listen() failed: Reason: " . socket_strerror($ret) );
  84. }
  85. // Listening...
  86. while( true )
  87. {
  88. $sockets = array( $this->socket );
  89. $client = null;
  90. if( socket_select( $sockets, $w = NULL, $e = NULL, 0 ) )
  91. {
  92. // Waiting for connections...
  93. if( ( $client = socket_accept( $this->socket ) ) < 0 )
  94. {
  95. throw new Zend_Http_Server_Exception( "socket_accept() failed: Reason: " .
  96. socket_strerror( $client ) );
  97. }
  98. }
  99. else
  100. {
  101. // Without this, the server will use 100% of available CPU constantly!
  102. usleep( 100 ); // The only sensible place to sleep. Sleep for 0.0001 seconds if no new connections have arrived. Still allows a potential 10000 requests a second :)
  103. }
  104. // New connection, forking.
  105. if( $client )
  106. {
  107. $pid = pcntl_fork();
  108. if( $pid == -1 )
  109. {
  110. die( "Could not fork new process!" );
  111. }
  112. else if( $pid )
  113. {
  114. // print "Storing socket for $pid\n";
  115. $this->connections[ $pid ] = $client;
  116. }
  117. else
  118. {
  119. $raw_request = "";
  120. $i = 1;
  121. while( $i < 10 )
  122. {
  123. // print "Read attempt: $i\n";
  124. $i++;
  125. // Child: reading
  126. $buffer = socket_read( $client, 2048, PHP_BINARY_READ );
  127. // print strlen( $buffer ) . " bytes read\n";
  128. if( $buffer === false )
  129. {
  130. // Child: Error or EOF. Exiting.
  131. exit;
  132. }
  133. else
  134. {
  135. $raw_request .= $buffer;
  136. if( $buffer === "" || strlen( $buffer ) < 2048 )
  137. {
  138. $request = new Request( $raw_request );
  139. $request->document_root = $this->document_root;
  140. socket_getpeername( $client, $request->remote_ip );
  141. if( $request->isComplete() )
  142. {
  143. $handler = new $this->handler( $request );
  144. $response = $handler->handle();
  145. socket_write( $client, $response->asString() );
  146. print( $request->remote_ip . " - - [" . date( "d/M/Y:H:i:s O" ) . "] \"" .
  147. $request->method . " " . $request->uri . " " . $request->protocol_version .
  148. "\" " . $response->getStatus() . " " . strlen( $response->getBody() ) . " \"" .
  149. trim( $request->headers[ "Referer" ] ) . "\" \"" .
  150. trim( $request->headers[ "User-Agent" ] ) . "\"\n" );
  151. exit;
  152. }
  153. else
  154. {
  155. unset( $request );
  156. }
  157. }
  158. }
  159. }
  160. // print "Here!\n";
  161. print( "Read more than ten times for request and still incomplete - bailing out" );
  162. exit;
  163. }
  164. }
  165. // Parent: Check for finished children
  166. while( ( $child = pcntl_wait( $status, WNOHANG ) ) > 0 )
  167. {
  168. // print "Closing socket for $child\n";
  169. socket_close( $this->connections[ $child ] );
  170. unset( $this->connections[ $child ] );
  171. // print "Connection count: " . count( $this->connections ) . "\n";
  172. }
  173. }
  174. }
  175. }