[SPIP] ~maj v3.0.14-->v3.0.17
[ptitvelo/web/www.git] / www / plugins-dist / svp / inc / svp_depoter_distant.php
1 <?php
2
3 /**
4 * Traitement des dépots distants
5 *
6 * Un dépot distant est une liste de paquets que l'on peut télécharger.
7 * Cette liste est donnée par un fichier XML que l'on peut relire
8 * régulièrement pour actualiser nos informations. Effectivement, chaque
9 * paquet (et plugin) décrit est inséré en base de données pour nous
10 * faciliter les recherches.
11 *
12 * @plugin SVP pour SPIP
13 * @license GPL
14 * @package SPIP\SVP\Depots
15 */
16
17 if (!defined("_ECRIRE_INC_VERSION")) return;
18 include_spip('inc/plugin');
19 include_spip('inc/svp_phraser');
20
21
22 /**
23 * Ajout d'un dépot et de son contenu (paquets, plugins) dans la base de données
24 *
25 * Si une erreur survient (syntaxe XML incorrecte, pas de plugin dans le dépot),
26 * son texte est placé dans le paramètre $erreur
27 *
28 * @param string $url
29 * URL du fichier XML de description du dépot
30 * @param string $erreur
31 * Texte d'un éventuel message d'erreur
32 * @return bool
33 * true si le dépot est ajouté correctement, false sinon
34 */
35 function svp_ajouter_depot($url, &$erreur='') {
36 include_spip('inc/distant');
37
38 // On considere que l'url a deja ete validee (correcte et nouveau depot)
39 $url = trim($url);
40 // Ajout du depot dans la table spip_depots. Les compteurs de paquets et de plugins
41 // sont mis a jour apres le traitement des paquets
42
43 // on recupère le XML
44 $fichier_xml = copie_locale($url, 'modif');
45 if (!$fichier_xml) {
46 $erreur = _T('svp:message_nok_xml_non_recupere', array('fichier' => $url));
47 return false;
48 }
49
50 $fichier_xml = _DIR_RACINE . $fichier_xml;
51
52 // Lire les donnees d'un depot de paquets
53 $infos = svp_phraser_depot($fichier_xml);
54 if (!$infos) {
55 $erreur = _T('svp:message_nok_xml_non_conforme', array('fichier' => $url));
56 return false;
57 }
58
59 $titre = filtrer_entites($infos['depot']['titre']);
60 $champs = array('titre' => $titre,
61 'descriptif' => filtrer_entites($infos['depot']['descriptif']),
62 'type' => $infos['depot']['type'],
63 'url_serveur' => $infos['depot']['url_serveur'],
64 'url_brouteur' => $infos['depot']['url_brouteur'],
65 'url_archives' => $infos['depot']['url_archives'],
66 'url_commits' => $infos['depot']['url_commits'],
67 'xml_paquets'=> $url,
68 'sha_paquets'=> sha1_file($fichier_xml),
69 'nbr_paquets' => 0,
70 'nbr_plugins' => 0,
71 'nbr_autres' => 0);
72
73 // verifier avant l'insertion que le depot n'existe pas deja
74 // car la recuperation pouvant etre longue on risque le probleme en cas de concurrence
75 if (sql_countsel('spip_depots','xml_paquets='.sql_quote($url))){
76 $erreur = _T('svp:message_nok_depot_deja_ajoute', array('url' => $url));
77 return false;
78 }
79 elseif (!$id_depot = sql_insertq('spip_depots', $champs)) {
80 $erreur = _T('svp:message_nok_sql_insert_depot', array('objet' => "$titre ($url)"));
81 return false;
82 }
83
84 // Ajout des paquets dans spip_paquets et actualisation des plugins dans spip_plugins
85 $ok = svp_actualiser_paquets($id_depot, $infos['paquets'], $nb_paquets, $nb_plugins, $nb_autres);
86 if (!$ok OR ($nb_paquets == 0)) {
87 // Si une erreur s'est produite, on supprime le depot deja insere
88 sql_delete('spip_depots','id_depot='.sql_quote($id_depot));
89 if (!$ok)
90 $erreur = _T('svp:message_nok_xml_non_conforme', array('fichier' => $url));
91 else
92 $erreur = _T('svp:message_nok_aucun_paquet_ajoute', array('url' => $url));
93 return false;
94 }
95
96 // On met à jour le nombre de paquets et de plugins du depot maintenant !
97 sql_updateq('spip_depots',
98 array('nbr_paquets'=> $nb_paquets, 'nbr_plugins'=> $nb_plugins, 'nbr_autres'=> $nb_autres),
99 'id_depot=' . sql_quote($id_depot));
100
101 // On vide les paquets locaux pour mettre a jour leurs donnees relatives au depot
102 // comme les mises a jour disponibles
103 include_spip('inc/svp_depoter_local');
104 svp_base_supprimer_paquets_locaux();
105
106 return true;
107 }
108
109 /**
110 * Suppression d'un dépot et de son contenu (paquets, plugins) dans la base de données
111 *
112 * Cette suppression entraîne des recalcul comme les versions maximales
113 * des plugins téléchargeables qui peuvent changer.
114 *
115 * @param int $id
116 * Identifiant du dépot
117 * @return bool
118 * false si le dépot n'est pas trouvé, true sinon
119 */
120 function svp_supprimer_depot($id){
121 $id = intval($id);
122
123 // Pas de depot a cet id ?
124 if (!$id_depot = sql_getfetsel('id_depot', 'spip_depots', 'id_depot='. sql_quote($id)) ){
125 return false;
126 }
127
128 // on calcule les versions max des plugins heberges par le depot
129 $vmax =array();
130
131 if ($resultats = sql_allfetsel('id_plugin, version', 'spip_paquets', 'id_depot='. sql_quote($id))) {
132 foreach ($resultats as $paquet) {
133 $id_plugin = $paquet['id_plugin'];
134 if (!isset($vmax[$id_plugin])
135 OR (spip_version_compare($vmax[$id_plugin], $paquet['version'], '<')))
136 $vmax[$id_plugin] = $paquet['version'];
137 }
138 }
139
140 // On supprime les paquets heberges par le depot
141 sql_delete('spip_paquets','id_depot='.sql_quote($id_depot));
142
143 // Si on est pas en mode runtime, on utilise surement l'espace public pour afficher les plugins.
144 // Il faut donc verifier que les urls suivent bien la mise à jour
145 // Donc avant de nettoyer la base des plugins du depot ayant disparus on supprime toutes les urls
146 // associees a ce depot : on les recreera apres le nettoyage
147 if (!_SVP_MODE_RUNTIME)
148 svp_actualiser_url_plugins($id_depot);
149
150 // Nettoyer les autres relations à ce dépot
151 svp_nettoyer_apres_suppression($id_depot, $vmax);
152
153 // Si on est pas en mode runtime, on utilise surement l'espace public pour afficher les plugins.
154 // Il faut donc s'assurer que les urls suivent bien la mise à jour
155 // - on supprime toutes les urls plugin
156 // - on les regenere pour la liste des plugins mise a jour
157 if (!_SVP_MODE_RUNTIME)
158 svp_actualiser_url_plugins($id_depot);
159
160 // On supprime le depot lui-meme
161 sql_delete('spip_depots','id_depot='.sql_quote($id_depot));
162
163 // on supprime les paquets locaux pour reactualisation
164 include_spip('inc/svp_depoter_local');
165 svp_base_supprimer_paquets_locaux();
166
167 return true;
168 }
169
170
171 /**
172 * Nettoyer la base de données après la suppression d'un dépot
173 *
174 * Supprime
175 * - les liens des plugins avec le dépot (table spip_depots_plugins)
176 * - les plugins dont aucun paquet n'est encore hébergé par un dépot restant (table spip_plugins)
177 * Remet à zéro la version maximale des plugins ayant vu leur paquet en version maximale supprimée
178 *
179 * @param int $id_depot
180 * Identifiant du dépot
181 * @param array $vmax
182 * Tableau de la version maximale des plugins du dépot supprimé
183 * Tableau (id_plugin => version maximale)
184 * @return bool
185 * true toujours.
186 **/
187 function svp_nettoyer_apres_suppression($id_depot, $vmax) {
188
189 // On rapatrie la liste des plugins du depot qui servira apres qu'on ait supprime les liens
190 // de la table spip_depots_plugins
191 $liens = sql_allfetsel('id_plugin', 'spip_depots_plugins', 'id_depot='.sql_quote($id_depot));
192 $plugins_depot = array_map('reset', $liens);
193
194 // On peut donc supprimer tous ces liens *plugins-depots* du depot
195 sql_delete('spip_depots_plugins', 'id_depot='.sql_quote($id_depot));
196
197 // On verifie pour chaque plugin concerne par la disparition de paquets si c'est la version
198 // la plus elevee qui a ete supprimee.
199 // Si oui, on positionne le vmax a 0, ce qui permettra de remettre a jour le plugin systematiquement
200 // a la prochaine actualisation.
201 // Cette operation est necessaire car on n'impose pas que les informations du plugin soient identiques
202 // pour chaque paquet !!!
203
204 // On insere, en encapsulant pour sqlite...
205 if (sql_preferer_transaction()) {
206 sql_demarrer_transaction();
207 }
208
209 if ($resultats = sql_allfetsel('id_plugin, vmax', 'spip_plugins', sql_in('id_plugin', $plugins_depot))) {
210 foreach ($resultats as $plugin) {
211 if (spip_version_compare($plugin['vmax'], $vmax[$plugin['id_plugin']], '='))
212 sql_updateq('spip_plugins', array('vmax' => ''), 'id_plugin=' . sql_quote($plugin['id_plugin']));
213 }
214 }
215
216 if (sql_preferer_transaction()) {
217 sql_terminer_transaction();
218 }
219
220 // Maintenant on calcule la liste des plugins du depot qui ne sont pas heberges
221 // par un autre depot => donc a supprimer
222 // - Liste de tous les plugins encore lies a un autre depot
223 // tous les plugins correspondants aux anciens paquets
224 $plugins_restants = sql_allfetsel('DISTINCT(id_plugin)', 'spip_paquets', sql_in('id_plugin', $plugins_depot));
225 $plugins_restants = array_map('array_shift', $plugins_restants);
226
227 // - L'intersection des deux tableaux renvoie les plugins a supprimer
228 $plugins_a_supprimer = array_diff($plugins_depot, $plugins_restants);
229
230 // On supprimer les plugins identifies
231 sql_delete('spip_plugins', sql_in('id_plugin', $plugins_a_supprimer));
232
233 return true;
234 }
235
236
237 /**
238 * Actualisation des plugins d'un dépot déjà crée
239 *
240 * Actualise les informations uniquement si la signature du fichier
241 * XML de description du dépot a changé
242 *
243 * @param int $id
244 * Identifiant du dépot
245 * @return bool
246 * false si erreur, true sinon
247 */
248 function svp_actualiser_depot($id){
249 include_spip('inc/distant');
250
251 $id = intval($id);
252
253 // pas de depot a cet id ?
254 if (!$depot = sql_fetsel('*', 'spip_depots', 'id_depot='. sql_quote($id)) ){
255 return false;
256 }
257
258 $fichier_xml = _DIR_RACINE . copie_locale($depot['xml_paquets'], 'modif');
259
260 $sha = sha1_file($fichier_xml);
261
262 if ($depot['sha_paquets'] == $sha) {
263 // Le fichier n'a pas change (meme sha1) alors on ne fait qu'actualiser la date
264 // de mise a jour du depot en mettant a jour *inutilement* le sha1
265 spip_log('Aucune modification du fichier XML, actualisation non declenchee - id_depot = ' . $depot['id_depot'], 'svp_actions.' . _LOG_INFO);
266 sql_replace('spip_depots', array_diff_key($depot, array('maj' => '')));
267 }
268 else {
269
270 // Le fichier a bien change il faut actualiser tout le depot
271 $infos = svp_phraser_depot($fichier_xml);
272
273 if (!$infos)
274 return false;
275
276 // On actualise les paquets dans spip_paquets en premier lieu.
277 // Lors de la mise a jour des paquets, les plugins aussi sont actualises
278 $ok = svp_actualiser_paquets($depot['id_depot'], $infos['paquets'],
279 $nb_paquets, $nb_plugins, $nb_autres);
280
281 // apres la mise a jour des paquets d'un depot, on actualise les informations des paquets locaux
282 // principalement l'info "maj_version" indiquant s'il existe un paquet plus recent
283 include_spip('inc/svp_depoter_local');
284 svp_actualiser_maj_version();
285
286 if ($ok) {
287 // On met à jour :
288 // -- les infos ne pouvant pas etre editees par le formulaire d'edition
289 // d'un depot et extraites du xml
290 // -- le nombre de paquets et de plugins du depot ainsi que le nouveau sha1
291 // ce qui aura pour effet d'actualiser la date de mise a jour
292 $champs = array('url_serveur' => $infos['depot']['url_serveur'],
293 'url_brouteur' => $infos['depot']['url_brouteur'],
294 'url_archives' => $infos['depot']['url_archives'],
295 'url_commits' => $infos['depot']['url_commits'],
296 'nbr_paquets' => $nb_paquets,
297 'nbr_plugins' => $nb_plugins,
298 'nbr_autres' => $nb_autres,
299 'sha_paquets' => $sha);
300 sql_updateq('spip_depots', $champs, 'id_depot=' . sql_quote($depot['id_depot']));
301 }
302 }
303
304 return true;
305 }
306
307
308 /**
309 * Actualisation de la table des paquets pour le dépot choisi
310 *
311 * Enlève de la base les paquets du dépots qui ne sont plus présents
312 * dans la description du XML. Ajoute ou met à jour les autres.
313 *
314 * @param int $id_depot
315 * Identifiant du dépot
316 * @param array $paquets
317 * Tableau des paquets extraits du fichier XML
318 * L'index est le nom de l'archive (xxxx.zip) et le contenu est
319 * un tableau à deux entrées :
320 * - Index 'plugin' : le tableau des infos du plugin
321 * - Index 'file' : le nom de l'archive .zip
322 * @param int $nb_paquets
323 * Nombre de paquets réellement inserés dans la base
324 * @param int $nb_plugins
325 * Nombre de plugins parmi les paquets inserés
326 * @param int &$nb_autres
327 * Nombre de contributions non issues de plugin parmi les paquets inserés
328 * @return bool
329 * false si aucun dépot ou paquets, true sinon
330 */
331 function svp_actualiser_paquets($id_depot, $paquets, &$nb_paquets, &$nb_plugins, &$nb_autres) {
332
333 // Initialisation des compteurs
334 $nb_paquets = 0;
335 $nb_plugins = 0;
336 $nb_autres = 0;
337
338 // Si aucun depot ou aucun paquet on renvoie une erreur
339 if ((!$id_depot) OR (!is_array($paquets)))
340 return false;
341
342 // On initialise l'url de base des logos du depot et son type afin de
343 // calculer l'url complete de chaque logo
344 $select = array('url_archives', 'type');
345 $depot = sql_fetsel($select, 'spip_depots', 'id_depot=' . sql_quote($id_depot));
346
347
348 // On supprime tous les paquets du depot
349 // qui ont ete evacues, c'est a dire ceux dont les signatures
350 // ne correspondent pas aux nouveaux...
351 // et on retablit les vmax des plugins restants...
352 $signatures = array();
353 foreach ($paquets as $_paquet) {
354 $signatures[] = $_paquet['md5'];
355 }
356
357 // tous les paquets du depot qui ne font pas parti des signatures
358 $anciens_paquets = sql_allfetsel('id_paquet', 'spip_paquets', array('id_depot=' . sql_quote($id_depot), sql_in('signature', $signatures, 'NOT')));
359 $anciens_paquets = array_map('array_shift', $anciens_paquets);
360
361 // pour ces vieux paquets, on les nettoie de la base
362 if ($anciens_paquets) {
363 // tous les plugins correspondants aux anciens paquets
364 $anciens_plugins = sql_allfetsel('pl.id_plugin', array('spip_plugins AS pl', 'spip_paquets AS pa'), array('pl.id_plugin=pa.id_plugin', sql_in('pa.id_paquet', $anciens_paquets)));
365 $anciens_plugins = array_map('array_shift', $anciens_plugins);
366
367 // suppression des anciens paquets
368 sql_delete('spip_paquets', sql_in('id_paquet', $anciens_paquets));
369 // suppressions des liaisons depots / anciens plugins
370 // on enlève la liaison lorsqu'il n'y a plus aucun paquet lie a un des plugins qui ont vu un paquet enlevé
371
372 // liste des plugins qui ont encore des paquets dans ce depot
373 $plugins_restants = sql_allfetsel('pl.id_plugin',
374 array('spip_plugins AS pl', 'spip_paquets AS pa'),
375 array(sql_in('pl.id_plugin', $anciens_plugins), 'pl.id_plugin=pa.id_plugin', 'pa.id_depot=' . sql_quote($id_depot)));
376 $plugins_restants = array_map('array_shift', $plugins_restants);
377 // par opposition, on retrouve ceux qui n'en ont plus...
378 $plugins_supprimes = array_diff($anciens_plugins, $plugins_restants);
379 sql_delete('spip_depots_plugins', array('id_depot='. sql_quote($id_depot), sql_in('id_plugin', $plugins_supprimes)));
380 unset($plugins_restants, $plugins_supprimes);
381
382 // supprimer les plugins orphelins
383 include_spip('inc/svp_depoter_local');
384 svp_supprimer_plugins_orphelins($anciens_plugins);
385
386 // corriger les vmax des plugins
387 svp_corriger_vmax_plugins($anciens_plugins);
388
389 // corriger les compats, branches aussi
390 svp_completer_plugins($anciens_plugins);
391 }
392
393 // on ne garde que les paquets qui ne sont pas presents dans la base
394 $signatures = sql_allfetsel('signature', 'spip_paquets', 'id_depot='.sql_quote($id_depot));
395 $signatures = array_map('array_shift', $signatures);
396 foreach ($paquets as $cle => $_infos) {
397 if (in_array($_infos['md5'], $signatures)) {
398 unset($paquets[$cle]);
399 }
400 }
401
402 // tableaux d'actions
403 $insert_paquets = array();
404 $insert_plugins = array();
405 $insert_contribs = array();
406 $prefixes = array(); // prefixe => id_plugin
407
408 // On met a jour ou on cree chaque paquet a partir du contenu du fichier xml
409 // On ne fait pas cas de la compatibilite avec la version de SPIP installee
410 // car l'operation doit permettre de collecter tous les paquets
411 foreach ($paquets as $_archive => $_infos) {
412
413 $insert_paquet = array();
414 // On initialise les informations specifiques au paquet :
415 // l'id du depot et les infos de l'archive
416 $insert_paquet['id_depot'] = $id_depot;
417 $insert_paquet['nom_archive'] = $_archive;
418 $insert_paquet['nbo_archive'] = $_infos['size'];
419 $insert_paquet['maj_archive'] = date('Y-m-d H:i:s', $_infos['date']);
420 $insert_paquet['src_archive'] = $_infos['source'];
421 $insert_paquet['date_modif'] = $_infos['last_commit'];
422 // On serialise le tableau des traductions par module
423 $insert_paquet['traductions'] = serialize($_infos['traductions']);
424 // On ajoute la signature
425 $insert_paquet['signature'] = $_infos['md5'];
426
427 // On verifie si le paquet est celui d'un plugin ou pas
428 // -- Les traitements du XML dependent de la DTD utilisee
429 // Formatage des informations extraites du plugin pour insertion dans la base SVP
430 $formater = charger_fonction('preparer_sql_' . $_infos['dtd'], 'plugins');
431 if ($champs_aplat = $formater($_infos['plugin'])) {
432 // Eclater les champs recuperes en deux sous tableaux, un par table (plugin, paquet)
433 $champs = eclater_plugin_paquet($champs_aplat);
434
435 $paquet_plugin = true;
436 // On complete les informations du paquet et du plugin
437 $insert_paquet = array_merge($insert_paquet, $champs['paquet']);
438 $insert_plugin = $champs['plugin'];
439 // On construit l'url complete du logo
440 // Le logo est maintenant disponible a la meme adresse que le zip et porte le nom du zip.
441 // Son extension originale est conservee
442 if ($insert_paquet['logo'])
443 $insert_paquet['logo'] = $depot['url_archives'] . '/'
444 . basename($insert_paquet['nom_archive'], '.zip') . '.'
445 . pathinfo($insert_paquet['logo'], PATHINFO_EXTENSION);
446
447 // On loge l'absence de categorie ou une categorie erronee et on positionne la categorie
448 // par defaut "aucune"
449 // Provisoire tant que la DTD n'est pas en fonction
450 if (!$insert_plugin['categorie']) {
451 spip_log("Categorie absente dans le paquet issu de <". $insert_paquet['src_archive'] .
452 "> du depot <" . $insert_paquet['id_depot'] . ">\n", 'svp_paquets.' . _LOG_INFO_IMPORTANTE);
453 $insert_plugin['categorie'] = 'aucune';
454 }
455 else {
456 $svp_categories = $GLOBALS['categories_plugin'];
457 if (!in_array($insert_plugin['categorie'], $svp_categories)) {
458 spip_log("Categorie &#107;" . $insert_plugin['categorie'] . "&#108; incorrecte dans le paquet issu de <". $insert_paquet['src_archive'] .
459 "> du depot <" . $insert_paquet['id_depot'] . ">\n", 'svp_paquets.' . _LOG_INFO_IMPORTANTE);
460 $insert_plugin['categorie'] = 'aucune';
461 }
462 }
463 }
464 else {
465 $paquet_plugin = false;
466 }
467 // On teste l'existence du paquet dans la base avec les champs
468 // id_depot, nom_archive et src_archive pour être sur de l'unicité.
469 // - si le paquet n'existe pas, on le crée,
470 // - sinon (et ça ne devrait pas arriver), on ne fait qu'un update
471 if (!$paquet = sql_fetsel('*', 'spip_paquets', array('id_depot='. sql_quote($insert_paquet['id_depot']),
472 'nom_archive='. sql_quote($insert_paquet['nom_archive']),
473 'src_archive='. sql_quote($insert_paquet['src_archive'])))) {
474 // Le paquet n'existe pas encore en base de donnees
475 // ------------------------------------------------
476
477 // On positionne la date de creation a celle du dernier commit ce qui est bien le cas
478 $insert_paquet['date_crea'] = $insert_paquet['date_modif'];
479
480 // Les collisions ne sont possibles que si on ajoute un nouveau paquet
481 $collision = false;
482
483 if ($paquet_plugin) {
484 // On est en presence d'un PLUGIN
485 // ------------------------------
486 // On evite les doublons de paquet
487 // Pour determiner un doublon on verifie actuellement :
488 // - le prefixe
489 // - la version du paquet et de la base
490 // - l'etat
491 $where = array('t1.id_plugin=t2.id_plugin',
492 't1.version=' . sql_quote($insert_paquet['version']),
493 't1.version_base=' . sql_quote($insert_paquet['version_base']),
494 't1.etatnum=' . sql_quote($insert_paquet['etatnum']),
495 't1.id_depot>' . intval(0),
496 't2.prefixe=' . sql_quote($insert_plugin['prefixe']));
497 if (!$id_paquet = sql_getfetsel('t1.id_paquet', 'spip_paquets AS t1, spip_plugins AS t2', $where)) {
498 // On traite d'abord le plugin du paquet pour recuperer l'id_plugin
499 // On rajoute le plugin dans la table spip_plugins si celui-ci n'y est pas encore ou on recupere
500 // l'id si il existe deja et on le met a jour si la version du paquet est plus elevee
501
502 $plugin = sql_fetsel('id_plugin, vmax', 'spip_plugins', array('prefixe=' . sql_quote($insert_plugin['prefixe'])));
503 if (!$plugin AND !array_key_exists($insert_plugin['prefixe'], $insert_plugins)) {
504 $insert_plugins[ $insert_plugin['prefixe'] ] = array_merge($insert_plugin, array('vmax' => $insert_paquet['version']));
505 }
506 else {
507 if ($plugin) {
508 $id_plugin = $plugin['id_plugin'];
509 $prefixes[$insert_plugin['prefixe']] = $id_plugin;
510 }
511 if (array_key_exists($insert_plugin['prefixe'], $insert_plugins)
512 AND (spip_version_compare($insert_plugins[ $insert_plugin['prefixe'] ]['vmax'], $insert_paquet['version'], '<='))) {
513 // attribuer au plugin le nom et le slogan du paquet le plus à jour
514 $insert_plugins[ $insert_plugin['prefixe'] ]['nom'] = $insert_plugin['nom'];
515 $insert_plugins[ $insert_plugin['prefixe'] ]['slogan'] = $insert_plugin['slogan'];
516 $insert_plugins[ $insert_plugin['prefixe'] ]['vmax'] = $insert_paquet['version'];
517 }
518 }
519
520 // On traite maintenant le paquet connaissant l'id du plugin
521 // temporaire qui sera supprime lors de la connaissance de l'id_paquet
522 $insert_paquet['prefixe'] = $insert_plugin['prefixe'];
523 $insert_paquets[] = $insert_paquet;
524 }
525 else
526 $collision = true;
527 }
528 else {
529 // On est en presence d'une CONTRIBUTION NON PLUGIN
530 // ------------------------------------------------
531 $where = array(
532 'id_depot=' . sql_quote($insert_paquet['id_depot']),
533 'nom_archive=' . sql_quote($insert_paquet['nom_archive']));
534 if (!$id_paquet = sql_getfetsel('id_paquet', 'spip_paquets', $where)) {
535 // Ce n'est pas un plugin, donc id_plugin=0 et toutes les infos plugin sont nulles
536 $insert_paquet['id_plugin'] = 0;
537 $insert_contribs[] = $insert_paquet;
538 } else
539 $collision = true;
540 }
541 // On loge le paquet ayant ete refuse dans un fichier a part afin de les verifier
542 // apres coup
543 if ($collision) {
544 spip_log("Collision avec le paquet <". $insert_paquet['nom_archive'] .
545 " / " . $insert_paquet['src_archive'] . "> du depot <" . $insert_paquet['id_depot'] . ">\n", 'svp_paquets.' . _LOG_INFO_IMPORTANTE);
546 }
547 }
548 else {
549 // Le paquet existe deja en base de donnees
550 // ----------------------------------------
551
552 // On ne devrait plus arriver ICI...
553 // Code obsolete ?
554 spip_log('!!!!!! Passage dans code obsolete (svp/svp_depoter_distant)', 'depoter');
555
556 // on effectue les traitements en attente
557 // pour que les updates soient corrects
558 svp_inserer_multi($insert_plugins, $insert_paquets, $insert_contribs, $prefixes);
559
560
561 // On met a jour le paquet en premier lieu qu'il soit un plugin ou une contribution
562 sql_updateq('spip_paquets', $insert_paquet,
563 'id_paquet=' . sql_quote($paquet['id_paquet']));
564
565 }
566 }
567
568 // on effectue les traitements en attente
569 // pour que les updates soient corrects
570 svp_inserer_multi($insert_plugins, $insert_paquets, $insert_contribs, $prefixes);
571
572 // On rajoute le plugin comme heberge par le depot si celui-ci n'est pas encore enregistre comme tel
573 $ids = sql_allfetsel('p.id_plugin',
574 array('spip_plugins AS p', 'spip_depots_plugins AS dp'),
575 array('p.id_plugin=dp.id_plugin', 'dp.id_depot='.sql_quote($id_depot)));
576 $ids = array_map('array_shift', $ids);
577
578 // inserer les liens avec le depots
579 $insert_dp = array();
580 $news_id = array_diff(array_values($prefixes), $ids);
581 foreach($news_id as $id) {
582 $insert_dp[] = array('id_depot'=>$id_depot, 'id_plugin'=>$id);
583 }
584 if ($insert_dp) {
585 sql_insertq_multi('spip_depots_plugins', $insert_dp);
586 }
587
588 // on recalcul les vmax des plugins de ce depot.
589 svp_corriger_vmax_plugins(array_values($prefixes));
590
591 // On compile maintenant certaines informations des paquets mis a jour dans les plugins
592 // (date de creation, date de modif, version spip...)
593 svp_completer_plugins_depot($id_depot);
594
595 // Si on est pas en mode runtime, on utilise surement l'espace public pour afficher les plugins.
596 // Il faut donc s'assurer que les urls suivent bien la mise à jour
597 // - on supprime toutes les urls plugin
598 // - on les regenere pour la liste des plugins mise a jour
599 if (!_SVP_MODE_RUNTIME)
600 svp_actualiser_url_plugins($id_depot);
601
602 // Calcul des compteurs de paquets, plugins et contributions
603 $nb_paquets = sql_countsel('spip_paquets', 'id_depot=' . sql_quote($id_depot));
604 $nb_plugins = sql_countsel('spip_depots_plugins', 'id_depot=' . sql_quote($id_depot));
605 $nb_autres = sql_countsel('spip_paquets', array('id_depot=' . sql_quote($id_depot), 'id_plugin=0'));
606
607 return true;
608 }
609
610
611 /**
612 * Insertion en masse de plugins ou de paquets.
613 *
614 * Les paquets peuvent de pas avoir d'info "prefixe" (à transformer en id_plugin)
615 * lorsqu'ils ne proviennent pas de plugin (squelettes...)
616 *
617 * @param array $insert_plugins
618 * Tableau de description de plugins.
619 * Une description est un tableau de couples (colonne sql => valeur)
620 * pour l'insertion en base de données.
621 * @param array $insert_paquets
622 * Tableau de description de paquets.
623 * Une description est un tableau de couples (colonne sql => valeur)
624 * pour l'insertion en base de données.
625 * @param array $insert_contribs
626 * Tableau de description de paquets (contributions non plugins).
627 * Une description est un tableau de couples (colonne sql => valeur)
628 * pour l'insertion en base de données.
629 * @param array $prefixes
630 * Couples de relation (préfixe de plugin => identifiant de plugin) connues,
631 * pour limiter les accès SQL.
632 * @return void
633 **/
634 function svp_inserer_multi(&$insert_plugins, &$insert_paquets, &$insert_contribs, &$prefixes) {
635
636 if (count($insert_plugins)) {
637 sql_insertq_multi('spip_plugins', $insert_plugins);
638 $insert_plugins = array();
639 }
640
641 if (count($insert_paquets)) {
642
643 // on cherche tous les id_plugin/prefixe que l'on a à récuperer
644 // en une seule requete
645 $prefixes_manquants = array();
646 foreach ($insert_paquets as $p) {
647 // on ne connait que le prefixe
648 if (isset($p['prefixe']) and !isset($prefixes[ $p['prefixe'] ])) {
649 $prefixes_manquants[] = $p['prefixe'];
650 }
651 }
652
653 // recuperer les nouveaux prefixes :
654 $new = sql_allfetsel(array('prefixe', 'id_plugin'), 'spip_plugins', sql_in('prefixe', $prefixes_manquants));
655 foreach ($new as $p) {
656 $prefixes[ $p['prefixe'] ] = $p['id_plugin'];
657 }
658
659 // inserer les id_plugin dans les paquets a inserer
660 // inserer le prefixe dans le paquet (pour raccourcis de jointures)
661 foreach ($insert_paquets as $c=>$p) {
662 if (isset($p['prefixe'])) {
663 $insert_paquets[$c]['id_plugin'] = $prefixes[ $insert_paquets[$c]['prefixe'] ];
664 } else {
665 $insert_paquets[$c]['prefixe'] = array_search($p['id_plugin'], $prefixes);
666 }
667 }
668
669 // on insere tout !
670 sql_insertq_multi('spip_paquets', $insert_paquets);
671 $insert_paquets = array();
672 }
673
674 // les contribs n'ont pas le même nombre de champs dans les insertions
675 // et n'ont pas de plugin rattachés.
676 if (count($insert_contribs)) {
677 sql_insertq_multi('spip_paquets', $insert_contribs);
678 $insert_contribs = array();
679 }
680 }
681
682 /**
683 * Complète les informations des plugins contenus dans un depot
684 * en compilant certaines informations (compatibilités, dates, branches)
685 *
686 * @param int $id_depot
687 * Identifiant du depot à actualiser
688 **/
689 function svp_completer_plugins_depot($id_depot) {
690 // On limite la revue des paquets a ceux des plugins heberges par le depot en cours d'actualisation
691 $ids_plugins = sql_allfetsel('id_plugin', 'spip_depots_plugins', array('id_depot=' . sql_quote($id_depot)));
692 $ids_plugins = array_map('reset', $ids_plugins);
693 if ($ids_plugins) {
694 svp_completer_plugins($ids_plugins);
695 }
696 }
697
698 /**
699 * Complète les informations des plugins, d'une liste de plugins donnés,
700 * en compilant certaines informations (compatibilités, dates, branches)
701 *
702 * @param array $ids_plugin
703 * Liste d'identifiants de plugins
704 * @return bool
705 * false si rien à faire, true sinon
706 **/
707 function svp_completer_plugins($ids_plugin) {
708
709 if (!$ids_plugin) {
710 return false;
711 }
712
713 include_spip('inc/svp_outiller');
714
715 // -- on recupere tous les paquets associes aux plugins indiques et on compile les infos
716 if ($resultats = sql_allfetsel('id_plugin, compatibilite_spip, date_crea, date_modif', 'spip_paquets',
717 array(sql_in('id_plugin', $ids_plugin), 'id_depot>'.intval(0)), '', 'id_plugin')) {
718
719 $plugin_en_cours = 0;
720 $inserts = array();
721
722 foreach($resultats as $paquet) {
723 // On finalise le plugin en cours et on passe au suivant
724 if ($plugin_en_cours != $paquet['id_plugin']) {
725 // On met a jour le plugin en cours
726 if ($plugin_en_cours) {
727 // On deduit maintenant les branches de la compatibilite globale
728 $complements['branches_spip'] = compiler_branches_spip($complements['compatibilite_spip']);
729 $inserts[$plugin_en_cours] = $complements;
730 }
731 // On passe au plugin suivant
732 $plugin_en_cours = $paquet['id_plugin'];
733 $complements = array('compatibilite_spip' => '', 'branches_spip' => '', 'date_crea' => 0, 'date_modif' => 0);
734 }
735
736 // On compile les compléments du plugin avec le paquet courant sauf les branches
737 // qui sont deduites en fin de compilation de la compatibilite
738 if ($paquet['date_modif'] > $complements['date_modif'])
739 $complements['date_modif'] = $paquet['date_modif'];
740 if (($complements['date_crea'] === 0)
741 OR ($paquet['date_crea'] < $complements['date_crea']))
742 $complements['date_crea'] = $paquet['date_crea'];
743 if ($paquet['compatibilite_spip'])
744 if (!$complements['compatibilite_spip'])
745 $complements['compatibilite_spip'] = $paquet['compatibilite_spip'];
746 else
747 $complements['compatibilite_spip'] = fusionner_intervalles($paquet['compatibilite_spip'], $complements['compatibilite_spip']);
748 }
749 // On finalise le dernier plugin en cours
750 $complements['branches_spip'] = compiler_branches_spip($complements['compatibilite_spip']);
751 $inserts[$plugin_en_cours] = $complements;
752
753 // On insere, en encapsulant pour sqlite...
754 if (sql_preferer_transaction()) {
755 sql_demarrer_transaction();
756 }
757
758 foreach ($inserts as $id_plugin => $complements) {
759 sql_updateq('spip_plugins', $complements, 'id_plugin=' . intval($id_plugin));
760 }
761
762 if (sql_preferer_transaction()) {
763 sql_terminer_transaction();
764 }
765
766 }
767
768 return true;
769 }
770
771
772 /**
773 * Recrée toutes les URLs propres de plugin
774 *
775 * Supprime toutes les urls de plugin de la table spip_urls puis les régénère.
776 *
777 * @return int
778 * Nombre d'URLs de plugin régénérées
779 **/
780 function svp_actualiser_url_plugins () {
781 $nb_plugins = 0;
782
783 // On supprime toutes les urls de plugin
784 sql_delete('spip_urls', array('type=\'plugin\''));
785
786 // On recupere les ids des plugins et on regenere les urls
787 if ($ids_plugin = sql_allfetsel('id_plugin', 'spip_plugins')) {
788 $ids_plugin = array_map('reset', $ids_plugin);
789 $nb_plugins = count($ids_plugin);
790
791 foreach ($ids_plugin as $_id) {
792 generer_url_entite($_id, 'plugin', '', '', true);
793 }
794 }
795
796 return $nb_plugins;
797 }
798
799 /**
800 * Éclate une description de paquet issu du XML du dépot en deux parties,
801 * une pour le plugin, l'autre pour le paquet
802 *
803 * Sépare en deux une description de champs désignant un paquet, en extrayant :
804 * - la partie plugin, soit ce qui peut être propre à plusieurs paquets.
805 * On trouve dedans le prefixe, nom, slogan, catégorie, tags
806 * - la partie paquet, soit ce qui est propre à ce conteneur là. On trouve
807 * dedans entre autres la description, la version, la compatibilité
808 * à SPIP, les dépendances, etc...
809 *
810 * @param array $champs_aplat
811 * Couples (clé => valeur) d'un paquet issu de l'analyse XML du dépot
812 * @return array
813 * Tableau de 2 index :
814 * - Index 'plugin' : couples (clé=>valeur) relatives au plugin
815 * - Index 'paquet' : couples (clé=>valeur) spécifiques au paquet
816 **/
817 function eclater_plugin_paquet($champs_aplat) {
818 return array(
819 'plugin' => array(
820 'prefixe' => $champs_aplat['prefixe'],
821 'nom' => $champs_aplat['nom'],
822 'slogan' => $champs_aplat['slogan'],
823 'categorie' => $champs_aplat['categorie'],
824 'tags' => $champs_aplat['tags']),
825 'paquet' => array(
826 'logo' => $champs_aplat['logo'],
827 'description' => $champs_aplat['description'],
828 'auteur' => $champs_aplat['auteur'],
829 'credit' => $champs_aplat['credit'],
830 'version' => $champs_aplat['version'],
831 'version_base' => $champs_aplat['version_base'],
832 'compatibilite_spip' => $champs_aplat['compatibilite_spip'],
833 'branches_spip' => $champs_aplat['branches_spip'],
834 'etat' => $champs_aplat['etat'],
835 'etatnum' => $champs_aplat['etatnum'],
836 'licence' => $champs_aplat['licence'],
837 'copyright' => $champs_aplat['copyright'],
838 'lien_doc' => $champs_aplat['lien_doc'],
839 'lien_demo' => $champs_aplat['lien_demo'],
840 'lien_dev' => $champs_aplat['lien_dev'],
841 'dependances' => $champs_aplat['dependances'])
842 );
843 }
844
845
846
847 /**
848 * Détermine la version max de chaque plugin, c'est à dire
849 * la version maxi d'un des paquets qui lui est lié.
850 *
851 * @param array $plugins Liste d'identifiant de plugins
852 **/
853 function svp_corriger_vmax_plugins($plugins) {
854 // tous les plugins encore lies a des depots (hors local)...
855 // la vmax est a retablir...
856 if ($plugins) {
857 $p = sql_allfetsel('DISTINCT(p.id_plugin)',
858 array('spip_plugins AS p', 'spip_paquets AS pa'),
859 array(sql_in('p.id_plugin', $plugins), 'p.id_plugin=pa.id_plugin', 'pa.id_depot>'.intval(0)));
860 $p = array_map('array_shift', $p);
861
862 // pour les autres, on la fixe correctement
863
864 // On insere, en encapsulant pour sqlite...
865 if (sql_preferer_transaction()) {
866 sql_demarrer_transaction();
867 }
868
869 foreach ($p as $id_plugin) {
870 $vmax = '';
871 if ($pa = sql_allfetsel('version', 'spip_paquets', array('id_plugin='.$id_plugin, 'id_depot>'.intval(0)))) {
872 foreach ($pa as $v) {
873 if (spip_version_compare($v['version'], $vmax, '>')) {
874 $vmax = $v['version'];
875 }
876 }
877 }
878 sql_updateq('spip_plugins', array('vmax'=>$vmax), 'id_plugin=' . intval($id_plugin));
879 }
880
881 if (sql_preferer_transaction()) {
882 sql_terminer_transaction();
883 }
884 }
885 }
886
887
888
889 ?>