lindev.fr

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

Mot-clé - service web

Fil des billets - Fil des commentaires

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.zip

Il faut maintenant 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 ..

19 fév. 2010

Halte là !

Sécurisez vos formulaires contre les spams

police.png

Vous avez un banal site vitrine , un livre d'or ou autres formulaires de contact / commentaires , sans protection , même minime , vous allez rapidement voir apparaître des messages non sollicités , qui peuvent même parfois se révéler dangereux .
Cet article vise à donner une solution ( parmi beaucoup d'autres ) pour éviter ce genre de désagrément , et sans le moindre captcha .
Nous allons prendre un simple formulaire de contact pour l'exemple

Le code de base , sans aucune protection

Le formulaire

<form name="contact" method="POST" action="send.php" >
    
    <table>
        <tr>
            <td>
                Pseudo :
            </td>
            <td>
                <input type="text" name="pseudo" >
            </td>
        </tr>
        
        <tr>
            <td>
                Mail :
            </td>
            <td>
                <input type="text" name="email" >
            </td>
        </tr>
        
        <tr>
            <td>
                Message :
            </td>
            <td>
                <textarea name="message" ></textarea>
            </td>
        </tr>
        
        <tr>
            <td>
                <input type="submit" name="envoyer" value="envoyer" />
            </td>
        </tr>
    </table>
    
</form>

Envoi du mail

<?php
/*
 * send.php
 * 
 */

//récupération et filtrage des données
$tData = filter_form( $_POST, "utf-8" );

//envoie du mail 
sendMail( $tdata );

?>

Voilà , quoi de plus simple .. mais quoi de plus vulnérable par le spam !!!!
Note: je ne traiterais pas ici des fonctions filter_form() et sendMail() , n'étant que des fonctions fictives pour éclaircir au maximum le code .

Protection 1 : rendre le formulaire unique

Et oui ce n'est pas parce que le formulaire est là qu'une personne malveillante doit y passer pour envoyer le mail , ce qui permet aux "pirates" de forger des requêtes , envoyé soit par une de leurs victimes , un robots ou autres méthodes détournées .

Pour rendre le formulaire unique , nous allons lui ajouter un jeton , qui sera changeant constamment , ainsi avant l'expédition du mail , l'on vérifie que le jeton est là et valide
Voilà le formulaire modifié

<form name="contact" method="POST" action="send.php" >
    
    <table>
        <tr>
            <td>
                Pseudo :
            </td>
            <td>
                <input type="text" name="pseudo" >
            </td>
        </tr>
        
        <tr>
            <td>
                Mail :
            </td>
            <td>
                <input type="text" name="email" >
            </td>
        </tr>
        
        <tr>
            <td>
                Message :
            </td>
            <td>
                <textarea name="message" ></textarea>
            </td>
        </tr>
        
        <tr>
            <td>
                <input type="submit" name="envoyer" value="envoyer" />
                
                <input type="hidden" name="jeton" value="<?php echo  md5('graindesel'.date('Y-m-d h:i:00',time()));?>" />
                
            </td>
        </tr>
    </table>
    
</form>

Et au niveau de send.php , il nous suffit d'ajouter la vérification du jeton de la façon suivante :

<?php
/*
 * send.php
 *
 */

//récupération et filtrage des données
$tData = filter_form($_POST,"utf-8");

//cree un tableau de 0 à 10
$validite = range(0, 10) ;
//initialise le resultat
$valide = false ;
//vérifie le jeton
foreach($validite as $v) {
        $valide |= ( $_POST['jeton'] == md5('graindesel'.date('Y-m-d h:i:00', time() - $v * 60)));
}

if( !$valide ){
	//redirection vers une page d'erreur
}else{
        //envoie du mail
        sendMail($tdata);
}

?>

Contrairement au formulaire initial cette fois le "pirate" est obligé de passer par le formulaire pour envoyer le mail , le jeton étant valide 11 minutes , un internaute devra remplir et envoyer ce formulaire en maximum 11 minutes , ce qui est largement faisable . :-)

Protection 2 : filtrage anti-spam

La protection du formulaire unique permet déjà de réduire de façon notable l'envoie de spam via cette page , maintenant certains réussirons toujours à passer outre , rien de bien compliqué à celà .
La derniére solution avant expédition , est d'utiliser un service enti-spam tel que akismet

Akismet est un Web-service à qui nous allons envoyer les données du formulaire , en réponse nous arons un simple booléen qui nous indiquera si oui ou non le message semble être un spam .

