svp_actionner.php 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411
  1. <?php
  2. /**
  3. * Gestion de l'actionneur : il effectue les actions sur les plugins
  4. *
  5. * @plugin SVP pour SPIP
  6. * @license GPL
  7. * @package SPIP\SVP\Actionneur
  8. */
  9. if (!defined("_ECRIRE_INC_VERSION")) return;
  10. /**
  11. * L'actionneur calcule l'ordre des actions, permet de les stocker
  12. * dans un fichier cache et de les effectuer.
  13. *
  14. * @package SPIP\SVP\Actionner
  15. **/
  16. class Actionneur {
  17. /**
  18. * Instance du décideur
  19. * @var Decideur */
  20. var $decideur;
  21. /**
  22. * Loguer les différents éléments
  23. *
  24. * Sa valeur sera initialisée par la configuration 'mode_log_verbeux' de SVP
  25. *
  26. * @var bool */
  27. var $log = false;
  28. /**
  29. * Liste des actions à faire
  30. * @var array
  31. * Tableau identifiant du paquet => type d'action
  32. */
  33. var $start = array();
  34. /**
  35. * Actions en cours d'analyse
  36. *
  37. * Lorsqu'on ajoute les actions à faire, elles sont réordonnées
  38. * et classées dans ces quatre sous-tableaux
  39. *
  40. * Chaque sous-tableau est composé d'une description courte du paquet
  41. * auquel est ajouté dans l'index 'todo' le type d'action à faire.
  42. *
  43. * @var array
  44. * Index 'off' : les paquets à désactiver (ordre inverse des dépendances)
  45. * Index 'lib' : les librairies à installer
  46. * Index 'on' : les paquets à activer (ordre des dépendances)
  47. * Index 'neutre' : autres actions dont l'ordre a peu d'importance.
  48. */
  49. var $middle = array(
  50. 'off' => array(),
  51. 'lib' => array(),
  52. 'on' => array(),
  53. 'neutre' => array(),
  54. );
  55. // actions à la fin (apres analyse, et dans l'ordre)
  56. /**
  57. * Liste des actions à faire
  58. *
  59. * Liste de description courtes des paquets + index 'todo' indiquant l'action
  60. * @var array */
  61. var $end = array();
  62. /**
  63. * Liste des actions faites
  64. * Liste de description courtes des paquets + index 'todo' indiquant l'action
  65. * @var array */
  66. var $done = array(); // faites
  67. /**
  68. * Actions en cours
  69. * Description courte du paquet + index 'todo' indiquant l'action
  70. * @var array */
  71. var $work = array();
  72. /**
  73. * Liste des erreurs
  74. *
  75. * @var array Liste des erreurs */
  76. var $err = array();
  77. /**
  78. * Verrou.
  79. * Le verrou est posé au moment de passer à l'action.
  80. * @var array
  81. * Index 'id_auteur' : Identifiant de l'auteur ayant déclenché des actions
  82. * Indix 'time' : timestamp de l'heure de déclenchement de l'action */
  83. var $lock = array('id_auteur'=>0, 'time'=>'');
  84. /**
  85. * SVP (ce plugin) est-il à désactiver dans une des actions ?
  86. *
  87. * Dans ce cas, on tente de le désactiver après d'autres plugins à désactiver
  88. * sinon l'ensemble des actions suivantes échoueraient.
  89. *
  90. * @var bool
  91. * false si SVP n'est pas à désactiver, true sinon */
  92. var $svp_off = false;
  93. /**
  94. * Constructeur
  95. *
  96. * Détermine si les logs sont activés et instancie un décideur.
  97. */
  98. function Actionneur(){
  99. include_spip('inc/config');
  100. $this->log = (lire_config('svp/mode_log_verbeux') == 'oui');
  101. include_spip('inc/svp_decider');
  102. $this->decideur = new Decideur();
  103. #$this->decideur->start();
  104. // pour denormaliser_version()
  105. include_spip('svp_fonctions');
  106. }
  107. /**
  108. * Ajoute un log
  109. *
  110. * Ajoute un log si la propriété $log l'autorise;
  111. *
  112. * @param mixed $quoi
  113. * La chose à logguer (souvent un texte)
  114. **/
  115. function log($quoi) {
  116. if ($this->log) {
  117. spip_log($quoi,'actionneur');
  118. }
  119. }
  120. /**
  121. * Ajoute une erreur
  122. *
  123. * Ajoute une erreur à la liste des erreurs présentées au moment
  124. * de traiter les actions.
  125. *
  126. * @param string $erreur
  127. * Le texte de l'erreur
  128. **/
  129. function err($erreur) {
  130. if ($erreur) {
  131. $this->err[] = $erreur;
  132. }
  133. }
  134. /**
  135. * Remet à zéro les tableaux d'actions
  136. */
  137. function clear() {
  138. $this->middle = array(
  139. 'off' => array(),
  140. 'lib' => array(),
  141. 'on' => array(),
  142. 'neutre' => array(),
  143. );
  144. $this->end = array();
  145. $this->done = array();
  146. $this->work = array();
  147. }
  148. /**
  149. * Ajoute les actions à faire dans l'actionneur
  150. *
  151. * @param array $todo
  152. * Tableau des actions à faire (identifiant de paquet => type d'action)
  153. **/
  154. function ajouter_actions($todo) {
  155. foreach ($todo as $id => $action) {
  156. $this->start[$id] = $action;
  157. }
  158. $this->ordonner_actions();
  159. }
  160. /**
  161. * Ajoute une librairie à installer
  162. *
  163. * Ajoute l'action de télécharger une librairie, si la libraire
  164. * n'est pas déjà présente et si le répertoire de librairie est
  165. * écrivable.
  166. *
  167. * @param string $nom Nom de la librairie
  168. * @param string $source URL pour obtenir la librairie
  169. */
  170. function add_lib($nom, $source) {
  171. if (!$this->decideur->est_presente_lib($nom)) {
  172. if (is_writable(_DIR_LIB)) {
  173. $this->middle['lib'][$nom] = array(
  174. 'todo'=>'getlib',
  175. 'n'=>$nom,
  176. 'p'=>$nom,
  177. 'v'=>$source,
  178. 's'=>$source,
  179. );
  180. } else {
  181. // erreur : impossible d'ecrire dans _DIR_LIB !
  182. // TODO : message et retour d'erreur a gerer...
  183. return false;
  184. }
  185. }
  186. return true;
  187. }
  188. /**
  189. * Ordonne les actions demandées
  190. *
  191. * La fonction définie quelles sont les actions graduellement réalisables.
  192. * Si un plugin A dépend de B qui dépend de C
  193. * - pour tout ce qui est à installer : ordre des dependances (d'abord C, puis B, puis A)
  194. * - pour tout ce qui est à désinstaller : ordre inverse des dependances. (d'abord A, puis B, puis C)
  195. *
  196. * On commence donc par séparer
  197. * - ce qui est à désinstaller,
  198. * - ce qui est à installer,
  199. * - les actions neutres (get, up sur non actif, kill)
  200. *
  201. * Dans les traitements, on commencera par faire
  202. * - ce qui est à désinstaller (il est possible que certains plugins
  203. * nécessitent la désinstallation d'autres présents - tel que : 1 seul
  204. * service d'envoi de mail)
  205. * - puis ce qui est a installer (à commencer par les librairies, puis paquets),
  206. * - puis les actions neutres
  207. */
  208. function ordonner_actions() {
  209. // nettoyer le terrain
  210. $this->clear();
  211. foreach ($this->start as $id=>$action) {
  212. $i = $this->decideur->infos_courtes_id($id);
  213. $i = $i['i'][$id];
  214. switch ($action) {
  215. case 'getlib':
  216. // le plugin en ayant besoin le fera
  217. // comme un grand...
  218. break;
  219. case 'geton':
  220. case 'on':
  221. $this->on($i, $action);
  222. break;
  223. case 'up':
  224. // si le plugin est actif
  225. if ($i['a'] == 'oui') {
  226. $this->on($i, $action);
  227. } else {
  228. $this->neutre($i, $action);
  229. }
  230. break;
  231. case 'upon':
  232. $this->on($i, $action);
  233. break;
  234. case 'off':
  235. case 'stop':
  236. $this->off($i, $action);
  237. break;
  238. case 'get':
  239. case 'kill':
  240. $this->neutre($i, $action);
  241. break;
  242. }
  243. }
  244. // c'est termine, on passe tout dans la fin...
  245. foreach ($this->middle as $acts) {
  246. $this->end = array_merge($this->end, $acts);
  247. }
  248. // si on a vu une desactivation de SVP
  249. // on le met comme derniere action...
  250. // sinon on ne pourrait pas faire les suivantes !
  251. if ($this->svp_off) {
  252. $this->log("SVP a desactiver a la fin.");
  253. foreach ($this->end as $c => $info) {
  254. if ($info['p'] == 'SVP') {
  255. unset($this->end[$c]);
  256. $this->end[] = $info;
  257. break;
  258. }
  259. }
  260. }
  261. $this->log("------------");
  262. #$this->log("Fin du tri :");
  263. #$this->log($this->end);
  264. }
  265. /**
  266. * Ajoute un paquet à activer
  267. *
  268. * À chaque fois qu'un nouveau paquet arrive ici, on le compare
  269. * avec ceux déjà présents pour savoir si on doit le traiter avant
  270. * ou après un des paquets à activer déjà présent.
  271. *
  272. * Si le paquet est une dépendance d'un autre plugin, il faut le mettre
  273. * avant (pour l'activer avant celui qui en dépend).
  274. *
  275. * Si le paquet demande une librairie, celle-ci est ajoutée (les
  276. * librairies seront téléchargées avant l'activation des plugins,
  277. * le plugin aura donc sa librairie lorsqu'il sera activé)
  278. *
  279. *
  280. * @param array $info
  281. * Description du paquet
  282. * @param string $action
  283. * Action à réaliser (on, upon)
  284. * @return void
  285. **/
  286. function on($info, $action) {
  287. $info['todo'] = $action;
  288. $p = $info['p'];
  289. $this->log("ON: $p $action");
  290. // si dependance, il faut le mettre avant !
  291. $in = $out = $deps = $deps_all = array();
  292. // raz des cles pour avoir les memes que $out (utile reellement ?)
  293. $this->middle['on'] = array_values($this->middle['on']);
  294. // ajout des dependance
  295. foreach ($info['dn'] as $dep) {
  296. $in[] = $dep['nom'];
  297. }
  298. // ajout des librairies
  299. foreach ($info['dl'] as $lib) {
  300. // il faudrait gerer un retour d'erreur eventuel !
  301. $this->add_lib($lib['nom'], $lib['lien']);
  302. }
  303. // on recupere : tous les prefix de plugin a activer (out)
  304. // ie. ce plugin peut dependre d'un de ceux la
  305. //
  306. // ainsi que les dependences de ces plugins (deps)
  307. // ie. ces plugins peuvent dependre de ce nouveau a activer.
  308. foreach ($this->middle['on'] as $inf) {
  309. $out[] = $inf['p'];
  310. foreach ($inf['dn'] as $dep) {
  311. $deps[$inf['p']][] = $dep['nom'];
  312. $deps_all[] = $dep['nom'];
  313. }
  314. }
  315. if (!$in) {
  316. // pas de dependance, on le met en premier !
  317. $this->log("- placer $p tout en haut");
  318. array_unshift($this->middle['on'], $info);
  319. } else {
  320. // intersection = dependance presente aussi
  321. // on place notre action juste apres la derniere dependance
  322. if ($diff = array_intersect($in, $out)) {
  323. $key = array();
  324. foreach($diff as $d) {$key[] = array_search($d, $out);}
  325. $key = max($key);
  326. $this->log("- placer $p apres " . $this->middle['on'][$key]['p']);
  327. if ($key == count($this->middle['on'])) {
  328. $this->middle['on'][] = $info;
  329. } else {
  330. array_splice($this->middle['on'], $key+1, 0, array($info));
  331. }
  332. // intersection = plugin dependant de celui-ci
  333. // on place notre plugin juste avant la premiere dependance a lui trouvee
  334. } elseif (in_array($p, $deps_all)) {
  335. foreach ($deps as $prefix=>$dep) {
  336. if (in_array($p, $dep)) {
  337. $key = array_search($prefix, $out);
  338. $this->log("- placer $p avant $prefix qui en depend ($key)");
  339. if ($key == 0) {
  340. array_unshift($this->middle['on'], $info);
  341. } else {
  342. array_splice($this->middle['on'], $key, 0, array($info));
  343. }
  344. break;
  345. }
  346. }
  347. // rien de particulier, il a des dependances mais les plugins
  348. // ne sont pas encore la ou les dependances sont deja actives
  349. // donc on le place tout en bas
  350. } else {
  351. $this->log("- placer $p tout en bas");
  352. $this->middle['on'][] = $info;
  353. }
  354. }
  355. unset($diff, $in, $out);
  356. }
  357. /**
  358. * Ajoute un paquet avec une action neutre
  359. *
  360. * Ces actions seront traitées en dernier, et peu importe leur
  361. * ordre car elles n'entrent pas en conflit avec des dépendances.
  362. *
  363. * @param array $info
  364. * Description du paquet
  365. * @param string $action
  366. * Action à réaliser (kill, get, up (sur plugin inactif))
  367. * @return void
  368. **/
  369. function neutre($info, $action) {
  370. $info['todo'] = $action;
  371. $this->log("NEUTRE: $info[p] $action");
  372. $this->middle['neutre'][] = $info;
  373. }
  374. /**
  375. * Ajoute un paquet à désactiver
  376. *
  377. * Ces actions seront traitées en premier.
  378. *
  379. * À chaque fois qu'un nouveau paquet arrive ici, on le compare
  380. * avec ceux déjà présents pour savoir si on doit le traiter avant
  381. * ou après un des paquets à désactiver déjà présent.
  382. *
  383. * Si le paquet est une dépendance d'un autre plugin, il faut le mettre
  384. * après (pour désactiver avant celui qui en dépend).
  385. *
  386. * @param array $info
  387. * Description du paquet
  388. * @param string $action
  389. * Action à réaliser (kill, get, up (sur plugin inactif))
  390. * @return void
  391. **/
  392. function off($info, $action) {
  393. $info['todo'] = $action;
  394. $p = $info['p'];
  395. $this->log("OFF: $p $action");
  396. // signaler la desactivation de SVP
  397. if ($p == 'SVP') {
  398. $this->svp_off = true;
  399. }
  400. // si dependance, il faut le mettre avant !
  401. $in = $out = array();
  402. // raz des cles pour avoir les memes que $out (utile reellement ?)
  403. $this->middle['off'] = array_values($this->middle['off']);
  404. foreach ($info['dn'] as $dep) {
  405. $in[] = $dep['nom'];
  406. }
  407. foreach ($this->middle['off'] as $inf) {
  408. $out[] = $inf['p'];
  409. }
  410. if (!$in) {
  411. // ce plugin n'a pas de dependance, on le met en dernier !
  412. $this->log("- placer $p tout en bas");
  413. $this->middle['off'][] = $info;
  414. } else {
  415. // ce plugin a des dependances,
  416. // on le desactive juste avant elles.
  417. // intersection = dependance presente aussi
  418. // on place notre action juste avant la premiere dependance
  419. if ($diff = array_intersect($in, $out)) {
  420. $key = array();
  421. foreach($diff as $d) {$key[] = array_search($d, $out);}
  422. $key = min($key);
  423. $this->log("- placer $p avant " . $this->middle['off'][$key]['p']);
  424. array_splice($this->middle['off'], $key, 0, array($info));
  425. } else {
  426. // aucune des dependances n'est a desactiver
  427. // (du moins à ce tour ci),
  428. // on le met en premier !
  429. $this->log("- placer $p tout en haut");
  430. array_unshift($this->middle['off'], $info); // etait ->middle['on'] ?? ...
  431. }
  432. }
  433. unset($diff, $in, $out);
  434. }
  435. /**
  436. * Retourne un bilan, texte HTML, des actions qui ont été faites
  437. *
  438. * Si c'est un affichage du bilan de fin, et qu'il reste des actions
  439. * à faire, un lien est proposé pour faire supprimer ces actions restantes
  440. * et le verrou qui va avec.
  441. *
  442. * @param bool $fin
  443. * Est-ce un affichage intermédiaire (false) ou le tout dernier (true).
  444. * @return string
  445. * Bilan des actions au format HTML
  446. **/
  447. function presenter_actions($fin = false) {
  448. $affiche = "";
  449. include_spip('inc/filtres_boites');
  450. if (count($this->err)) {
  451. $erreurs = "<ul>";
  452. foreach ($this->err as $i) {
  453. $erreurs .= "\t<li class='erreur'>" . $i . "</li>\n";
  454. }
  455. $erreurs .= "</ul>";
  456. $affiche .= boite_ouvrir(_T('svp:actions_en_erreur'), 'error') . $erreurs . boite_fermer();
  457. }
  458. if (count($this->done)) {
  459. $oks = true;
  460. $done = "<ul>";
  461. foreach ($this->done as $i) {
  462. $ok = ($i['done'] ? true : false);
  463. $oks = &$ok;
  464. $ok_texte = $ok ? 'ok' : 'fail';
  465. $cle_t = 'svp:message_action_finale_' . $i['todo'] . '_' . $ok_texte;
  466. $texte = _T($cle_t, array(
  467. 'plugin' => $i['n'],
  468. 'version' => denormaliser_version($i['v']),
  469. 'version_maj' => denormaliser_version($i['maj'])));
  470. if (is_string($i['done'])) {
  471. $texte .= " <span class='$ok_texte'>$i[done]</span>";
  472. }
  473. $done .= "\t<li class='$ok_texte'>$texte</li>\n";
  474. }
  475. $done .= "</ul>";
  476. $affiche .= boite_ouvrir(_T('svp:actions_realises'), ($oks ? 'success' : 'notice')) . $done . boite_fermer();
  477. }
  478. if (count($this->end)) {
  479. $todo = "<ul>";
  480. foreach ($this->end as $i) {
  481. $todo .= "\t<li>"._T('svp:message_action_'.$i['todo'],array(
  482. 'plugin'=>$i['n'],
  483. 'version'=>denormaliser_version($i['v']),
  484. 'version_maj'=>denormaliser_version($i['maj'])))."</li>\n";
  485. }
  486. $todo .= "</ul>\n";
  487. $titre = ($fin ? _T('svp:actions_non_traitees') : _T('svp:actions_a_faire'));
  488. // s'il reste des actions à faire alors que c'est la fin qui est affichée,
  489. // on met un lien pour vider. C'est un cas anormal qui peut surgir :
  490. // - en cas d'erreur sur une des actions bloquant l'espace privé
  491. // - en cas d'appel d'admin_plugins concurrent par le même admin ou 2 admins...
  492. if ($fin) {
  493. include_spip('inc/filtres');
  494. if ($this->lock['time']) {
  495. $time = $this->lock['time'];
  496. } else {
  497. $time = time();
  498. }
  499. $date = date('Y-m-d H:i:s', $time);
  500. $todo .= "<br />\n";
  501. $todo .= "<p class='error'>" . _T('svp:erreur_actions_non_traitees', array(
  502. 'auteur' => sql_getfetsel('nom', 'spip_auteurs', 'id_auteur=' . sql_quote($this->lock['id_auteur'])),
  503. 'date' => affdate_heure($date)
  504. )) . "</p>\n";
  505. $todo .= "<a href='" . parametre_url(self(), 'nettoyer_actions', '1'). "'>" . _T('svp:nettoyer_actions') . "</a>\n";
  506. }
  507. $affiche .= boite_ouvrir($titre, 'notice') . $todo . boite_fermer();
  508. }
  509. if ($affiche) {
  510. include_spip('inc/filtres');
  511. $affiche = wrap($affiche, "<div class='svp_retour'>");
  512. }
  513. return $affiche;
  514. }
  515. /**
  516. * Teste l'existance d'un verrou par un auteur ?
  517. *
  518. * Si un id_auteur est transmis, teste que c'est cet auteur
  519. * précis qui a posé le verrou.
  520. *
  521. * @see Actionneur::verouiller()
  522. *
  523. * @param int|string $id_auteur
  524. * Identifiant de l'auteur, ou vide
  525. * @return bool
  526. * true si un verrou est là, false sinon
  527. **/
  528. function est_verrouille($id_auteur = '') {
  529. if ($id_auteur == '') {
  530. return ($this->lock['id_auteur'] ? true : false);
  531. }
  532. return ($this->lock['id_auteur'] == $id_auteur);
  533. }
  534. /**
  535. * Pose un verrou
  536. *
  537. * Un verrou permet de garentir qu'une seule exécution d'actions
  538. * est lancé à la fois, ce qui évite que deux administrateurs
  539. * puissent demander en même temps des actions qui pourraient
  540. * s'entrechoquer.
  541. *
  542. * Le verrou est signé par l'id_auteur de l'auteur actuellement identifié.
  543. *
  544. * Le verrou sera sauvegardé en fichier avec la liste des actions
  545. *
  546. * @see Actionneur::sauver_actions()
  547. **/
  548. function verrouiller() {
  549. $this->lock = array(
  550. 'id_auteur' => $GLOBALS['visiteur_session']['id_auteur'],
  551. 'time' => time(),
  552. );
  553. }
  554. /**
  555. * Enlève le verrou
  556. **/
  557. function deverrouiller() {
  558. $this->lock = array(
  559. 'id_auteur' => 0,
  560. 'time' => '',
  561. );
  562. }
  563. /**
  564. * Sauvegarde en fichier cache la liste des actions et le verrou
  565. *
  566. * Crée un tableau contenant les informations principales qui permettront
  567. * de retrouver ce qui est à faire comme action, ce qui a été fait,
  568. * les erreurs générées, et le verrouillage.
  569. *
  570. * Le cache peut être lu avec la méthode get_actions()
  571. *
  572. * @see Actionneur::get_actions()
  573. **/
  574. function sauver_actions() {
  575. $contenu = serialize(array(
  576. 'todo' => $this->end,
  577. 'done' => $this->done,
  578. 'work' => $this->work,
  579. 'err' => $this->err,
  580. 'lock' => $this->lock,
  581. ));
  582. ecrire_fichier(_DIR_TMP . 'stp_actions.txt', $contenu);
  583. }
  584. /**
  585. * Lit le fichier cache de la liste des actions et verrou
  586. *
  587. * Restaure les informations contenues dans le fichier de cache
  588. * et écrites avec la méthode sauver_actions().
  589. *
  590. * @see Actionneur::sauver_actions()
  591. **/
  592. function get_actions() {
  593. lire_fichier(_DIR_TMP . 'stp_actions.txt', $contenu);
  594. $infos = unserialize($contenu);
  595. $this->end = $infos['todo'];
  596. $this->work = $infos['work'];
  597. $this->done = $infos['done'];
  598. $this->err = $infos['err'];
  599. $this->lock = $infos['lock'];
  600. }
  601. /**
  602. * Nettoyage des actions et verrou
  603. *
  604. * Remet tout à zéro pour pouvoir repartir d'un bon pied.
  605. **/
  606. function nettoyer_actions() {
  607. $this->todo = array();
  608. $this->done = array();
  609. $this->work = array();
  610. $this->err = array();
  611. $this->deverrouiller();
  612. $this->sauver_actions();
  613. }
  614. /**
  615. * Effectue une des actions qui reste à faire.
  616. *
  617. * Dépile une des actions à faire s'il n'y en a pas en cours
  618. * au moment de l'appel et traite cette action
  619. *
  620. * @see Actionneur::do_action()
  621. * @return bool|array
  622. * False si aucune action à faire,
  623. * sinon tableau de description courte du paquet + index 'todo' indiquant l'action
  624. **/
  625. function one_action() {
  626. // s'il reste des actions, on en prend une, et on la fait
  627. // de meme si une action est en cours mais pas terminee (timeout)
  628. // on tente de la refaire...
  629. if (count($this->end) OR $this->work) {
  630. // on verrouille avec l'auteur en cours pour
  631. // que seul lui puisse effectuer des actions a ce moment la
  632. if (!$this->est_verrouille()) {
  633. $this->verrouiller();
  634. }
  635. // si ce n'est pas verrouille par l'auteur en cours...
  636. // ce n'est pas normal, donc on quitte sans rien faire.
  637. elseif (!$this->est_verrouille($GLOBALS['visiteur_session']['id_auteur'])) {
  638. return false;
  639. }
  640. // si pas d'action en cours
  641. if (!$this->work) {
  642. // on prend une des actions en attente
  643. $this->work = array_shift($this->end);
  644. }
  645. $action = $this->work;
  646. $this->sauver_actions();
  647. // effectue l'action dans work
  648. $this->do_action();
  649. // si la liste des actions en attente est maintenant vide
  650. // on deverrouille aussitot.
  651. if (!count($this->end)) {
  652. $this->deverrouiller();
  653. $this->sauver_actions();
  654. }
  655. return $action;
  656. } else {
  657. // on ne devrait normalement plus tomber sur un cas de verrouillage ici
  658. // mais sait-on jamais. Tester ne couter rien :)
  659. if ($this->est_verrouille()) {
  660. $this->deverrouiller();
  661. $this->sauver_actions();
  662. }
  663. }
  664. return false;
  665. }
  666. /**
  667. * Effectue l'action en attente.
  668. *
  669. * Appelle une methode do_{todo} de l'Actionneur où todo
  670. * est le type d'action à faire.
  671. *
  672. * Place dans la clé 'done' de description courte du paquet
  673. * le résultat de l'action (un booléen indiquant si elle s'est bien
  674. * déroulée).
  675. **/
  676. function do_action() {
  677. if ($do = $this->work) {
  678. $todo = 'do_' . $do['todo'];
  679. lire_metas(); // avoir les metas a jour
  680. $this->log("Faire $todo avec $do[n]");
  681. $do['done'] = $this->$todo($do);
  682. $this->done[] = $do;
  683. $this->work = array();
  684. $this->sauver_actions();
  685. }
  686. }
  687. /**
  688. * Attraper et activer un paquet
  689. *
  690. * @param array $info
  691. * Description courte du paquet
  692. * @return bool
  693. * false si erreur, true sinon.
  694. */
  695. function do_geton($info) {
  696. if (!$this->tester_repertoire_plugins_auto()) {
  697. return false;
  698. }
  699. $i = sql_fetsel('*','spip_paquets','id_paquet='.sql_quote($info['i']));
  700. if ($dirs = $this->get_paquet_id($i)) {
  701. $this->activer_plugin_dossier($dirs['dossier'], $i);
  702. return true;
  703. }
  704. $this->log("GetOn : Erreur de chargement du paquet " .$info['n']);
  705. return false;
  706. }
  707. /**
  708. * Activer un paquet
  709. *
  710. * Soit il est là... soit il est à télécharger...
  711. *
  712. * @param array $info
  713. * Description courte du paquet
  714. * @return bool
  715. * false si erreur, true sinon.
  716. */
  717. function do_on($info) {
  718. $i = sql_fetsel('*','spip_paquets','id_paquet='.sql_quote($info['i']));
  719. // à télécharger ?
  720. if ($i['id_zone'] > 0) {
  721. return $this->do_geton($info);
  722. }
  723. // a activer uniquement
  724. // il faudra prendre en compte les autres _DIR_xx
  725. if (in_array($i['constante'], array('_DIR_PLUGINS','_DIR_PLUGINS_SUPPL'))) {
  726. $dossier = rtrim($i['src_archive'], '/');
  727. $this->activer_plugin_dossier($dossier, $i, $i['constante']);
  728. return true;
  729. }
  730. return false;
  731. }
  732. /**
  733. * Mettre à jour un paquet
  734. *
  735. * @param array $info
  736. * Description courte du paquet
  737. * @return bool|array
  738. * false si erreur,
  739. * description courte du nouveau plugin sinon.
  740. */
  741. function do_up($info) {
  742. // ecriture du nouveau
  743. // suppression de l'ancien (si dans auto, et pas au meme endroit)
  744. // OU suppression des anciens fichiers
  745. if (!$this->tester_repertoire_plugins_auto()) {
  746. return false;
  747. }
  748. // $i est le paquet a mettre à jour (donc present)
  749. // $maj est le paquet a telecharger qui est a jour (donc distant)
  750. $i = sql_fetsel('*','spip_paquets','id_paquet='.sql_quote($info['i']));
  751. // on cherche la mise a jour...
  752. // c'est a dire le paquet source que l'on met a jour.
  753. if ($maj = sql_fetsel('pa.*',
  754. array('spip_paquets AS pa', 'spip_plugins AS pl'),
  755. array(
  756. 'pl.prefixe='.sql_quote($info['p']),
  757. 'pa.version='.sql_quote($info['maj']),
  758. 'pa.id_plugin = pl.id_plugin',
  759. 'pa.id_depot>'.sql_quote(0)),
  760. '', 'pa.etatnum DESC', '0,1')) {
  761. if ($dirs = $this->get_paquet_id($maj)) {
  762. // Si le plugin a jour n'est pas dans le meme dossier que l'ancien...
  763. // il faut :
  764. // - activer le plugin sur son nouvel emplacement (uniquement si l'ancien est actif)...
  765. // - supprimer l'ancien (si faisable)
  766. if (($dirs['dossier'] . '/') != $i['src_archive']) {
  767. if ($i['actif'] == 'oui') {
  768. $this->activer_plugin_dossier($dirs['dossier'], $maj);
  769. }
  770. // l'ancien repertoire a supprimer pouvait etre auto/X
  771. // alors que le nouveau est auto/X/Y ...
  772. // il faut prendre en compte ce cas particulier et ne pas ecraser auto/X !
  773. if (substr($i['src_archive'], 0, 5) == 'auto/' and (false === strpos($dirs['dossier'], $i['src_archive']))) {
  774. if (supprimer_repertoire( constant($i['constante']) . $i['src_archive']) ) {
  775. sql_delete('spip_paquets', 'id_paquet=' . sql_quote($info['i']));
  776. }
  777. }
  778. }
  779. $this->ajouter_plugin_interessants_meta($dirs['dossier']);
  780. return $dirs;
  781. }
  782. }
  783. return false;
  784. }
  785. /**
  786. * Mettre à jour et activer un paquet
  787. *
  788. * @param array $info
  789. * Description courte du paquet
  790. * @return bool
  791. * false si erreur, true sinon
  792. */
  793. function do_upon($info) {
  794. $i = sql_fetsel('*', 'spip_paquets', 'id_paquet='.sql_quote($info['i']));
  795. if ($dirs = $this->do_up($info)) {
  796. $this->activer_plugin_dossier($dirs['dossier'], $i, $i['constante']);
  797. return true;
  798. }
  799. return false;
  800. }
  801. /**
  802. * Désactiver un paquet
  803. *
  804. * @param array $info
  805. * Description courte du paquet
  806. * @return bool
  807. * false si erreur, true sinon
  808. */
  809. function do_off($info) {
  810. $i = sql_fetsel('*','spip_paquets','id_paquet='.sql_quote($info['i']));
  811. // il faudra prendre en compte les autres _DIR_xx
  812. if (in_array($i['constante'], array('_DIR_PLUGINS','_DIR_PLUGINS_SUPPL'))) {
  813. include_spip('inc/plugin');
  814. $dossier = rtrim($i['src_archive'], '/');
  815. ecrire_plugin_actifs(array(rtrim($dossier,'/')), false, 'enleve');
  816. sql_updateq('spip_paquets', array('actif'=>'non', 'installe'=>'non'), 'id_paquet='.sql_quote($info['i']));
  817. $this->actualiser_plugin_interessants();
  818. // ce retour est un rien faux...
  819. // il faudrait que la fonction ecrire_plugin_actifs()
  820. // retourne au moins d'eventuels message d'erreur !
  821. return true;
  822. }
  823. return false;
  824. }
  825. /**
  826. * Désinstaller un paquet
  827. *
  828. * @param array $info
  829. * Description courte du paquet
  830. * @return bool
  831. * false si erreur, true sinon
  832. */
  833. function do_stop($info) {
  834. $i = sql_fetsel('*','spip_paquets','id_paquet=' . sql_quote($info['i']));
  835. // il faudra prendre en compte les autres _DIR_xx
  836. if (in_array($i['constante'], array('_DIR_PLUGINS','_DIR_PLUGINS_SUPPL'))) {
  837. include_spip('inc/plugin');
  838. $dossier = rtrim($i['src_archive'],'/');
  839. $installer_plugins = charger_fonction('installer', 'plugins');
  840. // retourne :
  841. // - false : pas de procedure d'install/desinstalle
  842. // - true : operation deja faite
  843. // - tableau : operation faite ce tour ci.
  844. $infos = $installer_plugins($dossier, 'uninstall');
  845. if (is_bool($infos) OR !$infos['install_test'][0]) {
  846. include_spip('inc/plugin');
  847. ecrire_plugin_actifs(array($dossier), false, 'enleve');
  848. sql_updateq('spip_paquets', array('actif'=>'non', 'installe'=>'non'), 'id_paquet='.sql_quote($info['i']));
  849. return true;
  850. } else {
  851. // echec
  852. $this->log("Échec de la désinstallation de " . $i['src_archive']);
  853. }
  854. }
  855. $this->actualiser_plugin_interessants();
  856. return false;
  857. }
  858. /**
  859. * Effacer les fichiers d'un paquet
  860. *
  861. * @param array $info
  862. * Description courte du paquet
  863. * @return bool
  864. * false si erreur, true sinon
  865. */
  866. function do_kill($info) {
  867. // on reverifie que c'est bien un plugin auto !
  868. // il faudrait aussi faire tres attention sur un site mutualise
  869. // cette option est encore plus delicate que les autres...
  870. $i = sql_fetsel('*','spip_paquets','id_paquet='.sql_quote($info['i']));
  871. if (in_array($i['constante'], array('_DIR_PLUGINS','_DIR_PLUGINS_SUPPL'))
  872. and substr($i['src_archive'], 0, 5) == 'auto/') {
  873. $dir = constant($i['constante']) . $i['src_archive'];
  874. if (supprimer_repertoire($dir)) {
  875. $id_plugin = sql_getfetsel('id_plugin', 'spip_paquets', 'id_paquet=' . sql_quote($info['i']));
  876. // on supprime le paquet
  877. sql_delete('spip_paquets', 'id_paquet=' . sql_quote($info['i']));
  878. // ainsi que le plugin s'il n'est plus utilise
  879. $utilise = sql_allfetsel(
  880. 'pl.id_plugin',
  881. array('spip_paquets AS pa', 'spip_plugins AS pl'),
  882. array('pa.id_plugin = pl.id_plugin', 'pa.id_plugin=' . sql_quote($id_plugin)));
  883. if (!$utilise) {
  884. sql_delete('spip_plugins', 'id_plugin=' . sql_quote($id_plugin));
  885. } else {
  886. // on met a jour d'eventuels obsoletes qui ne le sont plus maintenant
  887. // ie si on supprime une version superieure à une autre qui existe en local...
  888. include_spip('inc/svp_depoter_local');
  889. svp_corriger_obsolete_paquets(array($id_plugin));
  890. }
  891. // on tente un nettoyage jusqu'a la racine de auto/
  892. // si la suppression concerne une profondeur d'au moins 2
  893. // et que les repertoires sont vides
  894. $chemins = explode('/', $i['src_archive']); // auto / prefixe / version
  895. // le premier c'est auto
  896. array_shift($chemins);
  897. // le dernier est deja fait...
  898. array_pop($chemins);
  899. // entre les deux...
  900. while (count($chemins)) {
  901. $vide = true;
  902. $dir = constant($i['constante']) . 'auto/' . implode('/', $chemins);
  903. $fichiers = scandir($dir);
  904. if ($fichiers) {
  905. foreach ($fichiers as $f) {
  906. if ($f[0] != '.') {
  907. $vide = false;
  908. break;
  909. }
  910. }
  911. }
  912. // on tente de supprimer si c'est effectivement vide.
  913. if ($vide and !supprimer_repertoire($dir)) {
  914. break;
  915. }
  916. array_pop($chemins);
  917. }
  918. return true;
  919. }
  920. }
  921. return false;
  922. }
  923. /**
  924. * Installer une librairie
  925. *
  926. * @param array $info
  927. * Description courte du paquet (une librairie ici)
  928. * @return bool
  929. * false si erreur, true sinon
  930. */
  931. function do_getlib($info) {
  932. if (!defined('_DIR_LIB') or !_DIR_LIB) {
  933. $this->err(_T('svp:erreur_dir_dib_indefini'));
  934. $this->log("/!\ Pas de _DIR_LIB defini !");
  935. return false;
  936. }
  937. if (!is_writable(_DIR_LIB)) {
  938. $this->err(_T('svp:erreur_dir_dib_ecriture', array('dir' => _DIR_LIB )));
  939. $this->log("/!\ Ne peut pas écrire dans _DIR_LIB !");
  940. return false;
  941. }
  942. if(!autoriser('plugins_ajouter')){
  943. $this->err(_T('svp:erreur_auth_plugins_ajouter_lib'));
  944. $this->log("/!\ Pas autorisé à ajouter des libs !");
  945. return false;
  946. }
  947. $this->log("Recuperer la librairie : " . $info['n'] );
  948. // on recupere la mise a jour...
  949. include_spip('action/teleporter');
  950. $teleporter_composant = charger_fonction('teleporter_composant', 'action');
  951. $ok = $teleporter_composant('http', $info['v'], _DIR_LIB . $info['n']);
  952. if ($ok === true) {
  953. return true;
  954. }
  955. $this->err($ok);
  956. $this->log("Téléporteur en erreur : " . $ok);
  957. return false;
  958. }
  959. /**
  960. * Télécharger un paquet
  961. *
  962. * @param array $info
  963. * Description courte du paquet
  964. * @return bool
  965. * false si erreur, true sinon
  966. */
  967. function do_get($info) {
  968. if (!$this->tester_repertoire_plugins_auto()) {
  969. return false;
  970. }
  971. $i = sql_fetsel('*', 'spip_paquets', 'id_paquet=' . sql_quote($info['i']));
  972. if ($dirs = $this->get_paquet_id($info['i'])) {
  973. $this->ajouter_plugin_interessants_meta($dirs['dossier']);
  974. return true;
  975. }
  976. return false;
  977. }
  978. /**
  979. * Lancer l'installation d'un paquet
  980. *
  981. * @param array $info
  982. * Description courte du paquet
  983. * @return bool
  984. * false si erreur, true sinon
  985. */
  986. function do_install($info) {
  987. return $this->installer_plugin($info);
  988. }
  989. /**
  990. * Activer un plugin
  991. *
  992. * @param string $dossier
  993. * Chemin du répertoire du plugin
  994. * @param array $i
  995. * Description en BDD du paquet - row SQL (tableau clé => valeur)
  996. * @param string $constante
  997. * Constante indiquant le chemin de base du plugin (_DIR_PLUGINS, _DIR_PLUGINS_SUPPL, _DIR_PLUGINS_DIST)
  998. * @return void
  999. **/
  1000. function activer_plugin_dossier($dossier, $i, $constante='_DIR_PLUGINS') {
  1001. include_spip('inc/plugin');
  1002. $this->log("Demande d'activation de : " . $dossier);
  1003. //il faut absolument que tous les fichiers de cache
  1004. // soient inclus avant modification, sinon un appel ulterieur risquerait
  1005. // de charger des fichiers deja charges par un autre !
  1006. // C'est surtout le ficher de fonction le probleme (options et pipelines
  1007. // sont normalement deja charges).
  1008. if (@is_readable(_CACHE_PLUGINS_OPT)) {include_once(_CACHE_PLUGINS_OPT);}
  1009. if (@is_readable(_CACHE_PLUGINS_FCT)) {include_once(_CACHE_PLUGINS_FCT);}
  1010. if (@is_readable(_CACHE_PIPELINES)) {include_once(_CACHE_PIPELINES);}
  1011. include_spip('inc/plugin');
  1012. ecrire_plugin_actifs(array($dossier), false, 'ajoute');
  1013. $installe = $i['version_base'] ? 'oui' : 'non';
  1014. if ($installe == 'oui') {
  1015. if(!$i['constante'])
  1016. $i['constante'] = '_DIR_PLUGINS';
  1017. // installer le plugin au prochain tour
  1018. $new_action = array_merge($this->work, array(
  1019. 'todo'=>'install',
  1020. 'dossier'=>rtrim($dossier,'/'),
  1021. 'constante'=>$i['constante'],
  1022. 'v'=>$i['version'], // pas forcement la meme version qu'avant lors d'une mise a jour.
  1023. ));
  1024. array_unshift($this->end, $new_action);
  1025. $this->log("Demande d'installation de $dossier");
  1026. #$this->installer_plugin($dossier);
  1027. }
  1028. $this->ajouter_plugin_interessants_meta($dossier);
  1029. $this->actualiser_plugin_interessants();
  1030. }
  1031. /**
  1032. * Actualiser les plugins intéressants
  1033. *
  1034. * Décrémente chaque score de plugin présent dans la méta
  1035. * 'plugins_interessants' et signifiant que ces plugins
  1036. * ont été utilisés récemment.
  1037. *
  1038. * Les plugins atteignant un score de zéro sont évacués ce la liste.
  1039. */
  1040. function actualiser_plugin_interessants() {
  1041. // Chaque fois que l'on valide des plugins,
  1042. // on memorise la liste de ces plugins comme etant "interessants",
  1043. // avec un score initial, qui sera decremente a chaque tour :
  1044. // ainsi un plugin active pourra reter visible a l'ecran,
  1045. // jusqu'a ce qu'il tombe dans l'oubli.
  1046. $plugins_interessants = @unserialize($GLOBALS['meta']['plugins_interessants']);
  1047. if (!is_array($plugins_interessants)) {
  1048. $plugins_interessants = array();
  1049. }
  1050. $dossiers = array();
  1051. $dossiers_old = array();
  1052. foreach($plugins_interessants as $p => $score) {
  1053. if (--$score > 0) {
  1054. $plugins_interessants[$p] = $score;
  1055. $dossiers[$p.'/'] = true;
  1056. } else {
  1057. unset($plugins_interessants[$p]);
  1058. $dossiers_old[$p.'/'] = true;
  1059. }
  1060. }
  1061. // enlever les anciens
  1062. if ($dossiers_old) {
  1063. // ATTENTION, il faudra prendre en compte les _DIR_xx
  1064. sql_updateq('spip_paquets', array('recent'=>0), sql_in('src_archive', array_keys($dossiers_old)));
  1065. }
  1066. $plugs = sql_allfetsel('src_archive','spip_paquets', 'actif='.sql_quote('oui'));
  1067. $plugs = array_map('array_shift', $plugs);
  1068. foreach ($plugs as $dossier) {
  1069. $dossiers[$dossier] = true;
  1070. $plugins_interessants[ rtrim($dossier, '/') ] = 30; // score initial
  1071. }
  1072. $plugs = sql_updateq('spip_paquets', array('recent'=>1), sql_in('src_archive', array_keys($dossiers)));
  1073. ecrire_meta('plugins_interessants', serialize($plugins_interessants));
  1074. }
  1075. /**
  1076. * Ajoute un plugin dans les plugins intéressants
  1077. *
  1078. * Initialise à 30 le score du plugin indiqué par le chemin transmis,
  1079. * dans la liste des plugins intéressants.
  1080. *
  1081. * @param string $dir
  1082. * Chemin du répertoire du plugin
  1083. */
  1084. function ajouter_plugin_interessants_meta($dir) {
  1085. $plugins_interessants = @unserialize($GLOBALS['meta']['plugins_interessants']);
  1086. if (!is_array($plugins_interessants)) {
  1087. $plugins_interessants = array();
  1088. }
  1089. $plugins_interessants[$dir] = 30;
  1090. ecrire_meta('plugins_interessants', serialize($plugins_interessants));
  1091. }
  1092. /**
  1093. * Lancer l'installation d'un plugin
  1094. *
  1095. * @param array $info
  1096. * Description courte du paquet
  1097. * @return bool
  1098. * false si erreur, true sinon
  1099. */
  1100. function installer_plugin($info){
  1101. // il faut info['dossier'] et info['constante'] pour installer
  1102. if ($plug = $info['dossier']) {
  1103. $installer_plugins = charger_fonction('installer', 'plugins');
  1104. $infos = $installer_plugins($plug, 'install', $info['constante']);
  1105. if ($infos) {
  1106. // en absence d'erreur, on met a jour la liste des plugins installes...
  1107. if (!is_array($infos) OR $infos['install_test'][0]) {
  1108. $meta_plug_installes = @unserialize($GLOBALS['meta']['plugin_installes']);
  1109. if (!$meta_plug_installes) {
  1110. $meta_plug_installes=array();
  1111. }
  1112. $meta_plug_installes[] = $plug;
  1113. ecrire_meta('plugin_installes',serialize($meta_plug_installes),'non');
  1114. }
  1115. if (!is_array($infos)) {
  1116. // l'installation avait deja ete faite un autre jour
  1117. return true;
  1118. } else {
  1119. // l'installation est neuve
  1120. list($ok, $trace) = $infos['install_test'];
  1121. if ($ok) {
  1122. return true;
  1123. }
  1124. // l'installation est en erreur
  1125. $this->err(_T('svp:message_action_finale_install_fail',
  1126. array('plugin' => $info['n'], 'version'=>denormaliser_version($info['v']))) . "<br />" . $trace);
  1127. }
  1128. }
  1129. }
  1130. return false;
  1131. }
  1132. /**
  1133. * Télécharge un paquet
  1134. *
  1135. * Supprime les fichiers obsolètes (si présents)
  1136. *
  1137. * @param int|array $id_or_row
  1138. * Identifiant du paquet ou description ligne SQL du paquet
  1139. * @return bool|array
  1140. * False si erreur.
  1141. * Tableau de 2 index sinon :
  1142. * - dir : Chemin du paquet téléchargé depuis la racine
  1143. * - dossier : Chemin du paquet téléchargé, depuis _DIR_PLUGINS
  1144. */
  1145. function get_paquet_id($id_or_row) {
  1146. // on peut passer direct le row sql...
  1147. if (!is_array($id_or_row)) {
  1148. $i = sql_fetsel('*','spip_paquets','id_paquet='.sql_quote($id_or_row));
  1149. } else {
  1150. $i = $id_or_row;
  1151. }
  1152. unset($id_or_row);
  1153. if ($i['nom_archive'] and $i['id_depot']) {
  1154. $this->log("Recuperer l'archive : " . $i['nom_archive'] );
  1155. if ($adresse = sql_getfetsel('url_archives', 'spip_depots', 'id_depot='.sql_quote($i['id_depot']))) {
  1156. $zip = $adresse . '/' . $i['nom_archive'];
  1157. // destination : auto/prefixe/version (sinon auto/nom_archive/version)
  1158. $prefixe = sql_getfetsel('pl.prefixe',
  1159. array('spip_paquets AS pa', 'spip_plugins AS pl'),
  1160. array('pa.id_plugin = pl.id_plugin', 'pa.id_paquet=' . sql_quote($i['id_paquet'])));
  1161. // prefixe
  1162. $base = ($prefixe ? strtolower($prefixe) : substr($i['nom_archive'], 0, -4) ); // enlever .zip ...
  1163. // prefixe/version
  1164. $dest = $base . '/v' . denormaliser_version($i['version']);
  1165. // si on tombe sur un auto/X ayant des fichiers (et pas uniquement des dossiers)
  1166. // ou un dossier qui ne commence pas par 'v'
  1167. // c'est que auto/X n'était pas chargé avec SVP
  1168. // ce qui peut arriver lorsqu'on migre de SPIP 2.1 à 3.0
  1169. // dans ce cas, on supprime auto X pour mettre notre nouveau paquet.
  1170. $ecraser_base = false;
  1171. if (is_dir(_DIR_PLUGINS_AUTO . $base)) {
  1172. $base_files = scandir(_DIR_PLUGINS_AUTO . $base);
  1173. if (is_array($base_files)) {
  1174. $base_files = array_diff($base_files, array('.', '..'));
  1175. foreach ($base_files as $f) {
  1176. if (($f[0] != '.' and $f[0] != 'v') // commence pas par v
  1177. OR ($f[0] != '.' and !is_dir(_DIR_PLUGINS_AUTO . $base . '/' . $f))) { // commence par v mais pas repertoire
  1178. $ecraser_base = true;
  1179. break;
  1180. }
  1181. }
  1182. }
  1183. }
  1184. if ($ecraser_base) {
  1185. supprimer_repertoire(_DIR_PLUGINS_AUTO . $base);
  1186. }
  1187. // on recupere la mise a jour...
  1188. include_spip('action/teleporter');
  1189. $teleporter_composant = charger_fonction('teleporter_composant', 'action');
  1190. $ok = $teleporter_composant('http', $zip, _DIR_PLUGINS_AUTO . $dest);
  1191. if ($ok === true) {
  1192. return array(
  1193. 'dir'=> _DIR_PLUGINS_AUTO . $dest,
  1194. 'dossier' => 'auto/' . $dest, // c'est depuis _DIR_PLUGINS ... pas bien en dur...
  1195. );
  1196. }
  1197. $this->err($ok);
  1198. $this->log("Téléporteur en erreur : " . $ok);
  1199. } else {
  1200. $this->log("Aucune adresse pour le dépot " . $i['id_depot'] );
  1201. }
  1202. }
  1203. return false;
  1204. }
  1205. /**
  1206. * Teste que le répertoire plugins auto existe et
  1207. * que l'on peut ecrire dedans !
  1208. *
  1209. * @return bool
  1210. * True si on peut écrire dedans, false sinon
  1211. **/
  1212. function tester_repertoire_plugins_auto() {
  1213. include_spip('inc/plugin'); // pour _DIR_PLUGINS_AUTO
  1214. if (!defined('_DIR_PLUGINS_AUTO') or !_DIR_PLUGINS_AUTO) {
  1215. $this->err(_T('svp:erreur_dir_plugins_auto_indefini'));
  1216. $this->log("/!\ Pas de _DIR_PLUGINS_AUTO defini !");
  1217. return false;
  1218. }
  1219. if (!is_writable(_DIR_PLUGINS_AUTO)) {
  1220. $this->err(_T('svp:erreur_dir_plugins_auto_ecriture', array('dir'=>_DIR_PLUGINS_AUTO)));
  1221. $this->log("/!\ Ne peut pas écrire dans _DIR_PLUGINS_AUTO !");
  1222. return false;
  1223. }
  1224. return true;
  1225. }
  1226. /**
  1227. * Teste si le plugin SVP (celui-ci donc) a
  1228. * été désinstallé / désactivé dans les actions réalisées
  1229. *
  1230. * @note
  1231. * On ne peut tester sa désactivation que dans le hit où la désinstallation
  1232. * est réalisée, puisque après, s'il a été désactivé, au prochain hit
  1233. * on ne connaîtra plus ce fichier !
  1234. *
  1235. * @return bool
  1236. * true si SVP a été désactivé, false sinon
  1237. **/
  1238. function tester_si_svp_desactive() {
  1239. foreach ($this->done as $d) {
  1240. if ($d['p'] == 'SVP'
  1241. AND $d['done'] == true
  1242. AND in_array($d['todo'], array('off', 'stop'))) {
  1243. return true;
  1244. }
  1245. }
  1246. return false;
  1247. }
  1248. }
  1249. /**
  1250. * Gère le traitement des actions des formulaires utilisant l'Actionneur
  1251. *
  1252. * @param array $actions
  1253. * Liste des actions a faire (id_paquet => action)
  1254. * @param array $retour
  1255. * Tableau de retour du CVT dans la partie traiter
  1256. * @param string $redirect
  1257. * URL de retour
  1258. * @return void
  1259. **/
  1260. function svp_actionner_traiter_actions_demandees($actions, &$retour,$redirect=null) {
  1261. $actionneur = new Actionneur();
  1262. $actionneur->ajouter_actions($actions);
  1263. $actionneur->verrouiller();
  1264. $actionneur->sauver_actions();
  1265. $redirect = $redirect ? $redirect : generer_url_ecrire('admin_plugin');
  1266. $retour['redirect'] = generer_url_action('actionner', 'redirect='.urlencode($redirect));
  1267. set_request('_todo', '');
  1268. $retour['message_ok'] = _T("svp:action_patienter");
  1269. }
  1270. ?>