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

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

Finalisation des 3 étapes du formulaire de création d'une espèce.
Il reste le traitement final à coder.
Mise au point des css pour gérer les nom scientifiques dans une balise inline ou pas.

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