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

/spip/ecrire/public/composer.php

https://github.com/eyeswebcrea/espace-couture-sittler.fr
PHP | 725 lines | 482 code | 84 blank | 159 comment | 93 complexity | c6c4f910904b15e51d9484e24a1028b3 MD5 | raw file
Possible License(s): LGPL-2.1, GPL-3.0
  1. <?php
  2. /***************************************************************************\
  3. * SPIP, Systeme de publication pour l'internet *
  4. * *
  5. * Copyright (c) 2001-2011 *
  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. if (!defined('_ECRIRE_INC_VERSION')) return;
  12. include_spip('inc/texte');
  13. include_spip('inc/documents');
  14. include_spip('inc/distant');
  15. include_spip('inc/rubriques'); # pour calcul_branche (cf critere branche)
  16. include_spip('inc/acces'); // Gestion des acces pour ical
  17. include_spip('public/interfaces');
  18. include_spip('public/quete');
  19. # Charge et retourne un composeur ou '' s'il est inconnu. Le compile au besoin
  20. # Charge egalement un fichier homonyme de celui du squelette
  21. # mais de suffixe '_fonctions.php' pouvant contenir:
  22. # 1. des filtres
  23. # 2. des fonctions de traduction de balise, de critere et de boucle
  24. # 3. des declaration de tables SQL supplementaires
  25. # Toutefois pour 2. et 3. preferer la technique de la surcharge
  26. // http://doc.spip.org/@public_composer_dist
  27. function public_composer_dist($squelette, $mime_type, $gram, $source, $connect='') {
  28. $nom = calculer_nom_fonction_squel($squelette, $mime_type, $connect);
  29. // si deja en memoire (INCLURE a repetition) c'est bon.
  30. if (function_exists($nom)) return array($nom);
  31. if (isset($GLOBALS['var_mode']) && ($GLOBALS['var_mode'] == 'debug'))
  32. $GLOBALS['debug_objets']['courant'] = $nom;
  33. $phpfile = sous_repertoire(_DIR_SKELS,'',false,true) . $nom . '.php';
  34. // si squelette est deja compile et perenne, le charger
  35. if (!squelette_obsolete($phpfile, $source)
  36. AND lire_fichier ($phpfile, $skel_code,
  37. array('critique' => 'oui', 'phpcheck' => 'oui')))
  38. eval('?'.'>'.$skel_code);
  39. # spip_log($skel_code, 'comp')
  40. if (@file_exists($lib = $squelette . '_fonctions'.'.php'))
  41. include_once $lib;
  42. // tester si le eval ci-dessus a mis le squelette en memoire
  43. if (function_exists($nom)) return array($nom, $skel_code);
  44. // charger le source, si possible, et compiler
  45. if (lire_fichier ($source, $skel)) {
  46. $compiler = charger_fonction('compiler', 'public');
  47. $skel_code = $compiler($skel, $nom, $gram, $source, $connect);
  48. }
  49. // Ne plus rien faire si le compilateur n'a pas pu operer.
  50. if (!$skel_code) return false;
  51. foreach($skel_code as $id => $boucle) {
  52. $f = $boucle->return;
  53. if (@eval("return true; $f ;") === false) {
  54. // Code syntaxiquement faux (critere etc mal programme')
  55. $msg = array('zbug_erreur_compilation');
  56. erreur_squelette($msg, $boucle);
  57. // continuer pour trouver d'autres fautes eventuelles
  58. // mais prevenir que c'est mort
  59. $nom = '';
  60. }
  61. // Contexte de compil inutile a present
  62. // (mais la derniere valeur de $boucle est utilisee ci-dessous)
  63. $skel_code[$id] = $f;
  64. }
  65. if ($nom) {
  66. // Si le code est bon, concatener et mettre en cache
  67. if (function_exists($nom))
  68. $code = squelette_traduit($skel, $source, $phpfile, $skel_code);
  69. else {
  70. // code semantiquement faux: bug du compilateur
  71. // $boucle est en fait ici la fct principale du squelette
  72. $msg = array('zbug_erreur_compilation');
  73. erreur_squelette($msg, $boucle);
  74. $nom = '';
  75. }
  76. }
  77. if (isset($GLOBALS['var_mode']) AND $GLOBALS['var_mode'] == 'debug') {
  78. // Tracer ce qui vient d'etre compile
  79. $GLOBALS['debug_objets']['code'][$nom . 'tout'] = $code;
  80. // si c'est ce que demande le debusqueur, lui passer la main
  81. if ($GLOBALS['debug_objets']['sourcefile']
  82. AND (_request('var_mode_objet') == $nom)
  83. AND (_request('var_mode_affiche') == 'code') )
  84. erreur_squelette();
  85. }
  86. return $nom ? array($nom, $code) : false;
  87. }
  88. function squelette_traduit($squelette, $sourcefile, $phpfile, $boucles)
  89. {
  90. // Le dernier index est '' (fonction principale)
  91. $noms = substr(join (', ', array_keys($boucles)), 0, -2);
  92. if (CODE_COMMENTE)
  93. $code = "
  94. /*
  95. * Squelette : $sourcefile
  96. * Date : ".gmdate("D, d M Y H:i:s", @filemtime($sourcefile))." GMT
  97. * Compile : ".gmdate("D, d M Y H:i:s", time())." GMT
  98. * " . (!$boucles ? "Pas de boucle" : ("Boucles : " . $noms)) ."
  99. */ " ;
  100. $code = '<'. "?php\n" . $code . join('', $boucles) . "\n?" .'>';
  101. if (!isset($GLOBALS['var_nocache']) OR !$GLOBALS['var_nocache'])
  102. ecrire_fichier($phpfile, $code);
  103. return $code;
  104. }
  105. // Le squelette compile est-il trop vieux ?
  106. // http://doc.spip.org/@squelette_obsolete
  107. function squelette_obsolete($skel, $squelette) {
  108. static $date_change = null;
  109. // ne verifier la date de mes_fonctions et mes_options qu'une seule fois
  110. // par hit
  111. if (is_null($date_change)){
  112. if (@file_exists($fonc = 'mes_fonctions.php')
  113. OR @file_exists($fonc = 'mes_fonctions.php3'))
  114. $date_change = @filemtime($fonc); # compatibilite
  115. if (defined('_FILE_OPTIONS'))
  116. $date_change = max($date_change,@filemtime(_FILE_OPTIONS));
  117. }
  118. return (
  119. (isset($GLOBALS['var_mode']) AND in_array($GLOBALS['var_mode'], array('recalcul','preview','debug')))
  120. OR !@file_exists($skel)
  121. OR ((@file_exists($squelette)?@filemtime($squelette):0)
  122. > ($date = @filemtime($skel)))
  123. OR ($date_change > $date)
  124. );
  125. }
  126. // Activer l'invalideur de session
  127. // http://doc.spip.org/@invalideur_session
  128. function invalideur_session(&$Cache, $code=NULL) {
  129. $Cache['session']=spip_session();
  130. return $code;
  131. }
  132. //
  133. // Des fonctions diverses utilisees lors du calcul d'une page ; ces fonctions
  134. // bien pratiques n'ont guere de logique organisationnelle ; elles sont
  135. // appelees par certaines balises au moment du calcul des pages. (Peut-on
  136. // trouver un modele de donnees qui les associe physiquement au fichier
  137. // definissant leur balise ???
  138. //
  139. // http://doc.spip.org/@echapper_php_callback
  140. function echapper_php_callback($r) {
  141. static $src = array();
  142. static $dst = array();
  143. // si on recoit un tableau, on est en mode echappement
  144. // on enregistre le code a echapper dans dst, et le code echappe dans src
  145. if (is_array($r)) {
  146. $dst[] = $r[0];
  147. return $src[] = '___'.md5($r[0]).'___';
  148. }
  149. // si on recoit une chaine, on est en mode remplacement
  150. $r = str_replace($src, $dst, $r);
  151. $src = $dst = array(); // raz de la memoire
  152. return $r;
  153. }
  154. // http://doc.spip.org/@analyse_resultat_skel
  155. function analyse_resultat_skel($nom, $cache, $corps, $source='') {
  156. $headers = array();
  157. // Recupere les < ?php header('Xx: y'); ? > pour $page['headers']
  158. // note: on essaie d'attrapper aussi certains de ces entetes codes
  159. // "a la main" dans les squelettes, mais evidemment sans exhaustivite
  160. if (preg_match_all(
  161. '/(<[?]php\s+)@?header\s*\(\s*.([^:\']*):?\s*([^)]*)[^)]\s*\)\s*[;]?\s*[?]>/ims',
  162. $corps, $regs, PREG_SET_ORDER)){
  163. foreach ($regs as $r) {
  164. $corps = str_replace($r[0], '', $corps);
  165. # $j = Content-Type, et pas content-TYPE.
  166. $j = join('-', array_map('ucwords', explode('-', strtolower($r[2]))));
  167. if ($j=='X-Spip-Filtre' AND isset($headers[$j]))
  168. $headers[$j].="|".$r[3];
  169. else
  170. $headers[$j] = $r[3];
  171. }
  172. }
  173. // S'agit-il d'un resultat constant ou contenant du code php
  174. $process_ins = (
  175. strpos($corps,'<'.'?') === false
  176. OR strpos(str_replace('<'.'?xml', '', $corps),'<'.'?') === false
  177. )
  178. ? 'html'
  179. : 'php';
  180. // traiter #FILTRE{} ?
  181. if (isset($headers['X-Spip-Filtre'])
  182. AND strlen($headers['X-Spip-Filtre'])) {
  183. // proteger les <INCLUDE> et tous les morceaux de php
  184. if ($process_ins == 'php')
  185. $corps = preg_replace_callback(',<[?](\s|php|=).*[?]>,UimsS',
  186. 'echapper_php_callback', $corps);
  187. foreach (explode('|', $headers['X-Spip-Filtre']) as $filtre) {
  188. if ($f = chercher_filtre($filtre))
  189. $corps = $f($corps);
  190. }
  191. // restaurer les echappements
  192. $corps = echapper_php_callback($corps);
  193. unset($headers['X-Spip-Filtre']);
  194. }
  195. return array('texte' => $corps,
  196. 'squelette' => $nom,
  197. 'source' => $source,
  198. 'process_ins' => $process_ins,
  199. 'invalideurs' => $cache,
  200. 'entetes' => $headers,
  201. 'duree' => isset($headers['X-Spip-Cache']) ? intval($headers['X-Spip-Cache']) : 0
  202. );
  203. }
  204. //
  205. // fonction standard de calcul de la balise #INTRODUCTION
  206. // on peut la surcharger en definissant dans mes_fonctions :
  207. // function filtre_introduction()
  208. //
  209. // http://doc.spip.org/@filtre_introduction_dist
  210. function filtre_introduction_dist($descriptif, $texte, $longueur, $connect) {
  211. // Si un descriptif est envoye, on l'utilise directement
  212. if (strlen($descriptif))
  213. return propre($descriptif,$connect);
  214. // De preference ce qui est marque <intro>...</intro>
  215. $intro = '';
  216. $texte = preg_replace(",(</?)intro>,i", "\\1intro>", $texte); // minuscules
  217. while ($fin = strpos($texte, "</intro>")) {
  218. $zone = substr($texte, 0, $fin);
  219. $texte = substr($texte, $fin + strlen("</intro>"));
  220. if ($deb = strpos($zone, "<intro>") OR substr($zone, 0, 7) == "<intro>")
  221. $zone = substr($zone, $deb + 7);
  222. $intro .= $zone;
  223. }
  224. // [12025] On ne *PEUT* pas couper simplement ici car c'est du texte brut,
  225. // qui inclus raccourcis et modeles
  226. // un simple <articlexx> peut etre ensuite transforme en 1000 lignes ...
  227. // par ailleurs le nettoyage des raccourcis ne tient pas compte
  228. // des surcharges et enrichissement de propre
  229. // couper doit se faire apres propre
  230. //$texte = nettoyer_raccourcis_typo($intro ? $intro : $texte, $connect);
  231. // Cependant pour des questions de perfs on coupe quand meme, en prenant
  232. // large et en se mefiant des tableaux #1323
  233. if (strlen($intro))
  234. $texte = $intro;
  235. else
  236. if (strpos("\n".$texte, "\n|")===false
  237. AND strlen($texte) > 2.5*$longueur)
  238. $texte = couper($texte, 2*$longueur);
  239. // ne pas tenir compte des notes
  240. $notes = charger_fonction('notes', 'inc');
  241. $notes('','empiler');
  242. $texte = propre($texte,$connect);
  243. $notes('','depiler');
  244. if (!defined('_INTRODUCTION_SUITE')) define('_INTRODUCTION_SUITE', '&nbsp;(...)');
  245. $texte = couper($texte, $longueur, _INTRODUCTION_SUITE);
  246. return $texte;
  247. }
  248. //
  249. // Balises dynamiques
  250. //
  251. // elles sont traitees comme des inclusions
  252. // http://doc.spip.org/@synthetiser_balise_dynamique
  253. define('CODE_INCLURE_BALISE', '<' . '?php
  254. include_once("./" . _DIR_RACINE . "%s");
  255. if ($lang_select = "%s") $lang_select = lang_select($lang_select);
  256. inserer_balise_dynamique(balise_%s_dyn(%s), array(%s));
  257. if ($lang_select) lang_select();
  258. ?'
  259. .'>');
  260. function synthetiser_balise_dynamique($nom, $args, $file, $context_compil) {
  261. $r = sprintf(CODE_INCLURE_BALISE,
  262. $file,
  263. $context_compil[4]?$context_compil[4]:'',
  264. $nom,
  265. join(', ', array_map('argumenter_squelette', $args)),
  266. join(', ', array_map('_q', $context_compil)));
  267. return $r;
  268. }
  269. // http://doc.spip.org/@argumenter_squelette
  270. function argumenter_squelette($v) {
  271. if (!is_array($v))
  272. return "'" . texte_script($v) . "'";
  273. else {
  274. $out = array();
  275. foreach($v as $k=>$val)
  276. $out [] = argumenter_squelette($k) . '=>' . argumenter_squelette($val);
  277. return 'array(' . join(", ", $out) . ')';
  278. }
  279. }
  280. // verifier leurs arguments et filtres, et calculer le code a inclure
  281. // http://doc.spip.org/@executer_balise_dynamique
  282. function executer_balise_dynamique($nom, $args, $context_compil) {
  283. $p = strpos($nom,"_");
  284. $nomfonction = $nom;
  285. $nomfonction_generique = substr($nom,0,$p+1);
  286. if (!$file = include_spip("balise/". strtolower($nomfonction))) {
  287. // pas de fichier associe, passer au traitement generique
  288. $file = include_spip("balise/" .strtolower($nomfonction_generique));
  289. if ($file) {
  290. // et injecter en premier arg le nom de la balise
  291. array_unshift($args,$nom);
  292. // et passer sur la fonction generique pour la suite
  293. $nomfonction = $nomfonction_generique;
  294. }
  295. else {
  296. $msg = array('zbug_balise_inexistante',array('from'=>'CVT','balise'=>$nom));
  297. erreur_squelette($msg, $context_compil);
  298. return '';
  299. }
  300. }
  301. // Y a-t-il une fonction de traitement des arguments ?
  302. $f = 'balise_' . $nomfonction . '_stat';
  303. $r = !function_exists($f) ? $args : $f($args, $context_compil);
  304. if (!is_array($r)) return $r;
  305. // verifier que la fonction dyn est la,
  306. // sinon se replier sur la generique si elle existe
  307. if (!function_exists('balise_' . $nomfonction . '_dyn')) {
  308. $file = include_spip("balise/" .strtolower($nomfonction_generique));
  309. if (function_exists('balise_' . $nomfonction_generique . '_dyn')) {
  310. // et lui injecter en premier arg le nom de la balise
  311. array_unshift($r,$nom);
  312. $nomfonction = $nomfonction_generique;
  313. } else {
  314. $msg = array('zbug_balise_inexistante',array('from'=>'CVT','balise'=>$nom));
  315. erreur_squelette($msg, $context_compil);
  316. return '';
  317. }
  318. }
  319. if (!_DIR_RESTREINT)
  320. $file = _DIR_RESTREINT_ABS . $file;
  321. return synthetiser_balise_dynamique($nomfonction, $r, $file, $context_compil);
  322. }
  323. // http://doc.spip.org/@lister_objets_avec_logos
  324. function lister_objets_avec_logos ($type) {
  325. global $formats_logos;
  326. $logos = array();
  327. $chercher_logo = charger_fonction('chercher_logo', 'inc');
  328. $type = '/'
  329. . type_du_logo($type)
  330. . "on(\d+)\.("
  331. . join('|',$formats_logos)
  332. . ")$/";
  333. if ($d = @opendir(_DIR_LOGOS)) {
  334. while($f = readdir($d)) {
  335. if (preg_match($type, $f, $r))
  336. $logos[] = $r[1];
  337. }
  338. }
  339. @closedir($d);
  340. return join(',',$logos);
  341. }
  342. // fonction appelee par la balise #NOTES
  343. // Renvoyer l'etat courant des notes, le purger et en preparer un nouveau
  344. // http://doc.spip.org/@calculer_notes
  345. function calculer_notes() {
  346. $notes = charger_fonction('notes', 'inc');
  347. $r = $notes(array());
  348. $notes('','depiler');
  349. $notes('','empiler');
  350. return $r;
  351. }
  352. // Selectionner la langue de l'objet dans la boucle, sauf dans les
  353. // cas ou il ne le faut pas :-)
  354. function lang_select_public($lang, $lang_select, $titre=null) {
  355. // Cas 1. forcer_lang = true et pas de critere {lang_select}
  356. if (isset($GLOBALS['forcer_lang']) AND $GLOBALS['forcer_lang']
  357. AND $lang_select !== 'oui')
  358. return;
  359. // Cas 2. l'objet n'a pas de langue definie (ou definie a '')
  360. if (!strlen($lang))
  361. return;
  362. // Cas 3. l'objet est multilingue !
  363. if ($lang_select !== 'oui'
  364. AND strlen($titre) > 10
  365. AND strpos($titre, '<multi>') !== false
  366. AND strpos(echappe_html($titre), '<multi>') !== false)
  367. return;
  368. // Tous les cas ayant ete elimines, faire le job
  369. $GLOBALS['spip_lang'] = $lang;
  370. return;
  371. }
  372. // Si un tableau &doublons[articles] est passe en parametre,
  373. // il faut le nettoyer car il pourrait etre injecte en SQL
  374. // http://doc.spip.org/@nettoyer_env_doublons
  375. function nettoyer_env_doublons($envd) {
  376. foreach ($envd as $table => $liste) {
  377. $n = '';
  378. foreach(explode(',',$liste) as $val) {
  379. if ($a = intval($val) AND $val === strval($a))
  380. $n.= ','.$val;
  381. }
  382. if (strlen($n))
  383. $envd[$table] = $n;
  384. else
  385. unset($envd[$table]);
  386. }
  387. return $envd;
  388. }
  389. // http://doc.spip.org/@match_self
  390. function match_self($w){
  391. if (is_string($w)) return false;
  392. if (is_array($w)) {
  393. if (in_array(reset($w),array("SELF","SUBSELECT"))) return $w;
  394. foreach($w as $sw)
  395. if ($m=match_self($sw)) return $m;
  396. }
  397. return false;
  398. }
  399. // http://doc.spip.org/@remplace_sous_requete
  400. function remplace_sous_requete($w,$sousrequete){
  401. if (is_array($w)) {
  402. if (in_array(reset($w),array("SELF","SUBSELECT"))) return $sousrequete;
  403. foreach($w as $k=>$sw)
  404. $w[$k] = remplace_sous_requete($sw,$sousrequete);
  405. }
  406. return $w;
  407. }
  408. // http://doc.spip.org/@trouver_sous_requetes
  409. function trouver_sous_requetes($where){
  410. $where_simples = array();
  411. $where_sous = array();
  412. foreach($where as $k=>$w){
  413. if (match_self($w)) $where_sous[$k] = $w;
  414. else $where_simples[$k] = $w;
  415. }
  416. return array($where_simples,$where_sous);
  417. }
  418. // La fonction presente dans les squelettes compiles
  419. // http://doc.spip.org/@calculer_select
  420. function calculer_select ($select = array(), $from = array(),
  421. $from_type = array(),
  422. $where = array(), $join=array(),
  423. $groupby = array(), $orderby = array(), $limit = '',
  424. $having=array(), $table = '', $id = '', $serveur='', $requeter=true) {
  425. // retirer les criteres vides:
  426. // {X ?} avec X absent de l'URL
  427. // {par #ENV{X}} avec X absent de l'URL
  428. // IN sur collection vide (ce dernier devrait pouvoir etre fait a la compil)
  429. $menage = false;
  430. foreach($where as $k => $v) {
  431. if (is_array($v)){
  432. if ((count($v)>=2) && ($v[0]=='REGEXP') && ($v[2]=="'.*'")) $op= false;
  433. elseif ((count($v)>=2) && ($v[0]=='LIKE') && ($v[2]=="'%'")) $op= false;
  434. else $op = $v[0] ? $v[0] : $v;
  435. } else $op = $v;
  436. if ((!$op) OR ($op==1) OR ($op=='0=0')) {
  437. unset($where[$k]);
  438. $menage = true;
  439. }
  440. }
  441. // evacuer les eventuels groupby vide issus d'un calcul dynamique
  442. $groupby = array_diff($groupby,array(''));
  443. // remplacer les sous requetes recursives au calcul
  444. list($where_simples,$where_sous) = trouver_sous_requetes($where);
  445. //var_dump($where_sous);
  446. foreach($where_sous as $k=>$w) {
  447. $menage = true;
  448. // on recupere la sous requete
  449. $sous = match_self($w);
  450. if ($sous[0]=='SELF') {
  451. // c'est une sous requete identique a elle meme sous la forme (SELF,$select,$where)
  452. array_push($where_simples,$sous[2]);
  453. $where[$k] = remplace_sous_requete($w,"(".calculer_select(
  454. $sous[1],
  455. $from,
  456. $from_type,
  457. array($sous[2],'0=0'), // pour accepter une string et forcer a faire le menage car on a surement simplifie select et where
  458. $join,
  459. array(),array(),'',
  460. $having,$table,$id,$serveur,false).")");
  461. }
  462. if ($sous[0]=='SUBSELECT') {
  463. // c'est une sous requete explicite sous la forme identique a sql_select : (SUBSELECT,$select,$from,$where,$groupby,$orderby,$limit,$having)
  464. array_push($where_simples,$sous[3]); // est-ce utile dans ce cas ?
  465. $where[$k] = remplace_sous_requete($w,"(".calculer_select(
  466. $sous[1], # select
  467. $sous[2], #from
  468. array(), #from_type
  469. $sous[3]?(is_array($sous[3])?$sous[3]:array($sous[3])):array(), #where, qui peut etre de la forme string comme dans sql_select
  470. array(), #join
  471. $sous[4]?$sous[4]:array(), #groupby
  472. $sous[5]?$sous[5]:array(), #orderby
  473. $sous[6], #limit
  474. $sous[7]?$sous[7]:array(), #having
  475. $table,$id,$serveur,false
  476. ).")");
  477. }
  478. array_pop($where_simples);
  479. }
  480. foreach($having as $k => $v) {
  481. if ((!$v) OR ($v==1) OR ($v=='0=0')) {
  482. unset($having[$k]);
  483. }
  484. }
  485. // Installer les jointures.
  486. // Retirer celles seulement utiles aux criteres finalement absents mais
  487. // parcourir de la plus recente a la moins recente pour pouvoir eliminer Ln
  488. // si elle est seulement utile a Ln+1 elle meme inutile
  489. $afrom = array();
  490. $equiv = array();
  491. $k = count($join);
  492. foreach(array_reverse($join,true) as $cledef=>$j) {
  493. $cle = $cledef;
  494. // le format de join est :
  495. // array(table depart, cle depart [,cle arrivee[,condition optionnelle and ...]])
  496. if (count($join[$cle])==2) $join[$cle][] = $join[$cle][1];
  497. if (count($join[$cle])==3) $join[$cle][] = '';
  498. list($t,$c,$carr,$and) = $join[$cle];
  499. // si le nom de la jointure n'a pas ete specifiee, on prend Lx avec x sont rang dans la liste
  500. // pour compat avec ancienne convention
  501. if (is_numeric($cle))
  502. $cle = "L$k";
  503. if (!$menage
  504. OR isset($afrom[$cle])
  505. OR calculer_jointnul($cle, $select)
  506. OR calculer_jointnul($cle, array_diff($join,array($cle=>$join[$cle])))
  507. OR calculer_jointnul($cle, $having)
  508. OR calculer_jointnul($cle, $where_simples)) {
  509. // on garde une ecriture decomposee pour permettre une simplification ulterieure si besoin
  510. // sans recours a preg_match
  511. // un implode(' ',..) est fait dans reinjecte_joint un peu plus bas
  512. $afrom[$t][$cle] = array("\n" .
  513. (isset($from_type[$cle])?$from_type[$cle]:"INNER")." JOIN",
  514. $from[$cle],
  515. "AS $cle",
  516. "ON (",
  517. "$cle.$c",
  518. "=",
  519. "$t.$carr",
  520. ($and ? "AND ". $and:"") .
  521. ")");
  522. if (isset($afrom[$cle])){
  523. $afrom[$t] = $afrom[$t] + $afrom[$cle];
  524. unset($afrom[$cle]);
  525. }
  526. $equiv[]= $carr;
  527. } else { unset($join[$cledef]);}
  528. unset($from[$cle]);
  529. $k--;
  530. }
  531. if (count($afrom)) {
  532. // Regarder si la table principale ne sert finalement a rien comme dans
  533. //<BOUCLE3(MOTS){id_article}{id_mot}> class='on'</BOUCLE3>
  534. //<BOUCLE2(MOTS){id_article} />#TOTAL_BOUCLE<//B2>
  535. //<BOUCLE5(RUBRIQUES){id_mot}{tout} />#TOTAL_BOUCLE<//B5>
  536. // ou dans
  537. //<BOUCLE8(HIERARCHIE){id_rubrique}{tout}{type='Squelette'}{inverse}{0,1}{lang_select=non} />#TOTAL_BOUCLE<//B8>
  538. // qui comporte plusieurs jointures
  539. // ou dans
  540. // <BOUCLE6(ARTICLES){id_mot=2}{statut==.*} />#TOTAL_BOUCLE<//B6>
  541. // <BOUCLE7(ARTICLES){id_mot>0}{statut?} />#TOTAL_BOUCLE<//B7>
  542. // penser a regarder aussi la clause orderby pour ne pas simplifier abusivement
  543. // <BOUCLE9(ARTICLES){recherche truc}{par titre}>#ID_ARTICLE</BOUCLE9>
  544. // penser a regarder aussi la clause groubpy pour ne pas simplifier abusivement
  545. // <BOUCLE10(EVENEMENTS){id_rubrique} />#TOTAL_BOUCLE<//B10>
  546. list($t,$c) = each($from);
  547. reset($from);
  548. $e = '/\b(' . "$t\\." . join("|" . $t . '\.', $equiv) . ')\b/';
  549. if (!(strpos($t, ' ') OR // jointure des le depart cf boucle_doc
  550. calculer_jointnul($t, $select, $e) OR
  551. calculer_jointnul($t, $join, $e) OR
  552. calculer_jointnul($t, $where, $e) OR
  553. calculer_jointnul($t, $orderby, $e) OR
  554. calculer_jointnul($t, $groupby, $e) OR
  555. calculer_jointnul($t, $having, $e))
  556. && count($afrom[$t])) {
  557. reset($afrom[$t]);
  558. list($nt,$nfrom) = each($afrom[$t]);
  559. unset($from[$t]);
  560. $from[$nt] = $nfrom[1];
  561. unset($afrom[$t][$nt]);
  562. $afrom[$nt] = $afrom[$t];
  563. unset($afrom[$t]);
  564. $e = '/\b'.preg_quote($nfrom[6]).'\b/';
  565. $t = $nfrom[4];
  566. $alias = "";
  567. // verifier que les deux cles sont homonymes, sinon installer un alias dans le select
  568. $oldcle = explode('.',$nfrom[6]);
  569. $oldcle = end($oldcle);
  570. $newcle = explode('.',$nfrom[4]);
  571. $newcle = end($newcle);
  572. if ($newcle!=$oldcle){
  573. $alias = ", ".$nfrom[4]." AS $oldcle";
  574. }
  575. $select = remplacer_jointnul($t . $alias, $select, $e);
  576. $join = remplacer_jointnul($t, $join, $e);
  577. $where = remplacer_jointnul($t, $where, $e);
  578. $having = remplacer_jointnul($t, $having, $e);
  579. $groupby = remplacer_jointnul($t, $groupby, $e);
  580. $orderby = remplacer_jointnul($t, $orderby, $e);
  581. }
  582. $from = reinjecte_joint($afrom, $from);
  583. }
  584. $GLOBALS['debug']['aucasou'] = array ($table, $id, $serveur, $requeter);
  585. $r = sql_select($select, $from, $where,
  586. $groupby, array_filter($orderby), $limit, $having, $serveur, $requeter);
  587. unset($GLOBALS['debug']['aucasou']);
  588. return $r;
  589. }
  590. //condition suffisante (mais non necessaire) pour qu'une table soit utile
  591. // http://doc.spip.org/@calculer_jointnul
  592. function calculer_jointnul($cle, $exp, $equiv='')
  593. {
  594. if (!is_array($exp)) {
  595. if ($equiv) $exp = preg_replace($equiv, '', $exp);
  596. return preg_match("/\\b$cle\\./", $exp);
  597. } else {
  598. foreach($exp as $v) {
  599. if (calculer_jointnul($cle, $v, $equiv)) return true;
  600. }
  601. return false;
  602. }
  603. }
  604. // http://doc.spip.org/@reinjecte_joint
  605. function reinjecte_joint($afrom, $from)
  606. {
  607. $from_synth = array();
  608. foreach($from as $k=>$v){
  609. $from_synth[$k]=$from[$k];
  610. if (isset($afrom[$k])) {
  611. foreach($afrom[$k] as $kk=>$vv) $afrom[$k][$kk] = implode(' ',$afrom[$k][$kk]);
  612. $from_synth["$k@"]= implode(' ',$afrom[$k]);
  613. unset($afrom[$k]);
  614. }
  615. }
  616. return $from_synth;
  617. }
  618. // http://doc.spip.org/@remplacer_jointnul
  619. function remplacer_jointnul($cle, $exp, $equiv='')
  620. {
  621. if (!is_array($exp)) {
  622. return preg_replace($equiv, $cle, $exp);
  623. } else {
  624. foreach($exp as $k => $v) {
  625. $exp[$k] = remplacer_jointnul($cle, $v, $equiv);
  626. }
  627. return $exp;
  628. }
  629. }
  630. // calcul du nom du squelette
  631. // http://doc.spip.org/@calculer_nom_fonction_squel
  632. function calculer_nom_fonction_squel($skel, $mime_type='html', $connect='')
  633. {
  634. // ne pas doublonner les squelette selon qu'ils sont calcules depuis ecrire/ ou depuis la racine
  635. if (strlen(_DIR_RACINE) AND substr($skel,0,strlen(_DIR_RACINE))==_DIR_RACINE)
  636. $skel = substr($skel,strlen(_DIR_RACINE));
  637. return $mime_type
  638. . (!$connect ? '' : preg_replace('/\W/',"_", $connect)) . '_'
  639. . md5($GLOBALS['spip_version_code'] . ' * ' . $skel);
  640. }
  641. ?>