1 | <?php |
---|
2 | |
---|
3 | if (!defined("_ECRIRE_INC_VERSION")) return; |
---|
4 | |
---|
5 | // Générer une URL pour la read API de Zotero |
---|
6 | function 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 |
---|
16 | function 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 |
---|
30 | function 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) |
---|
40 | function 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 |
---|
251 | function 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 |
---|
269 | function 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 |
---|
278 | function 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 |
---|
362 | function 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 |
---|
379 | function 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 |
---|
416 | function 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 | ?> |
---|