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

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

Intégration des fonctions de gestion du cache dans inc/taxonomer.
Utilisation de importer_charset sur le nom de l'auteur.

  • Property svn:eol-style set to native
File size: 19.4 KB
Line 
1<?php
2/**
3 * Ce fichier contient l'ensemble des constantes et functions implémentant le service de taxonomie ITIS.
4 *
5 * @package SPIP\TAXONOMIE\ITIS
6 */
7
8if (!defined("_ECRIRE_INC_VERSION")) return;
9
10if (!defined('_TAXONOMIE_ITIS_ENDPOINT_BASE_URL'))
11        /**
12         * Préfixe des URL du service web de ITIS.
13         * Le service fournit des données au format XML ou JSON
14         */
15        define('_TAXONOMIE_ITIS_ENDPOINT_BASE_URL', 'http://www.itis.gov/ITISWebService/');
16
17if (!defined('_TAXONOMIE_ITIS_TAXON_BASE_URL'))
18        /**
19         * URL à fournir dans la citation du service ITIS.
20         */
21        define('_TAXONOMIE_ITIS_TAXON_BASE_URL', 'http://www.itis.gov/servlet/SingleRpt/SingleRpt?search_topic=TSN&search_value=');
22
23if (!defined('_TAXONOMIE_ITIS_SITE_URL'))
24        /**
25         * URL à fournir dans la citation du service ITIS.
26         */
27        define('_TAXONOMIE_ITIS_SITE_URL', 'http://www.itis.gov');
28
29if (!defined('_TAXONOMIE_ITIS_REGEXP_RANKNAME'))
30        /**
31         * Ligne d'un fichier ITIS hiérachie généré.
32         * Il est indispensable de respecter les majuscules des noms de groupe pour éviter de matcher
33         * les suborder, infrakingdom...
34         */
35        define('_TAXONOMIE_ITIS_REGEXP_RANKNAME', '#(%groups_list%):\s*(\w+)\s*\[([^\]]*)\]\s*\[(\d+)\]#');
36
37
38/**
39 * Configuration de la correspondance entre langue Wikipedia et code de langue SPIP.
40 * La langue du service est l'index, le code SPIP est la valeur.
41 */
42$GLOBALS['itis_language'] = array(
43        'french' => 'fr',
44        'english' => 'en',
45        'spanish' => 'es'
46);
47/**
48 * Configuration de l'api des actions du service web ITIS
49 */
50$GLOBALS['itis_webservice'] = array(
51        'search' => array(
52                'commonname' => array(
53                        'function' => 'searchByCommonName',
54                        'argument' => 'srchKey',
55                        'list' => 'commonNames',
56                        'index' => 'commonName'
57                ),
58                'scientificname' => array(
59                        'function' => 'searchByScientificName',
60                        'argument' => 'srchKey',
61                        'list' => 'scientificNames',
62                        'index' => 'combinedName'
63                )
64        ),
65        'vernacular' => array(
66                'vernacularlanguage' => array(
67                        'function' => 'getTsnByVernacularLanguage',
68                        'argument' => 'language',
69                        'list' => 'ax23:vernacularTsns',
70                        'index' => 'commonName'
71                )
72        ),
73        'getfull' => array(
74                'record' => array(
75                        'function' => 'getFullRecordFromTSN',
76                        'argument' => 'tsn',
77                        'list' => 'ns:return',
78                        'index' => 'scientificName,taxRank,kingdom,commonNameList,taxonAuthor,parentTSN'
79                )
80        ),
81        'get' => array(
82                'scientificname' => array(
83                        'multiple' => false,
84                        'function' => 'getScientificNameFromTSN',
85                        'argument' => 'tsn',
86                        'index' => 'combinedName',
87                ),
88                'kingdomname' => array(
89                        'multiple' => false,
90                        'function' => 'getKingdomNameFromTSN',
91                        'argument' => 'tsn',
92                        'index' => 'kingdomName',
93                ),
94                'parent' => array(
95                        'multiple' => false,
96                        'function' => 'getHierarchyUpFromTSN',
97                        'argument' => 'tsn',
98                        'index' => 'parentTsn',
99                ),
100                'rankname' => array(
101                        'multiple' => false,
102                        'function' => 'getTaxonomicRankNameFromTSN',
103                        'argument' => 'tsn',
104                        'index' => 'rankName',
105                ),
106                'author' => array(
107                        'multiple' => false,
108                        'function' => 'getTaxonAuthorshipFromTSN',
109                        'argument' => 'tsn',
110                        'index' => 'authorship',
111                ),
112                'coremetadata' => array(
113                        'multiple' => false,
114                        'function' => 'getCoreMetadataFromTSN',
115                        'argument' => 'tsn',
116                        'index' => 'rankId',
117                ),
118                'experts' => array(
119                        'multiple' => true,
120                        'function' => 'getExpertsFromTSN',
121                        'argument' => 'tsn',
122                        'list' => 'experts',
123                ),
124                'commonnames' => array(
125                        'multiple' => true,
126                        'function' => 'getCommonNamesFromTSN',
127                        'argument' => 'tsn',
128                        'list' => 'commonNames',
129                ),
130                'othersources' => array(
131                        'multiple' => true,
132                        'function' => 'getOtherSourcesFromTSN',
133                        'argument' => 'tsn',
134                        'list' => 'otherSources',
135                ),
136                'hierarchyfull' => array(
137                        'multiple' => true,
138                        'function' => 'getFullHierarchyFromTSN',
139                        'argument' => 'tsn',
140                        'list' => 'hierarchyList',
141                ),
142                'hierarchydown' => array(
143                        'multiple' => true,
144                        'function' => 'getHierarchyDownFromTSN',
145                        'argument' => 'tsn',
146                        'list' => 'hierarchyList',
147                ),
148        ),
149);
150
151
152// -----------------------------------------------------------------------
153// ------------ API du web service ITIS - Actions principales ------------
154// -----------------------------------------------------------------------
155
156/**
157 * Recherche un taxon dans la base ITIS par son nom commun ou scientifique
158 * et retourne son identifiant unique nommé tsn ou 0 si le taxon n'existe pas.
159 *
160 * @api
161 *
162 * @param string        $api
163 *              Recherche par nom commun ou par nom scientifique. Prend les valeurs 'commonname' ou 'scientificname'
164 * @param string        $recherche
165 *              Nom à rechercher précisément. Seul le taxon dont le nom coincidera exactement sera retourné.
166 *
167 * @return int
168 *              Identifiant unique tsn dans la base ITIS ou 0 si la recherche échoue
169 */
170function itis_search_tsn($api, $recherche) {
171        global $itis_webservice;
172        $tsn = 0;
173
174        // Normaliser la recherche: trim et mise en lettres minuscules
175        $recherche = strtolower(trim($recherche));
176
177        // Construire l'URL de la fonction de recherche
178        $url = itis_api2url('json', 'search', $api, rawurlencode($recherche));
179
180        // Acquisition des données spécifiées par l'url
181        include_spip('inc/taxonomer');
182        $data = url2json_data($url);
183
184        // Récupération du TSN du taxon recherché
185        $api = $itis_webservice['search'][$api];
186        if (isset($data[$api['list']])
187        AND $data[$api['list']]) {
188                // La recherche peut renvoyer plusieurs taxons. On considère que le "bon" taxon
189                // correspond à celui dont le nom est exactement celui recherché.
190                foreach ($data[$api['list']] as $_data) {
191                        if ($_data
192                        AND (strcasecmp($_data[$api['index']], $recherche) == 0)) {
193                                // On est sur le bon taxon, on renvoie le TSN
194                                $tsn = intval($_data['tsn']);
195                                break;
196                        }
197                }
198        }
199
200        return $tsn;
201}
202
203
204/**
205 * Renvoie l'ensemble des informations sur un taxon désigné par son identifiant unique tsn.
206 *
207 * @api
208 *
209 * @param int   $tsn
210 *              Identifiant unique du taxon dans la base ITIS (tsn)
211 *
212 * @return array
213 *      Si le taxon est trouvé, le tableau renvoyé possède les index associatifs suivants:
214 *      - 'nom_scientique'  : le nom scientifique du taxon en minuscules
215 *      - 'rang'            : le nom anglais du rang taxonomique du taxon
216 *      - 'regne'           : le nom scientifque du règne du taxon en minuscules
217 *      - 'tsn_parent'      : le tsn du parent du taxon ou 0 si le taxon est un règne
218 *      - 'auteur'          : la citation d’auteurs et la date de publication
219 *      - 'nom_commun'      : un tableau indexé par langue (au sens d'ITIS, English, French...) fournissant le nom commun
220 *                            dans chacune des langues
221 */
222function itis_get_record($tsn) {
223        global $itis_webservice;
224        $output =array();
225
226        // Construire l'URL de l'api sollicitée
227        $url = itis_api2url('xml', 'getfull', 'record', strval($tsn));
228
229        // Acquisition des données spécifiées par l'url
230        $api = $itis_webservice['getfull']['record'];
231        include_spip('inc/distant');
232        $flux = recuperer_page($url);
233
234        if ($flux) {
235                // Suppression du préfixe ax21: des balises afin de récupérer des index associatifs non préfixés
236                $flux = str_replace('ax21:parentTsn', 'ax21:TsnParent', $flux );
237                $flux = str_replace('ax21:', '', $flux);
238                // Suppression des suffixes xsi:type="xxx" ou xsi:nil="xxx" pour avoir des index de tableau simples
239                $flux = preg_replace(';\sxsi:(type|nil)="\w*";i', '', $flux);
240
241                // Phrasage de la chaine XML obtenue
242                include_spip('inc/xml');
243                $arbre = spip_xml_parse($flux);
244                if (spip_xml_match_nodes(",^{$api['list']},", $arbre, $matches) > 0) {
245                        $record = reset($matches);
246                        // Il est compliqué de créer une configuration du service qui permette un traitement générique de chaque
247                        // information. Le code est donc spécifique à chaque information.
248                        // Le résultat est stocké dans un tableau dont chaque index est le nom du champ correspondant de spip_taxon.
249                        if (isset($record[0])) {
250                                $record = $record[0];
251                                // Nom scientifique, rang taxonomique, règne et TSN parent
252                                $output['nom_scientifique'] = (empty($record['scientificName'][0]['combinedName'][0])
253                                        ? ''
254                                        : strtolower($record['scientificName'][0]['combinedName'][0]));
255                                $output['rang'] = (empty($record['taxRank'][0]['rankName'][0])
256                                        ? ''
257                                        : strtolower($record['taxRank'][0]['rankName'][0]));
258                                $output['regne'] = (empty($record['kingdom'][0]['kingdomName'][0])
259                                        ? ''
260                                        : strtolower($record['kingdom'][0]['kingdomName'][0]));
261                                $output['tsn_parent'] = (empty($record['parentTSN'][0]['TsnParent'][0])
262                                        ? 0
263                                        : intval($record['parentTSN'][0]['TsnParent'][0]));
264                                // Auteur
265                                $output['auteur'] = '';
266                                if (!empty($record['taxonAuthor'])) {
267                                        foreach ($record['taxonAuthor'] as $_author) {
268                                                if (isset($_author['authorship'][0])) {
269                                                        $output['auteur'] = $output['auteur'] ? ', ' . $_author['authorship'][0] : $_author['authorship'][0];
270                                                }
271                                        }
272                                }
273                                // Noms communs dans différentes langues
274                                $output['nom_commun'] = '';
275                                if (!empty($record['commonNameList'][0]['commonNames'])) {
276                                        foreach ($record['commonNameList'][0]['commonNames'] as $_nom) {
277                                                if (isset($_nom['commonName'][0]) AND isset($_nom['language'][0])) {
278                                                        $output['nom_commun'][$_nom['language'][0]] = $_nom['commonName'][0];
279                                                }
280                                        }
281                                }
282                        }
283                }
284        }
285
286        return $output;
287}
288
289
290/**
291 * Renvoie les informations demandées sur un taxon désigné par son identifiant unique tsn.
292 *
293 * @api
294 *
295 * @param string        $api
296 *              Type d'information demandé. Prend les valeurs
297 *      - 'scientificname' : le nom scientifique du taxon
298 *      - 'kingdomname' : le règne du taxon
299 *      - 'parent' : le taxon parent dont son tsn
300 *      - 'rankname' : le rang taxonomique du taxon
301 *      - 'author' : le ou les auteurs du taxon
302 *      - 'coremetadata' : les métadonnées (à vérifier)
303 *              - 'experts' : les experts du taxon
304 *              - 'commonnames' : le ou les noms communs
305 *              - 'othersources' : les sources d'information sur le taxon
306 *              - 'hierarchyfull' : la hiérarchie complète jusqu'au taxon
307 *              - 'hierarchydown' : la hiérarchie (à vérifier)
308 * @param int           $tsn
309 *              Identifiant unique du taxon dans la base ITIS (tsn)
310 *
311 * @return array
312 *              Le tableau renvoyé est caractéristique du type d'information demandé.
313 */
314function itis_get_information($api, $tsn) {
315        global $itis_webservice;
316        $output =array();
317
318        // Construire l'URL de l'api sollicitée
319        $url = itis_api2url('json', 'get', $api, strval($tsn));
320
321        // Acquisition des données spécifiées par l'url
322        include_spip('inc/taxonomer');
323        $data = url2json_data($url);
324
325        // On vérifie que le tableau est complet sinon on retourne un tableau vide
326        $api = $itis_webservice['get'][$api];
327        if ($api['multiple']) {
328                if (isset($data[$api['list']][0])
329                AND $data[$api['list']][0]) {
330                        $output = $data[$api['list']];
331                }
332        }
333        else {
334                if (isset($data[$api['index']])
335                AND $data[$api['index']]) {
336                        $output = $data;
337                }
338        }
339
340        return $output;
341}
342
343
344/**
345 * Renvoie la liste des noms communs des taxons dans une langue donnée.
346 *
347 * @api
348 *
349 * @param $language
350 *
351 *
352 * @return array
353 *      Liste des langues vernaculaires exprimées en anglais.
354 */
355function itis_list_vernaculars($language) {
356        global $itis_webservice, $itis_language;
357        $vernaculars =array();
358
359        // Construire l'URL de l'api sollicitée
360        $url = itis_api2url('xml', 'vernacular', 'vernacularlanguage', $language);
361
362        // Acquisition des données spécifiées par l'url
363        $api = $itis_webservice['vernacular']['vernacularlanguage'];
364        include_spip('inc/distant');
365        $flux = recuperer_page($url);
366
367        // Suppression du préfixe ax21: des balises afin de récupérer des index associatif non préfixés
368        $flux = str_replace('ax21:', '', $flux);
369
370        // Phrasage de la chaine XML obtenue
371        include_spip('inc/xml');
372        $arbre = spip_xml_parse($flux);
373        if (spip_xml_match_nodes(",^{$api['list']},", $arbre, $matches) > 0) {
374                $names = reset($matches);
375                $tag_language = '[' . $itis_language[$language] . ']';
376                foreach ($names as $_name) {
377                        $vernaculars[$_name['tsn'][0]] .= $tag_language . $_name[$api['index']][0];
378                }
379        }
380
381        return $vernaculars;
382}
383
384
385// -----------------------------------------------------------------------------------------------
386// ------------ API du web service ITIS - Fonctions de lecture des fichiers de taxons ------------
387// -----------------------------------------------------------------------------------------------
388
389/**
390 * Lecture du fichier hiérarchique ITIS des taxons d'un règne.
391 *
392 * @api
393 *
394 * @param string        $kingdom
395 *              Nom scientifique du règne en lettres minuscules (animalia, plantae, fungi)
396 * @param string        $upto
397 *              Rang taxonomique minimal jusqu'où charger le règne. Ce rang est fourni en anglais et
398 *              correspond à : phylum (pour le règne animalia) ou division (pour les règnes fungi et plantae),
399 *              class, order, family, genus.
400 * @param int           $sha_file
401 *              Sha calculé à partir du fichier de taxons correspondant au règne choisi. Le sha est retourné
402 *              par la fonction afin d'être stocké par le plugin.
403 *
404 * @return array
405 */
406function itis_read_hierarchy($kingdom, $upto, &$sha_file) {
407        $hierarchy = array();
408        $sha_file = false;
409
410        include_spip('inc/taxonomer');
411        static $group_ids = array(
412                'kingdom' => 1,
413                'class' => 3,
414                'order' => 4,
415                'family' => 5,
416                'genus' => 6,
417                'specie' => 7);
418        $rang_phylum = $kingdom==_TAXONOMIE_REGNE_ANIMAL ? 'phylum': 'division';
419        $group_ids[$rang_phylum] = 2;
420        asort($group_ids);
421
422        if (array_key_exists($upto, $group_ids)) {
423                include_spip('inc/charsets');
424                // Construire la regexp qui permet de limiter la hiérarchie comme demandée
425                $groups_list = implode('|', array_map('ucfirst', array_slice(array_flip($group_ids), 0, $group_ids[$upto])));
426                $regexp = str_replace('%groups_list%', $groups_list, _TAXONOMIE_ITIS_REGEXP_RANKNAME);
427
428                $file = find_in_path('services/itis/' . ucfirst($kingdom) . '_Genus.txt');
429                if (file_exists($file)
430                AND ($sha_file = sha1_file($file))) {
431                        $lines = file($file);
432                        if ($lines) {
433                                $groups = array();
434                                for ($i=1;$i<=array_search($upto, $group_ids);$i++) {
435                                        $groups[$i] = 0;
436                                }
437                                // Scan du fichier ligne par ligne
438                                foreach ($lines as $_line) {
439                                        $taxon = array(
440                                                'regne' => $kingdom,
441                                                'nom_commun' => '',
442                                                'descriptif' => '',
443                                                'edite' => 'non');
444                                        if (preg_match($regexp, $_line, $match)) {
445                                                // Initialisation du taxon
446                                                $taxon['rang'] = strtolower($match[1]);
447                                                $taxon['nom_scientifique'] = strtolower($match[2]);
448                                                $taxon['auteur'] = importer_charset(trim($match[3]), 'iso-8859-1');
449                                                $tsn = intval($match[4]);
450                                                $taxon['tsn'] = $tsn;
451
452                                                // Recherche du parent
453                                                $taxon_group_id = $group_ids[$taxon['rang']];
454                                                if ($taxon_group_id == 1) {
455                                                        // On traite à part le cas du règne qui ne se rencontre qu'une fois en début de fichier
456                                                        $taxon['tsn_parent'] = 0;
457                                                }
458                                                else {
459                                                        for($i=$taxon_group_id-1;$i>=1;$i--) {
460                                                                if ($groups[$i]) {
461                                                                        $taxon['tsn_parent'] = $groups[$i];
462                                                                        break;
463                                                                }
464                                                        }
465                                                }
466
467                                                // Insertion du taxon dans la hiérarchie
468                                                $hierarchy[$tsn] = $taxon;
469
470                                                // Stockage du groupe venant d'être inséré
471                                                $groups[$taxon_group_id] = $tsn;
472                                                // On vide les groupes d'après
473                                                for($i=$taxon_group_id+1;$i<=5;$i++) {
474                                                        $groups[$i] = 0;
475                                                }
476                                        }
477                                }
478                        }
479                }
480        }
481
482        return $hierarchy;
483}
484
485
486/**
487 * Lit le fichier des noms communs (tout règne confondu) d'une langue donnée et renvoie un tableau
488 * de tous ces noms indexés par leur TSN.
489 *
490 * @api
491 *
492 * @param string        $language
493 * @param int           $sha_file
494 *
495 * @return array
496 */
497function itis_read_vernaculars($language, &$sha_file) {
498        global $itis_language;
499        $vernaculars =array();
500        $sha_file = false;
501
502        // Ouvrir le fichier de nom communs correspondant au code de langue spécifié
503        $file = find_in_path("services/itis/vernaculars_${language}.csv");
504        if (file_exists($file)
505        AND ($sha_file = sha1_file($file))) {
506                // Lecture du fichier csv comme un fichier texte sachant que :
507                // - le délimiteur de colonne est une virgule
508                // - le caractère d'encadrement d'un texte est le double-quotes
509                $lines = file($file);
510                if ($lines) {
511                        // Créer le tableau de sortie à partir du tableau issu du csv (tsn, nom commun)
512                        $tag_language = '[' . $itis_language[$language] . ']';
513                        foreach ($lines as $_line) {
514                                $name = explode(',', trim($_line));
515                                $vernaculars[intval($name[0])] = $tag_language . trim($name[1], '"');
516                        }
517                }
518        }
519
520        return $vernaculars;
521}
522
523
524// ---------------------------------------------------------------------
525// ------------ API du web service ITIS - Fonctions annexes ------------
526// ---------------------------------------------------------------------
527
528/**
529 * Renvoie la langue telle que le service ITIS la désigne à partir du code de langue
530 * de SPIP.
531 *
532 * @api
533 *
534 * @param string    $language_code
535 *      Code de langue de SPIP. La variable globale $itis_language définit le transcodage langue ITIS
536 *      vers code SPIP.
537 *
538 * @return string
539 *      Langue au sens d'ITIS ou chaine vide sinon.
540 */
541function itis_spipcode2language($language_code) {
542        global $itis_language;
543
544        if (!$language = array_search($language_code,  $itis_language)) {
545                $language = '';
546        }
547
548        return $language;
549}
550
551
552/**
553 * Construit la phrase de crédits précisant que les données fournies proviennent de la base de données
554 * d'ITIS.
555 *
556 * @api
557 *
558 * @param int   $id_taxon
559 *      Id du taxon nécessaire pour construire l'url de la page ITIS fournissant une information complète sur
560 *      le taxon.
561 *
562 * @return string
563 *      Phrase de crédit.
564 */
565function itis_credit($id_taxon) {
566        // On recherche le tsn du taxon afin de construire l'url vers sa page sur ITIS
567        $taxon = sql_fetsel('tsn, nom_scientifique', 'spip_taxons', 'id_taxon='. sql_quote($id_taxon));
568
569        // On crée l'url du taxon sur le site ITIS
570        $url_taxon = _TAXONOMIE_ITIS_TAXON_BASE_URL . $taxon['tsn'];
571        $link_taxon = '<a href="' . $url_taxon . '" rel="noreferrer"><em>' . ucfirst($taxon['nom_scientifique']) . '</em></a>';
572        $link_site = '<a href="' . _TAXONOMIE_ITIS_SITE_URL . '" rel="noreferrer">' . _TAXONOMIE_ITIS_SITE_URL . '</a>';
573
574        // On établit la citation
575        $credit = _T('taxonomie:credit_itis', array('url_site' => $link_site, 'url_taxon' => $link_taxon));
576
577        return $credit;
578}
579
580
581/**
582 * Calcule le sha de chaque fichier ITIS fournissant des données, à savoir, ceux des règnes et ceux des noms
583 * communs par langue.
584 *
585 * @api
586 *
587 * @return array
588 *      Tableau à deux index principaux:
589 *      - 'taxons'      : tableau associatif indexé par règne
590 *      - 'traductions' : tableau associatif par code de langue SPIP
591 */
592function itis_review_sha() {
593        global $itis_language;
594        $shas = array();
595
596        include_spip('inc/taxonomer');
597        $kingdoms = lister_regnes();
598
599        foreach ($kingdoms as $_kingdom) {
600                $file = find_in_path('services/itis/' . ucfirst($_kingdom) . '_Genus.txt');
601                if (file_exists($file)
602                AND ($sha_file = sha1_file($file))) {
603                        $shas['taxons'][$_kingdom] = $sha_file;
604                }
605        }
606
607        foreach (array_keys($itis_language) as $_language) {
608                $file = find_in_path("services/itis/vernaculars_${_language}.csv");
609                if (file_exists($file)
610                AND ($sha_file = sha1_file($file))) {
611                        $shas['traductions'][$itis_language[$_language]] = $sha_file;
612                }
613        }
614
615        return $shas;
616}
617
618
619// ----------------------------------------------------------------
620// ------------ Fonctions internes utilisées par l'API ------------
621// ----------------------------------------------------------------
622
623/**
624 * @param $format
625 * @param $area
626 * @param $api
627 * @param $key
628 *
629 * @return string
630 */
631function itis_api2url($format, $area, $api, $key) {
632        global $itis_webservice;
633
634        // Construire l'URL de l'api sollicitée
635        $url = _TAXONOMIE_ITIS_ENDPOINT_BASE_URL
636                 . ($format=='json' ? 'jsonservice/' : 'services/ITISService/')
637                 . $itis_webservice[$area][$api]['function'] . '?'
638                 . $itis_webservice[$area][$api]['argument'] . '=' . $key;
639
640        return $url;
641}
642?>
Note: See TracBrowser for help on using the repository browser.