Enregistrement Akismet

Il vous faut une clef ( gratuite ) , pour celà allez vous enregistrer sur le site d'akismet

Utilisation akismet

Le site vous propose de nombreux plugins déjà prêts pour des applications comme Dotclear , Wordpress , punBB ect ... Mais aussi des "class" php pour des scripts perso comme le notre .

Nous allons donc télécharger la classe proposé par le site achingbrain.net

L'utilisation est trés simple, dézipez l'archive afin de rendre la classe accessible par votre serveur web ... ( je vais la mettre au même endroit que send.php pour l'exemple )

et voilà la modification de send.php pour utiliser ce service :

<?php
/*
 * send.php
 *
 */

//récupération et filtrage des données
$tData = filter_form($_POST,"utf-8");

//cree un tableau de 0 à 10
$validite = range(0, 10) ;
//initialise le resultat
$valide = false ;
//vérifie le jeton
foreach($validite as $v) {
        $valide |= ( $_POST['jeton'] == md5('graindesel'.date('Y-m-d h:i:00', mktime() + $v * 60)));
}

if( !$valide ){
	//redirection vers une page d'erreur
}else{
    
    //Test AKISMET
    $APIKey = 'aoeu1aoue';
    $MyURL = 'http://www.lindev.fr/contact/';

    $akismet = new Akismet($MyURL ,$APIKey);
    $akismet->setCommentAuthor( $tdata['pseudo'] );
    $akismet->setCommentAuthorEmail( $tdata['email'] );
    $akismet->setCommentContent( $tdata['message'] );
    $akismet->setPermalink( $MyURL );

    if($akismet->isCommentSpam()){
        //redirection vers une page d'erreur
    }else{
        //envoie du mail
        sendMail($tdata);
    }
}

?>

Cette fois non seulement l'utilisateur doit passer par le formulaire , mais en plus le message sera vérifié par un service anti-spam , ce qui vous permet d'éliminer plus de 90% des mails/messages non sollicités qui peuvent provenir de ce genre de formulaire .
Et ce sans captcha :-)

Autre barrière:

Il existe encore une autre barrière , si vous êtes encore embêté , l'interrogation de listes rbls , qui vous indique si l'adresse ip du client qui remplis votre formulaire est listé comme spammeur ou non ..
Juste pour information , en voici une pour exemple :

http://bsb.spamlookup.net/

A bientot , Ch.

01 fév. 2010

couchDB par la pratique

C'est quoi couchDB

couchDB.png

CouchDB est un serveur de base de données orienté Document et accessible via une API REST HTTP/JSON.
Sans schéma, sans tables, ce qui offre une flexibilité sans limite de vos documents.

Comment , simplement car couchDB est une base qui n'est pas relationnel , il n'y a donc pas de structure qui fige les documents .

Comment l'utiliser

CouchDB utilise le protocole HTTP , avec des entêtes en GET , PUT , POST , DELETE , COPY.

Avec une possibilité d'activer l'authentification HTTP pour restreindre les accès selon vos souhaits
Pour vous simplifier la vie , j'ai développé une librairie qui réuni les méthodes indispensables pour utiliser une base couchDB , cette librairie vous permettra les action suivantes :

 * Création / suppression de bases
 * insertions de documents
 * suppressions .. 
 * copie
 * déplacements
 * réplication 
 * lecture
 * etc ..


Pour la documentation complète , voir le wiki .

oscar_couchDB

Nous allons quand même ici expliquer l'utilisation basic d'une base couchDB avec cette librairie

initialisation

Comme le précise la doc , il nous suffit d'inclure simplement la lib :

require_once 'Oscar_couchDB.php';

Nous allons ensuite récupérer une instance de la classe :

$Ocdb   =   Oscar_couchDB::getInstance();

Commençons par configurer l'accès au serveur principal , qui a comme adresse ip 10.0.0.220:

$Ocdb->set_host('10.0.0.220');
$Ocdb->set_port(5999);

Nous voilà fin prêt à attaquer ....

Commençons par créer notre table

if( ! $Ocdb->add("mabase") ){
   echo "Échec à la création de la base de données";
}

Une fois notre base crée , nous allons pouvoir la remplir avec des documents , pour créer un document , il faut de nouveau faire appel à la méthode add().

$doc = array("NOM"=>"Document A","TYPE"=>"texte");
 
