PageRenderTime 49ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

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

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