source: spip-zone/_plugins_/taxonomie/trunk/services/itis/itis_api.php @ 114150

Last change on this file since 114150 was 114150, checked in by eric@…, 7 months ago

Renommer la fonction regne_lister() en regne_lister_defaut() et créer la fonction regne_repertorier() qui retourne les règnes chargés en base.
Ne pas afficher d'espèce si le règne n'est pas chargé.
Corriger les affichages si la liste des taxons est vide.

  • Property svn:eol-style set to native
File size: 33.7 KB
Line 
1<?php
2/**
3 * Ce fichier contient l'ensemble des constantes et fonctions implémentant le service de taxonomie ITIS.
4 *
5 * @package SPIP\TAXONOMIE\SERVICES\ITIS
6 */
7if (!defined('_ECRIRE_INC_VERSION')) {
8        return;
9}
10
11if (!defined('_TAXONOMIE_ITIS_ENDPOINT_BASE_URL')) {
12        /**
13         * Préfixe des URL du service web de ITIS.
14         */
15        define('_TAXONOMIE_ITIS_ENDPOINT_BASE_URL', 'http://www.itis.gov/ITISWebService/');
16}
17
18if (!defined('_TAXONOMIE_ITIS_TAXON_BASE_URL')) {
19        /**
20         * URL de base d'une page d'un taxon sur le site d'ITIS.
21         * Cette URL est fournie dans les credits.
22         */
23        define('_TAXONOMIE_ITIS_TAXON_BASE_URL', 'http://www.itis.gov/servlet/SingleRpt/SingleRpt?search_topic=TSN&search_value=');
24}
25
26if (!defined('_TAXONOMIE_ITIS_SITE_URL')) {
27        /**
28         * URL de la page d'accueil du site ITIS.
29         * Cette URL est fournie dans les credits.
30         */
31        define('_TAXONOMIE_ITIS_SITE_URL', 'http://www.itis.gov');
32}
33
34if (!defined('_TAXONOMIE_ITIS_REGEXP_RANKNAME')) {
35        /**
36         * Ligne d'un fichier ITIS hiérachie généré.
37         * Il est indispensable de respecter les majuscules des noms de groupe pour éviter de matcher
38         * les suborder, infrakingdom...
39         */
40        define('_TAXONOMIE_ITIS_REGEXP_RANKNAME', '#(%rank_list%):\s*(([A-Z]\s+)?[\w-]+)\s*(.+)\s*\[(\d+)\]\s*$#');
41}
42
43if (!defined('_TAXONOMIE_ITIS_CACHE_TIMEOUT')) {
44        /**
45         * Période de renouvellement du cache de Wikipedia (365 jours)
46         */
47        define('_TAXONOMIE_ITIS_CACHE_TIMEOUT', 86400 * 30 * 6);
48}
49
50
51$GLOBALS['itis_language'] = array(
52        /**
53         * Variable globale de configuration de la correspondance entre langue ITIS
54         * et code de langue SPIP. La langue du service est l'index, le code SPIP est la valeur.
55         */
56        'afrikaans'  => 'af',
57        'arabic'     => 'ar',
58        'chinese'    => 'zh',
59        'dutch'      => 'nl',
60        'english'    => 'en',
61        'fijan'      => 'fj',
62        'french'     => 'fr',
63        'german'     => 'de',
64        'greek'      => 'el',
65        'hausa'      => 'ha',
66        'hindi'      => 'hi',
67        'icelandic'  => 'is',
68        'japanese'   => 'ja',
69        'korean'     => 'ko',
70        'italian'    => 'it',
71        'malagasy'   => 'mg',
72        'portuguese' => 'pt',
73        'spanish'    => 'es',
74);
75
76$GLOBALS['itis_webservice'] = array(
77        /**
78         * Variable globale de configuration de l'api des actions du service web ITIS
79         */
80        'search'     => array(
81                'commonname'     => array(
82                        'function' => 'searchByCommonName',
83                        'argument' => 'srchKey',
84                        'list'     => 'commonNames',
85                        'index'    => array(
86                                'tsn'        => 'tsn',
87                                'nom_commun' => 'commonName',
88                                'langage'    => 'language'
89                        ),
90                        'compare'  => 'commonName'
91                ),
92                'commonnamebegin' => array(
93                        'function' => 'searchByCommonNameBeginsWith',
94                        'argument' => 'srchKey',
95                        'list'     => 'commonNames',
96                        'index'    => array(
97                                'tsn'        => 'tsn',
98                                'nom_commun' => 'commonName',
99                                'langage'    => 'language'
100                        ),
101                        'compare'  => 'commonName'
102                ),
103                'commonnameend' => array(
104                        'function' => 'searchByCommonNameEndsWith',
105                        'argument' => 'srchKey',
106                        'list'     => 'commonNames',
107                        'index'    => array(
108                                'tsn'        => 'tsn',
109                                'nom_commun' => 'commonName',
110                                'langage'    => 'language'
111                        ),
112                        'compare'  => 'commonName'
113                ),
114                'scientificname' => array(
115                        'function' => 'searchByScientificName',
116                        'argument' => 'srchKey',
117                        'list'     => 'scientificNames',
118                        'index'    => array(
119                                'tsn'              => 'tsn',
120                                'nom_scientifique' => 'combinedName',
121                                'regne'            => 'kingdom'
122                        ),
123                        'compare'  => 'combinedName'
124                )
125        ),
126        'vernacular' => array(
127                'vernacularlanguage' => array(
128                        'function' => 'getTsnByVernacularLanguage',
129                        'argument' => 'language',
130                        'list'     => 'vernacularTsns',
131                        'index'    => array('tsn' => 'commonName')
132                )
133        ),
134        'getfull'    => array(
135                'record' => array(
136                        'function' => 'getFullRecordFromTSN',
137                        'argument' => 'tsn',
138                        'list'     => '',
139                        'index'    => array(
140                                'nom_scientifique'  => 'scientificName/combinedName',
141                                'rang_taxon'        => 'taxRank/rankName',
142                                'regne'             => 'kingdom/kingdomName',
143                                'tsn_parent'        => 'parentTSN/parentTsn',
144                                'auteur'            => 'taxonAuthor/authorship',
145                                'nom_commun'        => 'commonNameList/commonNames',
146                                'credibilite'       => 'credibilityRating/credRating',
147                                'usage_valide'      => 'usage/taxonUsageRating',
148                                'zone_geographique' => 'geographicDivisionList/geoDivisions'
149                        )
150                )
151        ),
152        'get'        => array(
153                'scientificname' => array(
154                        'function' => 'getScientificNameFromTSN',
155                        'argument' => 'tsn',
156                        'list'     => '',
157                        'type'     => 'string',
158                        'index'    => 'combinedName',
159                ),
160                'kingdomname'    => array(
161                        'function' => 'getKingdomNameFromTSN',
162                        'argument' => 'tsn',
163                        'list'     => '',
164                        'type'     => 'string',
165                        'index'    => 'kingdomName',
166                ),
167                'parent'         => array(
168                        'function' => 'getHierarchyUpFromTSN',
169                        'argument' => 'tsn',
170                        'list'     => '',
171                        'type'     => 'string',
172                        'index'    => 'parentTsn',
173                ),
174                'rankname'       => array(
175                        'function' => 'getTaxonomicRankNameFromTSN',
176                        'argument' => 'tsn',
177                        'list'     => '',
178                        'type'     => 'string',
179                        'index'    => 'rankName',
180                ),
181                'author'         => array(
182                        'function' => 'getTaxonAuthorshipFromTSN',
183                        'argument' => 'tsn',
184                        'list'     => '',
185                        'type'     => 'string',
186                        'index'    => 'authorship',
187                ),
188                'coremetadata'   => array(
189                        'function' => 'getCoreMetadataFromTSN',
190                        'argument' => 'tsn',
191                        'list'     => '',
192                        'type'     => 'array',
193                        'index'    => array(''),
194                ),
195                'experts'        => array(
196                        'function' => 'getExpertsFromTSN',
197                        'argument' => 'tsn',
198                        'list'     => 'experts',
199                        'type'     => 'array',
200                        'index'    => array(''),
201                ),
202                'commonnames'    => array(
203                        'function' => 'getCommonNamesFromTSN',
204                        'argument' => 'tsn',
205                        'list'     => 'commonNames',
206                        'type'     => 'array',
207                        'index'    => array(
208                                'langue'     => 'language',
209                                'nom_commun' => 'commonName',
210                        ),
211                ),
212                'othersources'   => array(
213                        'function' => 'getOtherSourcesFromTSN',
214                        'argument' => 'tsn',
215                        'list'     => 'otherSources',
216                        'type'     => 'array',
217                        'index'    => array(''),
218                ),
219                'hierarchyfull'  => array(
220                        'function' => 'getFullHierarchyFromTSN',
221                        'argument' => 'tsn',
222                        'list'     => 'hierarchyList',
223                        'type'     => 'array',
224                        'index'    => array(
225                                'rang_taxon'       => 'rankName',
226                                'tsn'              => 'tsn',
227                                'nom_scientifique' => 'taxonName',
228                                'tsn_parent'       => 'parentTsn',
229                        ),
230                ),
231                'hierarchydown'  => array(
232                        'function' => 'getHierarchyDownFromTSN',
233                        'argument' => 'tsn',
234                        'list'     => 'hierarchyList',
235                        'type'     => 'array',
236                        'index'    => array(''),
237                ),
238                'hierarchyup'  => array(
239                        'function' => 'getHierarchyUpFromTSN',
240                        'argument' => 'tsn',
241                        'list'     => '',
242                        'type'     => 'array',
243                        'index'    => array(''),
244                ),
245        ),
246);
247
248
249// -----------------------------------------------------------------------
250// ------------ API du web service ITIS - Actions principales ------------
251// -----------------------------------------------------------------------
252
253/**
254 * Recherche un taxon dans la base ITIS par son nom commun ou scientifique
255 * et retourne son identifiant unique nommé TSN ou 0 si le taxon n'existe pas.
256 * Selon le critère de correspondance de la recherche (stricte ou pas) la fonction
257 * retourne un ou plusieurs taxons.
258 *
259 * @api
260 * @uses itis_build_url()
261 * @uses inc_taxonomie_requeter_dist()
262 *
263 * @param string $action
264 *        Recherche par nom commun ou par nom scientifique. Prend les valeurs `commonname`, `scientificname`
265 *        ou `commonnamebegin`.
266 * @param string $search
267 *        Nom à rechercher précisément. Seul le taxon dont le nom coincidera exactement sera retourné.
268 * @param bool   $strict
269 *        `true` indique une correspondance stricte de la chaine recherchée ce qui a pour conséquence de renvoyer
270 *        une seule valeur de TSN. `false` indique une correspondance partielle et peut donc renvoyer plusieurs TSN.
271 *
272 * @return array
273 *        Si la recherche est stricte, la fonction retourne l'identifiant unique TSN dans la base ITIS
274 *        ou 0 si la recherche échoue.
275 *        Sinon, la fonction retourne une liste de couples de valeurs (TNS, valeur trouvée).
276 */
277function itis_search_tsn($action, $search, $strict = true) {
278
279        $tsns = array();
280
281        // Normaliser la recherche: trim et mise en lettres minuscules
282        $search = strtolower(trim($search));
283
284        // Construire l'URL de la fonction de recherche
285        $url = itis_build_url('json', 'search', $action, rawurlencode($search));
286
287        // Acquisition des données spécifiées par l'url
288        $requeter = charger_fonction('taxonomie_requeter', 'inc');
289        $data = $requeter($url);
290
291        // Récupération du TSN du taxon recherché
292        $api = $GLOBALS['itis_webservice']['search'][$action];
293        if (!empty($data[$api['list']])) {
294                // La recherche peut renvoyer plusieurs taxons. Suivant le critère de correspondance de la recherche
295                // on renvoie le "bon" taxon ou tous les taxons trouvés.
296                foreach ($data[$api['list']] as $_data) {
297                        if ($_data) {
298                                if (($action == 'commonnamebegin')
299                                or !$strict
300                                or ($strict and (strcasecmp($_data[$api['compare']], $search) === 0))) {
301                                        $tsn = array();
302                                        foreach ($api['index'] as $_key => $_destination) {
303                                                if ($_key == 'langage') {
304                                                        $tsn[$_key] = $GLOBALS['itis_language'][strtolower($_data[$_destination])];
305                                                } elseif ($_key == 'tsn') {
306                                                        $tsn[$_key] = intval($_data[$_destination]);
307                                                } else {
308                                                        $tsn[$_key] = $_data[$_destination];
309                                                }
310                                        }
311                                        $tsns[] = $tsn;
312                                        if ($strict) {
313                                                break;
314                                        }
315                                }
316                        }
317                }
318        }
319
320        return $tsns;
321}
322
323
324/**
325 * Renvoie l'ensemble des informations sur un taxon désigné par son identifiant unique TSN.
326 *
327 * @api
328 *
329 * @uses cache_est_valide()
330 * @uses itis_build_url()
331 * @uses inc_taxonomie_requeter_dist()
332 * @uses cache_ecrire()
333 * @uses cache_lire()
334 *
335 * @param int $tsn
336 *        Identifiant unique du taxon dans la base ITIS, le TSN
337 *
338 * @return array
339 *        Si le taxon est trouvé, le tableau renvoyé possède les index associatifs suivants:
340 *        - `nom_scientifique`  : le nom scientifique complet du taxon tel qu'il doit être affiché (avec capitales).
341 *        - `rang`              : le nom anglais du rang taxonomique du taxon
342 *        - `regne`             : le nom scientifique du règne du taxon en minuscules
343 *        - `tsn_parent`        : le TSN du parent du taxon ou 0 si le taxon est un règne
344 *        - `auteur`            : la citation d’auteurs et la date de publication
345 *        - `nom_commun`        : un tableau indexé par langue (au sens d'ITIS en minuscules, `english`, `french`,
346 *                                `spanish`...) fournissant le nom commun dans chacune des langues
347 *        - `credibilite`       : Information sur la crédibilité des informations du taxon
348 *        - `usage_valide`      : Indication sur la validité de l'utilisation du taxon
349 *        - `zone_geographique` : un tableau indexé par langue unique `english` des zones géographiques où le taxon
350 *                                est localisé. Les zones sont libellées en anglais.
351 */
352function itis_get_record($tsn) {
353
354        $record = array();
355
356        if (intval($tsn)) {
357                // Construction des options permettant de nommer le fichier cache.
358                // -- inutile de préciser la durée de conservation car on utilise la valeur par défaut à savoir 6 mois.
359                include_spip('inc/cache');
360                $cache = array(
361                        'service'  => 'itis',
362                        'action'   => 'record',
363                        'tsn'      => $tsn
364                );
365
366                if ((!$file_cache = cache_est_valide('taxonomie', $cache))
367                or (defined('_TAXONOMIE_CACHE_FORCER') ? _TAXONOMIE_CACHE_FORCER : false)) {
368                        // Construire l'URL de l'api sollicitée
369                        $url = itis_build_url('json', 'getfull', 'record', strval($tsn));
370
371                        // Acquisition des données spécifiées par l'url
372                        $requeter = charger_fonction('taxonomie_requeter', 'inc');
373                        $data = $requeter($url);
374
375                        // Récupération des informations choisies parmi l'enregistrement reçu à partir de la configuration
376                        // de l'action.
377                        $api = $GLOBALS['itis_webservice']['getfull']['record'];
378                        include_spip('inc/filtres');
379                        $data = $api['list'] ? table_valeur($data, $api['list'], null) : $data;
380                        if (!empty($data)) {
381                                foreach ($api['index'] as $_destination => $_keys) {
382                                        $element = $_keys ? table_valeur($data, $_keys, null) : $data;
383                                        $record[$_destination] = is_string($element) ? trim($element) : $element;
384                                }
385                        }
386
387                        // Insérer de base le tsn.
388                        $record['tsn'] = intval($tsn);
389
390                        // Passer en minuscules le rang et le règne exprimé en anglais.
391                        $record['rang_taxon'] = strtolower($record['rang_taxon']);
392                        $record['regne'] = strtolower($record['regne']);
393
394                        // On réorganise le sous-tableau des noms communs
395                        $names = array();
396                        if (!empty($record['nom_commun']) and is_array($record['nom_commun'])) {
397                                foreach ($record['nom_commun'] as $_name) {
398                                        if (!empty($_name) and isset($GLOBALS['itis_language'][strtolower($_name['language'])])) {
399                                                $langue_spip = $GLOBALS['itis_language'][strtolower($_name['language'])];
400                                                $names[$langue_spip] = trim($_name['commonName']);
401                                        }
402                                }
403                        }
404                        // Et on modifie l'index des noms communs avec le tableau venant d'être construit.
405                        $record['nom_commun'] = $names;
406
407                        // L'indicateur d'usage est mis à true/false.
408                        $record['usage_valide'] = ($record['usage_valide'] == 'valid') or ($record['usage_valide'] == 'accepted');
409
410                        // On réorganise le sous-tableau des zones géographiques.
411                        $zones = array();
412                        if (!empty($record['zone_geographique']) and is_array($record['zone_geographique'])) {
413                                foreach ($record['zone_geographique'] as $_zone) {
414                                        $zones[] = trim($_zone['geographicValue']);
415                                }
416                        }
417                        // Et on modifie l'index des zones géographiques avec le tableau venant d'être construit
418                        // en positionnant celles-ci sous un idne 'english' car les zones sont libellées en anglais.
419                        unset($record['zone_geographique']);
420                        $record['zone_geographique'][$GLOBALS['itis_language']['english']] = $zones;
421
422                        // Mise en cache systématique pour gérer le cas où la page cherchée n'existe pas.
423                        cache_ecrire('taxonomie', $cache, $record);
424                } else {
425                        // Lecture et désérialisation du cache
426                        $record = cache_lire('taxonomie', $file_cache);
427                }
428        }
429
430        return $record;
431}
432
433
434/**
435 * Renvoie les informations demandées sur un taxon désigné par son identifiant unique TSN.
436 *
437 * @api
438 *
439 * @uses cache_est_valide()
440 * @uses itis_build_url()
441 * @uses inc_taxonomie_requeter_dist()
442 * @uses cache_ecrire()
443 * @uses cache_lire()
444 *
445 * @param string $action
446 *        Type d'information demandé. Prend les valeurs
447 *        - `scientificname` : le nom scientifique du taxon
448 *        - `kingdomname`    : le règne du taxon
449 *        - `parent`         : le taxon parent dont son TSN
450 *        - `rankname`       : le rang taxonomique du taxon
451 *        - `author`         : le ou les auteurs du taxon
452 *        - `coremetadata`   : les métadonnées (à vérifier)
453 *        - `experts`        : les experts du taxon
454 *        - `commonnames`    : le ou les noms communs
455 *        - `othersources`   : les sources d'information sur le taxon
456 *        - `hierarchyfull`  : la hiérarchie complète jusqu'au taxon et ses descendants directs
457 *        - `hierarchyup`    : la hiérarchie limitée au parent direct
458 * @param int    $tsn
459 *        Identifiant unique du taxon dans la base ITIS (TSN)
460 *
461 * @return string|int|array
462 *        Chaine ou tableau caractéristique du type d'information demandé.
463 */
464function itis_get_information($action, $tsn) {
465
466        $information = array();
467
468        if (intval($tsn)) {
469                // Construction des options permettant de nommer le fichier cache.
470                // -- inutile de préciser la durée de conservation car on utilise la valeur par défaut à savoir 6 mois.
471                include_spip('inc/cache');
472                $cache = array(
473                        'service'  => 'itis',
474                        'action'   => $action,
475                        'tsn'      => $tsn
476                );
477
478                if ((!$file_cache = cache_est_valide('taxonomie', $cache))
479                or (defined('_TAXONOMIE_CACHE_FORCER') ? _TAXONOMIE_CACHE_FORCER : false)) {
480                        // Construire l'URL de l'api sollicitée
481                        $url = itis_build_url('json', 'get', $action, strval($tsn));
482
483                        // Acquisition des données spécifiées par l'url
484                        $requeter = charger_fonction('taxonomie_requeter', 'inc');
485                        $data = $requeter($url);
486
487                        // On vérifie que le tableau est complet sinon on retourne un tableau vide
488                        $api = $GLOBALS['itis_webservice']['get'][$action];
489                        include_spip('inc/filtres');
490                        $data = $api['list'] ? table_valeur($data, $api['list'], null) : $data;
491                        $type = $api['type'];
492                        $index = $api['index'];
493
494                        // TODO : problème si l'information est une chaine
495                        if ($type == 'string') {
496                                // L'information est limitée à une chaine ou un entier unique.
497                                // On renvoie la valeur seule.
498                                $information = '';
499                                if (!empty($data[$index])) {
500                                        $information = $data[$index];
501                                        if (in_array($action, array('rankname', 'kingdomname'))) {
502                                                $information = strtolower($information);
503                                        } elseif ($action == 'parent') {
504                                                $information = intval($information);
505                                        }
506                                }
507                        } else {
508                                // L'information demandée est un tableau.
509                                $information = array();
510                                if (!empty($data)) {
511                                        // On vérifie si une fonction de post-formatage existe
512                                        $format = "itis_format_$action";
513                                        if (!function_exists($format)) {
514                                                $format = '';
515                                        }
516                                        foreach ($data as $_data) {
517                                                $item = array();
518                                                // On construit le tableau de l'item brut correspondant à la configuration de l'action
519                                                foreach ($index as $_key_information => $_key_data) {
520                                                        $item[$_key_information] = $_data[$_key_data];
521                                                }
522                                                // Si un formatage existe on formate l'item avant de l'ajouter au tableau de sortie.
523                                                $information[] = $format ? $format($item) : $item;
524                                        }
525                                }
526                        }
527
528                        // Mise en cache systématique pour gérer le cas où la page cherchée n'existe pas.
529                        cache_ecrire('taxonomie', $cache, $information);
530                } else {
531                        // Lecture et désérialisation du cache
532                        $information = cache_lire('taxonomie', $file_cache);
533                }
534        }
535
536        return $information;
537}
538
539
540/**
541 * Renvoie la liste des noms communs définis pour certains taxons dans une langue donnée mais
542 * tout règne confondu.
543 * Peu de taxons sont traduits dans la base ITIS, seules le français, l'anglais et
544 * l'espagnol sont réellement utilisables.
545 * Pour l'anglais, le nombre de taxons est très important car les 4 règnes non supportés par
546 * le plugin Taxonomie sont fortement traduits.
547 *
548 * @api
549 * @uses itis_build_url()
550 * @uses inc_taxonomie_requeter_dist()
551 *
552 * @param $language
553 *        Langue au sens d'ITIS écrite en minuscules. Vaut `french`, `english`, `spanish`...
554 *
555 * @return array
556 *        Tableau des noms communs associés à leur TSN. Le format du tableau est le suivant:
557 *        - l'index représente le TSN du taxon,
558 *        - la valeur fournit le tableau des noms communs, chaque nom étant préfixé du code de langue
559 *        de SPIP (ex: `[fr]bactéries`)
560 */
561function itis_list_vernaculars($language) {
562
563        $vernaculars = array();
564
565        // Construire l'URL de l'api sollicitée
566        $url = itis_build_url('json', 'vernacular', 'vernacularlanguage', $language);
567
568        // Acquisition des données spécifiées par l'url
569        include_spip('inc/distant');
570        $requeter = charger_fonction('taxonomie_requeter', 'inc');
571        $data = $requeter($url, _INC_DISTANT_MAX_SIZE * 7);
572
573        $api = $GLOBALS['itis_webservice']['vernacular']['vernacularlanguage'];
574        if (!empty($data[$api['list']])) {
575                $tag_language = '[' . $GLOBALS['itis_language'][$language] . ']';
576                $destination = reset($api['index']);
577                $key = key($api['index']);
578                foreach ($data[$api['list']] as $_data) {
579                        if (!empty($_data[$destination])
580                                and !empty($_data[$key])
581                        ) {
582                                $vernaculars[$_data[$key]][] = $tag_language . $_data[$destination];
583                        }
584                }
585        }
586
587        return $vernaculars;
588}
589
590
591// -----------------------------------------------------------------------------------------------
592// ------------ API du web service ITIS - Fonctions de lecture des fichiers de taxons ------------
593// -----------------------------------------------------------------------------------------------
594
595/**
596 * Lit le fichier hiérarchique ITIS des taxons d'un règne et renvoie la liste des taxons retenus.
597 *
598 * @api
599 *
600 * @param string $kingdom
601 *        Nom scientifique du règne en lettres minuscules : `animalia`, `plantae`, `fungi`.
602 * @param array  $ranks_hierarchy
603 *        Liste des rangs disponibles pour le règne concerné structurée comme une hiérarchie du règne aux rangs
604 *        inférieurs. Cette liste contient tous les rangs principaux, secondaires et intercalaires.
605 *        Le tableau est de la forme [nom anglais du rang en minuscules] = détails du rang
606 * @param string $sha_file
607 *        Sha calculé à partir du fichier de taxons correspondant au règne choisi. Le sha est retourné
608 *        par la fonction afin d'être stocké par le plugin.
609 *
610 * @return array
611 *        Chaque élément du tableau est un taxon. Un taxon est un tableau associatif dont chaque
612 *        index correspond à un champ de la table `spip_taxons`. Le tableau est ainsi prêt pour une
613 *        insertion en base de données.
614 */
615function itis_read_hierarchy($kingdom, $ranks_hierarchy, &$sha_file) {
616
617        $hierarchy = array();
618        $sha_file = false;
619
620        if ($ranks_hierarchy) {
621                // Extraire de la liste les rangs du règne au genre, seuls rangs disponibles dans le fichier ITIS.
622                include_spip('inc/taxonomie');
623                $id_genre = $ranks_hierarchy[_TAXONOMIE_RANG_GENRE]['id'];
624                foreach ($ranks_hierarchy as $_rang => $_description) {
625                        if ($_description['id'] <= $id_genre) {
626                                $ranks[$_rang] = $_description['id'];
627                        }
628                }
629
630                // Classer la liste des rangs de manière à aller du règne au genre.
631                asort($ranks);
632
633                // Construire la regexp à partir de la liste des rangs maintenant connue.
634                $rank_list = implode('|', array_map('ucfirst', array_keys($ranks)));
635                $regexp = str_replace('%rank_list%', $rank_list, _TAXONOMIE_ITIS_REGEXP_RANKNAME);
636
637                $file = find_in_path("services/itis/${kingdom}_genus.txt");
638                if (file_exists($file) and ($sha_file = sha1_file($file))) {
639                        $lines = file($file);
640                        if ($lines) {
641                                $parents = array();
642                                $rank_position = 0;
643                                foreach ($ranks as $_rank_name => $_rank_id) {
644                                        $parents[$_rank_id] = 0;
645                                        $rank_position++;
646                                        $ranks[$_rank_name] = $rank_position;
647                                }
648                                $max_rank_position = $rank_position;
649                                // Scan du fichier ligne par ligne
650                                include_spip('inc/charsets');
651                                foreach ($lines as $_line) {
652                                        $taxon = array(
653                                                'regne'       => $kingdom,
654                                                'nom_commun'  => '',
655                                                'descriptif'  => '',
656                                                'indicateurs' => '',
657                                                'edite'       => 'non',
658                                                'importe'     => 'oui',
659                                                'espece'      => 'non',
660                                                'statut'      => 'publie',
661                                        );
662                                        if (preg_match($regexp, $_line, $match)) {
663                                                // Initialisation du taxon
664                                                // -- rang et nom scientifique en minuscules
665                                                $taxon['rang_taxon'] = strtolower($match[1]);
666                                                $taxon['nom_scientifique'] = $match[2];
667                                                // -- Importer le nom de l'auteur qui est en ISO-8859-1 dans le charset du site
668                                                $taxon['auteur'] = trim(importer_charset(trim($match[4]), 'iso-8859-1'), '[]');
669                                                $tsn = intval($match[5]);
670                                                $taxon['tsn'] = $tsn;
671
672                                                // Vérifier si il existe un indicateur spécial dans le nom scientifique comme
673                                                // un X pour indiquer un taxon hybride.
674                                                if (strtolower(trim($match[3])) == 'x') {
675                                                        $taxon['indicateurs'] = 'hybride';
676                                                }
677
678                                                // Recherche du parent
679                                                $taxon_rank_position = $ranks[$taxon['rang_taxon']];
680                                                if ($taxon_rank_position == $ranks[_TAXONOMIE_RANG_REGNE]) {
681                                                        // On traite à part le cas du règne qui ne se rencontre qu'une fois en début de fichier
682                                                        $taxon['tsn_parent'] = 0;
683                                                } else {
684                                                        // On recherche le premier parent donc la position n'est pas 0.
685                                                        for ($i = $taxon_rank_position - 1; $i >= 1; $i--) {
686                                                                if ($parents[$i]) {
687                                                                        $taxon['tsn_parent'] = $parents[$i];
688                                                                        break;
689                                                                }
690                                                        }
691                                                }
692
693                                                // Insertion du taxon dans la hiérarchie
694                                                $hierarchy[$tsn] = $taxon;
695
696                                                // Stockage du TSN du rang venant d'être inséré
697                                                $parents[$taxon_rank_position] = $tsn;
698                                                // On vide les position de rangs d'après
699                                                for ($i = $taxon_rank_position + 1; $i <= $max_rank_position; $i++) {
700                                                        $parents[$i] = 0;
701                                                }
702                                        } else {
703                                                // On trace la ligne qui n'est pas détectée comme une ligne de taxon.
704                                                spip_log("Ligne non phrasée: ${_line}", 'taxonomie');
705                                        }
706                                }
707                        }
708                }
709        }
710
711        return $hierarchy;
712}
713
714
715/**
716 * Lit le fichier des noms communs - tout règne confondu - d'une langue donnée et renvoie un tableau
717 * de tous ces noms indexés par leur TSN.
718 * La base de données ITIS contient souvent plusieurs traductions d'une même langue pour un taxon donné. Cette
719 * fonction met à jour séquentiellement les traductions sans s'en préoccuper. De fait, c'est la dernière traduction
720 * rencontrée qui sera fournie dans le tableau de sortie.
721 *
722 * @api
723 *
724 * @param string $language
725 *        Langue au sens d'ITIS écrite en minuscules. Vaut `french`, `english`, `spanish` etc.
726 * @param string $sha_file
727 *        Sha calculé à partir du fichier des noms communs choisi. Le sha est retourné
728 *        par la fonction afin d'être stocké par le plugin.
729 *
730 * @return array
731 *        Tableau des noms communs d'une langue donnée indexé par TSN. Le nom commun est préfixé
732 *        par le tag de langue SPIP pour être utilisé simplement dans une balise `<multi>`.
733 */
734function itis_read_vernaculars($language, &$sha_file) {
735
736        $vernaculars = array();
737        $sha_file = false;
738
739        // Ouvrir le fichier de nom communs correspondant au code de langue spécifié
740        $file = find_in_path("services/itis/vernaculars_${language}.csv");
741        if (file_exists($file) and ($sha_file = sha1_file($file))) {
742                // Lecture du fichier csv comme un fichier texte sachant que :
743                // - le délimiteur de colonne est une virgule
744                // - le caractère d'encadrement d'un texte est le double-quotes
745                $lines = file($file);
746                if ($lines) {
747                        // Créer le tableau de sortie à partir du tableau issu du csv (TSN, nom commun)
748                        $tag_language = '[' . $GLOBALS['itis_language'][$language] . ']';
749                        foreach ($lines as $_line) {
750                                list($tsn, $name) = explode(',', trim($_line));
751                                $vernaculars[intval($tsn)] = $tag_language . trim($name, '"');
752                        }
753                }
754        }
755
756        return $vernaculars;
757}
758
759
760/**
761 * Lit le fichier des rangs d'un règne donné et construit la hiérarchie de ces mêmes rangs.
762 *
763 * @api
764 *
765 * @param string $kingdom
766 *        Nom scientifique du règne en lettres minuscules : `animalia`, `plantae`, `fungi`.
767 * @param string $sha_file
768 *        Sha calculé à partir du fichier de taxons correspondant au règne choisi. Le sha est retourné
769 *        par la fonction afin d'être stocké par le plugin.
770 *
771 * @return array
772 *        Tableau des rangs identifiés par leur nom scientifique en anglais et organisé comme une hiérarchie
773 *        du règne au rang de plus bas niveau.
774 */
775function itis_read_ranks($kingdom, &$sha_file) {
776
777        $ranks = array();
778        $sha_file = false;
779
780        // Ouvrir le fichier des rangs du règne spécifié.
781        $file = find_in_path("services/itis/${kingdom}_ranks.json");
782        if (file_exists($file) and ($sha_file = sha1_file($file))) {
783                // Lecture du fichier json et décodage en tableau.
784                include_spip('inc/flock');
785                lire_fichier($file, $content);
786                if ($content) {
787                        $itis_ranks = json_decode($content, true);
788                        if ($itis_ranks) {
789                                // Le fichier est toujours classé du règne au rang fils le plus bas dans l'arborescence.
790                                // On peut donc être assuré que le parent d'un rang donné a toujours été préalablement
791                                // traité sauf le premier, le règne.
792                                include_spip('inc/taxonomie');
793                                $rank_ids = array();
794                                foreach ($itis_ranks as $_rank) {
795                                        $rank_name = strtolower($_rank['rank_name']);
796                                        // -- Sauvegarde de l'id qui servira lors de la lecture du fichier hiérarchique des taxons.
797                                        $ranks[$rank_name]['id'] = $_rank['rank_id'];
798                                        // -- Détermination des parents
799                                        if (isset($rank_ids[$_rank['dir_parent_rank_id']]) and isset($rank_ids[$_rank['req_parent_rank_id']])) {
800                                                // Cas des rangs enfant du règne.
801                                                $ranks[$rank_name]['parent'] = $rank_ids[$_rank['dir_parent_rank_id']];
802                                                $ranks[$rank_name]['parent_principal'] = $rank_ids[$_rank['req_parent_rank_id']];
803                                        } else {
804                                                // Cas du règne qui n'a pas de parent.
805                                                $ranks[$rank_name]['parent'] = '';
806                                                $ranks[$rank_name]['parent_principal'] = '';
807                                        }
808                                        // -- Détermination du type de rang
809                                        $ranks[$rank_name]['type'] = rang_informer_type($rank_name);
810
811                                        // -- Sauvegarde de l'id ITIS du rang traité pour les descendants.
812                                        $rank_ids[$_rank['rank_id']] = $rank_name;
813                                }
814                        }
815                }
816        }
817
818        return $ranks;
819}
820
821
822// ---------------------------------------------------------------------
823// ------------ API du web service ITIS - Fonctions annexes ------------
824// ---------------------------------------------------------------------
825
826/**
827 * Renvoie la langue telle que le service ITIS la désigne à partir du code de langue
828 * de SPIP.
829 *
830 * @api
831 *
832 * @param string $spip_language
833 *        Code de langue de SPIP. Prend les valeurs `fr`, `en`, `es`, etc.
834 *        La variable globale `$GLOBALS['itis_language']` définit le transcodage langue ITIS vers code SPIP.
835 *
836 * @return string
837 *      Langue au sens d'ITIS en minuscules - `french`, `english`, `spanish` - ou chaine vide sinon.
838 */
839function itis_find_language($spip_language) {
840
841        if (!$language = array_search($spip_language, $GLOBALS['itis_language'])) {
842                $language = '';
843        }
844
845        return $language;
846}
847
848
849/**
850 * Construit la phrase de crédits précisant que les données fournies proviennent de la base de données
851 * d'ITIS.
852 *
853 * @api
854 *
855 * @param int   $id_taxon
856 *        Id du taxon nécessaire pour construire l'url de la page ITIS fournissant une information complète sur
857 *        le taxon.
858 * @param array $informations
859 *        Tableau des informations complémentaires sur la source. Pour ITIS ce tableau est vide.
860 *
861 * @return string
862 *        Phrase de crédit.
863 */
864function itis_credit($id_taxon, $informations = array()) {
865
866        // On recherche le TSN du taxon afin de construire l'url vers sa page sur ITIS
867        $taxon = sql_fetsel('tsn, nom_scientifique', 'spip_taxons', 'id_taxon=' . sql_quote($id_taxon));
868
869        // On crée l'url du taxon sur le site ITIS
870        $url_taxon = _TAXONOMIE_ITIS_TAXON_BASE_URL . $taxon['tsn'];
871        $link_taxon = '<a class="nom_scientifique_inline" href="' . $url_taxon . '" rel="noreferrer">' . ucfirst($taxon['nom_scientifique']) . '</a>';
872        $link_site = '<a href="' . _TAXONOMIE_ITIS_SITE_URL . '" rel="noreferrer">' . _TAXONOMIE_ITIS_SITE_URL . '</a>';
873
874        // On établit la citation
875        $credit = _T('taxonomie:credit_itis', array_merge(array('url_site' => $link_site, 'url_taxon' => $link_taxon), $informations));
876
877        return $credit;
878}
879
880
881/**
882 * Calcule le sha de chaque fichier ITIS fournissant des données, à savoir, ceux des règnes et ceux des noms
883 * communs par langue.
884 *
885 * @api
886 *
887 * @return array
888 *    Tableau à deux index principaux:
889 *        - `taxons`        : tableau associatif indexé par règne
890 *        - `traductions`    : tableau associatif par code de langue SPIP
891 */
892function itis_review_sha() {
893
894        $shas = array();
895
896        include_spip('inc/taxonomie');
897        $kingdoms = regne_lister_defaut();
898
899        foreach ($kingdoms as $_kingdom) {
900                $file = find_in_path('services/itis/' . ucfirst($_kingdom) . '_Genus.txt');
901                if (file_exists($file) and ($sha_file = sha1_file($file))) {
902                        $shas['taxons'][$_kingdom] = $sha_file;
903                }
904        }
905
906        foreach (array_keys($GLOBALS['itis_language']) as $_language) {
907                $file = find_in_path("services/itis/vernaculars_${_language}.csv");
908                if (file_exists($file) and ($sha_file = sha1_file($file))) {
909                        $shas['traductions'][$GLOBALS['itis_language'][$_language]] = $sha_file;
910                }
911        }
912
913        return $shas;
914}
915
916
917// ----------------------------------------------------------------
918// ---------- Fonctions internes de formatage des sorties ---------
919// ----------------------------------------------------------------
920
921/**
922 * Formatage d'un item de la liste des ascendants d'un taxon.
923 *
924 * @internal
925 *
926 * @param array $item
927 *        Tableau extrait du service get et représentant un taxon ascendant. Les valeurs sont insérées btutes.
928 *
929 * @return array
930 *        Tableau dont les valeurs ont été formatées (rang taxonomique en minuscules).
931 */
932function itis_format_hierarchyfull($item) {
933
934        // Le formatage d'un item de la hiérarchie consiste uniquement à passer en minuscule l'identifiant du rang.
935        if (isset($item['rang_taxon'])) {
936                $item['rang_taxon'] = strtolower($item['rang_taxon']);
937        }
938
939        return $item;
940}
941
942
943// ----------------------------------------------------------------
944// ------------ Fonctions internes utilisées par l'API ------------
945// ----------------------------------------------------------------
946
947/**
948 * Construit l'URL de la requête ITIS correspondant à la demande utilisateur.
949 *
950 * @internal
951 *
952 * @param string $format
953 *        Format du résultat de la requête. Prend les valeurs `json` ou `xml`. Le `json` est recommandé.
954 * @param string $group
955 *        Groupe d'actions du même type. Prend les valeurs:
956 *        - `search`        : groupe des actions de recherche du TSN à partir du nom commun ou scientifique
957 *        - `vernacular`    : groupe de l'action fournissant les noms communs d'une langue donnée
958 *        - `getfull`        : groupe de l'action fournissant l'ensemble des informations d'un taxon
959 *        - `get`            : groupe des actions fournissant une information précise sur un taxon
960 * @param string $action
961 *        Nom de l'action du service ITIS. Les valeurs dépendent du groupe. Par exemple, pour le groupe
962 *        `search` les actions sont `commonname` et `scientificname`.
963 * @param string $key
964 *        Clé de recherche qui dépend de l'action demandée. Ce peut être le nom scientifique, le TSN, etc.
965 *        Cette clé doit être encodée si besoin par l'appelant.
966 *
967 * @return string
968 *        L'URL de la requête au service
969 */
970function itis_build_url($format, $group, $action, $key) {
971
972        // Construire l'URL de l'api sollicitée
973        $url = _TAXONOMIE_ITIS_ENDPOINT_BASE_URL
974                   . ($format == 'json' ? 'jsonservice/' : 'services/ITISService/')
975                   . $GLOBALS['itis_webservice'][$group][$action]['function'] . '?'
976                   . $GLOBALS['itis_webservice'][$group][$action]['argument'] . '=' . $key;
977
978        return $url;
979}
Note: See TracBrowser for help on using the repository browser.