$retour = $Ocdb->add("mabase","0001",$doc);
if(  $retour == false ){
    echo "Erreur à la création du document , erreur : $retour";
}else{
    echo "Document crée avec succès , <br>ID: ".$retour['id']."<br>REVISION: ".$retour['rev'].";
}

Comme vous l'aurez remarqué un document possède à sa création une révision , cela permet par exemple lors d'une modification non volontaire , de revenir en arrière .
Cependant , cela reste limité en temps , car si l'on compacte la base , seule la dernière révision est disponible .

Pour connaitre les révisions d'un document , vous pouvez faire appel à cette méthode :

$Ocdb->all_revs("mabase", "0001");

0001 étant l'id du document qui se doit d'être unique .

Et pour compacter la base pour un gain de place :

$Ocdb->compact_database('mabase');

Maintenant , comment récupérer notre enregistrement ?
Nous allons simplement utiliser la méthode get()

$mondocument = $Ocdb->get("mabase","0001");

Vous voilà avec un tableau $mondocument qui contient toutes les données que vous y avez entrées ainsi que son id et sa révision .

Pour lire une révision spécifique , il est possible de préciser celle-ci comme-ceci :

$mondocument = $Ocdb->get("mabase","0001",$revision);

Dans l'ordre des choses , nous allons supprimer ce document , voici la méthode :

$database = 'mabase';
$iddocument = '0001';
$revdoc = '1-872c3e4693b3e608148fb85b3f64df74';

$Ocdb->delete($database, $iddocument, $revdoc);

Ici la révision du document est obligatoire .



Voilà pour ces quelques exemples , il y a encore de nombreuses autres méthodes aussi simples les unes que les autres à utiliser , je vous laisse les découvrir via la documentation ici

replication

Il y a un point important , car c'est un avantage non négligeable de couchDB , la replication , qui est d'une simplicité étonnante .

Dans la librairie , il y a donc une méthode qui vous permet de répliquer vos données , de façon manuelle , mais aussi automatique , voici sa mise en place .

Commençons par paramétrer les coordonées des serveur A et B

$Ocdb->set_replication('10.0.0.220','10.0.0.221','5984','mabase','mabase_Repli');

Nous avons donc ici spécifié l'adresse du serveur source , suivi de celle du serveur cible , le port du serveur cible , la base de données source , et pour finir la base de données cible , qui n'est pas obligatoirement du même nom.

De plus si les base source/cible n'héxiste(s) pas , la librairie tentera de la/les créer .
Le réplication paramétrée , activons l'automatisme pour être certains que chaque action faite sur le serveur source soit immédiatement faite sur le serveur cible.

$Ocdb->auto_replique(TRUE);

Et voilà , plutôt simple non ?

Si le serveur cible n'est pas disponible , ce n'est pas grave , la réplication se faisant sur les logs binaire , il rattrapera automatiquement son retard lorsqu'il sera de nouveau disponible .
De plus , si le serveur source , tombe , vous pouvez attaquer directement sa réplication , en changeant les paramètres via set_replication , et lorsque le serveur sera de nouveau disponible , il se mettra automatiquement à jour , toujours grâce au logs binaires .

utile

Nous avons vue ici l'utilisation de quelques méthodes de la librairie Oscar_couchDB , mais il faut savoir que vous pouvez creer des vues en javascript qui vous permettent de faire des requêtes , filtres ect sur les documents en base , je vous donne un lien complet pour apprivoiser celà .
unixGarden

La librairie est disponible à plusieurs endroits :

 *  phpClasses
 *  dans les libs de mon fw fw-oscar.fr

12 janv. 2010

CouchDB

Installer couchDB debian Lenny

couchDB.png

Pour installer couchDB sur debian lenny ( stable ), une toute petite manip est nécessaire afin d'avoir la version 0.10.0. Sinon , vous aurez la version 0.8.0 qui est une version trop ancienne pour une bonne utilisation .

La manip

Le principe est simple , utiliser les paquets de squeeze.

Editez votre sources.list:

vim /etc/apt/sources.list

Ajouter le dépot squeeze :

deb http://ftp2.fr.debian.org/debian/ squeeze main contrib non-free

Un petit update

apt-get update

Et enfin , l'installation :

apt-get install couchdb

Attention : Une fois l'installation terminée , n'oubliez surtout pas de retirer le dépot de votre source.list .

Configuration

Fichier : /etc/couchdb/default.ini

Si vous désirez vous connecter de l'extérieur , ou pour utiliser une réplication entre deux machines , il vous faudra enlever ( commenter ) le paramétre bind_address = 127.0.0.1

