Exemple de démon PHP

Ce court article va vous expliquer comment exécuter un "démon" php en tant que service windows.

Article lu   fois.

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

1. Introduction

Le but de cet article est de vous montrer comment faire tourner un script PHP5 en tant que service Windows. Ce besoin s'avère parfois nécessaire lorsque vous disposez de scripts "démons" qui doivent s'exécuter inconditionnellement pour effectuer leurs opérations. Sous linux ou unix, il est assez simple de mettre en oeuvre de tels démons et de les faire démarrer au boot de la machine. Sous windows par contre, c'est une autre paire de manches. Wez Furlong a créé l'extension win32service.dll qui permet de faire cela. Nous allons donc voir comment la mettre en oeuvre à l'aide d'un petit exemple.

2. Téléchargement de l'extension

Avant de télécharger l'extension, assurez-vous que vous disposez d'une version de PHP5 suffisament récente pour être compatible avec celle-ci. Pour l'exemple qui vous sera expliqué en section 3, j'ai utilisé la version 5.0.3.3 disponible ici et l'extension proprement dite est disponible ici

Si vous ne savez pas comment installer PHP5, référez-vous à d'autres tutoriels de ce site décrivant les étapes à suivre. Pour installer l'extension, vous devez simplement télécharger le fichier et le sauvegarder dans le répertoire "ext" de php, ce répertoire étant le répertoire par défaut pour les extensions. Si vous avez spécifié un autre répertoire dans php.ini via la directive extension_dir, placez-y votre extension.

Il est inutile de faire charger cette extension par Apache car les scripts de type démon seront exécutés via PHP-CLI. Vous ne devez donc pas modifier votre php.ini. Nous verrons comment charger l'extension dynamiquement directement dans le script.

3. Petit exemple de démon

Pour vous fournir un petit exemple, j'ai décidé de développer un petit démon qui effectue le backup d'une DB SQLite toutes les heures. Tous les commentaires utiles sont dans le script.

 
Sélectionnez

<?php
define(TARGETDB,'c:/dvpactivedb.db');
define(BACKUPDB,'d:/dvpbackupdb.db');
define(LOGFILE,'c:/backupDaemon.log');
define(BACKUPINTERVAL,3600);
define(ERR_CD1,'Impossible d\'ouvrir le fichier Log');
define(ERR_CD2,'La base de données à sauvegarder n\'a pu être trouvée');
define(ERR_CD3,'Impossible de copier la base de donnée');
 
class BackupDaemon
{
 private $logFileRes=null;
 
	function __construct()
	{
            $this->startDaemon();
	}
 
	private function startDaemon()
	{
	 $x = win32_start_service_ctrl_dispatcher('PHP_BackupDB');
         $sleepTime=1;
         $this->backupDB(); /* On commence par effectuer un backup directement
            La condition de cette boucle sert à vérifier qu'on a pas tenté de stopper
            le service dans le SCM. Il ne faut donc pas trop dormir trop longtemps(sleep) sous peine que l'utilisateur
            ne puisse stopper le service.
         */
	 while (WIN32_SERVICE_CONTROL_STOP != win32_get_last_control_message()) {
 
                if($sleepTime == BACKUPINTERVAL)
                {
                	$sleepTime=1;
                	$this->backupDB();
                }
                sleep(1);
                $sleepTime++;
	 }
	}
 
        private function backupDB()
        {
        	if(!file_exists(TARGETDB))
        	{
        	 $this->handleError(ERR_CD2);
        	}
 
        	if(!(copy(TARGETDB,BACKUPDB)))
        	{
        	  $this->handleError(ERR_CD3);
        	}
                $this->logIt('Dernier backup effectué correctement:'.date('y/m/d h:i:s'));
 
        }
	private function logIt($msg)
	{
	 if(!is_resource($this->logFileRes))
	 {
	 	$this->logFileRes=fopen(LOGFILE,'a+') or $this->handleError();
	 }
	 fwrite($this->logFileRes,$msg."\r\n");
	}
 
	private function handleError($err)
	{
              if($err != ERR_CD1)
              {
              	$this->logIt($err);
              }
              $this->__destruct();
	}
	function __destruct()
	{       /* Si le fichier log a été correctement ouvert, on le ferme */
		if(is_resource($this->logFileRes))
		{
			fclose($this->logFileRes);
		}
		die();
	}
 
 
}
 
/* On vérifie que l'extension est chargée, si elle ne l'est pas, on la charge*/
if(!extension_loaded('php_win32service'))
{
  dl('php_win32service.dll') or die('Impossible de charger la librairie php_win32service.dll');
}
 
/* On vérifie les paramètres passés au script */
if(isset($argv[1]))
{
 $validParams=array('install','uninstall');
 if(!in_array($argv[1],$validParams))
 {
  die('Veuillez specifier install || uninstall comme premier parametre');
 }
 
 if ($argv[1] == 'install') {
         /*
            Création du service dans le SCM (service control manager)
            La fonction win32_create_service crée le service dans le SCM. Le nom du service
            est donné en tant que premier paramètre, le label qu'il aura dans le SCM dans le second
            et le fichier qu'il devra lancer ainsi que l'argument run dans le 3ème paramètre.
         */
	$createService = win32_create_service(array(
		'service' => 'PHP_BackupDB',
		'display' => 'Exemple de démon DVP',
		'params' => __FILE__,
	));
        if($createService !== true)
        {
        	die('Impossible de créer le service!');
        }
        else
        {
        	die('Service cree avec succes');
        }
 
 } 
 else if ($argv[1] == 'uninstall') 
 {
        /* win32_delete_service marque le service comme "disabled/désactivé" dans le SCM. */
	$removeService = win32_delete_service('PHP_BackupDB2');
        switch($removeService)
        {
        	case 1060: die('Ce service n\'existe pas');break;
        	case 1072: die('Ce service n\'a pu être supprimé, il est probablement actif ou corrompu!');break;
        	case 0:die('Service supprime avec succes');break;
        	default:die();break;
        }
 
 }
}
else
{
 $daemon=new BackupDaemon();
}
?>
 

Lorsque vous aurez téléchargé ou recopié ce script, vous devez l'exécuter en ligne de commande comme suit pour installer le service:

Image non disponible

Lorsque le service a été créé, vous pourrez dès lors le démarrer soit en exécutant
net start lenomdevotreservice
soit, en ouvrant l'interface graphique permettant de gérer les services, comme ceci:

Image non disponible

et en cliquant sur démarrer/start

4. Fonctionnement

Grâce à cette nouvelle extension, il est désormais assez facile d'exécuter un script PHP5 en tant que service windows. A l'heure actuelle, il n'y a quasiment aucune documentation sur cette extension. Elle est assez basique et comprend peu de fonctions. Ces fonctions ont été utilisées dans le script donné en exemple.

L'utilisateur par défaut qui est "owner" du service est l'utilisateur system. La fonction win32_create_service permet de spécifier un autre utilisateur en lui passant 'user' => le_user comme paramètre. Ne perdez pas de vue lorsque vous créerez vos services qu'il faut toujours vérifier si le SCM envoie un signal d'interruption du service. Si vous faites un démon qui dort pendant 1h (sleep 3600), l'utilisateur ne pourra jamais stopper le service car le signal ne sera jamais intercepté par le script. La plateforme que j'ai utilisé pour tester cette extension est Windows XP pro service pack1.

5. Téléchargement

Vous pouvez télécharger ce script ici

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Copyright © 2005 Developpez. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.