PageRenderTime 25ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/ecrire/inc/admin.php

https://bitbucket.org/re_al_/real.test.spip
PHP | 299 lines | 129 code | 25 blank | 145 comment | 26 complexity | 63e4ed0d22c9364550014624dfbe0614 MD5 | raw file
Possible License(s): LGPL-2.1, MIT
  1. <?php
  2. /***************************************************************************\
  3. * SPIP, Systeme de publication pour l'internet *
  4. * *
  5. * Copyright (c) 2001-2017 *
  6. * Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
  7. * *
  8. * Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
  9. * Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne. *
  10. \***************************************************************************/
  11. /**
  12. * Gestion d'administration d'un SPIP
  13. *
  14. * @param SPIP\Core\Admin
  15. **/
  16. if (!defined('_ECRIRE_INC_VERSION')) {
  17. return;
  18. }
  19. /**
  20. * Teste qu'un utilisateur a des droits sur les fichiers du site et
  21. * exécute l'action (en base) demandée si c'est le cas.
  22. *
  23. * Demande / vérifie le droit de création de répertoire par le demandeur;
  24. * Mémorise dans les meta que ce script est en cours d'exécution.
  25. * Si elle y est déjà c'est qu'il y a eu suspension du script, on reprend.
  26. *
  27. * @uses debut_admin()
  28. * @uses admin_verifie_session()
  29. * @uses fin_admin()
  30. *
  31. * @param string $script
  32. * Script d'action (en base) à exécuter si on a des droits d'accès aux fichiers
  33. * @param string $titre
  34. * Titre de l'action demandée
  35. * @param string $comment
  36. * Commentaire supplémentaire
  37. * @param bool $anonymous
  38. * ?
  39. * @return string
  40. * Code HTML de la page (pour vérifier les droits),
  41. * sinon code HTML de la page après le traitement effectué.
  42. **/
  43. function inc_admin_dist($script, $titre, $comment = '', $anonymous = false) {
  44. $reprise = true;
  45. if (!isset($GLOBALS['meta'][$script])
  46. or !isset($GLOBALS['meta']['admin'])
  47. ) {
  48. $reprise = false;
  49. $res = debut_admin($script, $titre, $comment);
  50. if ($res) {
  51. return $res;
  52. }
  53. spip_log("meta: $script " . join(',', $_POST));
  54. ecrire_meta($script, serialize($_POST));
  55. }
  56. $res = admin_verifie_session($script, $anonymous);
  57. if ($res) {
  58. return $res;
  59. }
  60. $base = charger_fonction($script, 'base');
  61. $base($titre, $reprise);
  62. fin_admin($script);
  63. return '';
  64. }
  65. /**
  66. * Gestion dans la meta "admin" du script d'administation demandé,
  67. * pour éviter des exécutions en parallèle, notamment après Time-Out.
  68. *
  69. * Cette meta contient le nom du script et, à un hachage près, du demandeur.
  70. * Le code de ecrire/index.php dévie toute demande d'exécution d'un script
  71. * vers le script d'administration indiqué par cette meta si elle est là.
  72. *
  73. * Au niveau de la fonction inc_admin, on controle la meta 'admin'.
  74. *
  75. * - Si la meta n'est pas là, c'est le début on la crée.
  76. * - Sinon, si le hachage actuel est le même que celui en base,
  77. * c'est une reprise, on continue.
  78. * - Sinon, si le hachage diffère à cause du connect, c'est une arrivée
  79. * inoppotune, on refuse sa connexion.
  80. * - Enfin, si hachage diffère pour une autre raison, c'est que l'operation
  81. * se passe mal, on la stoppe
  82. *
  83. * @uses fichier_admin()
  84. *
  85. * @param string $script
  86. * Script d'action (en base)
  87. * @param bool $anonymous
  88. * ?
  89. * @return string
  90. * Code HTML si message d'erreur, '' sinon;
  91. */
  92. function admin_verifie_session($script, $anonymous = false) {
  93. include_spip('base/abstract_sql');
  94. $pref = sprintf('_%d_', $GLOBALS['visiteur_session']['id_auteur']);
  95. $signal = fichier_admin($script, "$script$pref");
  96. $valeur = sql_getfetsel('valeur', 'spip_meta', "nom='admin'");
  97. if ($valeur === null) {
  98. ecrire_meta('admin', $signal, 'non');
  99. } else {
  100. if (!$anonymous and ($valeur != $signal)) {
  101. if (!preg_match('/^(.*)_(\d+)_/', $GLOBALS['meta']['admin'], $l)
  102. or intval($l[2]) != $GLOBALS['visiteur_session']['id_auteur']
  103. ) {
  104. include_spip('inc/minipres');
  105. spip_log("refus de lancer $script, priorite a $valeur");
  106. return minipres(_T('info_travaux_texte'), '', array('status' => 503));
  107. }
  108. }
  109. }
  110. $journal = 'spip';
  111. if (autoriser('configurer')) {
  112. // c'est une action webmestre, soit par ftp soit par statut webmestre
  113. $journal = 'webmestre';
  114. }
  115. // on pourrait statuer automatiquement les webmestres a l'init d'une action auth par ftp ... ?
  116. spip_log("admin $pref" . ($valeur ? ' (reprise)' : ' (init)'), $journal);
  117. return '';
  118. }
  119. /**
  120. * Retourne l'emplacement du répertoire où sera testé l'accès utilisateur
  121. *
  122. * Dans le répertoire temporaire si on est admin, sinon dans le répertoire
  123. * de transfert des admins restreints
  124. *
  125. * @return string
  126. * Chemin du répertoire.
  127. **/
  128. function dir_admin() {
  129. if (autoriser('configurer')) {
  130. return _DIR_TMP;
  131. } else {
  132. return _DIR_TRANSFERT . $GLOBALS['visiteur_session']['login'] . '/';
  133. }
  134. }
  135. /**
  136. * Retourne le nom d'un fichier de teste d'authentification par accès
  137. * aux fichiers
  138. *
  139. * Le nom calculé est un hash basé sur l’heure, l’action et l’auteur.
  140. *
  141. * @param string $action
  142. * Nom du script d'action (en base)
  143. * @param string $pref
  144. * Préfixe au nom du fichier calculé
  145. * @return string
  146. * Nom du fichier
  147. **/
  148. function fichier_admin($action, $pref = 'admin_') {
  149. return $pref .
  150. substr(md5($action . (time() & ~2047) . $GLOBALS['visiteur_session']['login']), 0, 10);
  151. }
  152. /**
  153. * Demande la création d'un répertoire (pour tester l'accès de l'utilisateur)
  154. * et sort ou quitte sans rien faire si le répertoire est déjà là.
  155. *
  156. * Si l'on est webmestre, la plupart des actions n'ont pas besoin
  157. * de tester la création du répertoire (toutes sauf repair ou delete_all).
  158. * On considère qu'un webmestre a déjà du prouver ses droits sur les fichiers.
  159. * Dans ce cas, on quitte sans rien faire également.
  160. *
  161. * @uses dir_admin()
  162. * @uses fichier_admin()
  163. *
  164. * @param string $script
  165. * Script d'action (en base) à exécuter ensuite
  166. * @param string $action
  167. * Titre de l'action demandée
  168. * @param string $corps
  169. * Commentaire supplémentaire
  170. * @return string
  171. * Code HTML de la page (pour vérifier les droits),
  172. * sinon chaîne vide si déjà fait.
  173. **/
  174. function debut_admin($script, $action = '', $corps = '') {
  175. if ((!$action) || !(autoriser('webmestre') or autoriser('chargerftp'))) {
  176. include_spip('inc/minipres');
  177. return minipres();
  178. } else {
  179. $dir = dir_admin();
  180. $signal = fichier_admin($script);
  181. if (@file_exists($dir . $signal)) {
  182. spip_log("Action admin: $action");
  183. return '';
  184. }
  185. include_spip('inc/minipres');
  186. // Si on est un super-admin, un bouton de validation suffit
  187. // sauf dans les cas destroy
  188. if ((autoriser('webmestre') or $script === 'repair')
  189. and $script != 'delete_all'
  190. ) {
  191. if (_request('validation_admin') == $signal) {
  192. spip_log("Action super-admin: $action");
  193. return '';
  194. }
  195. $corps .= '<input type="hidden" name="validation_admin" value="' . $signal . '" />';
  196. $suivant = _T('bouton_valider');
  197. $js = '';
  198. } else {
  199. // cet appel permet d'assurer un copier-coller du nom du repertoire a creer dans tmp (esj)
  200. // l'insertion du script a cet endroit n'est pas xhtml licite
  201. // mais evite de l'embarquer dans toutes les pages minipres
  202. $corps .= http_script('', 'spip_barre.js');
  203. $corps .= '<fieldset><legend>'
  204. . _T('info_authentification_ftp')
  205. . aider('ftp_auth')
  206. . "</legend>\n<label for='fichier'>"
  207. . _T('info_creer_repertoire')
  208. . "</label>\n"
  209. . "<span id='signal' class='formo'>" . $signal . '</span>'
  210. . "<input type='hidden' id='fichier' name='fichier' value='"
  211. . $signal
  212. . "' />"
  213. . _T('info_creer_repertoire_2', array('repertoire' => joli_repertoire($dir)))
  214. . '</fieldset>';
  215. $suivant = _T('bouton_recharger_page');
  216. // code volontairement tordu:
  217. // provoquer la copie dans le presse papier du nom du repertoire
  218. // en remettant a vide le champ pour que ca marche aussi en cas
  219. // de JavaScript inactif.
  220. $js = " onload='var range=document.createRange(); var signal = document.getElementById(\"signal\"); var userSelection = window.getSelection(); range.setStart(signal,0); range.setEnd(signal,1); userSelection.addRange(range);'";
  221. }
  222. // admin/xxx correspond
  223. // a exec/base_xxx de preference
  224. // et exec/xxx sinon (compat)
  225. if (tester_url_ecrire("base_$script")) {
  226. $script = "base_$script";
  227. }
  228. $form = copy_request($script, $corps, $suivant);
  229. $info_action = _T('info_action', array('action' => "$action"));
  230. return minipres($info_action, $form, $js);
  231. }
  232. }
  233. /**
  234. * Clôture la phase d'administration en supprimant le répertoire
  235. * testant l'accès au fichiers ainsi que les metas d'exécution
  236. *
  237. * @param string $action
  238. * Nom de l'action (en base) qui a été exécutée
  239. **/
  240. function fin_admin($action) {
  241. $signal = dir_admin() . fichier_admin($action);
  242. spip_unlink($signal);
  243. if ($action != 'delete_all') {
  244. effacer_meta($action);
  245. effacer_meta('admin');
  246. spip_log("efface les meta admin et $action ");
  247. }
  248. }
  249. /**
  250. * Génère un formulaire avec les données postées
  251. *
  252. * Chaque donnée est mise en input hidden pour
  253. * les soumettre avec la validation du formulaire.
  254. *
  255. * @param string $script
  256. * Nom du script (pour l'espace privé) de destination
  257. * @param string $suite
  258. * Corps du formulaire
  259. * @param string $submit
  260. * Texte du bouton de validation
  261. * @return string
  262. * Code HTML du formulaire
  263. **/
  264. function copy_request($script, $suite, $submit = '') {
  265. include_spip('inc/filtres');
  266. foreach (array_merge($_POST, $_GET) as $n => $c) {
  267. if (!in_array($n, array('fichier', 'exec', 'validation_admin')) and !is_array($c)) {
  268. $suite .= "\n<input type='hidden' name='" . spip_htmlspecialchars($n) . "' value='" .
  269. entites_html($c) .
  270. "' />";
  271. }
  272. }
  273. return generer_form_ecrire($script, $suite, '', $submit);
  274. }