Dans ce fichier , vous pouvez aussi paramétrer le port auquel le serveur écoute . ainsi que d'autres choses ... mais je ne suis pas encore aller plus loin pour le moment .

Fichier : /etc/couchdb/local.ini

Pour un accès administrateur un peu plus privé , dé-commentez le paramètre admin = ...
Et mettez votre mot de passe , il sera crypté au prochain redémarrage de couchDB .

Redémarrage

Redémarrez votre serveur couchDB :

/etc/init.d/couchdb restart

Note: J'ai fais deux installations et deux fois j'ai rencontré le problème suivant , pas moyen de me connecter au serveur ... dans les logs , un problème de bind ( le port déjà occupé ? ).
Solution , couper tous les process à coup de kill -9 et redémarrer couchdb .

Utilisation

Administration

Par défaut , une interface web d'administration est disponible à l'adresse suivante :

http://<ip du serveur>:5984/_utils

Avec php

Pour l'utilisation de couchDB avec php , j'ai développé une petite librairie simplifiant grandement les actions de bases Ajout / suppression / modification / clonage / lecture / réplication / ect ...
Cette librairie est disponible à plusieurs endroits :
fw-oswar.fr
phpclasses.org
freashmeat





Je trouve cet outil vraiment complémentaire à une base , il y a encore beaucoup à découvrir dessus ( les vues , les fonctions ect ... ) .. mais une chose à la fois .

Ch.

21 sept. 2009

big brother is watching you !

Surveiller la disponibilité d'un site camera.jpg

Rien de bien extraordinaire , mais le principe m'amuse alors autant partager , et pourquoi pas récupérer des idées dans vos commentaires .

Le principe :

L'on me demande un moyen de vérifier si des sites distants sont disponibles , ou non de façon permanente .

J'ai donc décidé de développer un bout de script , qui ne fait ni plus ni moins que:

  • Tester la résolution DNS ( Type A uniquement pour le moment )
  • récupérer les en-têtes envoyés par le serveur en réponse à une requête HTTP.
  • Récupération de ce qui m'intéresse , à savoir le code de status http , et le temps qu'a mis la réponse à me parvenir .

Ensuite , grâce à ces informations , je peux faire toute sorte de graphiques m'indiquant la disponibilité du/des sites surveillés dans le temps .

Exemple :

viewer.png

Le code

pour récupérer des données le plus proche de la réalité possible Comme j'ai dit plus haut , le code est très simple et rapide à mettre en place , il vous faudra cependant activer curl pour l'utiliser .

Vérifier la résolution de nom

Pour cette étape , nous allons utiliser la fonction native à php 4&5 checkdnsrr() :

checkdnsrr($adresse,"A");

Récupérer les entêtes HTTP

Pas besoin de récupérer la totalité , celà surchargerais inutilement les deux cotés , une première solution consiste à utiliser la fonction get_headers() en natif dans php5 :

get_headers  ( "htp://".$adresse  , true );

L'inconvénient de cette fonction , est qu'elle ne possède pas de timeout hormis celui de php , qui est bien trop long et peut pratique .
Les tests avec cette fonction se sont donc révélé bon , mais a généré l'augmentation de la consommation de mémoire de façon spectaculaire , voyez vous-même !

eluna.png

La solution , est donc d'utiliser curl , qui s'est révélé bien plus efficace , voici donc la fonction de remplacement de get_headers() ( sources fr2.php.net )

function get_headers_curl($url)
{
    $ch = curl_init();

    curl_setopt($ch, CURLOPT_URL,            $url);
    curl_setopt($ch, CURLOPT_HEADER,         true);
    curl_setopt($ch, CURLOPT_NOBODY,         true);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_TIMEOUT,        20);

    $r = curl_exec($ch);
    $r = split("\n", $r);
    return $r;
} 

Si vous ne pouvez pas utiliser curl , vous pouvez aussi utiliser la fonction suivante , qui se base sur fsockopen() en natif dans php .

Note:merci à clochix de m'avoir signalé cette autre alternative.

/*
 * Fonction de remplacement de get_headers 
 * Attention à ne pas mettre les http:// devant l'adresse 
 */
