Maison  >  Article  >  développement back-end  >  Comment implémenter un serveur Web dynamique en php

Comment implémenter un serveur Web dynamique en php

墨辰丷
墨辰丷original
2018-06-08 10:42:162747parcourir

Cet article présente principalement la méthode d'implémentation d'un serveur Web dynamique en PHP. Les amis intéressés peuvent s'y référer. J'espère qu'il sera utile à tout le monde.

Si vous souhaitez implémenter un serveur Web, vous devez avoir une compréhension générale du fonctionnement du serveur Web. Commençons par un serveur de texte statique. Prenons l'exemple de l'accès à 1.html du serveur Web

1 Le client envoie une requête http au serveur si le numéro de port que le serveur écoute est. 9002, puis dans L'adresse du propre accès test de cette machine est http://localhost:9002/1.html.

2. Le serveur écoute le port 9002, donc après avoir reçu la requête, il peut obtenir la ressource uri à laquelle il faut accéder dans la requête à partir de la tête http dans le répertoire Web. Emplacement.

3. Le serveur lit le fichier de ressources auquel il faut accéder, puis le remplit dans l'entité http et le renvoie au client.

Le schéma schématique est le suivant :

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);

Le code a été téléchargé sur github https://github.com/zhoumengkang /php/tree/master/ php-webserver/static

Comme mentionné dans le code ci-dessus, tant que le fichier est exécuté dans le terminal, un serveur Web statique sera démarré.

L'image ci-dessous est une capture d'écran de moi accédant au fichier 1.jpg dans mon répertoire Web

Le serveur Web statique simple est terminé. La question est de savoir comment lui permettre de prendre en charge la sortie de contenu dynamique. Devons-nous seulement exécuter un certain programme sur le serveur Web et renvoyer le résultat au client ? Mais de cette façon, le code du serveur Web est couplé au code métier. Comment résoudre un serveur Web qui peut être utilisé dans divers scénarios commerciaux ?

L'avènement de CGI a résolu ce problème. Alors, qu’est-ce que CGI ? Le passage suivant est copié :

CGI est un standard d'interface entre les applications externes (programmes CGI) et les serveurs Web. Il s'agit d'une procédure de transfert d'informations entre les programmes CGI et les serveurs Web. La spécification CGI permet aux serveurs Web d'exécuter des programmes externes et d'envoyer leur sortie aux navigateurs Web. CGI transforme l'ensemble de simples documents hypermédia statiques du Web en un tout nouveau média interactif.

C'est tellement déroutant. Pour donner un exemple précis, par exemple, la variable globale <span style="font-family:NSimsun">$_SERVER['QUERY_STRING']</span> de PHP que nous utilisons est transmise par le serveur Web via le protocole CGI. Par exemple, dans Nginx, vous vous souvenez peut-être que le code de configuration de fastcgi

est le suivant :

fastcgi_param  
QUERY_STRING      
 $query_string;

Oui, nginx passe sa variable globale <span style="font-family:NSimsun">$query_string</span> à la variable d'environnement de fastcgi_param.

Ci-dessous, nous utilisons également les CGI <span style="font-family:NSimsun">QUERY_STRING</span> comme pont pour transmettre les informations de l'uri demandées par le client au programme cgi. Stockez <span style="font-family:NSimsun">putenv</span> dans la variable d'environnement de la requête via <span style="font-family:NSimsun">QUERY_STRING</span>.

Nous convenons que les ressources accessibles sur le serveur Web sont <span style="font-family:NSimsun">.cgi</span>. Le suffixe indique un accès dynamique. C'est un peu similaire à la configuration de l'emplacement dans nginx pour trouver des scripts php. C'est une règle de vérifier si un programme cgi doit être demandé. Afin de le distinguer du serveur Web, j'ai écrit un programme cgi en C pour interroger les informations utilisateur et interroger les informations utilisateur en fonction de l'identifiant utilisateur.

La logique d'accès approximative est la suivante

Si vous souhaitez exécuter la démo, vous devez effectuer les opérations suivantes

1. Modifier<span style="font-family:NSimsun">config.php</span> Le répertoire racine du projet dans <span style="font-family:NSimsun">WEB_ROOT</span>

2. Compilez <span style="font-family:NSimsun">cgi-demouser.c</span>, compilez la commande <span style="font-family:NSimsun">gcc -o user.cgi user.c</span>, puis placez le fichier <span style="font-family:NSimsun">user.cgi</span> sous le répertoire racine du projet que vous avez configuré

3. Exécutez <span style="font-family:NSimsun">php start.php</span> dans le terminal, afin que le serveur Web démarre

4. Pass http://localhost:9003/user.cgi?id=1 Vous pouvez accéder et voir l'effet suivant

En fait, c'est uniquement sur le serveur statique. Sur la base d'un jugement cgi, il s'agit du traitement du transfert des demandes et de la fusion des codes des trois fichiers sur github en un seul fichier que tout le monde peut regarder

php
<?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);

Résumé : Ci-dessus C'est tout le contenu de cet article, j'espère qu'il sera utile à l'étude de chacun.

Recommandations associées :

La fonction d'utilisation de curl pour simuler une adresse IP en PHP

Comment utiliser le module MagickWand pour manipuler des images et ajouter des filigranes en PHP

Auto-intelligent Définition et compétences d'utilisation des ressources définies

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn