lindev : administration linux , développement php

Aller au contenu | Aller au menu | Aller à la recherche

05 avr. 2010

Nginx + php fastcgi + perl

nginx-logo2.pngCa y est , voici la deuxième partie certainement attendu .. non !! ha .. bon .. spa grave ..
Je disais donc , nginx est maintenant en place , mais il faudrait peut être penser à le rendre compatible avec les 90% des sites sur le net aujourd'hui , c'est à dire php .. et pourquoi pas python tant que l'on y est .
Pour mettre en place cette liaison , nous allons utiliser php en fast-cgi .
Nginx ne possédant pas de mod_php comme apache , les requêtes php seronts donc transmises aux process php que nous aurons lancés en tâche de fond .
Je ne vais pas débattre des avantages et des inconvénients d'utiliser php en fastcgi , ce n'est pas le but de ce topic , mais sachez juste qu'aujourd'hui php en fastcgi est très apprécié , pour sa stabilité et sa sécurité , c'est pourquoi l'on retrouve souvent ce mode de fonctionnement chez les hébergeurs aujourd'hui ...
Vous n'étiez pas au courant ? ..

Note du 24/08/10 : Depuis php 5.3.3 il est bien plus simple et performant d'utiliser php-fpm , voir le tuto à ce sujet

PHP compilation

Et oui encore , il nous faut compiler php spécialement pour le mod fast-cgi ( ne vous inquiétez pas , il est maintenant impossible de repasser en mode cgi simple , vous aurez forcement du Fastcgi ).
Comme d'hab voici les étapes ,

  1. Récupération des source
  2. décompactage
  3. création du fichier de config à la compilation
  4. trio : ./configure make / make / install

Récupération de php

Voilà les lignes de commande correspondantes ( PHP 5.3.2 )

wget http://fr2.php.net/get/php-5.3.2.tar.gz/from/this/mirror
tar xzf php-5.3.2.tar.gz
cd /usr/local/src/php-5.3.2/
vim my_configure

Config de compilation

Voici un exemple , de config de php ( celui de ma machine de dev ) je vous laisse ajuster selon vos besoins ..

#!/bin/sh

export OPTIM=-02
./configure --prefix=/usr/local \
        --with-xsl \
        --enable-soap \
        --with-gettext \
        --enable-mbstring --with-mbstring=all \
        --disable-debug \
        --enable-memory-limit \
        --enable-ftp \
        --with-mcrypt \
        --enable-zip \
        --enable-calendar \
        --enable-exif \
        --enable-pdo \
        --with-pdo-mysql \
        --with-mysql \
        --with-pdo-sqlite \
        --with-sqlite \
        --with-zlib \
        --with-jpeg-dir \
        --with-gd \
        --enable-bcmath \
        --with-curl \

Compilation , go go go

make 
make install 

Vérification

Nous voilà avec normalement un exécutable nommé php-cgi dans /usr/local/bin_

Process FastCgi

Nous allons donc maintenant créer un script qui sera chargé de lancer X process , qui ont pour mission de répondre aux requêtes php envoyées par nginx.

Création

cd /etc/init.d/
vim php-fastcgi

Le script peut exister sous des formes plus ou moins différentes , voici celui que j'utilise :

download.pngphp-fastcgiwrapper php-fastcgi

warning.pngLà encore les script est adapté , si vous avez suivi à la lettre mon tutoriel , si vous avez effectué des modification vérifiez les paramètres , notamment:

  • USER
  • PHP_CGI

Ajout au RC

Il faut lui aussi le rendre exécutable , et le mettre dans le RC , afin que les process soient lancés au démarrage de la machine .

chmod 777 php-fastcgi
update-rc.d php-fastcgi defaults

warning.pngConcernant le nombre de process fils lancés , il faudra adapter selon la charge de votre site ... en production , la commande

netstat -atup

Vous donnera des indications sur l'état de vos process , n'en ajoutez pas trop ! travaillez de façon logique .

Vous pouvez démarrer les process :

/etc/init.d/php-fastcgi start

Liaison avec Nginx

Et bien voilà , il ne nous reste plus qu'à lui indiquer de transmettre les requêtes php aux process que nous avons lancés .

fastcgi_params

Dans un premier temps il faudra éditer le fichier de configuration fastcgi_params de nginx .

cd /etc/nginx/
vim fastcgi_params

A la fin de ce fichier , ajouter les lignes suivantes :

fastcgi_split_path_info ^(.+\.php)(.*)$;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;

Ces lignes permettent entre autre d'indiquer aux process quel script executer , ainsi que son chemin .

