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

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

Mise au point de la liste des langues dans ITIS

  • Property svn:eol-style set to native
File size: 33.2 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'              => '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'             => '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/taxonomie_cacher');
358                $options_cache = array();
359
360                if (!$file_cache = cache_taxonomie_existe('itis', 'record', $tsn, $options_cache)
361                or !filemtime($file_cache)
362                or (time() - filemtime($file_cache) > _TAXONOMIE_ITIS_CACHE_TIMEOUT)
363                or (_TAXONOMIE_CACHE_FORCER)) {
364                        // Construire l'URL de l'api sollicitée
365                        $url = itis_build_url('json', 'getfull', 'record', strval($tsn));
366
367                        // Acquisition des données spécifiées par l'url
368                        $requeter = charger_fonction('taxonomie_requeter', 'inc');
369                        $data = $requeter($url);
370
371                        // Récupération des informations choisies parmi l'enregistrement reçu à partir de la configuration
372                        // de l'action.
373                        $api = $GLOBALS['itis_webservice']['getfull']['record'];
374                        include_spip('inc/filtres');
375                        $data = $api['list'] ? table_valeur($data, $api['list'], null) : $data;
376                        if (!empty($data)) {
377                                foreach ($api['index'] as $_destination => $_keys) {
378                                        $element = $_keys ? table_valeur($data, $_keys, null) : $data;
379                                        $record[$_destination] = is_string($element) ? trim($element) : $element;
380                                }
381                        }
382
383                        // Insérer de base le tsn.
384                        $record['tsn'] = intval($tsn);
385
386                        // Passer en minuscules le rang et le règne exprimé en anglais.
387                        $record['rang'] = strtolower($record['rang']);
388                        $record['regne'] = strtolower($record['regne']);
389
390                        // On réorganise le sous-tableau des noms communs
391                        $names = array();
392                        if (!empty($record['nom_commun']) and is_array($record['nom_commun'])) {
393                                foreach ($record['nom_commun'] as $_name) {
394                                        if (!empty($_name) and isset($GLOBALS['itis_language'][strtolower($_name['language'])])) {
395                                                $langue_spip = $GLOBALS['itis_language'][strtolower($_name['language'])];
396                                                $names[$langue_spip] = trim($_name['commonName']);
397                                        }
398                                }
399                        }
400                        // Et on modifie l'index des noms communs avec le tableau venant d'être construit.
401                        $record['nom_commun'] = $names;
402
403                        // L'indicateur d'usage est mis à true/false.
404                        $record['usage_valide'] = ($record['usage_valide'] == 'valid') or ($record['usage_valide'] == 'accepted');
405
406                        // On réorganise le sous-tableau des zones géographiques.
407                        $zones = array();
408                        if (!empty($record['zone_geographique']) and is_array($record['zone_geographique'])) {
409                                foreach ($record['zone_geographique'] as $_zone) {
410                                        $zones[] = trim($_zone['geographicValue']);
411                                }
412                        }
413                        // Et on modifie l'index des zones géographiques avec le tableau venant d'être construit
414                        // en positionnant celles-ci sous un idne 'english' car les zones sont libellées en anglais.
415                        unset($record['zone_geographique']);
416                        $record['zone_geographique'][$GLOBALS['itis_language']['english']] = $zones;
417
418                        // Mise en cache systématique pour gérer le cas où la page cherchée n'existe pas.
419                        cache_taxonomie_ecrire(serialize($record), 'itis', 'record', $tsn, $options_cache);
420                } else {
421                        // Lecture et désérialisation du cache
422                        lire_fichier($file_cache, $contenu);
423                        $record = unserialize($contenu);
424                }
425        }
426
427        return $record;
428}
429
430
431/**
432 * Renvoie les informations demandées sur un taxon désigné par son identifiant unique TSN.
433 *
434 * @api
435 * @uses itis_build_url()
436 * @uses inc_taxonomie_requeter_dist()
437 *
438 * @param string $action
439 *        Type d'information demandé. Prend les valeurs
440 *        - `scientificname` : le nom scientifique du taxon
441 *        - `kingdomname`    : le règne du taxon
442 *        - `parent`         : le taxon parent dont son TSN
443 *        - `rankname`       : le rang taxonomique du taxon
444 *        - `author`         : le ou les auteurs du taxon
445 *        - `coremetadata`   : les métadonnées (à vérifier)
446 *        - `experts`        : les experts du taxon
447 *        - `commonnames`    : le ou les noms communs
448 *        - `othersources`   : les sources d'information sur le taxon
449 *        - `hierarchyfull`  : la hiérarchie complète jusqu'au taxon et ses descendants directs
450 *        - `hierarchyup`    : la hiérarchie limitée au parent direct
451 * @param int    $tsn
452 *        Identifiant unique du taxon dans la base ITIS (TSN)
453 *
454 * @return string|int|array
455 *        Chaine ou tableau caractéristique du type d'information demandé.
456 */
457function itis_get_information($action, $tsn) {
458
459        include_spip('inc/taxonomie_cacher');
460        $options_cache = array();
461
462        if (!$file_cache = cache_taxonomie_existe('itis', $action, $tsn, $options_cache)
463        or !filemtime($file_cache)
464        or (time() - filemtime($file_cache) > _TAXONOMIE_ITIS_CACHE_TIMEOUT)
465        or (_TAXONOMIE_CACHE_FORCER)) {
466                // Construire l'URL de l'api sollicitée
467                $url = itis_build_url('json', 'get', $action, strval($tsn));
468
469                // Acquisition des données spécifiées par l'url
470                $requeter = charger_fonction('taxonomie_requeter', 'inc');
471                $data = $requeter($url);
472
473                // On vérifie que le tableau est complet sinon on retourne un tableau vide
474                $api = $GLOBALS['itis_webservice']['get'][$action];
475                include_spip('inc/filtres');
476                $data = $api['list'] ? table_valeur($data, $api['list'], null) : $data;
477                $type = $api['type'];
478                $index = $api['index'];
479
480                if ($type == 'string') {
481                        // L'information est limitée à une chaine ou un entier unique.
482                        // On renvoie la valeur seule.
483                        $information = '';
484                        if (!empty($data[$index])) {
485                                $information = $data[$index];
486                                if (in_array($action, array('rankname', 'kingdomname'))) {
487                                        $information = strtolower($information);
488                                } elseif ($action == 'parent') {
489                                        $information = intval($information);
490                                }
491                        }
492                } else {
493                        // L'information demandée est un tableau.
494                        $information = array();
495                        if (!empty($data)) {
496                                $format = "itis_format_$action";
497                                if (function_exists($format)) {
498                                        $information = $format($tsn, $data, $index);
499                                } else {
500                                        foreach ($data as $_data) {
501                                                $item = array();
502                                                foreach ($index as $_key_information => $_key_data) {
503                                                        $item[$_key_information] = $_data[$_key_data];
504                                                }
505                                                $information[] = $item;
506                                        }
507                                }
508                        }
509                }
510
511                // Mise en cache systématique pour gérer le cas où la page cherchée n'existe pas.
512                cache_taxonomie_ecrire(serialize($information), 'itis', $action, $tsn, $options_cache);
513        } else {
514                // Lecture et désérialisation du cache
515                lire_fichier($file_cache, $contenu);
516                $information = unserialize($contenu);
517        }
518
519        return $information;
520}
521
522
523/**
524 * Renvoie la liste des noms communs définis pour certains taxons dans une langue donnée mais
525 * tout règne confondu.
526 * Peu de taxons sont traduits dans la base ITIS, seules le français, l'anglais et
527 * l'espagnol sont réellement utilisables.
528 * Pour l'anglais, le nombre de taxons est très important car les 4 règnes non supportés par
529 * le plugin Taxonomie sont fortement traduits.
530 *
531 * @api
532 * @uses itis_build_url()
533 * @uses inc_taxonomie_requeter_dist()
534 *
535 * @param $language
536 *        Langue au sens d'ITIS écrite en minuscules. Vaut `french`, `english`, `spanish`...
537 *
538 * @return array
539 *        Tableau des noms communs associés à leur TSN. Le format du tableau est le suivant:
540 *        - l'index représente le TSN du taxon,
541 *        - la valeur fournit le tableau des noms communs, chaque nom étant préfixé du code de langue
542 *        de SPIP (ex: `[fr]bactéries`)
543 */
544function itis_list_vernaculars($language) {
545
546        $vernaculars = array();
547
548        // Construire l'URL de l'api sollicitée
549        $url = itis_build_url('json', 'vernacular', 'vernacularlanguage', $language);
550
551        // Acquisition des données spécifiées par l'url
552        include_spip('inc/distant');
553        $requeter = charger_fonction('taxonomie_requeter', 'inc');
554        $data = $requeter($url, _INC_DISTANT_MAX_SIZE * 7);
555
556        $api = $GLOBALS['itis_webservice']['vernacular']['vernacularlanguage'];
557        if (!empty($data[$api['list']])) {
558                $tag_language = '[' . $GLOBALS['itis_language'][$language] . ']';
559                $destination = reset($api['index']);
560                $key = key($api['index']);
561                foreach ($data[$api['list']] as $_data) {
562                        if (!empty($_data[$destination])
563                                and !empty($_data[$key])
564                        ) {
565                                $vernaculars[$_data[$destination]][] = $tag_language . $_data[$key];
566                        }
567                }
568        }
569
570        return $vernaculars;
571}
572
573
574// -----------------------------------------------------------------------------------------------
575// ------------ API du web service ITIS - Fonctions de lecture des fichiers de taxons ------------
576// -----------------------------------------------------------------------------------------------
577
578/**
579 * Lit le fichier hiérarchique ITIS des taxons d'un règne et renvoie la liste des taxons retenus.
580 *
581 * @api
582 *
583 * @param string $kingdom
584 *        Nom scientifique du règne en lettres minuscules : `animalia`, `plantae`, `fungi`.
585 * @param array  $ranks_hierarchy
586 *        Liste des rangs disponibles pour le règne concerné structurée comme une hiérarchie du règne aux rangs
587 *        inférieurs. Cette liste contient tous les rangs principaux, secondaires et intercalaires.
588 *        Le tableau est de la forme [nom anglais du rang en minuscules] = détails du rang
589 * @param int    $sha_file
590 *        Sha calculé à partir du fichier de taxons correspondant au règne choisi. Le sha est retourné
591 *        par la fonction afin d'être stocké par le plugin.
592 *
593 * @return array
594 *        Chaque élément du tableau est un taxon. Un taxon est un tableau associatif dont chaque
595 *        index correspond à un champ de la table `spip_taxons`. Le tableau est ainsi prêt pour une
596 *        insertion en base de données.
597 */
598function itis_read_hierarchy($kingdom, $ranks_hierarchy, &$sha_file) {
599
600        $hierarchy = array();
601        $sha_file = false;
602
603        if ($ranks_hierarchy) {
604                // Extraire de la liste les rangs du règne au genre, seuls rangs disponibles dans le fichier ITIS.
605                include_spip('inc/taxonomie');
606                $id_genre = $ranks_hierarchy[_TAXONOMIE_RANG_GENRE]['id'];
607                foreach ($ranks_hierarchy as $_rang => $_description) {
608                        if ($_description['id'] <= $id_genre) {
609                                $ranks[$_rang] = $_description['id'];
610                        }
611                }
612
613                // Classer la liste des rangs de manière à aller du règne au genre.
614                asort($ranks);
615
616                // Construire la regexp à partir de la liste des rangs maintenant connue.
617                $rank_list = implode('|', array_map('ucfirst', array_keys($ranks)));
618                $regexp = str_replace('%rank_list%', $rank_list, _TAXONOMIE_ITIS_REGEXP_RANKNAME);
619
620                $file = find_in_path("services/itis/${kingdom}_genus.txt");
621                if (file_exists($file) and ($sha_file = sha1_file($file))) {
622                        $lines = file($file);
623                        if ($lines) {
624                                $parents = array();
625                                $rank_position = 0;
626                                foreach ($ranks as $_rank_name => $_rank_id) {
627                                        $parents[$_rank_id] = 0;
628                                        $rank_position++;
629                                        $ranks[$_rank_name] = $rank_position;
630                                }
631                                $max_rank_position = $rank_position;
632                                // Scan du fichier ligne par ligne
633                                include_spip('inc/charsets');
634                                foreach ($lines as $_line) {
635                                        $taxon = array(
636                                                'regne'      => $kingdom,
637                                                'nom_commun' => '',
638                                                'descriptif' => '',
639                                                'indicateur' => '',
640                                                'edite'      => 'non'
641                                        );
642                                        if (preg_match($regexp, $_line, $match)) {
643                                                // Initialisation du taxon
644                                                // -- rang et nom scientifique en minuscules
645                                                $taxon['rang'] = strtolower($match[1]);
646                                                $taxon['nom_scientifique'] = $match[2];
647                                                // -- Importer le nom de l'auteur qui est en ISO-8859-1 dans le charset du site
648                                                $taxon['auteur'] = trim(importer_charset(trim($match[4]), 'iso-8859-1'), '[]');
649                                                $tsn = intval($match[5]);
650                                                $taxon['tsn'] = $tsn;
651
652                                                // Vérifier si il existe un indicateur spécial dans le nom scientifique comme
653                                                // un X pour indiquer un taxon hybride.
654                                                if (strtolower(trim($match[3])) == 'x') {
655                                                        $taxon['indicateur'] = 'hybride';
656                                                }
657
658                                                // Recherche du parent
659                                                $taxon_rank_position = $ranks[$taxon['rang']];
660                                                if ($taxon_rank_position == $ranks[_TAXONOMIE_RANG_REGNE]) {
661                                                        // On traite à part le cas du règne qui ne se rencontre qu'une fois en début de fichier
662                                                        $taxon['tsn_parent'] = 0;
663                                                } else {
664                                                        // On recherche le premier parent donc la position n'est pas 0.
665                                                        for ($i = $taxon_rank_position - 1; $i >= 1; $i--) {
666                                                                if ($parents[$i]) {
667                                                                        $taxon['tsn_parent'] = $parents[$i];
668                                                                        break;
669                                                                }
670                                                        }
671                                                }
672
673                                                // Insertion du taxon dans la hiérarchie
674                                                $hierarchy[$tsn] = $taxon;
675
676                                                // Stockage du TSN du rang venant d'être inséré
677                                                $parents[$taxon_rank_position] = $tsn;
678                                                // On vide les position de rangs d'après
679                                                for ($i = $taxon_rank_position + 1; $i <= $max_rank_position; $i++) {
680                                                        $parents[$i] = 0;
681                                                }
682                                        } else {
683                                                // On trace la ligne qui n'est pas détectée comme une ligne de taxon.
684                                                spip_log("Ligne non phrasée: ${_line}", 'taxonomie');
685                                        }
686                                }
687                        }
688                }
689        }
690
691        return $hierarchy;
692}
693
694
695/**
696 * Lit le fichier des noms communs - tout règne confondu - d'une langue donnée et renvoie un tableau
697 * de tous ces noms indexés par leur TSN.
698 * La base de données ITIS contient souvent plusieurs traductions d'une même langue pour un taxon donné. Cette
699 * fonction met à jour séquentiellement les traductions sans s'en préoccuper. De fait, c'est la dernière traduction
700 * rencontrée qui sera fournie dans le tableau de sortie.
701 *
702 * @api
703 *
704 * @param string $language
705 *        Langue au sens d'ITIS écrite en minuscules. Vaut `french`, `english`, `spanish` etc.
706 * @param int    $sha_file
707 *        Sha calculé à partir du fichier des noms communs choisi. Le sha est retourné
708 *        par la fonction afin d'être stocké par le plugin.
709 *
710 * @return array
711 *        Tableau des noms communs d'une langue donnée indexé par TSN. Le nom commun est préfixé
712 *        par le tag de langue SPIP pour être utilisé simplement dans une balise `<multi>`.
713 */
714function itis_read_vernaculars($language, &$sha_file) {
715
716        $vernaculars = array();
717        $sha_file = false;
718
719        // Ouvrir le fichier de nom communs correspondant au code de langue spécifié
720        $file = find_in_path("services/itis/vernaculars_${language}.csv");
721        if (file_exists($file) and ($sha_file = sha1_file($file))) {
722                // Lecture du fichier csv comme un fichier texte sachant que :
723                // - le délimiteur de colonne est une virgule
724                // - le caractère d'encadrement d'un texte est le double-quotes
725                $lines = file($file);
726                if ($lines) {
727                        // Créer le tableau de sortie à partir du tableau issu du csv (TSN, nom commun)
728                        $tag_language = '[' . $GLOBALS['itis_language'][$language] . ']';
729                        foreach ($lines as $_line) {
730                                list($tsn, $name) = explode(',', trim($_line));
731                                $vernaculars[intval($tsn)] = $tag_language . trim($name, '"');
732                        }
733                }
734        }
735
736        return $vernaculars;
737}
738
739
740/**
741 * Lit le fichier des rangs d'un règne donné et construit la hiérarchie de ces mêmes rangs.
742 *
743 * @api
744 *
745 * @param string $kingdom
746 *        Nom scientifique du règne en lettres minuscules : `animalia`, `plantae`, `fungi`.
747 * @param int    $sha_file
748 *        Sha calculé à partir du fichier de taxons correspondant au règne choisi. Le sha est retourné
749 *        par la fonction afin d'être stocké par le plugin.
750 *
751 * @return array
752 *        Tableau des rangs identifiés par leur nom scientifique en anglais et organisé comme une hiérarchie
753 *        du règne au rang de plus bas niveau.
754 */
755function itis_read_ranks($kingdom, &$sha_file) {
756
757        $ranks = array();
758        $sha_file = false;
759
760        // Ouvrir le fichier des rangs du règne spécifié.
761        $file = find_in_path("services/itis/${kingdom}_ranks.json");
762        if (file_exists($file) and ($sha_file = sha1_file($file))) {
763                // Lecture du fichier json et décodage en tableau.
764                include_spip('inc/flock');
765                lire_fichier($file, $content);
766                if ($content) {
767                        $itis_ranks = json_decode($content, true);
768                        if ($itis_ranks) {
769                                // Le fichier est toujours classé du règne au rang fils le plus bas dans l'arborescence.
770                                // On peut donc être assuré que le parent d'un rang donné a toujours été préalablement
771                                // traité sauf le premier, le règne.
772                                include_spip('inc/taxonomie');
773                                $rank_ids = array();
774                                foreach ($itis_ranks as $_rank) {
775                                        $rank_name = strtolower($_rank['rank_name']);
776                                        // -- Sauvegarde de l'id qui servira lors de la lecture du fichier hiérarchique des taxons.
777                                        $ranks[$rank_name]['id'] = $_rank['rank_id'];
778                                        // -- Détermination des parents
779                                        if (isset($rank_ids[$_rank['dir_parent_rank_id']]) and isset($rank_ids[$_rank['req_parent_rank_id']])) {
780                                                // Cas des rangs enfant du règne.
781                                                $ranks[$rank_name]['parent'] = $rank_ids[$_rank['dir_parent_rank_id']];
782                                                $ranks[$rank_name]['parent_principal'] = $rank_ids[$_rank['req_parent_rank_id']];
783                                        } else {
784                                                // Cas du règne qui n'a pas de parent.
785                                                $ranks[$rank_name]['parent'] = '';
786                                                $ranks[$rank_name]['parent_principal'] = '';
787                                        }
788                                        // -- Détermination du type de rang
789                                        $ranks[$rank_name]['type'] = rang_informer_type($rank_name);
790
791                                        // -- Sauvegarde de l'id ITIS du rang traité pour les descendants.
792                                        $rank_ids[$_rank['rank_id']] = $rank_name;
793                                }
794                        }
795                }
796        }
797
798        return $ranks;
799}
800
801
802// ---------------------------------------------------------------------
803// ------------ API du web service ITIS - Fonctions annexes ------------
804// ---------------------------------------------------------------------
805
806/**
807 * Renvoie la langue telle que le service ITIS la désigne à partir du code de langue
808 * de SPIP.
809 *
810 * @api
811 *
812 * @param string $spip_language
813 *        Code de langue de SPIP. Prend les valeurs `fr`, `en`, `es`, etc.
814 *        La variable globale `$GLOBALS['itis_language']` définit le transcodage langue ITIS vers code SPIP.
815 *
816 * @return string
817 *      Langue au sens d'ITIS en minuscules - `french`, `english`, `spanish` - ou chaine vide sinon.
818 */
819function itis_find_language($spip_language) {
820
821        if (!$language = array_search($spip_language, $GLOBALS['itis_language'])) {
822                $language = '';
823        }
824
825        return $language;
826}
827
828
829/**
830 * Construit la phrase de crédits précisant que les données fournies proviennent de la base de données
831 * d'ITIS.
832 *
833 * @api
834 *
835 * @param int   $id_taxon
836 *        Id du taxon nécessaire pour construire l'url de la page ITIS fournissant une information complète sur
837 *        le taxon.
838 * @param array $informations
839 *        Tableau des informations complémentaires sur la source. Pour ITIS ce tableau est vide.
840 *
841 * @return string
842 *        Phrase de crédit.
843 */
844function itis_credit($id_taxon, $informations = array()) {
845
846        // On recherche le TSN du taxon afin de construire l'url vers sa page sur ITIS
847        $taxon = sql_fetsel('tsn, nom_scientifique', 'spip_taxons', 'id_taxon=' . sql_quote($id_taxon));
848
849        // On crée l'url du taxon sur le site ITIS
850        $url_taxon = _TAXONOMIE_ITIS_TAXON_BASE_URL . $taxon['tsn'];
851        $link_taxon = '<a class="nom_scientifique_inline" href="' . $url_taxon . '" rel="noreferrer">' . ucfirst($taxon['nom_scientifique']) . '</a>';
852        $link_site = '<a href="' . _TAXONOMIE_ITIS_SITE_URL . '" rel="noreferrer">' . _TAXONOMIE_ITIS_SITE_URL . '</a>';
853
854        // On établit la citation
855        $credit = _T('taxonomie:credit_itis', array_merge(array('url_site' => $link_site, 'url_taxon' => $link_taxon), $informations));
856
857        return $credit;
858}
859
860
861/**
862 * Calcule le sha de chaque fichier ITIS fournissant des données, à savoir, ceux des règnes et ceux des noms
863 * communs par langue.
864 *
865 * @api
866 *
867 * @return array
868 *    Tableau à deux index principaux:
869 *        - `taxons`        : tableau associatif indexé par règne
870 *        - `traductions`    : tableau associatif par code de langue SPIP
871 */
872function itis_review_sha() {
873
874        $shas = array();
875
876        include_spip('inc/taxonomie');
877        $kingdoms = regne_lister();
878
879        foreach ($kingdoms as $_kingdom) {
880                $file = find_in_path('services/itis/' . ucfirst($_kingdom) . '_Genus.txt');
881                if (file_exists($file) and ($sha_file = sha1_file($file))) {
882                        $shas['taxons'][$_kingdom] = $sha_file;
883                }
884        }
885
886        foreach (array_keys($GLOBALS['itis_language']) as $_language) {
887                $file = find_in_path("services/itis/vernaculars_${_language}.csv");
888                if (file_exists($file) and ($sha_file = sha1_file($file))) {
889                        $shas['traductions'][$GLOBALS['itis_language'][$_language]] = $sha_file;
890                }
891        }
892
893        return $shas;
894}
895
896
897// ----------------------------------------------------------------
898// ------------ Fonctions internes utilisées par l'API ------------
899// ----------------------------------------------------------------
900
901/**
902 * Construit l'URL de la requête ITIS correspondant à la demande utilisateur.
903 *
904 * @internal
905 *
906 * @param string $format
907 *        Format du résultat de la requête. Prend les valeurs `json` ou `xml`. Le `json` est recommandé.
908 * @param string $group
909 *        Groupe d'actions du même type. Prend les valeurs:
910 *        - `search`        : groupe des actions de recherche du TSN à partir du nom commun ou scientifique
911 *        - `vernacular`    : groupe de l'action fournissant les noms communs d'une langue donnée
912 *        - `getfull`        : groupe de l'action fournissant l'ensemble des informations d'un taxon
913 *        - `get`            : groupe des actions fournissant une information précise sur un taxon
914 * @param string $action
915 *        Nom de l'action du service ITIS. Les valeurs dépendent du groupe. Par exemple, pour le groupe
916 *        `search` les actions sont `commonname` et `scientificname`.
917 * @param string $key
918 *        Clé de recherche qui dépend de l'action demandée. Ce peut être le nom scientifique, le TSN, etc.
919 *        Cette clé doit être encodée si besoin par l'appelant.
920 *
921 * @return string
922 *        L'URL de la requête au service
923 */
924function itis_build_url($format, $group, $action, $key) {
925
926        // Construire l'URL de l'api sollicitée
927        $url = _TAXONOMIE_ITIS_ENDPOINT_BASE_URL
928                   . ($format == 'json' ? 'jsonservice/' : 'services/ITISService/')
929                   . $GLOBALS['itis_webservice'][$group][$action]['function'] . '?'
930                   . $GLOBALS['itis_webservice'][$group][$action]['argument'] . '=' . $key;
931
932        return $url;
933}
934
935function itis_format_hierarchyfull($tsn, $data, $index) {
936
937        $information = array(
938                'ascendants' => array(),
939                'fils'       => array(),
940                'taxon'      => array()
941        );
942
943        if (!empty($data)) {
944                foreach ($data as $_data) {
945                        // On constitue le bloc du taxon.
946                        $taxon = array();
947                        foreach ($index as $_key_information => $_key_data) {
948                                if ($_key_information == 'rang') {
949                                        $taxon[$_key_information] = strtolower($_data[$_key_data]);
950                                } elseif (($_key_information == 'tsn') or ($_key_information == 'tsn_parent')) {
951                                        $taxon[$_key_information] = $_data[$_key_data] ? intval($_data[$_key_data]) : 0;
952                                } else {
953                                        $taxon[$_key_information] = $_data[$_key_data];
954                                }
955                        }
956
957                        // On affecte ce bloc soit dans la liste des parents, soit dans la liste des enfants, soit dans
958                        // l'index du taxon lui-même.
959                        if ($tsn == $taxon['tsn']) {
960                                $information['taxon'] = $taxon;
961                        } elseif ($tsn == $taxon['tsn_parent']) {
962                                $information['fils'][] = $taxon;
963                        } else {
964                                $information['ascendants'][] = $taxon;
965                        }
966                }
967        }
968
969        return $information;
970}
Note: See TracBrowser for help on using the repository browser.