PHP, XML & Prévisions Météo

On ne sait plus trop comment s'habiller ces jours-ci. Un jour on se ballade poils au vent, caressé par un soleil complice et le lendemain on rentre du travail en vélo, arrosé par une pluie moqueuse. Un climat indécis, idéal pour présenter ma dernière classe : WdWeather.

Présentation

Utilisant les services pratiques et connus de weather.com, WdWeather permet d'obtenir les prévisions météorologiques jusqu'à 10 jours (limite imposée par le service). Les informations sont aussi nombreuses que variées. Ainsi pour chaque jour on obtient, en autre, les informations suivantes :

  • Les heures de lever et de coucher du soleil
  • Les températures les plus basse et les plus hautes

Et pour chaque période de la journée (Jour / Nuit) :

  • Le numéro du pictogramme associé au temps.
  • Une description du temps en anglais, par exemple : Mostly Sunny.
  • La force et la direction du vent.
  • Les précipitations.
  • Le taux d'humidité.

Bref, il y a de quoi faire.
Voyons justement comment tout ça marche.

Comment ça marche ?

C'est vraiment très simple. Le principe est le suivant:

  1. On demande le code de la ville dont on souhaite connaitre les prévisions météo.
  2. On demande les prévisions météo pour les jours à venir.
  3. On affiche le résultat.

C'est tellement fastoche que je me suis presque endormi en écrivant les étapes.

Le Code

<?php

class WdWeather
{
    var $markup_contents = '([^<]+)';
    
    function getCityCode($search)
    {
        #
        # we create a nice looking URL
        #
        
        $search = explode(','$search);
        $search = array_map('urlencode'$search);
        $search = implode(',+'$search);
        
        #
        # ask the service about the location
        #
    
        $xml = file_get_contents
        (
            'http://xml.weather.com/search/search?where=' . $search
        );
        
        #
        # try to get the first result
        #
        
        if (!preg_match('#loc id="([^"]+)#'$xml$matches))
        {
            return;
        }
        
        return $matches[1];
    }

    function getWeather($city_code$days)
    {
        $xml = file_get_contents
        (
            'http://xml.weather.com/weather/local/' . $city_code .
            '?cc=*&unit=s&dayf=' . $days
        );
        
        if (!$xml)
        {
            return;
        }
        
        return $this->parseDays($xml);
    }
    
    function parseDays($xml)
    {
        $days = array();
        
        #
        # split xml by days
        #

        $parts = preg_split('#<day d=[^>]+>#'$xml);

        array_shift($parts);

        $mc = $this->markup_contents;

        foreach ($parts as $xml)
        {
            $days[] = $this->parseDay($xml);
        }
        
        return $days;
    }

    function parseDay($xml)
    {
        $mc = $this->markup_contents;
    
        preg_match
        (
            '#' .
            
            '<hi>' . $mc . '</hi>\s*' .
            '<low>' . $mc . '</low>\s*' .
            '<sunr>' . $mc . '</sunr>\s*' .
            '<suns>' . $mc . '</suns>\s*' .
            '<part p="d">(.*)</part>\s*' .
            '<part p="n">(.*)</part>' .
            
            '#ms',
            
            $xml$matches
        );
        
        array_shift($matches);
                    
        #
        # parse day periods (day / night)
        #
        
        $matches[4] = $this->parseDayPeriod($matches[4]);
        $matches[5] = $this->parseDayPeriod($matches[5]);
        
        #
        #
        #
        
        return array_combine
        (
            array('hi''low''sunr''suns''day''night')$matches
        );
    }
    
    function parseDayPeriod($xml)
    {
        $mc = $this->markup_contents;

        preg_match
        (
            '#' .
            
            '<icon>' . $mc . '</icon>\s*' .
            '<t>' . $mc . '</t>\s*' .
            '<wind>(.*)</wind>\s*' .
            '<bt>' . $mc . '</bt>\s*' .
            '<ppcp>' . $mc . '</ppcp>\s*' .
            '<hmid>' . $mc . '</hmid>' .
            
            '#ms',
            
            $xml$matches
        );
        
        array_shift($matches);
        
        $matches[2] = $this->parseWind($matches[2]);
        
        return array_combine
        (
            array('icon''t''wind''bt''ppcp''hmid')$matches
        );
    }
    
    function parseWind($xml)
    {
        $mc = $this->markup_contents;

        preg_match
        (
            '#' .
            
            '<s>' . $mc . '</s>\s*' .
            '<gust>' . $mc . '</gust>\s*' .
            '<d>' . $mc . '</d>\s*' .
            '<t>' . $mc . '</t\s*' .
            
            '#ms',
            
            $xml$matches
        );
        
        array_shift($matches);
        
        return array_combine
        (
            array('s''gust''d''t')$matches
        );
    }

