source: spip-zone/_plugins_/zotspip/trunk/inc/zotspip.php @ 59619

Last change on this file since 59619 was 59619, checked in by joseph@…, 8 years ago

être plus précis dans les log

File size: 15.2 KB
Line 
1<?php
2
3if (!defined("_ECRIRE_INC_VERSION")) return;
4
5// Générer une URL pour la read API de Zotero
6function zotero_url($params) {
7        include_spip('inc/config');
8        if (strpos($params,'?'))
9                return 'https://api.zotero.org/'.lire_config('zotspip/type_librairie').'s/'.lire_config('zotspip/id_librairie').'/'.$params.'&key='.lire_config('zotspip/api_key');
10        else
11                return 'https://api.zotero.org/'.lire_config('zotspip/type_librairie').'s/'.lire_config('zotspip/id_librairie').'/'.$params.'?key='.lire_config('zotspip/api_key');
12}
13
14
15// Accéder à l'API Zotero
16function zotero_get($params) {
17        include_spip('inc/distant');
18        $url = zotero_url($params);
19        $ret = recuperer_page($url);
20        if ($ret)
21                spip_log("$url chargé avec succès.",'zotspip');
22        else {
23                spip_log("ECHEC chargement de la page $url. Voir prive_spip.log pour le code HTTP renvoyé.",'zotspip');
24                spip_log("ECHEC chargement de la page $url.");
25        }
26        return $ret;
27}
28
29// Extraire l'identifiant d'un item à partir de l'URL
30function zotspip_extraire_itemkey($url){
31        if (preg_match('#items/(.*)\?#',$url,$matches))
32                return $matches[1];
33        else
34                return '';
35}
36
37// Mise à jour de la base de données
38// $forcer : forcer la mise à jour complète de la base
39// $n integer : nombre d'items à mettre à jour simultanément (max 50)
40function zotspip_maj_items($forcer=false, $n=50) {
41        if ($n>50) $n=50;
42       
43        if ($forcer)
44                $zotspip_maj_items = array('forcer' => true, 'start' => 0);
45        else
46                $zotspip_maj_items = isset($GLOBALS['meta']['zotspip_maj_items']) ? unserialize($GLOBALS['meta']['zotspip_maj_items']) : array('forcer' => false, 'start' => 0);
47       
48        $feed = zotero_get('items/?format=atom&order=dateModified&sort=desc&content=json,csljson&limit='.$n.'&start='.$zotspip_maj_items['start']);
49        // On vérifie qu'on a bien eu un retour
50        if (!$feed)
51                return 0;
52       
53        // On parse le flux ATOM reçu
54        include_spip('inc/xml');
55        $xml = spip_xml_parse($feed, false);
56       
57        if (spip_xml_match_nodes(',^entry,', $xml, $entrees)){
58                include_spip('base/abstract_sql');
59                foreach ($entrees['entry'] as $entree) {
60                        $id_zitem = spip_xml_aplatit($entree['zapi:key']);
61                        $updated = spip_xml_aplatit($entree['updated']);
62                       
63                        // Faire une vérification sur la date de maj (seulement si on ne force pas)
64                        if (!$zotspip_maj_items['forcer']) {
65                                if (strtotime($updated)==strtotime(sql_getfetsel('maj','spip_zitems','id_zitem='.sql_quote($id_zitem)))) {
66                                        effacer_meta('zotspip_maj_items');
67                                        return 1;
68                                }
69                        }
70                       
71                        // On initialise la ligne SQL à insérer
72                        $insertion = array(
73                                'id_zitem' => $id_zitem,
74                                'id_parent' => '0', // 0 si pas de parent
75                                'annee' => isset($entree['zapi:year']) ? spip_xml_aplatit($entree['zapi:year']) : NULL,
76                                'titre' => '',
77                                'auteurs' => '',
78                                'resume' => '',
79                                'date' => '',
80                                'pages' => '',
81                                'publication' => '',
82                                'editeur' => '',
83                                'type' => '',
84                                'volume' => '',
85                                'numero' => '',
86                                'doi' => '',
87                                'isbn' => '',
88                                'issn' => '',
89                                'url' => '',
90                                'extras' => '',
91                                'mimetype' => '',
92                                'poids' => 0,
93                                'fichier' => '',
94                                'json' => '',
95                                'csljson' => '',
96                                'maj' => $updated
97                        );
98                       
99                        // On récupère le parent et/ou le lien du fichier
100                        $links = array(); // NB : il faut réinitialiser $links sinon les résultats s'accumulent
101                        if (spip_xml_match_nodes(',^link,', $entree, $links)) {
102                                foreach (array_keys($links) as $link){
103                                        list($balise, $attributs) = spip_xml_decompose_tag($link);
104                                        if ($attributs['rel'] == 'enclosure') {
105                                                $insertion['fichier'] = $attributs['href'];
106                                                $insertion['poids'] = $attributs['length'];
107                                        }
108                                        if ($attributs['rel'] == 'up')
109                                                $insertion['id_parent'] = zotspip_extraire_itemkey($attributs['href']);
110                                }
111                        }
112                       
113                        // Récupération du code json et de csljson
114                        $subcontents = array();
115                        if (spip_xml_match_nodes(',^zapi:subcontent,', $entree['content type="application/xml"'][0], $subcontents)) {
116                                foreach ($subcontents as $cle_subcontent => $subcontent){
117                                        list($balise, $attributs) = spip_xml_decompose_tag($cle_subcontent);
118                                        if ($attributs['zapi:type']=='json')
119                                                $insertion['json'] = spip_xml_aplatit($subcontent);
120                                        if ($attributs['zapi:type']=='csljson')
121                                                $insertion['csljson'] = spip_xml_aplatit($subcontent);
122                                }
123                        }
124                        $data = json_decode($insertion['json'],true);
125                       
126                        // Gestion des champs (NB : on stocke une quantité plus limitée des champs, juste à des fins de tri)
127                        $correspondances = array(
128                                'abstractNote' => 'resume',
129                                'billNumber' => 'numero',
130                                'blogTitle' => 'publication',
131                                'bookTitle' => 'publication',
132                                'caseName' => 'titre',
133                                'codePages' => 'pages',
134                                'company' => 'editeur',
135                                'date' => 'date',
136                                'dateDecided' => 'date',
137                                'dateEnacted' => 'date',
138                                'dictionaryTitle' => 'publication',
139                                'distributor' => 'editeur',
140                                'docketNumber' => 'numero',
141                                'documentNumber' => 'numero',
142                                'DOI' => 'doi',
143                                'encyclopaediaTitle' => 'publication',
144                                'episodeNumber' => 'numero',
145                                'extras' => 'extras',
146                                'firstPage' => 'pages',
147                                'forumTitle' => 'publication',
148                                'genre' => 'type_doc',
149                                'institution' => 'editeur',
150                                'interviewMedium' => 'publication',
151                                'ISBN' => 'isbn',
152                                'ISSN' => 'issn',
153                                'issue' => 'numero',
154                                'issueDate' => 'date',
155                                'itemType' => 'type',
156                                'label' => 'editeur',
157                                'letterType' => 'type_doc',
158                                'manuscriptType' => 'type_doc',
159                                'mapType' => 'type_doc',
160                                'meetingName' => 'publication',
161                                'mimeType' => 'mimetype',
162                                'nameOfAct' => 'titre',
163                                'network' => 'editeur',
164                                'note' => 'resume',
165                                'numPages' => 'pages',
166                                'pages' => 'pages',
167                                'patentNumber' => 'numero',
168                                'postType' => 'type_doc',
169                                'presentationType' => 'type_doc',
170                                'proceedingsTitle' => 'publication',
171                                'conferenceName' => 'conference',
172                                'programTitle' => 'titre',
173                                'publicationTitle' => 'publication',
174                                'publicLawNumber' => 'numero',
175                                'publisher' => 'editeur',
176                                'reportNumber' => 'numero',
177                                'reportType' => 'type_doc',
178                                'series' => 'collection',
179                                'seriesNumber' => 'numero',
180                                'seriesTitle' => 'collection',
181                                'studio' => 'editeur',
182                                'subject' => 'titre',
183                                'thesisType' => 'type_doc',
184                                'title' => 'titre',
185                                'university' => 'editeur',
186                                'url' => 'url',
187                                'version' => 'numero',
188                                'volume' => 'volume'
189                        );
190                        foreach ($correspondances as $zot => $spip)
191                                if (isset($data[$zot]))
192                                        $insertion[$spip] = $data[$zot];
193                       
194                        // Gestion des creators
195                        $creators = array();
196                        if (is_array($data['creators'])) {
197                                foreach($data['creators'] as $creator) {
198                                        $creators[] = array(
199                                                'auteur' => isset($creator['name']) ? $creator['name'] : ($creator['lastName'] . ($creator['firstName'] ? (', '.$creator['firstName']) : '')),
200                                                'id_zitem' => $id_zitem,
201                                                'role' => $creator['creatorType']
202                                        );
203                                        if ($insertion['auteurs'] == '')
204                                                $insertion['auteurs'] .= isset($creator['name']) ? $creator['name'] : ($creator['lastName'] . ($creator['firstName'] ? (' '.$creator['firstName']) : ''));
205                                        else
206                                                $insertion['auteurs'] .= isset($creator['name']) ? (', '.$creator['name']) : (', '.$creator['lastName'] . ($creator['firstName'] ? (' '.$creator['firstName']) : ''));
207                                }
208                        }
209                       
210                        // Gestion des tags
211                        $tags = array();
212                        if (is_array($data['tags'])) {
213                                foreach ($data['tags'] as $tag)
214                                        $tags[] = array(
215                                                'tag' => $tag['tag'],
216                                                'id_zitem' => $id_zitem
217                                        );
218                        }
219                       
220                        // Insertion en base de données
221                        sql_replace('spip_zitems',$insertion);
222                        sql_delete('spip_zcreators','id_zitem='.sql_quote($id_zitem));
223                        if (count($creators)) sql_insertq_multi('spip_zcreators',$creators);
224                        sql_delete('spip_ztags','id_zitem='.sql_quote($id_zitem));
225                        if (count($tags)) sql_insertq_multi('spip_ztags',$tags);
226                       
227                }
228        }
229       
230        // Faut-il continuer la synchronisation ?
231        $links = array();
232        if (spip_xml_match_nodes(',^link rel="next",', $xml, $links)) {
233                $link_next = array_keys($links);
234                list($balise, $attributs) = spip_xml_decompose_tag($link_next[0]);
235                if (preg_match('#start=([0-9]+)#',$attributs['href'],$matches)) {
236                        if ($matches[1]>$zotspip_maj_items['start']) {
237                                $zotspip_maj_items['start'] = $matches[1];
238                                ecrire_meta('zotspip_maj_items',serialize($zotspip_maj_items));
239                                ecrire_metas();
240                                return -5;
241                        }
242                }
243        }
244       
245        // Sinon, c'est qu'on a fini la synchronisation
246        effacer_meta('zotspip_maj_items');
247        return 1; //0 si rien à faire, 1 si effectuée, -5 si tâche pas finie
248}
249
250// Nettoyer la base de données
251function zotspip_nettoyer() {
252        // Suppression des items qui ne sont plus dans la base
253        $feed = zotero_get('items/?format=keys');
254        if ($feed) {
255                $items_zotero = explode("\n",trim($feed));
256                include_spip('base/abstract_sql');
257                $requete = sql_allfetsel('id_zitem','spip_zitems');
258                $items_spip = array();
259                foreach ($requete as $item)
260                        $items_spip[] = $item['id_zitem'];
261                $diff = array_diff($items_spip,$items_zotero);
262                foreach ($diff as $id_zitem)
263                        zotspip_supprimer_item($id_zitem);
264        }
265        return 1;
266}
267
268// Supprimer un item
269function zotspip_supprimer_item($id_zitem) {
270        include_spip('base/abstract_sql');
271        sql_delete('spip_zcreators','id_zitem='.sql_quote($id_zitem));
272        sql_delete('spip_tags','id_zitem='.sql_quote($id_zitem));
273        sql_delete('spip_zitems_zcollections','id_zitem='.sql_quote($id_zitem));
274        sql_delete('spip_zitems','id_zitem='.sql_quote($id_zitem));
275}
276
277// Télécharge le schéma de données Zotero
278function zotspip_maj_schema_zotero() {
279        include_spip('inc/distant');
280       
281        // Lire le cache du schéma de données
282        lire_fichier_securise(_DIR_TMP . 'schema_zotero.php', $schema);
283        $schema = @unserialize($schema);
284       
285        if (!$schema)
286                $schema = array(
287                        'itemTypes' => array(),
288                        'itemFields' => array(),
289                        'itemTypeFields' => array(),
290                        'creatorTypes' => array()
291                );
292       
293        // Si on n'a pas commencé la synchronisation
294        if (!isset($schema['sync'])) {
295                $itemTypes = recuperer_page("https://api.zotero.org/itemTypes");
296                if (!$itemTypes) {
297                        spip_log("ECHEC chargement de https://api.zotero.org/itemTypes. Voir prive_spip.log pour le code HTTP renvoyé.",'zotspip');
298                        spip_log("ECHEC chargement de https://api.zotero.org/itemTypes.");
299                        return 0;
300                } else
301                        spip_log("https://api.zotero.org/itemTypes chargé avec succès.",'zotspip');
302                $itemTypes = json_decode($itemTypes,true);
303                $schema['itemTypes'] = array();
304                foreach ($itemTypes as $itemType)
305                        $schema['itemTypes'][] = $itemType['itemType'];
306                $schema['sync'] = $schema['itemTypes'];
307                $itemFields = recuperer_page("https://api.zotero.org/itemFields");
308                if (!$itemFields) {
309                        spip_log("ECHEC chargement de https://api.zotero.org/itemFields. Voir prive_spip.log pour le code HTTP renvoyé.",'zotspip');
310                        spip_log("ECHEC chargement de https://api.zotero.org/itemFields");
311                        return 0;
312                } else
313                        spip_log("https://api.zotero.org/itemTypes chargé avec succès.",'zotspip');
314                $itemFields = json_decode($itemFields,true);
315                $schema['itemFields'] = array();
316                foreach ($itemFields as $itemField)
317                        $schema['itemFields'][] = $itemField['field'];
318        }
319       
320        // On synchronise par palier de 10
321        for ($i = 1; $i <= min(10,count($schema['sync'])); $i++) {
322                $type = $schema['sync'][0];
323                $itemTypeFields = recuperer_page("https://api.zotero.org/itemTypeFields?itemType=$type");
324                if (!$itemTypeFields) {
325                        spip_log("ECHEC chargement de https://api.zotero.org/itemTypeFields?itemType=$type. Voir prive_spip.log pour le code HTTP renvoyé.",'zotspip');
326                        spip_log("ECHEC chargement de https://api.zotero.org/itemTypeFields?itemType=$type");
327                        return 0;
328                } else
329                        spip_log("https://api.zotero.org/itemTypes chargé avec succès.",'zotspip');
330                $itemTypeFields = json_decode($itemTypeFields,true);
331                $schema['itemTypeFields'][$type] = array();
332                foreach ($itemTypeFields as $itemTypeField)
333                        $schema['itemTypeFields'][$type][] = $itemTypeField['field'];
334                $schema['creatorTypes'][$type] = array();
335                $creatorTypes = recuperer_page("https://api.zotero.org/itemTypeCreatorTypes?itemType=$type");
336                if (!$creatorTypes) {
337                        spip_log("ECHEC chargement de https://api.zotero.org/itemTypeCreatorTypes?itemType=$type. Voir prive_spip.log pour le code HTTP renvoyé.",'zotspip');
338                        spip_log("ECHEC chargement de https://api.zotero.org/itemTypeCreatorTypes?itemType=$type");
339                        return 0;
340                } else
341                        spip_log("https://api.zotero.org/itemTypes chargé avec succès.",'zotspip');
342                $creatorTypes = json_decode($creatorTypes,true);
343                foreach ($creatorTypes as $creatorType)
344                        $schema['creatorTypes'][$type][] = $creatorType['creatorType'];
345                unset($schema['sync'][0]);
346                $schema['sync'] = array_values($schema['sync']);
347        }
348       
349        if (!count($schema['sync']))
350                unset($schema['sync']);
351
352        // Sauver le schéma en cache
353        ecrire_fichier_securise(_DIR_TMP . 'schema_zotero.php', serialize($schema));
354       
355        if (isset($schema['sync']))
356                return -5; // Continuer la synchronisation
357        else
358                return 1;
359}
360
361// Renvoie le tableau des valeurs à transmettre pour un item Zotero
362function form_item_zotero_charger() {
363        $contexte = array('itemType' => '');
364        include_spip('zotspip_fonctions');
365        foreach (schema_zotero('itemFields') as $field)
366                if ($field=='date')
367                        $contexte['itemDate'] = '';
368                else
369                        $contexte[$field] = '';
370        $contexte['creatorType'] = array('author');
371        $contexte['firstName'] = array('');
372        $contexte['lastName'] = array('');
373        $contexte['tags'] = array('');
374       
375        return $contexte;
376}
377
378// Renvoie le json de l'item Zotero saisie
379function form_item_zotero_traiter() {
380        $itemType = _request('itemType');
381        if ($itemType !='') {
382                $zitem = array('itemType' => $itemType);
383               
384                $zitem['creators'] = array();
385                $creatorType = _request('creatorType');
386                $firstName = _request('firstName');
387                $lastName = _request('lastName');
388                foreach ($creatorType as $cle => $valeur)
389                        if ($lastName[$cle])
390                                $zitem['creators'][] = array(
391                                        'creatorType' => $creatorType[$cle],
392                                        'firstName' => $firstName[$cle],
393                                        'lastName' => $lastName[$cle]
394                                );
395               
396                include_spip('zotspip_fonctions');
397                $itemTypeFields = schema_zotero('itemTypeFields');
398                foreach ($itemTypeFields[$itemType] as $field)
399                        if ($field=='date')
400                                $zitem['date'] = _request('itemDate');
401                        else
402                                $zitem[$field] = _request($field);
403               
404                $zitem['tags'] = array();
405                $tags = _request('tags');
406                foreach ($tags as $tag)
407                        if ($tag)
408                                $zitem['tags'][] = array('tag' => $tag);
409               
410                return json_encode($zitem);
411        } else
412                return '';
413}
414
415// Poster un résultat vers l'API Zotero
416function zotero_poster($params_url,$datas,$methode='POST') {
417        include_spip('inc/distant');
418        $url = zotero_url($params_url);
419        // Préparer les données
420        list($type, $postdata) = prepare_donnees_post($datas, '');
421        $datas = $type . 'Content-Length: '.strlen($postdata)."\r\n\r\n".$postdata;
422        // ouvrir la connexion et envoyer la requete et ses en-tetes
423        list($f, $fopen) = init_http($methode, $url, false, '', $datas, _INC_DISTANT_VERSION_HTTP, '');
424        if (!$f) {
425                spip_log("ECHEC init_http $url");
426                spip_log("ECHEC init_http $url",'zotspip');
427                return false;
428        }
429        $headers = recuperer_entetes($f, '');
430        fclose($f);
431        $result = @file_get_contents($url);
432        spip_log("$methode sur $url => HTTP $headers",'zotspip');
433       
434        return array(
435                'headers' => $headers,
436                'result' => $result
437        );
438}
439
440
441?>
Note: See TracBrowser for help on using the repository browser.