Dépôt officiel du core SPIP * Anciennement présent sur svn://trac.rezo.net/spip * Les plugins-dist faisant partie de la distribution SPIP sont présents dans https://git.spip.net/SPIP/[nom du plugin dist] https://www.spip.net
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 
 

745 lignes
22 KiB

  1. <?php
  2. /***************************************************************************\
  3. * SPIP, Système de publication pour l'internet *
  4. * *
  5. * Copyright © avec tendresse depuis 2001 *
  6. * Arnaud Martin, Antoine Pitrou, Philippe Rivière, Emmanuel Saint-James *
  7. * *
  8. * Ce programme est un logiciel libre distribué sous licence GNU/GPL. *
  9. * Pour plus de détails voir le fichier COPYING.txt ou l'aide en ligne. *
  10. \***************************************************************************/
  11. /**
  12. * Gestion de l'authentification par sessions
  13. * à utiliser pour valider l'accès (bloquant)
  14. * ou pour reconnaître un utilisateur (non bloquant)
  15. *
  16. * @package SPIP\Core\Session
  17. */
  18. if (!defined('_ECRIRE_INC_VERSION')) {
  19. return;
  20. }
  21. $GLOBALS['visiteur_session'] = array(); # globale decrivant l'auteur
  22. /**
  23. * 3 actions sur les sessions, selon le type de l'argument:
  24. *
  25. * - numerique: efface toutes les sessions de l'auteur (retour quelconque)
  26. * - tableau: cree une session pour l'auteur decrit et retourne l'identifiant
  27. * - bool: predicat de validite de la session indiquee par le cookie
  28. *
  29. * @uses supprimer_sessions()
  30. * @uses ajouter_session()
  31. * @uses verifier_session()
  32. *
  33. * @param int|array|bool $auteur
  34. * @return bool|null|void
  35. */
  36. function inc_session_dist($auteur = false) {
  37. if (is_numeric($auteur)) {
  38. return supprimer_sessions($auteur, $auteur > 0);
  39. } else {
  40. if (is_array($auteur)) {
  41. return ajouter_session($auteur);
  42. } else {
  43. return verifier_session($auteur);
  44. }
  45. }
  46. }
  47. /**
  48. * Supprimer toutes les vieilles sessions d'un auteur
  49. *
  50. * Cette fonction efface toutes les sessions appartenant a l'auteur
  51. * On en profite pour effacer toutes les sessions
  52. * creees il y a plus de 4*_RENOUVELLE_ALEA
  53. * Tenir compte de l'ancien format ou les noms commencaient par "session_"
  54. * et du meme coup des repertoires plats
  55. *
  56. * Attention : id_auteur peut etre negatif (cas des auteurs temporaires pendant le dump)
  57. *
  58. * @uses verifier_session()
  59. * @uses fichier_session()
  60. * @uses spip_session()
  61. *
  62. * @param int $id_auteur
  63. * Identifiant d'auteur dont on veut supprimer les sessions
  64. * @param bool $toutes
  65. * Supprimer aussi les vieilles sessions des autres auteurs ?
  66. * @param bool $actives
  67. * false pour ne pas supprimer les sessions valides de $id_auteur.
  68. * false revient donc a uniquement supprimer les vieilles sessions !
  69. */
  70. function supprimer_sessions($id_auteur, $toutes = true, $actives = true) {
  71. $nb_files = 0;
  72. $nb_max_files = (defined('_MAX_NB_SESSIONS_OUVERTES') ? _MAX_NB_SESSIONS_OUVERTES : 1000);
  73. spip_log("supprimer sessions auteur $id_auteur", "session");
  74. if ($toutes or $id_auteur !== $GLOBALS['visiteur_session']['id_auteur']) {
  75. if ($dir = opendir(_DIR_SESSIONS)) {
  76. $t = $_SERVER['REQUEST_TIME'] - (4*_RENOUVELLE_ALEA); // 48h par defaut
  77. $t_short = $_SERVER['REQUEST_TIME'] - max(_RENOUVELLE_ALEA/4,3*3600); // 3h par defaut
  78. $t = time() - (4 * _RENOUVELLE_ALEA);
  79. while (($f = readdir($dir)) !== false) {
  80. $nb_files++;
  81. if (preg_match(",^[^\d-]*(-?\d+)_\w{32}\.php[3]?$,", $f, $regs)) {
  82. $f = _DIR_SESSIONS . $f;
  83. if (($actives and $regs[1] == $id_auteur) or ($t > filemtime($f))) {
  84. spip_unlink($f);
  85. }
  86. // si il y a trop de sessions ouvertes, on purge les sessions anonymes de plus de 3H
  87. // cf http://core.spip.org/issues/3276
  88. elseif ($nb_files>$nb_max_files and !intval($regs[1]) and ($t_short > filemtime($f))) {
  89. spip_unlink($f);
  90. }
  91. }
  92. }
  93. }
  94. } else {
  95. verifier_session();
  96. spip_unlink(fichier_session('alea_ephemere', true));
  97. }
  98. // forcer le recalcul de la session courante
  99. spip_session(true);
  100. }
  101. /**
  102. * Ajoute une session pour l'auteur décrit par un tableau issu d'un SELECT-SQL
  103. *
  104. * @uses spip_php_session_start() Lorsque session anonyme
  105. * @uses hash_env()
  106. * @uses preparer_ecriture_session()
  107. * @uses fichier_session()
  108. * @uses ecrire_fichier_session()
  109. *
  110. * @param array $auteur
  111. * Description de la session de l'auteur. Peut contenir (par exemple)
  112. * les clés : id_auteur, nom, login, email, statut, lang, ...
  113. * @return bool|string
  114. */
  115. function ajouter_session($auteur) {
  116. // Si le client a deja une session valide pour son id_auteur
  117. // on conserve le meme fichier
  118. // Attention un visiteur peut avoir une session et un id=0,
  119. // => ne pas melanger les sessions des differents visiteurs
  120. $id_auteur = isset($auteur['id_auteur']) ? intval($auteur['id_auteur']) : 0;
  121. // Si ce n'est pas un inscrit (les inscrits ont toujours des choses en session)
  122. // on va vérifier s'il y a vraiment des choses à écrire
  123. if (!$id_auteur) {
  124. // On supprime les données de base pour voir le contenu réel de la session
  125. $auteur_verif = $auteur;
  126. if (isset($auteur_verif['id_auteur'])) {
  127. unset($auteur_verif['id_auteur']);
  128. }
  129. if (isset($auteur_verif['hash_env'])) {
  130. unset($auteur_verif['hash_env']);
  131. }
  132. if (isset($auteur_verif['ip_change'])) {
  133. unset($auteur_verif['ip_change']);
  134. }
  135. if (isset($auteur_verif['date_session'])) {
  136. unset($auteur_verif['date_session']);
  137. }
  138. // Les variables vraiment nulle ne sont pas à prendre en compte non plus
  139. foreach ($auteur_verif as $variable => $valeur) {
  140. if ($valeur === null) {
  141. unset($auteur_verif[$variable]);
  142. }
  143. }
  144. // Si après ça la session est vide alors on supprime l'éventuel fichier et on arrête là
  145. if (!$auteur_verif) {
  146. if (isset($_COOKIE['spip_session']) and isset($_SESSION[$_COOKIE['spip_session']])) {
  147. unset($_SESSION[$_COOKIE['spip_session']]);
  148. }
  149. if (isset($_COOKIE['spip_session'])) {
  150. unset($_COOKIE['spip_session']);
  151. }
  152. return false;
  153. }
  154. }
  155. if (!isset($_COOKIE['spip_session'])
  156. or !preg_match(',^' . $id_auteur . '_,', $_COOKIE['spip_session'])
  157. ) {
  158. $_COOKIE['spip_session'] = $id_auteur . '_' . md5(uniqid(rand(), true));
  159. }
  160. // Maintenant on sait qu'on a des choses à écrire
  161. // On s'assure d'avoir au moins ces valeurs
  162. $auteur['id_auteur'] = $id_auteur;
  163. if (!isset($auteur['hash_env'])) {
  164. $auteur['hash_env'] = hash_env();
  165. }
  166. if (!isset($auteur['ip_change'])) {
  167. $auteur['ip_change'] = false;
  168. }
  169. if (!isset($auteur['date_session'])) {
  170. $auteur['date_session'] = time();
  171. }
  172. if (isset($auteur['prefs'])
  173. and is_string($auteur['prefs'])
  174. and $prefs = @unserialize($auteur['prefs'])) {
  175. $auteur['prefs'] = $prefs;
  176. }
  177. $fichier_session = "";
  178. // les sessions anonymes sont stockees dans $_SESSION
  179. if (!$id_auteur) {
  180. spip_php_session_start();
  181. $_SESSION[$_COOKIE['spip_session']] = preparer_ecriture_session($auteur);
  182. } else {
  183. $fichier_session = fichier_session('alea_ephemere');
  184. if (!ecrire_fichier_session($fichier_session, $auteur)) {
  185. spip_log('Echec ecriture fichier session ' . $fichier_session, "session" . _LOG_HS);
  186. include_spip('inc/minipres');
  187. echo minipres();
  188. exit;
  189. }
  190. // verifier et limiter le nombre maxi de sessions
  191. // https://core.spip.net/issues/3807
  192. lister_sessions_auteur($id_auteur);
  193. }
  194. // poser le cookie de session SPIP
  195. include_spip('inc/cookie');
  196. $duree = definir_duree_cookie_session($auteur);
  197. spip_setcookie( 'spip_session', $_COOKIE['spip_session'], [
  198. 'expires' => time() + $duree
  199. ]);
  200. spip_log("ajoute session $fichier_session cookie $duree", "session");
  201. // Si on est admin, poser le cookie de correspondance
  202. if (!function_exists('autoriser')) {
  203. include_spip('inc/autoriser');
  204. }
  205. if (autoriser('ecrire','','',$auteur) and _DUREE_COOKIE_ADMIN) {
  206. spip_setcookie('spip_admin', '@' . ($auteur['email'] ?: $auteur['login']), [
  207. 'expires' => time() + max(_DUREE_COOKIE_ADMIN, $duree)
  208. ]);
  209. } // sinon le supprimer ...
  210. else {
  211. spip_setcookie('spip_admin', '', [
  212. 'expires' => 1
  213. ]);
  214. }
  215. # on en profite pour purger les vieilles sessions anonymes abandonnees
  216. # supprimer_sessions(0, true, false);
  217. return $_COOKIE['spip_session'];
  218. }
  219. /**
  220. * Calcule le temps de validité en seconde du cookie de session
  221. *
  222. * Applique un coefficient multiplicateur à la durée de renouvellement de l'alea
  223. * (noté ensuite `dR`, valant 12h par défaut) pour déterminer la durée du cookie.
  224. *
  225. * - `2 * dR`, par défaut
  226. * - `20 * dR` si le visiteur a indiqué vouloir rester connecté quelques jours
  227. * sur le formulaire de login (la clé `cookie` vaut alors `oui`)
  228. * - `c * dR`, un coeficient défini manuellement si la clé `cookie` est numérique
  229. *
  230. * @param array $auteur
  231. * Description de l'auteur
  232. * @return int
  233. * Durée en secondes
  234. **/
  235. function definir_duree_cookie_session($auteur) {
  236. $coef = 2;
  237. if (isset($auteur['cookie'])) {
  238. if (is_numeric($auteur['cookie'])) {
  239. $coef = $auteur['cookie'];
  240. } else {
  241. $coef = 20;
  242. }
  243. }
  244. return (int)(_RENOUVELLE_ALEA * $coef);
  245. }
  246. /**
  247. * Vérifie si le cookie spip_session indique une session valide
  248. *
  249. * Si oui, la decrit dans le tableau $visiteur_session et retourne id_auteur
  250. * La rejoue si IP change puis accepte le changement si $change=true
  251. *
  252. * Retourne false en cas d'echec, l'id_auteur de la session si defini, null sinon
  253. *
  254. * @uses spip_php_session_start() Si session anonyme
  255. * @uses fichier_session()
  256. * @uses ajouter_session()
  257. * @uses hash_env()
  258. *
  259. * @param bool $change
  260. * @return bool|int|null
  261. */
  262. function verifier_session($change = false) {
  263. // si pas de cookie, c'est fichu
  264. if (!isset($_COOKIE['spip_session'])) {
  265. return false;
  266. }
  267. $fichier_session = "";
  268. // est-ce une session anonyme ?
  269. if (!intval($_COOKIE['spip_session'])) {
  270. spip_php_session_start();
  271. if (!isset($_SESSION[$_COOKIE['spip_session']]) or !is_array($_SESSION[$_COOKIE['spip_session']])) {
  272. return false;
  273. }
  274. $GLOBALS['visiteur_session'] = $_SESSION[$_COOKIE['spip_session']];
  275. } else {
  276. // Tester avec alea courant
  277. $fichier_session = fichier_session('alea_ephemere', true);
  278. if ($fichier_session and @file_exists($fichier_session)) {
  279. include($fichier_session);
  280. } else {
  281. // Sinon, tester avec alea precedent
  282. $fichier_session = fichier_session('alea_ephemere_ancien', true);
  283. if (!$fichier_session or !@file_exists($fichier_session)) {
  284. return false;
  285. }
  286. // Renouveler la session avec l'alea courant
  287. include($fichier_session);
  288. spip_log('renouvelle session ' . $GLOBALS['visiteur_session']['id_auteur'], "session");
  289. spip_unlink($fichier_session);
  290. ajouter_session($GLOBALS['visiteur_session']);
  291. }
  292. }
  293. // Compatibilite ascendante : auteur_session est visiteur_session si
  294. // c'est un auteur SPIP authentifie (tandis qu'un visiteur_session peut
  295. // n'etre qu'identifie, sans aucune authentification).
  296. if (isset($GLOBALS['visiteur_session']['id_auteur']) and $GLOBALS['visiteur_session']['id_auteur']) {
  297. $GLOBALS['auteur_session'] = &$GLOBALS['visiteur_session'];
  298. }
  299. // Si l'adresse IP change, inc/presentation mettra une balise image
  300. // avec un URL de rappel demandant a changer le nom de la session.
  301. // Seul celui qui a l'IP d'origine est rejoue
  302. // ainsi un eventuel voleur de cookie ne pourrait pas deconnecter
  303. // sa victime, mais se ferait deconnecter par elle.
  304. if (hash_env() != $GLOBALS['visiteur_session']['hash_env']) {
  305. if (!$GLOBALS['visiteur_session']['ip_change']) {
  306. define('_SESSION_REJOUER', true);
  307. $GLOBALS['visiteur_session']['ip_change'] = true;
  308. ajouter_session($GLOBALS['visiteur_session']);
  309. } else {
  310. if ($change) {
  311. spip_log("session non rejouee, vol de cookie ?", "session");
  312. }
  313. }
  314. } else {
  315. if ($change) {
  316. spip_log("rejoue session $fichier_session " . $_COOKIE['spip_session'], "session");
  317. if ($fichier_session) {
  318. spip_unlink($fichier_session);
  319. }
  320. $GLOBALS['visiteur_session']['ip_change'] = false;
  321. unset($_COOKIE['spip_session']);
  322. ajouter_session($GLOBALS['visiteur_session']);
  323. }
  324. }
  325. // Si la session a ete initiee il y a trop longtemps, elle est annulee
  326. if (isset($GLOBALS['visiteur_session'])
  327. and defined('_AGE_SESSION_MAX')
  328. and _AGE_SESSION_MAX > 0
  329. and time() - @$GLOBALS['visiteur_session']['date_session'] > _AGE_SESSION_MAX
  330. ) {
  331. unset($GLOBALS['visiteur_session']);
  332. return false;
  333. }
  334. return is_numeric($GLOBALS['visiteur_session']['id_auteur'])
  335. ? $GLOBALS['visiteur_session']['id_auteur']
  336. : null;
  337. }
  338. /**
  339. * Lire une valeur dans la session SPIP
  340. *
  341. * @api
  342. * @example `$login = session_get('login');`
  343. *
  344. * @param string $nom
  345. * Clé dont on souhaite la valeur
  346. * @return mixed|null
  347. * Valeur, si trouvée, `null` sinon.
  348. */
  349. function session_get($nom) {
  350. return isset($GLOBALS['visiteur_session'][$nom]) ? $GLOBALS['visiteur_session'][$nom] : null;
  351. }
  352. /**
  353. * Ajouter une donnée dans la session SPIP
  354. *
  355. * @api
  356. * @uses ajouter_session()
  357. * @uses terminer_actualiser_sessions() Ajoute la fonction en fin de hit.
  358. *
  359. * @param string $nom
  360. * @param null $val
  361. * @return void|array
  362. */
  363. function session_set($nom, $val = null) {
  364. static $remove = array();
  365. static $actualiser_sessions = false;
  366. if ($nom === false) {
  367. return $remove;
  368. }
  369. if (is_null($val)) {
  370. // rien a faire
  371. if (!isset($GLOBALS['visiteur_session'][$nom])) {
  372. return;
  373. }
  374. unset($GLOBALS['visiteur_session'][$nom]);
  375. $remove[] = $nom;
  376. } else {
  377. // On ajoute la valeur dans la globale
  378. $GLOBALS['visiteur_session'][$nom] = $val;
  379. if ($remove) {
  380. $remove = array_diff($remove, array($nom));
  381. }
  382. }
  383. if (!$actualiser_sessions) {
  384. // il faut creer la session si on en a pas, la premiere fois
  385. ajouter_session($GLOBALS['visiteur_session']);
  386. // in register la fonction qui mettra a jour toutes les sessions en fin de hit
  387. register_shutdown_function('terminer_actualiser_sessions');
  388. $actualiser_sessions = true;
  389. }
  390. }
  391. /**
  392. * En fin de hit, synchroniser toutes les sessions
  393. *
  394. * @uses actualiser_sessions()
  395. */
  396. function terminer_actualiser_sessions() {
  397. // se remettre dans le dossier de travail au cas ou Apache a change
  398. chdir(_ROOT_CWD);
  399. // recuperer les variables a effacer
  400. $remove = session_set(false);
  401. // mettre a jour toutes les sessions
  402. actualiser_sessions($GLOBALS['visiteur_session'], $remove);
  403. }
  404. /**
  405. * Mettre à jour les sessions existantes pour un auteur
  406. *
  407. * Quand on modifie une fiche auteur on appelle cette fonction qui va
  408. * mettre à jour les fichiers de session de l'auteur en question.
  409. * (auteurs identifiés seulement)
  410. *
  411. * Ne concerne que les sessions des auteurs loges (id_auteur connu)
  412. *
  413. * @uses ajouter_session()
  414. * @uses fichier_session()
  415. * @uses preg_files()
  416. * @uses preparer_ecriture_session()
  417. * @uses ecrire_fichier_session()
  418. *
  419. * @param array $auteur
  420. * @param array $supprimer_cles
  421. * Liste des clés à supprimer des tableaux de sessions
  422. */
  423. function actualiser_sessions($auteur, $supprimer_cles = array()) {
  424. $id_auteur = isset($auteur['id_auteur']) ? intval($auteur['id_auteur']) : 0;
  425. $id_auteur_courant = isset($GLOBALS['visiteur_session']['id_auteur']) ? intval($GLOBALS['visiteur_session']['id_auteur']) : 0;
  426. // si l'auteur est celui de la session courante, verifier/creer la session si besoin
  427. $fichier_session_courante = "";
  428. if ($id_auteur == $id_auteur_courant) {
  429. $auteur = array_merge($GLOBALS['visiteur_session'], $auteur);
  430. ajouter_session($auteur);
  431. if ($id_auteur) {
  432. $fichier_session_courante = fichier_session('alea_ephemere');
  433. }
  434. }
  435. // si session anonyme on ne fait rien d'autre ici : les sessions anonymes sont non partagees
  436. if (!$id_auteur) {
  437. return;
  438. }
  439. // les préférences sont désérialisées, toujours.
  440. // [fixme] Le champ 'prefs' sert aussi à l’inscription
  441. if (isset($auteur['prefs']) and is_string($auteur['prefs'])) {
  442. $auteur['prefs'] = @unserialize($auteur['prefs']);
  443. if (!is_array($auteur['prefs'])) {
  444. $auteur['prefs'] = [];
  445. }
  446. }
  447. // memoriser l'auteur courant (celui qui modifie la fiche)
  448. $sauve = $GLOBALS['visiteur_session'];
  449. // .. mettre a jour les sessions de l'auteur cible
  450. // attention au $ final pour ne pas risquer d'embarquer un .php.jeton temporaire
  451. // cree par une ecriture concurente d'une session (fichier atomique temporaire)
  452. $sessions = lister_sessions_auteur($id_auteur);
  453. // 1ere passe : lire et fusionner les sessions
  454. foreach ($sessions as $session) {
  455. $GLOBALS['visiteur_session'] = array();
  456. // a pu etre supprime entre le preg initial et le moment ou l'on arrive la (concurrence)
  457. if ($session !== $fichier_session_courante
  458. and @file_exists($session)
  459. ) {
  460. include $session; # $GLOBALS['visiteur_session'] est alors l'auteur cible
  461. $auteur = array_merge($GLOBALS['visiteur_session'], $auteur);
  462. }
  463. }
  464. // supprimer les eventuelles cles dont on ne veut plus
  465. foreach ($supprimer_cles as $cle) {
  466. unset($auteur[$cle]);
  467. }
  468. $auteur_session = preparer_ecriture_session($auteur);
  469. // seconde passe : ecrire les sessions qui ne sont pas a jour
  470. foreach ($sessions as $session) {
  471. $GLOBALS['visiteur_session'] = array();
  472. // a pu etre supprime entre le preg initial et le moment ou l'on arrive la (concurrence)
  473. if (@file_exists($session)) {
  474. include $session; # $GLOBALS['visiteur_session'] est alors l'auteur cible
  475. // est-ce que cette session est a mettre a jour ?
  476. if ($auteur_session != $GLOBALS['visiteur_session']) {
  477. ecrire_fichier_session($session, $auteur);
  478. }
  479. }
  480. }
  481. if ($id_auteur == $id_auteur_courant) {
  482. $GLOBALS['visiteur_session'] = $auteur;
  483. $GLOBALS['auteur_session'] = &$GLOBALS['visiteur_session'];
  484. } else {
  485. // restaurer l'auteur courant
  486. $GLOBALS['visiteur_session'] = $sauve;
  487. }
  488. }
  489. /**
  490. * lister les sessions et en verifier le nombre maxi
  491. * en supprimant les plus anciennes si besoin
  492. * https://core.spip.net/issues/3807
  493. *
  494. * @param int $id_auteur
  495. * @param int $nb_max
  496. * @return array
  497. */
  498. function lister_sessions_auteur($id_auteur, $nb_max = null) {
  499. if (is_null($nb_max)) {
  500. if (!defined('_NB_SESSIONS_MAX')) {
  501. define('_NB_SESSIONS_MAX', 100);
  502. }
  503. $nb_max = _NB_SESSIONS_MAX;
  504. }
  505. // liste des sessions
  506. $sessions = preg_files(_DIR_SESSIONS, '/' . $id_auteur . '_.*\.php$');
  507. // si on en a plus que la limite, supprimer les plus vieilles
  508. // si ce ne sont pas des sessions anonymes car elles sont alors chacune differentes
  509. if ($id_auteur
  510. and count($sessions) > $nb_max) {
  511. // limiter le nombre de sessions ouvertes par un auteur
  512. // filemtime sur les sessions
  513. $sessions = array_flip($sessions);
  514. // 1ere passe : lire les filemtime
  515. foreach ($sessions as $session => $z) {
  516. if ($d = @filemtime($session)
  517. ) {
  518. $sessions[$session] = $d;
  519. } else {
  520. $sessions[$session] = 0;
  521. }
  522. }
  523. // les plus anciennes en premier
  524. asort($sessions);
  525. $sessions = array_keys($sessions);
  526. while (count($sessions) > $nb_max) {
  527. $session = array_shift($sessions);
  528. @unlink($session);
  529. }
  530. }
  531. return $sessions;
  532. }
  533. /**
  534. * Préparer le tableau de session avant écriture
  535. *
  536. * Nettoyage de quelques variables sensibles, et appel d'un pipeline
  537. *
  538. * @pipeline preparer_fichier_session
  539. * @param array $auteur
  540. * @return array
  541. */
  542. function preparer_ecriture_session($auteur) {
  543. $row = $auteur;
  544. // ne pas enregistrer ces elements de securite
  545. // dans le fichier de session
  546. unset($auteur['pass']);
  547. unset($auteur['htpass']);
  548. unset($auteur['low_sec']);
  549. unset($auteur['alea_actuel']);
  550. unset($auteur['alea_futur']);
  551. $auteur = pipeline('preparer_fichier_session', array('args' => array('row' => $row), 'data' => $auteur));
  552. // ne pas enregistrer les valeurs vraiment nulle dans le fichier
  553. foreach ($auteur as $variable => $valeur) {
  554. if ($valeur === null) {
  555. unset($auteur[$variable]);
  556. }
  557. }
  558. return $auteur;
  559. }
  560. /**
  561. * Ecrire le fichier d'une session
  562. *
  563. * @param string $fichier
  564. * @param array $auteur
  565. * @return bool
  566. */
  567. function ecrire_fichier_session($fichier, $auteur) {
  568. $auteur = preparer_ecriture_session($auteur);
  569. // enregistrer les autres donnees du visiteur
  570. $texte = "<" . "?php\n";
  571. foreach ($auteur as $var => $val) {
  572. $texte .= '$GLOBALS[\'visiteur_session\'][' . var_export($var, true) . '] = '
  573. . var_export($val, true) . ";\n";
  574. }
  575. $texte .= "?" . ">\n";
  576. return ecrire_fichier($fichier, $texte);
  577. }
  578. /**
  579. * Calculer le nom du fichier session
  580. *
  581. * @param string $alea
  582. * @param bool $tantpis
  583. * @return string
  584. */
  585. function fichier_session($alea, $tantpis = false) {
  586. include_spip('inc/acces');
  587. charger_aleas();
  588. if (empty($GLOBALS['meta'][$alea])) {
  589. if (!$tantpis) {
  590. spip_log("fichier session ($tantpis): $alea indisponible", "session");
  591. include_spip('inc/minipres');
  592. echo minipres();
  593. }
  594. return ''; // echec mais $tanpis
  595. } else {
  596. $repertoire = sous_repertoire(_DIR_SESSIONS, '', false, $tantpis);
  597. $c = $_COOKIE['spip_session'];
  598. return $repertoire . intval($c) . '_' . md5($c . ' ' . $GLOBALS['meta'][$alea]) . '.php';
  599. }
  600. }
  601. /**
  602. * Code à insérer par `inc/presentation` pour rejouer la session
  603. *
  604. * @note
  605. * Pourquoi insère-t-on le src par js et non directement en statique dans le HTML ?
  606. * Historiquement, inséré par une balise `<script>` en r424
  607. * puis modifié par `<img>` statique + js en r427
  608. *
  609. * @see action_cookie_dist() qui sera appelé
  610. *
  611. * @return string
  612. */
  613. function rejouer_session() {
  614. return '<img src="' . generer_url_action('cookie', 'change_session=oui', true) . '" width="0" height="0" alt="" />';
  615. }
  616. /**
  617. * On verifie l'IP et le nom du navigateur
  618. *
  619. * @return string
  620. */
  621. function hash_env() {
  622. static $res = '';
  623. if ($res) {
  624. return $res;
  625. }
  626. return $res = md5($GLOBALS['ip'] . (isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : ''));
  627. }
  628. /**
  629. * Démarre une session PHP si ce n'est pas déjà fait.
  630. *
  631. * @link http://php.net/manual/fr/function.session-start.php
  632. * @uses is_php_session_started()
  633. * @return bool True si une session PHP est ouverte.
  634. **/
  635. function spip_php_session_start() {
  636. if (!is_php_session_started()) {
  637. return session_start();
  638. }
  639. return true;
  640. }
  641. /**
  642. * Indique si une sesssion PHP est active
  643. *
  644. * @link http://php.net/manual/fr/function.session-status.php#113468
  645. * @return bool true si une session PHP est active
  646. **/
  647. function is_php_session_started() {
  648. if (php_sapi_name() !== 'cli') {
  649. return session_status() === PHP_SESSION_ACTIVE ? true : false;
  650. }
  651. return false;
  652. }