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

Last change on this file since 113783 was 113783, checked in by root, 4 months ago

Mise au point des services de Taxonomie avec l'API des caches de Cache Factory.
A voir aussi comment gérer les get unitaires avec la sérialisation.
On change l'ordre des composants en mettant le tsn est premier pour un meilleur classement.

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