"Daemonizer" un script PHP
16/10/2005
Suite à mon document sur la création de serveurs en PHP, peut-être certains d’entre vous ont dû se poser la question : comment « daemonizer » un script PHP ? En clair, comment faire en sorte qu’il fonctionne en arrière-plan sans user de saletés telles que nohup, comme un véritable serveur tel que Apache, MySQL, Samba, etc ?
Il est clair que la documentation de PHP manque de précision sur ce point, ce qui m’a forcé à aller récupérer quelques morceaux de réponse un peu partout et même à m’inspirer de programmes écrits en C ou en Perl. Je vais récapituler dans ce billet ce que j’ai appris.
Pour « daemonizer » un script PHP, il faut 3 étapes bien distinctes :
- Le script doit se relancer lui-même en redirigeant tous les flux (STDIN, STDOUT, STDERR) vers
/dev/null. Faute de quoi la sortie du script sera envoyée sur votre terminal. De plus, un problème avec OpenSSH se produit également lorsqu’on ne le fait pas. - Le processus doit être « forké ». En d’autres termes, on va faire une copie à l’identique du processus. La seule différence est que cette copie sera orpheline, c’est à dire qu’elle sera enfant direct de INIT (le processus racine du système), et non du terminal à partir duquel le démon a été lancé. On fermera ensuite le processus original. Si le fork n’st pas fait, l’administrateur se verra contraint de faire CTRL + C pour détacher le démon, ce qui n’est pas problématique (le processus ne sera pas fermé), mais peu esthétique.
- Le processus doit être transformé en « chef de session ». Cela n’est pas réellement nécéssaire mais plus propre : ça évitera que le processus ne soit encore rattaché au terminal qui l’a lancé.
Pour programmer ces trois points, nous aurons besoin de 3 fonctions (respectivement) : proc_open(), pcntl_fork() et posix_setsid().
Voici le code :
// On se place dans le même répertoire que le script chdir(dirname(__FILE__)); // On vérifie que l’extension PCNTL est bien là if (!is_callable(‘pcntl_fork’)) { die(‘Error : PCNTL extension not available, recompile PHP with –enable-pcntl’.« \n »); } // Si cela n’est pas déjà été fait… if (!in_array(‘/redirected’, $argv)) { // … on relance le script en redirigeant les flux $desc = array( 0 => array(‘file’, ‘/dev/null’, ‘r’), 1 => array(‘file’, ‘/dev/null’, ‘a’), 2 => array(‘file’, ‘/dev/null’, ‘a’) ); // Note : on peut améliorer ceci en repassant les paramètres de ligne de commande proc_open(‘php -f ‘.basename(__FILE__).‘ /redirected’, $desc, $null); // Puis on ferme le processus parent die(); } // On tente de forker $pid = pcntl_fork(); if ($pid == -1) { // Erreur lors du fork die(‘Error: cannot fork’.« \n »); } if ($pid) { // Fork réalisé : on ferme le processus original die(); } else { // Fork déjà réalisé : on ne fait rien } // On devient maître de session posix_setsid(); // Let’s go !
Vous pouvez coder tout ce que vous voulez à la suite, ce sera « daemonizé ».