function get_headers_sock($adresse, $timeout=15){
    //Tableau qui vat contenir les entêtes
    $Theaders   =   array();
    $UserAgent = "User-Agent : Mozilla/4.0 (compatible; MSIE 5.0; Windows 95)";

    $fp = fsockopen($adresse, 80, $errno, $errstr, $timeout);
    if (!$fp) {
        echo "$errstr ($errno)<br />\n";
    } else {
        $out = "HEAD / HTTP/1.1\r\n";
        $out .= "Host: $adresse\r\n";
        $out .= "$UserAgent\r\n";
        $out .= "Connection : Close\r\n\r\n";

        fwrite($fp, $out);
        while (!feof($fp)) {
            $Theaders[] =   fgets($fp, 128);
        }
        fclose($fp);
    }


    //renvoi des entêtes
    if(!empty($Theaders)){
        return $Theaders;
    }else{
        return null;
    }
    
}

Cette fonction retourne tout comme get_headers() un tableau avec une ligne = une entrée .
Le timeout est ici défini à 20 secondes , car je juge que si l'entête n'est toujours pas là en 20secondes , le site n'est pas navigable normalement , donc indisponible .

Le code de status HTTP

Après avoir reçut la réponse HTTP , l'on décortique l'entrée du tableau n°0 qui correspond normalement à : HTTP/1.1 <code http> <etat>

Une petite expression régulière plus tard , on se retrouve avec le code http seul

//récupération des entêtes
$header = get_headers_curl($adresse);
if(!empty($header){

  //le code http sera disponible dans $retour[1]
  preg_match('#([0-9]{3})#',$header[0],$retour);

}

Le temps pour faire tout ça !

Il ne nous reste plus qu'à récupérer le temps total pour effectuer ces opérations ( temps d'envoi + temps de réception ).
Rien de plus simple , comme dans beaucoup d'exemple sur le net , nous utiliserons microtime()

$debut  = microtime(true);
$header =   get_headers_curl("http://".$adresse) ;
//ou  get_headers_sock($adresse); ( attention à ne pas mettre http devant )
$fin    =  microtime(true);
$temps  =   round($fin-$debut,4);

Et voilà , nous avons toutes les infos nécessaire , ne reste plus qu'à les enregistrer .. en base , fichier .. comme vous voulez .

Exemple de code complet :

<?php
//definition du user_agent

$useragent="Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.1) Gecko/20061204 Firefox/2.0.0.1";

//adresse à surveiller ( sans les http )
$adresse = "lindev.fr";
        
$retour = array(0,0);
$dns        =   0;
$temps      =   0;

//test du dns
if( checkdnsrr($adresse,"A")){


	$debut  = microtime(true);
        $header =   get_headers_curl("http://".$adresse) ;
        $fin    =  microtime(true);
        $temps  =   round($fin-$debut,4);

        preg_match('#([0-9]{3})#',$header[0],$retour);
        $dns    =   1;

}else{
        echo "Résolution DNS impossible";   
}

//enregistrement des resulats
$result =   array(
   "DNS"           =>     $dns,
   "reponse"       =>  $retour[1],
   "tempsReponse"  =>  $temps
);

//si timeout , impose le code 503
if($result['reponse'] == NULL){
   $result['reponse'] = 503;
}

//enregistrement dans la base de données / ou fichier
        ... ... ...
function get_headers_curl($url)
{
    $ch = curl_init();

    curl_setopt($ch, CURLOPT_URL,            $url);
    curl_setopt($ch, CURLOPT_HEADER,         true);
    curl_setopt($ch, CURLOPT_NOBODY,         true);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_TIMEOUT,        20);

    $r = curl_exec($ch);
    $r = split("\n", $r);
    return $r;
} 
?>

Mise en place

Il faut maintenant lancer ce script de façon régulière afin de surveiller le site de façon précise .
Je vais donc dans mon cas le lancer toutes les 10min , via cron

Vous voilà avec une table qui se remplis toute seule des informations citées ci-dessus , il ne vous reste plus qu'à en faire ce que bon vous semble avec .

Pour info , les graphiques générés ci-dessus sont fait via JPgraph qui fera pourquoi pas l'objet d'un billet pour son initiation .

Conclusion

Voilà une approche d'un outil qui je pense peut s'avérer utile , à partir du moment ou les sites surveillés ne se trouvent pas au même endroit que ce script de monitoring .
Ensuite , n'a de limite que votre imagination pour le faire évoluer , pour par exemple lancer des alertes au bout de X minutes de non-disponibilités , tester d'autres type de services comme les mails , ftp ect ...

J'attends vos retours et vos critiques sur l'idée ou la façon de faire afin d'améliorer tout ça .

A bientôt ,

Ch.

- page 1 de 2