    static function toCelsius($f)
    {
        if (!is_numeric($f))
        {
            return $f;
        }
    
        return round(($f-32) * 5 / 9);
    }
    
    static function to24H($time)
    {
        preg_match('#(\d+)\:(\d+)\s+(AM|PM)?#'$time$matches);
        
        if ($matches[3] == 'PM')
        {
            $matches[1] += 12;
        }

        return $matches[1] . ':' . $matches[2];
    }
}

?>

L'exemple

Trois lignes d'initialisation :

  1. On crée l'objet.
  2. On récupère le code de la ville qui nous intéresse. Ici Toulouse, parce que c'est chez moi.
  3. On récupère les prévisions météo pour les quatre jours qui viennent.
<?php

$weather = new WdWeather();

$code = $weather->getCityCode('Toulouse, France');
$days = $weather->getWeather($code4);

define('WEATHER_ICONS_URL''wdweather/');

?>

On met tout ça dans un tableau

<table id="weather" cellpadding="4" cellspacing="0">
<tr>

Pour chaque jour on affiche les informations suivantes :

  • Pictogramme des conditions météo pour le jour et la nuit.
  • Heures de lever et de coucher du soleil.
  • Température la plus haute, température la plus basse.
<?php

foreach ($days as $day)
{
    echo '<td>';
    
    $title = $day['day']['t'];
    
    echo '<img src="' . WEATHER_ICONS_URL . $day['day']['icon'] . '.png"';
    echo ' alt="' . $title . '" title="' . $title . '" />';

    $title = $day['night']['t'];

    echo '<img src="' . WEATHER_ICONS_URL . $day['night']['icon'] . '.png"';
    echo ' alt="' . $title . '" title="' . $title . '" />';

    echo '<br />';

    echo WdWeather::to24H($day['sunr']);
    echo ' &middot; ';
    echo WdWeather::to24H($day['suns']);
    
    echo '<br />';
    
    echo $day['hi'] == 'N/A' ? '&mdash;' : WdWeather::toCelsius($day['hi']) . '°C';
    echo ' &middot; ';
    echo $day['low'] == 'N/A' ? '&mdash;' : WdWeather::toCelsius($day['low']) . '°C';

    echo '</td>';
}

?>

Et voilà, c'est fini. On remarquera juste l'utilisation de la méthode WdWeather::to24H() pour transformer la vilaine heure sur 12H en jolie heure sur 24H. On remarquera aussi l'utilisation de la méthode WdWeather::toCelsius()pour transformer les vilains degrés Fahrenheit en jolis degrés Celsius.

</tr>
</table>

Le résultat

Voici le résultat pour ce glorieux jour de soleil. Nous sommes le 19 Avril 2008, il est 12H27 et dans quelques heures le weekend va être tout trempé et morne.

Espérons que ces prévisions là soient toutes pourries :-)

WdWeather

Cadeau bonux

Pour ceux qui sont tentés, voici quelques pictogrammes pour agrémenter vos présentations. Vous en trouverez sans doute de bien mieux ailleurs, mais là vous n'avez pas à chercher ;-)

Cet article a frappé votre imagination ? Abonnez-vous pour être informé de ceux à venir.

Commenter

Un avis sur cet article ? Partagez-le et faites vous des amis (ou pas) !

Marquer

Del.icio.us / Google / Live / Ma.gnolia / Yahoo

14 commentaires

007
007 a écrit : le 12 aoû 2008

Bonne info ! Tres bon script et bonne explication ! Continue comme ca, je t'ajoute dans mes lectures rss quodiennes

yanice
Yanice a écrit : le 12 mai 2009

il ya une chose qui m'échappe, sur la plupart des sites proposant des tuto pour l'utilisation de weather.com, on voit des fonctions « maisons » pour convertir les degré Fahrenheit en degré Celsius, or le paramètre « unit » de l'url du xml permet de l'obtenir directement « &unit=m ». sinon, pour ce qui est de la recherche du code de la ville, comment faire pour rechercher Alger? Venise? ou même Pékin? merci

Olivier
Olivier a écrit : le 16 mai 2009

Salut Yanice,

Merci pour l'info concernant le paramètre « unit ». Comme tu peux peut-être t'en douter, je n'avais aucune documentation lors de la création de la classe et c'est vrai que je n'y suis pas retourné depuis.

Concernant la recherche du code de la ville, il faut peut-être utiliser son appellation Anglaise…

SAMY
SAMY a écrit : le 04 aoû 2009

Salut,

j'ai un soucis, j'ai rien qui s'affiche à l'écran, la page reste blanche.

pourtant j'ai tout fait comme toi

il me récupere le code « $code ». j'ai vu qu'il déconnait à partir de « $days = $weather->getWeather($code, 4); » et du foreach

Cordialement

Olivier
Olivier a écrit : le 10 aoû 2009

