PageRenderTime 46ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/_core_/tags/spip-2.1.1/plugins/compresseur/inc/compresseur.php

https://bitbucket.org/pombredanne/spip-zone-treemap
PHP | 314 lines | 230 code | 39 blank | 45 comment | 35 complexity | 6a8aaedc6cd7a6b6a7801eef73b4ccfb MD5 | raw file
  1. <?php
  2. // http://doc.spip.org/@compacte_css
  3. function compacte_css ($contenu) {
  4. // nettoyer la css de tout ce qui sert pas
  5. $contenu = preg_replace(",/\*.*\*/,Ums","",$contenu); // pas de commentaires
  6. $contenu = preg_replace(",\s(?=\s),Ums","",$contenu); // pas d'espaces consecutifs
  7. $contenu = preg_replace("/\s?({|;|,|:)\s?/ms","$1",$contenu); // pas d'espaces dans les declarations css
  8. $contenu = preg_replace("/\s}/ms","}",$contenu); // pas d'espaces dans les declarations css
  9. $contenu = preg_replace(",#([0-9a-f])(\\1)([0-9a-f])(\\3)([0-9a-f])(\\5),i","#$1$3$5",$contenu); // passser les codes couleurs en 3 car si possible
  10. $contenu = preg_replace(",([^{}]*){},Ums"," ",$contenu); // supprimer les declarations vides
  11. $contenu = trim($contenu);
  12. return $contenu;
  13. }
  14. // Compacte du javascript grace a Dean Edward's JavaScriptPacker
  15. // utile pour prive/jquery.js par exemple
  16. // http://doc.spip.org/@compacte_js
  17. function compacte_js($flux) {
  18. // si la closure est demandee, on pourrait zapper cette etape
  19. // mais avec le risque, en localhost, de depasser 200ko et d'echec
  20. #if ($GLOBALS['meta']['auto_compress_closure'] == 'oui')
  21. # return $flux;
  22. if (!strlen($flux))
  23. return $flux;
  24. include_spip('lib/JavascriptPacker/class.JavaScriptPacker');
  25. $packer = new JavaScriptPacker($flux, 0, true, false);
  26. // en cas d'echec (?) renvoyer l'original
  27. if (!strlen($t = $packer->pack())) {
  28. spip_log('erreur de compacte_js');
  29. return $flux;
  30. }
  31. return $t;
  32. }
  33. // Appelee par compacte_head() si le webmestre le desire, cette fonction
  34. // compacte les scripts js dans un fichier statique pose dans local/
  35. // en entree : un <head> html.
  36. // http://doc.spip.org/@compacte_head_js
  37. function compacte_head_js($flux) {
  38. $url_base = url_de_base();
  39. $url_page = substr(generer_url_public('A'), 0, -1);
  40. $dir = preg_quote($url_page,',').'|'.preg_quote(preg_replace(",^$url_base,",_DIR_RACINE,$url_page),',');
  41. $scripts = array();
  42. $flux_nocomment = preg_replace(",<!--.*-->,Uims","",$flux);
  43. foreach (extraire_balises($flux_nocomment,'script') as $s) {
  44. if (extraire_attribut($s, 'type') === 'text/javascript'
  45. AND $src = extraire_attribut($s, 'src')
  46. AND !strlen(strip_tags($s))
  47. AND (
  48. preg_match(',^('.$dir.')(.*)$,', $src, $r)
  49. OR (
  50. // ou si c'est un fichier
  51. $src = preg_replace(',^'.preg_quote(url_de_base(),',').',', '', $src)
  52. // enlever un timestamp eventuel derriere un nom de fichier statique
  53. AND $src2 = preg_replace(",[.]js[?].+$,",'.js',$src)
  54. // verifier qu'il n'y a pas de ../ ni / au debut (securite)
  55. AND !preg_match(',(^/|\.\.),', substr($src,strlen(_DIR_RACINE)))
  56. // et si il est lisible
  57. AND @is_readable($src2)
  58. )
  59. )) {
  60. if ($r)
  61. $scripts[$s] = explode('&',
  62. str_replace('&amp;', '&', $r[2]), 2);
  63. else
  64. $scripts[$s] = $src;
  65. }
  66. }
  67. if (list($src,$comms) = filtre_cache_static($scripts,'js')){
  68. $scripts = array_keys($scripts);
  69. $flux = str_replace(reset($scripts),
  70. $comms
  71. ."<script type='text/javascript' src='$src'></script>\n",$flux);
  72. $flux = str_replace($scripts,"",$flux);
  73. }
  74. return $flux;
  75. }
  76. // Appelee par compacte_head() si le webmestre le desire, cette fonction
  77. // compacte les feuilles de style css dans un fichier statique pose dans local/
  78. // en entree : un <head> html.
  79. // http://doc.spip.org/@compacte_head_css
  80. function compacte_head_css($flux) {
  81. $url_base = url_de_base();
  82. $url_page = substr(generer_url_public('A'), 0, -1);
  83. $dir = preg_quote($url_page,',').'|'.preg_quote(preg_replace(",^$url_base,",_DIR_RACINE,$url_page),',');
  84. $css = array();
  85. $flux_nocomment = preg_replace(",<!--.*-->,Uims","",$flux);
  86. foreach (extraire_balises($flux_nocomment, 'link') as $s) {
  87. if (extraire_attribut($s, 'rel') === 'stylesheet'
  88. AND (!($type = extraire_attribut($s, 'type'))
  89. OR $type == 'text/css')
  90. AND is_null(extraire_attribut($s, 'name')) # css nommee : pas touche
  91. AND is_null(extraire_attribut($s, 'id')) # idem
  92. AND !strlen(strip_tags($s))
  93. AND $src = preg_replace(",^$url_base,",_DIR_RACINE,extraire_attribut($s, 'href'))
  94. AND (
  95. // regarder si c'est du format spip.php?page=xxx
  96. preg_match(',^('.$dir.')(.*)$,', $src, $r)
  97. OR (
  98. // ou si c'est un fichier
  99. // enlever un timestamp eventuel derriere un nom de fichier statique
  100. $src2 = preg_replace(",[.]css[?].+$,",'.css',$src)
  101. // verifier qu'il n'y a pas de ../ ni / au debut (securite)
  102. AND !preg_match(',(^/|\.\.),', substr($src2,strlen(_DIR_RACINE)))
  103. // et si il est lisible
  104. AND @is_readable($src2)
  105. )
  106. )) {
  107. $media = strval(extraire_attribut($s, 'media'));
  108. if ($r)
  109. $css[$media][$s] = explode('&',
  110. str_replace('&amp;', '&', $r[2]), 2);
  111. else
  112. $css[$media][$s] = $src;
  113. }
  114. }
  115. // et mettre le tout dans un cache statique
  116. foreach($css as $m=>$s){
  117. // si plus d'une css pour ce media ou si c'est une css dynamique
  118. if (count($s)>1 OR is_array(reset($s))){
  119. if (list($src,$comms) = filtre_cache_static($s,'css')){
  120. $s = array_keys($s);
  121. $flux = str_replace(reset($s),
  122. $comms
  123. ."<link rel='stylesheet'".($m?" media='$m'":"")." href='$src' type='text/css' />\n",$flux);
  124. $flux = str_replace($s,"",$flux);
  125. }
  126. }
  127. }
  128. return $flux;
  129. }
  130. // http://doc.spip.org/@filtre_cache_static
  131. function filtre_cache_static($scripts,$type='js'){
  132. $nom = "";
  133. if (!is_array($scripts) && $scripts) $scripts = array($scripts);
  134. if (count($scripts)){
  135. $dir = sous_repertoire(_DIR_VAR,'cache-'.$type);
  136. $nom = $dir . md5(serialize($scripts)) . ".$type";
  137. if (
  138. $GLOBALS['var_mode']=='recalcul'
  139. OR !file_exists($nom)
  140. ) {
  141. $fichier = "";
  142. $comms = array();
  143. $total = 0;
  144. foreach($scripts as $script){
  145. if (!is_array($script)) {
  146. // c'est un fichier
  147. $comm = $script;
  148. // enlever le timestamp si besoin
  149. $script = preg_replace(",[?].+$,",'',$script);
  150. if ($type=='css'){
  151. $fonctions = array('urls_absolues_css');
  152. if (isset($GLOBALS['compresseur_filtres_css']) AND is_array($GLOBALS['compresseur_filtres_css']))
  153. $fonctions = $GLOBALS['compresseur_filtres_css'] + $fonctions;
  154. $script = appliquer_fonctions_css_fichier($fonctions, $script);
  155. }
  156. lire_fichier($script, $contenu);
  157. }
  158. else {
  159. // c'est un squelette
  160. $comm = _SPIP_PAGE . "=$script[0]"
  161. . (strlen($script[1])?"($script[1])":'');
  162. parse_str($script[1],$contexte);
  163. $contenu = recuperer_fond($script[0],$contexte);
  164. if ($type=='css'){
  165. $fonctions = array('urls_absolues_css');
  166. if (isset($GLOBALS['compresseur_filtres_css']) AND is_array($GLOBALS['compresseur_filtres_css']))
  167. $fonctions = $GLOBALS['compresseur_filtres_css'] + $fonctions;
  168. $contenu = appliquer_fonctions_css_contenu($fonctions, $contenu, self('&'));
  169. }
  170. }
  171. $f = 'compacte_'.$type;
  172. $fichier .= "/* $comm */\n". $f($contenu) . "\n\n";
  173. $comms[] = $comm;
  174. $total += strlen($contenu);
  175. }
  176. // calcul du % de compactage
  177. $pc = intval(1000*strlen($fichier)/$total)/10;
  178. $comms = "compact [\n\t".join("\n\t", $comms)."\n] $pc%";
  179. $fichier = "/* $comms */\n\n".$fichier;
  180. // ecrire
  181. ecrire_fichier($nom,$fichier,true);
  182. // ecrire une version .gz pour content-negociation par apache, cf. [11539]
  183. ecrire_fichier("$nom.gz",$fichier,true);
  184. }
  185. // closure compiler ou autre super-compresseurs
  186. compresse_encore($nom, $type);
  187. }
  188. // Le commentaire detaille n'apparait qu'au recalcul, pour debug
  189. return array($nom, (isset($comms) AND $comms) ? "<!-- $comms -->\n" : '');
  190. }
  191. // experimenter le Closure Compiler de Google
  192. function compresse_encore (&$nom, $type) {
  193. # Closure Compiler n'accepte pas des POST plus gros que 200 000 octets
  194. # au-dela il faut stocker dans un fichier, et envoyer l'url du fichier
  195. # dans code_url ; en localhost ca ne marche evidemment pas
  196. if (
  197. $GLOBALS['meta']['auto_compress_closure'] == 'oui'
  198. AND $type=='js'
  199. ) {
  200. lire_fichier($nom, $fichier);
  201. $dest = dirname($nom).'/'.md5($fichier).'.js';
  202. if (!@file_exists($dest)) {
  203. include_spip('inc/distant');
  204. $datas=array(
  205. 'output_format' => 'text',
  206. 'output_info' => 'compiled_code',
  207. 'compilation_level' => 'SIMPLE_OPTIMIZATIONS', // 'SIMPLE_OPTIMIZATIONS', 'WHITESPACE_ONLY', 'ADVANCED_OPTIMIZATIONS'
  208. );
  209. if (strlen($fichier) < 200000)
  210. $datas['js_code'] = $fichier;
  211. else
  212. $datas['url_code'] = url_absolue($nom);
  213. $cc = recuperer_page('http://closure-compiler.appspot.com/compile',
  214. $trans=false, $get_headers=false,
  215. $taille_max = null,
  216. $datas,
  217. $boundary = -1);
  218. if ($cc AND !preg_match(',^\s*Error,', $cc)) {
  219. spip_log('Closure Compiler: success');
  220. $cc = "/* $nom + Closure Compiler */\n".$cc;
  221. ecrire_fichier ($dest, $cc, true);
  222. ecrire_fichier ("$dest.gz", $cc, true);
  223. } else
  224. ecrire_fichier ($dest, '', true);
  225. }
  226. if (@filesize($dest))
  227. $nom = $dest;
  228. }
  229. }
  230. function appliquer_fonctions_css_fichier($fonctions,$css) {
  231. if (!preg_match(',\.css$,i', $css, $r)) return $css;
  232. $url_absolue_css = url_absolue($css);
  233. // verifier qu'on a un array
  234. if (is_string($fonctions))
  235. $fonctions = array($fonctions);
  236. $sign = implode(",",$fonctions);
  237. $sign = substr(md5("$css-$sign"), 0,8);
  238. $file = basename($css,'.css');
  239. $file = sous_repertoire (_DIR_VAR, 'cache-css')
  240. . preg_replace(",(.*?)(_rtl|_ltr)?$,","\\1-f-" . $sign . "\\2",$file)
  241. . '.css';
  242. if ((@filemtime($f) > @filemtime($css))
  243. AND ($GLOBALS['var_mode'] != 'recalcul'))
  244. return $f;
  245. if ($url_absolue_css==$css){
  246. if (strncmp($GLOBALS['meta']['adresse_site'],$css,$l=strlen($GLOBALS['meta']['adresse_site']))!=0
  247. OR !lire_fichier(_DIR_RACINE . substr($css,$l), $contenu)){
  248. include_spip('inc/distant');
  249. if (!$contenu = recuperer_page($css))
  250. return $css;
  251. }
  252. }
  253. elseif (!lire_fichier($css, $contenu))
  254. return $css;
  255. $contenu = appliquer_fonctions_css_contenu($fonctions, $contenu, $css);
  256. // ecrire la css
  257. if (!ecrire_fichier($file, $contenu))
  258. return $css;
  259. return $file;
  260. }
  261. function appliquer_fonctions_css_contenu($fonctions, &$contenu, $base) {
  262. foreach($fonctions as $f)
  263. if (function_exists($f))
  264. $contenu = $f($contenu, $base);
  265. return $contenu;
  266. }
  267. function compresseur_embarquer_images_css($contenu, $source){
  268. #$path = suivre_lien(url_absolue($source),'./');
  269. $base = ((substr($source,-1)=='/')?$source:(dirname($source).'/'));
  270. return preg_replace_callback(
  271. ",url\s*\(\s*['\"]?([^'\"/][^:]*[.](png|gif|jpg))['\"]?\s*\),Uims",
  272. create_function('$x',
  273. 'return "url(\"".filtre_embarque_fichier($x[1],"'.$base.'")."\")";'
  274. ), $contenu);
  275. }