source: spip-zone/_plugins_/rainette/trunk/inc/charger_meteo.php @ 107858

Last change on this file since 107858 was 107858, checked in by eric@…, 3 years ago

Encore un include manquant.

  • Property svn:eol-style set to native
File size: 13.0 KB
Line 
1<?php
2/**
3 * Ce fichier contient la fonction standard de chargement et fourniture du fichier cache des données météo.
4 * Elle s'applique à tous les services et à tous les types de données.
5 *
6 * @package SPIP\RAINETTE\CACHE
7 */
8if (!defined('_ECRIRE_INC_VERSION')) {
9        return;
10}
11
12
13/**
14 * Renvoyer le nom du fichier cache des données météos correspondant au lieu et au type de données choisis après l'avoir
15 * éventuellement mis à jour.
16 *
17 * Si le fichier cache est obsolète ou absent, on le crée après avoir chargé puis phrasé le flux XML ou JSON
18 * et stocké les données collectées et transcodées dans un tableau standardisé. L'appelant doit s'assurer que la
19 * périodicité est compatible avec le service; cette fonction ne retourne donc que des erreurs de chargement.
20 *
21 * @uses service2cache()
22 * @uses service2donnees()
23 * @uses indice2risque_uv()
24 *
25 * @param string $lieu
26 *        Le lieu concerné par la méteo exprimé selon les critères requis par le service
27 * @param string $mode
28 *        Le type de données météorologiques demandé :
29 *            - `conditions`, la valeur par défaut
30 *            - `previsions`
31 *            - `conditions`
32 *            - `infos`
33 * @param int $periodicite
34 *        La périodicité horaire des prévisions :
35 *            - `24`, les prévisions de la journée
36 *            - `12`, les prévisions du jour et de la nuit
37 *            - `6`, les prévisions de la journée par période de 4h
38 *            - `3`, les prévisions de la journée par période de 3h
39 *            - `1`, les prévisions de la journée pour chaque heure
40 *            - `0`, pour les modes `conditions` et `infos`
41 * @param string $service
42 *        Le nom abrégé du service :
43 *            - `weather` pour le weather.com, la valeur par défaut car elle ne nécessite aucune inscription
44 *            - `wwo` pour World Weather Online
45 *            - `wunderground` pour Wunderground
46 *            - `owm` pour Open Weather Map
47 *            - `apixu` pour APIXU
48 *
49 * @return string
50 *        Le nom du fichier cache correspondant à la demande.
51 */
52function inc_charger_meteo_dist($lieu, $mode = 'conditions', $periodicite = 0, $service = 'weather') {
53
54        // Traitement des cas ou les arguments sont vides (ce qui est différent de non passés à l'appel)
55        // On considère à ce stade que la cohérence entre le mode, la périodicité et le service (qui selon ne supporte
56        // pas toutes les périodicités) est déjà assurée et n'est donc pas à tester.
57        if (!$mode) {
58                $mode = 'conditions';
59                $periodicite = 0;
60        }
61        if (!$service) {
62                $service = 'weather';
63        }
64
65        // En fonction du service, on inclut le fichier d'API.
66        // Le principe est que chaque service propose la même liste de fonctions d'interface dans un fichier unique.
67        include_spip("services/${service}");
68
69        // Acquérir la configuration statique du service (periode, format, données...)
70        $configurer = "${service}_service2configuration";
71        $configuration = $configurer($mode);
72
73        // Acquérir la configuration dynamique du service (celle modifiable par l'utilisateur via
74        // le formulaire et stockée en BDD dans la table spip_meta) et la merger avec la configuration statique.
75        // Cependant, celle-ci pouvant être incomplète on la complète par les valeurs par défaut quand
76        // cela est nécessaire.
77        include_spip('inc/rainette_normaliser');
78        $configuration_utilisateur = normaliser_configuration_utilisateur($service, $configuration['defauts']);
79
80        // Concaténer l'ensemble des configurations.
81        $configuration = array_merge($configuration, $configuration_utilisateur);
82
83        // Si on a demandé le mode 'previsions' sans préciser la periodicité horaire des données, il faut prendre l'intervalle
84        // par défaut configuré pour le service.
85        if (($mode == 'previsions') and !$periodicite) {
86                $periodicite = $configuration['previsions']['periodicite_defaut'];
87        }
88
89        // Construire le nom du fichier cache
90        $cache = service2cache($lieu, $mode, $periodicite, $configuration);
91
92        // Déterminer le système d'unité utilisé dans le cache et celui requis par la configuration.
93        // Si ces systèmes d'unité diffèrent il faut renouveler le cache sinon on affichera des données
94        // fausses avec une unité correcte et ce jusqu'à la prochaine échéance du cache.
95        $unite_configuree = '';
96        $unite_cache = '';
97        if (file_exists($cache) and ($mode != 'infos')) {
98                $unite_configuree = $configuration['unite']
99                        ? $configuration['unite']
100                        : $configuration['defauts']['unite'];
101
102                lire_fichier($cache, $contenu);
103                $tableau = unserialize($contenu);
104                $index = count($tableau) - 1;
105                $unite_cache = isset($tableau[$index]['config']['unite'])
106                        ? $tableau[$index]['config']['unite']
107                        : $configuration['defauts']['unite'];
108        }
109
110        // Mise à jour du cache avec les nouvelles données météo si:
111        // - le fichier cache n'existe pas
112        // - la période de validité du cache est échue
113        // - le système d'unités du cache n'est pas celui requis
114        if (!file_exists($cache)
115        or (!filemtime($cache) or (time() - filemtime($cache) > $configuration['periode_maj']))
116        or (($mode != 'infos') and ($unite_configuree != $unite_cache))) {
117                // Construire l'url de la requête
118                $urler = "${service}_service2url";
119                $url = $urler($lieu, $mode, $periodicite, $configuration);
120
121                // Acquérir le flux XML ou JSON dans un tableau et traiter les cas d'erreurs du plugin ou du service.
122                include_spip('inc/rainette_requeter');
123                $flux = requeter($url, $configuration['format_flux'], $service);
124                $tableau = array();
125                $erreur = array(
126                        'type' => '',
127                        'service' => array(
128                                'code' => '',
129                                'message' => ''
130                        )
131                );
132                if (!empty($flux['erreur'])) {
133                        // Erreur lors du traitement de la requête due à l'URL ou à la conversion en XML ou JSON.
134                        // Cette erreur n'est pas retournée par le service.
135                        $erreur['type'] = $flux['erreur'];
136                } else {
137                        // On teste une erreur d'acquisition renvoyée par le service. Pour tous les services, une cle de base
138                        // est explicitement utilisée pour distinguer les erreurs; sa présence permet d'identifier un cas d'erreur.
139                        include_spip('inc/filtres');
140                        $configuration_erreur = $configurer('erreurs');
141                        $flux_erreur = $flux;
142                        if (!empty($configuration_erreur['cle_base'])) {
143                                $flux_erreur = table_valeur($flux, implode('/', $configuration_erreur['cle_base']), null);
144                        }
145
146                        // On normalise le flux en utilisant le mode d'erreur pour vérifier si on obtient bien une erreur.
147                        $erreur_service = service2donnees($configuration_erreur,'erreurs', $flux_erreur, -1);
148                        $verifier = "${service}_erreur_verifier";
149                        if ($verifier($erreur_service)) {
150                                // Une erreur est renvoyée par le service, on formate l'erreur correctement.
151                                $erreur['type'] = 'reponse_service';
152                                $erreur['service'] = array_merge($erreur['service'], $erreur_service);
153                        } else {
154                                // On se positionne sur le niveau de base du flux des données où commence le tableau des données météorologiques.
155                                if (!empty($configuration['cle_base'])) {
156                                        $flux = table_valeur($flux, implode('/', $configuration['cle_base']), null);
157                                }
158
159                                if (empty($flux)) {
160                                        // Pas d'erreur retournée par le service mais aucune donnée fournie. Ce cas est peut-être impossible
161                                        // mais on le traite tout de même par sécurité avec un type particulier.
162                                        $erreur['type'] = 'aucune_donnee';
163                                } else {
164                                        // En mode prévisions, le niveau de base est un tableau de n éléments, chaque élément étant un tableau contenant
165                                        // les données météorologiques d'un jour à venir ([0] => jour0[], [1] => jour1[]...).
166                                        // En mode infos ou conditions, on a directement accès aux données météorologiques (jour[]).
167                                        // Pour réaliser un traitement standard, on transforme donc le jour[] en un tableau d'un seul élément ([0] => jour[])
168                                        // qui pourra être traité comme celui des prévisions.
169                                        if (($mode == 'conditions') or ($mode == 'infos')) {
170                                                $flux = array($flux);
171                                        }
172
173                                        // Convertir le flux en tableau standard pour la mise en cache. Ce traitement se déroule en
174                                        // 3 étapes :
175                                        // -1- initialisation du tableau standard à partir uniquement des données reçues du service
176                                        // -2- complément du tableau avec les données propres à chaque service
177                                        // -3- complément du tableau avec les données communes à tous les services
178                                        foreach ($flux as $_index_jour => $_flux_jour) {
179                                                // Pour les informations et les conditions les données récupérées concernent toute la même "période".
180                                                // Par contre, pour les prévisions on distingue 2 type de données :
181                                                // - celles du jour indépendamment de la période horaire
182                                                // - celles correspondant à une période horaire choisie (24, 12, 6, 3, 1)
183                                                //   Ces donnnées sont stockées à un index horaire de 0 à n qui représente la période horaire.
184                                                // Pour avoir un traitement identique pour les deux types de données on considère que l'index horaire
185                                                // des données jour est égal à -1.
186                                                // On crée donc le tableau des index correspondant au mode choisi et on boucle dessus.
187                                                $periodes_horaires = array(-1);
188                                                if ($periodicite) {
189                                                        for ($i = 0; $i <  (24 / $periodicite); $i++) {
190                                                                $periodes_horaires[] = $i;
191                                                        }
192                                                }
193
194                                                // On détermine le flux heure en fonction du service. Ce flux heure coincide avec le flux jour dans
195                                                // la majeure partie des cas
196                                                $flux_heure = $_flux_jour;
197                                                if ((count($periodes_horaires) > 1)     and !empty($configuration['cle_heure'])) {
198                                                        $flux_heure = table_valeur($_flux_jour, implode('/', $configuration['cle_heure']), null);
199                                                }
200
201                                                // On boucle sur chaque periode horaire pour remplir le tableau complet.
202                                                foreach ($periodes_horaires as $_periode) {
203                                                        // 1- Initialiser le tableau normalisé des informations à partir des données brutes
204                                                        //    fournies par le service.
205                                                        //    Suivant la période il faut prendre le flux jour ou le flux heure. On calcule donc le flux heure
206                                                        //    quand c'est nécessaire.
207                                                        $flux_a_normaliser = $_periode == -1
208                                                                ? $_flux_jour
209                                                                : ($configuration['structure_heure'] ? $flux_heure[$_periode] : $flux_heure);
210                                                        $donnees = service2donnees(
211                                                                $configuration,
212                                                                $mode,
213                                                                $flux_a_normaliser,
214                                                                $_periode);
215
216                                                        if ($donnees) {
217                                                                // 2- Compléments spécifiques au service et au mode.
218                                                                //    Si ces compléments sont inutiles, la fonction n'existe pas
219                                                                $completer = "${service}_complement2${mode}";
220                                                                if (function_exists($completer)) {
221                                                                        $donnees = $mode == 'previsions'
222                                                                                ? $completer($donnees, $configuration, $_periode)
223                                                                                : $completer($donnees, $configuration);
224                                                                }
225
226                                                                // 3- Compléments standard communs à tous les services mais fonction du mode
227                                                                if ($mode == 'conditions') {
228                                                                        // Vérifier que l'indice uv si celui-ci est fourni
229                                                                        // Calcul du risque uv à partir de l'indice uv si celui-ci est fourni
230                                                                        include_spip('inc/rainette_convertir');
231                                                                        $donnees['risque_uv'] = is_int($donnees['indice_uv'])
232                                                                                ? indice2risque_uv($donnees['indice_uv'])
233                                                                                : $donnees['indice_uv'];
234                                                                }
235
236                                                                // Ajout du bloc à l'index en cours
237                                                                if ($_periode == -1) {
238                                                                        $tableau[$_index_jour] = $donnees;
239                                                                } else {
240                                                                        $tableau[$_index_jour]['heure'][$_periode] = $donnees;
241                                                                }
242                                                        }
243                                                }
244                                        }
245                                }
246                        }
247                }
248
249                // 4- Compléments standard à tous les services et tous les modes
250                $extras = array();
251                $extras['credits'] = $configuration['credits'];
252                $extras['config'] = array_merge(
253                        $configuration_utilisateur,
254                        array('source' => normaliser_configuration_donnees($mode, $configuration['donnees']))
255                );
256                $extras['lieu'] = $lieu;
257                $extras['mode'] = $mode;
258                $extras['periodicite_cache'] = $periodicite;
259                $extras['service'] = $service;
260                $extras['erreur'] = $erreur;
261
262                // On range les données et les extras dans un tableau associatif à deux entrées ('donnees', 'extras')
263                if ($tableau) {
264                        // Pour les modes "conditions" et "infos" l'ensemble des données météo est accessible sous
265                        // l'index 'donnees'. Il faut donc supprimer l'index 0 provenant du traitement commun avec
266                        // les prévisions.
267                        // Pour les prévisions l'index 0 à n désigne le jour, il faut donc le conserver
268                        $tableau = array(
269                                'donnees' => ($mode != 'previsions' ? array_shift($tableau) : $tableau),
270                                'extras' => $extras
271                        );
272                } else {
273                        // Traitement des erreurs de flux. On positionne toujours les bloc extra contenant l'erreur,
274                        // le bloc des données qui est mis à tableau vide dans ce cas à l'index 1.
275                        $tableau = array(
276                                'donnees' => array(),
277                                'extras'  => $extras
278                        );
279                }
280
281                // Pipeline de fin de chargement des données météo. Peut-être utilisé :
282                // -- pour effectuer des traitements annexes à partir des données météo (archivage, par exemple)
283                // -- pour ajouter ou modifier des données au tableau (la modification n'est pas conseillée cependant)
284                $tableau = pipeline('post_chargement_meteo',
285                                                        array(
286                                                                'args' => array('lieu' => $lieu, 'mode' => $mode, 'service' => $service),
287                                                                'data' => $tableau
288                                                        ));
289
290                // Création du nouveau cache
291                ecrire_fichier($cache, serialize($tableau));
292        }
293
294        return $cache;
295}
Note: See TracBrowser for help on using the repository browser.