Il semblerait que le code « partenaire » soit maintenant obligatoire, ce qui n'était pas le cas auparavant… Je suis en train de décortiquer l'extension « 1-ClickWeather » de Firefox afin de trouver une solution. Sinon, vous pouvez toujours vous enregistrer :

http://www.weather.com/services/oap.html

Samy
Samy a écrit : le 11 aoû 2009

Il semblerait que le code « partenaire » soit maintenant obligatoire, ce qui n'était pas le cas auparavant… Je suis en train de décortiquer l'extension « 1-ClickWeather » de Firefox afin de trouver une solution. Sinon, vous pouvez toujours vous enregistrer :

http://www.weather.com/services/oap.html

On peut meme pas s'enregistrer sur le site, le lien new user ne marche pas

yanice
Yanice a écrit : le 13 aoû 2009

ben pas de quoi :) sinon, pour l'appellation anglaise des villes, c'est ce que je me suis résolu à faire, mais disons que c'est extrêmement fastidieux et particulièrement compliqué. d'autant que toutes les villes n'ont pas de nom « anglais »; bref vous vous rendez-bien compte du boulot que ça entraîne, donc si quelqu'un trouve un jour une meilleure solution, je suis preneur!!

soraya
Soraya a écrit : le 19 oct 2009

merci pour le parseur  !!! je l'ai utilisé et impec. il faut cependant changer l 'url dans la finction function getWeather($city_code, $days) par 'http://xml.weather.com/weather/local/' . $city_code . '?cc=*&unit=s&dayf=' (..xml..à la place de.. xoap..)

Sinon une question: comment je peux faire pour afficher les jours ? « monday, tuesday.. »  ??

merci ;)
vive le p2p

soraya
Soraya a écrit : le 19 oct 2009

à yanice: j'ai mis directement le code ville de type FRXXXX que tu peux trouver ici http://xoap.weather.com/search/search?where=%20paris

tu affectes ce code à la variable $code: $code = « FRXX0076 »;

hasta batata !

Fabrice
Fabrice a écrit : le 19 jan 2010

Bonjour, ce code à l'air pas mal mais je n'arrive pas a le faire fonctionner. Y'a t'il une personne qui pourrait faire les corrections afin qu'il fonctionne en s'enregistrant comme partenaire.

j'ai créer un page wdweather.php et j'y ai copier le code fournit « Le Code ». ensuite j'ai créé un page météo ou j'y ai mis le r este du code « L'exemple »

probleme : Parse error: syntax error, unexpected T_STATIC, expecting T_OLD_FUNCTION or T_FUNCTION or T_VAR or '}' in /homepages/29/d311675876/htdocs/wdweather.php on line 171

j'imagine que le code a du changé depuis le temps et je voulai donc savoir si il était possible de l'avoir corrigé ?

Merci à vous tous !!

Olivier
Olivier a écrit : le 27 jan 2010

Le message d'erreur que tu rapportes est assez typique. C'est la version 4 de PHP qui interprète le code, essaie donc avec la version 5, il ne devrait pas y avoir de problème.

Tu as raison, ce serait pas mal de mettre à jour le code. Promis je m'en occupe dès qu'une mairie me demande la météo sur son site.

Pascal
Pascal a écrit : le 07 mar 2010

Salut, Super code, clair et précis. Mais tout comme Soraya, je n'arrive pas a récupérer le jour et la date et la mettre en francais, quelqu'un à la soluce ?

Merci à vous

Pascal

olivier
Olivier a écrit : le 07 mar 2010

Le jour et la date ne font pas partie du flux XML. Pour cela, il suffit de faire une itération depuis la date d'interrogation du service :

<?php

$now = time();

for ($i = 0 ; $i < 6 ; $i++)
{
    echo "j+$i: " . date('D'strtotime("+$i day"$now)) . " <br />";
}

?>

Pour que les jours apparaissent en français, il vous faudra paramétrer PHP en utilisant la fonction setlocale() :

<?php

setlocale(LC_TIME, 'fr_FR.UTF8''fr.UTF8');

?>

Comme l'a suggérer Soraya, j'ai modifié le code de la fonction pour utiliser « xml. » à la place « xoap. ». On obtient les mêmes résultats, sauf que « xoap. » requiert le code partenaire que l'on obtient en s'enregistrant, ce que j'ai fais pour tirer tout ça au clair.

ba
Ba a écrit : le 14 avr 2010

Bonjour, Script tres clair ./ Merci y'aurait il un moyen pour éviter de switcher trop vite entre les températures du jour et de la nuit? Car par exemple à 15h défois je me retrouve avec les températures basses du soir? Merci

Laisser un commentaire

Pour ne pas retrouver mon blog noyé de spam à mon retour de vacances, les nouveaux commentaires devront attendre d'être approuvés pour apparaitre sur le blog. Je vous remercie de votre compréhension et vous souhaite un bel été.

 
 Souhaitez-vous être informé par E-Mail d'une réponse à votre message ?