Vhost ou Nginx.conf

Selon l'utilisation ou non de vhost , il vous faut ajouter ( en fait elles y sont déjà dans le conf principale si vous avez utilisé mon fichier de config nginx.conf ) les lignes suivantes dans les accolades de server .

location ~ \.php$ {

          include /etc/nginx/fastcgi_params; #or whatever you named it
          fastcgi_pass  127.0.0.1:9000;
	  index index.php;
        }


Exemple d'un vhost:

server{

        listen 8282;

        server_name lindev.fr;

        root /home/apache2/lindev.fr;

        
        location /  {

                index index.php;

        }

        location ~ \.php$ {

          include /etc/nginx/fastcgi_params; #or whatever you named it
          fastcgi_pass  127.0.0.1:9000;
	  index index.php;
        }

}

Et voilà votre serveur peut maintenant gérer les fichiers .php

Restart Nginx

Pour que les modifications prennent effet, il vous faut demander à Nginx de relire sont/ses fichiers de conf .

/usr/local/nginx/sbin -s reload

Et bien voilà pour php .. On fait la même chose avec perl ? aller .. go !

Perl CPAN

Certains sites demandent la gestion de perl , principalement pour des site de graph , tel qu'eluna , je vais donc faire en sorte que notre serveur puisse gérer ce genre de site .. même pas peur !

FCGI

Il nous faut dans un premier temps installer le paquet FCGI par cpan :

perl -MCPAN -e 'install FCGI'

Wrapper perl fastcgi

Il faut ensuite , créer le script qui ( comme pour php ) lance des process en fastcgi en attente de script à traiter .

vim /usr/bin/fastcgi-wrapper.pl

download.pngVoilà le contenu de ce script : fastcgi-wrapper.plfastcgi-wrapper.pl

On n'oubli pas de le rendre exécutable

chmod 755 /usr/bin/fastcgi-wrapper.pl



Ok maintenant , nous allons créer le script qui se situe dans le RC , pour lancer les process :

vim /etc/init.d/perl-fastcgi

download.pngVoici le fichier perl-fastcgiperl-fastcgi

On le rend exécutable , et on l'ajoute au RC

chmod 755 /etc/init.d/perl-fastcgi
update-rc.d perl-fastcgi defaults
/etc/init.d/perl-fastcgi start

Liaison perl - Nginx

Nous y voilà , les process perl sont lancés , il écoutent sur le port 8999 , il ne nous reste plus qu'à ajouter dans les Vhost qui en ont besoin , les lignes suivantes :

location ~ \.pl$ {
        gzip off;
        include /etc/nginx/fastcgi_params;
        fastcgi_pass  127.0.0.1:8999;
        fastcgi_index index.pl;
    }

warning.pngCette fois , pas besoin de modifier les fichier fcgi_params car les modifications à apporter sont les même que précédemment avec php .

Nginx restart

Et bien oui comme pour php , on relance la lecture des fichiers de conf de nginx , afin de prendre en compte les modifications .

/usr/local/nginx/sbin/nginx -s reload

Good job

Ca y est , Nginx est maintenant capable de gérer les script php et perl en plus des fichiers statiques ...

Il reste encore quelques petites choses utiles à voir , comme la gestion du SSL , les redirections automatique , les réécritures d'url, pour du 301 ou l'utilisation de framework tel que symphony , Zend ou autre basé sur la réécriture d'url et un peut de sécurité en plus ...

Voilà le programme de la troisième partie sur nginx ..

05 fév. 2009

Php , survolons les sockets

Nous allons voir dans cet article , l'utilisation des sockets en php Dans quel but , et bien , par curiosité .. simplement ..

Pré-requis :

il nous faut pour les sockets avoir compilé php avec l'option --enable-sockets ... Voilà , rien de plus ..

Que faire ?

Nous allons une partie serveur qui va écouter sur un port donné , et distribuer les messages aux clients qui se connectent . Le but n'est pas d'avoir un programme fini , mais bien d'avoir une première approche avec les sockets en PHP.

Partie Serveur:

Entamons donc notre script serveur.php

Création d'une socket

Nous allons ici , creer la socket , et mettre le script en écoute de connexion ...

set_time_limit(0); 
ob_implicit_flush();	

