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. Le lendemain on rentre du boulot en vélo, arrosé par une pluie moqueuse. Des conditions climatiques perplexes, idéales 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:
- On demande le code de la ville dont on souhaite connaitre les prévisions météo.
- On demande les prévisions météo pour les jours à venir.
- 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 :
- On crée l'objet.
- On récupère le code de la ville qui nous intéresse. Ici Toulouse, parce que c'est chez moi.
- 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($code, 4);
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 ' · ';
echo WdWeather::to24H($day['suns']);
echo '<br />';
echo $day['hi'] == 'N/A' ? '—' : WdWeather::toCelsius($day['hi']) . '°C';
echo ' · ';
echo $day['low'] == 'N/A' ? '—' : 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 :-)

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 ;-)
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 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 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 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 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 a écrit : le 11 aoû 2009
On peut meme pas s'enregistrer sur le site, le lien new user ne marche pas
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 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 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 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 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 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 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.