This article mainly introduces the method of implementing dynamic web server in PHP. Interested friends can refer to it. I hope it will be helpful to everyone.
If you want to implement a web server, you need to have a general understanding of the operating principles of the web server. Let’s start with a static text server, taking 1.html that accesses the web server as an example
1. The client sends an http request to the server. If the port number the server listens to is 9002, then in The address of this machine's own test access is http://localhost:9002/1.html.
2. The server listens to port 9002. After receiving the request, it can obtain the uri resource that needs to be accessed in the request from the http header in the web directory. Location.
3. The server reads the resource file that needs to be accessed, then fills it into the http entity and returns it to the client.
The schematic diagram is as follows:
php <?php class web_config { // 监听的端口号 const PORT = 9003; // 项目根目录 const WEB_ROOT = "/Users/zhoumengkang/Documents/html"; } class server { private $ip; private $port; public function __construct($ip, $port) { $this->ip = $ip; $this->port = $port; $this->await(); } private function await() { $sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); if ($sock < 0) { echo "Error:" . socket_strerror(socket_last_error()) . "\n"; } $ret = socket_bind($sock, $this->ip, $this->port); if (!$ret) { echo "BIND FAILED:" . socket_strerror(socket_last_error()) . "\n"; exit; } echo "OK\n"; $ret = socket_listen($sock); if ($ret < 0) { echo "LISTEN FAILED:" . socket_strerror(socket_last_error()) . "\n"; } do { $new_sock = null; try { $new_sock = socket_accept($sock); } catch (Exception $e) { echo $e->getMessage(); echo "ACCEPT FAILED:" . socket_strerror(socket_last_error()) . "\n"; } try { $request_string = socket_read($new_sock, 1024); $response = $this->output($request_string); socket_write($new_sock, $response); socket_close($new_sock); } catch (Exception $e) { echo $e->getMessage(); echo "READ FAILED:" . socket_strerror(socket_last_error()) . "\n"; } } while (TRUE); } /** * @param $request_string * @return string */ private function output($request_string){ // 静态 GET /1.html HTTP/1.1 ... $request_array = explode(" ",$request_string); if(count($request_array) < 2){ return $this->not_found(); } $uri = $request_array[1]; $filename = web_config::WEB_ROOT . $uri; echo "request:".$filename."\n"; // 静态文件的处理 if (file_exists($filename)) { return $this->add_header(file_get_contents($filename)); } else { return $this->not_found(); } } /** * 404 返回 * @return string */ private function not_found(){ $content = " <h1>File Not Found </h1> "; return "HTTP/1.1 404 File Not Found\r\nContent-Type: text/html\r\nContent-Length: ".strlen($content)."\r\n\r\n".$content; } /** * 加上头信息 * @param $string * @return string */ private function add_header($string){ return "HTTP/1.1 200 OK\r\nContent-Length: ".strlen($string)."\r\nServer: mengkang\r\n\r\n".$string; } } $server = new server("127.0.0.1", web_config::PORT);
The code has been uploaded to github https://github.com/zhoumengkang/php/tree/master/php- webserver/static
As mentioned in the above code, as long as the file is executed in the terminal, a static web server will be started.
The picture below is a screenshot of me accessing the 1.jpg file in my web directory
The simple static web server has been completed, and the following question is How to make it support the output of dynamic content. Do we only need to execute a certain program inside the web server and return the result to the client? But in this way, the web server code is coupled with the business code. How to solve a web server that can be used in various business scenarios?
The emergence of CGI solved this problem. So what is CGI? The following passage is copied:
CGI is an interface standard between external applications (CGI programs) and Web servers. It is a procedure for transferring information between CGI programs and Web servers. The CGI specification allows Web servers to execute external programs and send their output to Web browsers. CGI turns the Web's simple set of static hypermedia documents into a complete new interactive media.
It’s so confusing. Let’s give a specific example. For example, the global variable of PHP we are using <span style="max-width:90%">$_SERVER['QUERY_STRING']</span>
is the one that the Web server uses through the CGI protocol. Up, passed over. For example, in Nginx, maybe you remember that the fastcgi configuration
code is as follows:
fastcgi_param QUERY_STRING $query_string;
Yes, nginx sets its own global variable <span style="font-family:NSimsun">$query_string</span>
Passed to the environment variable of fastcgi_param.
Below we also use CGI’s <span style="font-family:NSimsun">QUERY_STRING</span>
as a bridge to pass the information in the uri requested by the client to the cgi program. Use <span style="font-family:NSimsun">putenv</span>
to store <span style="font-family:NSimsun">QUERY_STRING</span>
into the environment variable of the request.
We agree that the resource accessed in the Web server is <span style="font-family:NSimsun">.cgi</span>
. The suffix indicates dynamic access. This is somewhat similar to configuring location in nginx to find php scripts. The procedure is the same. It's all a rule to check whether a cgi program should be requested. In order to distinguish it from the Web server, I wrote a cgi program in C to query user information and query user information based on user ID.
The approximate access logic is as shown below
If you want to run the demo, you need to do the following operations
1. Modify## The project root directory in #config.php<span style="max-width:90%"></span>
WEB_ROOT<span style="font-family:NSimsun"></span>
2. Compilecgi-demo\user.c<span style="font-family:NSimsun"></span>, compile the command
gcc -o user.cgi user.c<span style="font-family:NSimsun"></span>, and then
user.cgi<span style="font-family:NSimsun"></span> Put the file under the root directory of your configured project
3. Execute php start.php<span style="font-family:NSimsun"></span> in the terminal, like this The web server is started
4. Passhttp://localhost:9003/user.cgi?id=1 I saw the following effect during the visit
In fact, I just did some cgi based on the static server. I judged that the request was forwarded and processed the three on github. The code of the files is merged into one file for everyone to watchphp <?php class web_config { // 监听的端口号 const PORT = 9003; // 项目根目录 const WEB_ROOT = "/Users/zhoumengkang/Documents/html"; // 系统支持的 cgi 程序的文件扩展名 const CGI_EXTENSION = "cgi"; } class server { private $ip; private $port; public function __construct($ip, $port) { $this->ip = $ip; $this->port = $port; $this->await(); } private function await() { $sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); if ($sock < 0) { echo "Error:" . socket_strerror(socket_last_error()) . "\n"; } $ret = socket_bind($sock, $this->ip, $this->port); if (!$ret) { echo "BIND FAILED:" . socket_strerror(socket_last_error()) . "\n"; exit; } echo "OK\n"; $ret = socket_listen($sock); if ($ret < 0) { echo "LISTEN FAILED:" . socket_strerror(socket_last_error()) . "\n"; } do { $new_sock = null; try { $new_sock = socket_accept($sock); } catch (Exception $e) { echo $e->getMessage(); echo "ACCEPT FAILED:" . socket_strerror(socket_last_error()) . "\n"; } try { $request_string = socket_read($new_sock, 1024); $response = $this->output($request_string); socket_write($new_sock, $response); socket_close($new_sock); } catch (Exception $e) { echo $e->getMessage(); echo "READ FAILED:" . socket_strerror(socket_last_error()) . "\n"; } } while (TRUE); } /** * @param $request_string * @return string */ private function output($request_string){ // 静态 GET /1.html HTTP/1.1 ... // 动态 GET /user.cgi?id=1 HTTP/1.1 ... $request_array = explode(" ",$request_string); if(count($request_array) < 2){ return ""; } $uri = $request_array[1]; echo "request:".web_config::WEB_ROOT . $uri."\n"; $query_string = null; if ($uri == "/favicon.ico") { return ""; } if (strpos($uri,"?")) { $uriArr = explode("?", $uri); $uri = $uriArr[0]; $query_string = isset($uriArr[1]) ? $uriArr[1] : null; } $filename = web_config::WEB_ROOT . $uri; if ($this->cgi_check($uri)) { $this->set_env($query_string); $handle = popen(web_config::WEB_ROOT.$uri, "r"); $read = stream_get_contents($handle); pclose($handle); return $this->add_header($read); } // 静态文件的处理 if (file_exists($filename)) { return $this->add_header(file_get_contents($filename)); } else { return $this->not_found(); } } /** * 设置环境变量 给 cgi 程序使用 * @param $query_string * @return bool */ private function set_env($query_string){ if($query_string == null){ return false; } if (strpos($query_string, "=")) { putenv("QUERY_STRING=".$query_string); } } /** * 判断请求的 uri 是否是合法的 cgi 资源 * @param $uri * @return bool */ private function cgi_check($uri){ $info = pathinfo($uri); $extension = isset($info["extension"]) ? $info["extension"] : null; if( $extension && in_array($extension,explode(",",web_config::CGI_EXTENSION))){ return true; } return false; } /** * 404 返回 * @return string */ private function not_found(){ $content = "<h1>File Not Found </h1>"; return "HTTP/1.1 404 File Not Found\r\nContent-Type: text/html\r\nContent-Length: ".strlen($content)."\r\n\r\n".$content; } /** * 加上头信息 * @param $string * @return string */ private function add_header($string){ return "HTTP/1.1 200 OK\r\nContent-Length: ".strlen($string)."\r\nServer: mengkang\r\n\r\n".$string; } } $server = new server("127.0.0.1", web_config::PORT);
Summary:The above is the entire content of this article, I hope it will be helpful to everyone's study.
related suggestion:
The function of using curl to forge IP in PHP
phpThe method of using MagickWand module to operate pictures and add watermarks
smarty self Definition and usage skills of defined resources
The above is the detailed content of How to implement dynamic web server in php. For more information, please follow other related articles on the PHP Chinese website!