try {
			
	//creation du socket
	$Psock	=	socket_create(AF_INET,SOCK_STREAM,SOL_TCP);
			
	//en cas d'erreur à la creation de la socket
	if ( $Psock	===	FALSE ){
		$msgerror	=	socket_strerror(socket_last_error());
		throw new Exception($msgerror);
	}
			
			
	//nommage de la socket cree
	$ret	=	socket_bind($Psock, '127.0.0.1', 10005);
			
	//en cas d'erreur au nommage de la socket
	if ( $ret	===	FALSE ){
		$msgerror	=	socket_strerror(socket_last_error());
		throw new Exception($msgerror);
	}
			
			
			
			
	//Attente des connexions entrantes
	$ret	=	socket_listen( $Psock, 0 );
			
	//en cas d'erreur
	if ( $ret	===	FALSE ){
		$msgerror	=	socket_strerror(socket_last_error());
		throw new Exception($msgerror);
	}
			
			
			
					
	//Acceptation des connexions entrantes
				
	//endormissement si aucune connexion
	$Csock	=	socket_accept($Psock);
				
	//en cas d'erreur
	if ( $ret	===	FALSE ){
		$msgerror	=	socket_strerror(socket_last_error());
		throw new Exception($msgerror);
	}
			
	//Message lor d'une connexion
	echo "<br><b>Réception d'une connexion ! </b><br>";
				
					
	//Souhaitons la bienvenue au client
	$ret	=	@socket_write($Csock, "Welcome<br>", strlen("Welcome<br>"));
							
			
	//Fermeture de la connexion cliente
        if( is_ressource($Csock) ){
	       socket_close($Csock);
               unset($Csock);
        }
			
	//fermeture du serveur
	if(is_resource($this->Psock)){
		socket_close($this->Psock);
		unset($this->Psock);
	}
			
}catch (Exception $e){
	print_r( $e->getMessage() );
	exit(1);
}

Voilà , pour la partie serveur .. comme vous pouvez le voir , il n'y a rien de vraiment palpitant .. ici , une simple connexion .. et hop , le serveur envoie un message au client , puis il s'arrête aussitôt . Nous aurions trés bien pu mettre une boucle infinie pour accepter autant de connexions que possible , ou un message spécifique stop le serveur . En effet, la fonction socket_accept($Psock); est bloquante , c'est à dire que le script s'arrete à cette ligne tant qu'aucune connexion n'a eu lieu , c'est pourquoi nous avons ajouté en debut de script , la ligne : set_time_limit(0); afin de ne pas être limité dans le temps ... pour la suite des possibilités , je laisse libre votre imagination ..

Partie Client :

Pour la partie client , le tout debut , est le même .. mais moins long tout de même ... regardez client.php

/*
 * Création d'une socket Inet
 */
try{
	
	
	
	$Psock	=	socket_create(AF_INET,SOCK_STREAM,SOL_TCP);
	
	//en cas d'erreur à la creation de la socket
	if ( $Psock	===	FALSE ){
		$msgerror	=	socket_strerror(socket_last_error());
		throw new Exception($msgerror);
	}
	
	
	
	/*
	 * Connexion au serveur 
	 */
	$ret	=	socket_connect($Psock,'127.0.0.1',10005);
	
	//en cas d'erreur à la creation de la socket
	if ( $Psock	===	FALSE ){
		$msgerror	=	socket_strerror(socket_last_error());
		throw new Exception($msgerror);
	}
	
			
	echo $buf = socket_read($Psock, 2048);
	
	socket_close($Psock);
	
	
}catch(Exception $e){
	print_r( $e->getMessage() );
	exit(1);
}

Et voilà pour la partie cliente , comme pour la partie serveur , nous créons une socket via la fonction socket_create() , ensuite , nous tentons une connexion de l'autre coté du "tube" via socket_connect() , si aucune erreur n'est détecté , nous attendons sagement un message du serveur ... socket_read() est aussi bloquant , tant qu'aucun message (ou une chaîne vide) n'arrive , le script reste endormis à cette ligne , toujours sans consommer de ressources ...

Dés réception de données , notre script va simplement l'afficher à l'écran puis se déconnecter ...

Test sans parti serveur

Pour tester trés rapidement les sockets au niveau client , vous pouvez simplement , changer le numéro de port et l'adresse à laquelle vous vous connectez .. exemple , si vous avez ssh sur votre machine , remplacez 10005 par 22 , vous allez voir un message du style :

SSH-2.0-OpenSSH_4.3p2 Debian-9etch3 

Ou sur votre serveur de mail , mettez l'adresse de votre serveur , et le port 25

220 mailhost.creavi.fr ESMTP Postfix (Debian/GNU) 

Et voilà pour le survol des sockets , qui peut aboutir à de nombreuses applications intéressantes , rien que pour leurs conception ...

Christophe.