"; } function compacte_ecrire_balise_link_dist($src,$media=""){ return ""; } // http://doc.spip.org/@compacte_css function compacte_css ($contenu) { // nettoyer la css de tout ce qui sert pas $contenu = preg_replace(",/\*.*\*/,Ums","",$contenu); // pas de commentaires $contenu = preg_replace(",\s(?=\s),Ums","",$contenu); // pas d'espaces consecutifs $contenu = preg_replace("/\s?({|;|,|:)\s?/ms","$1",$contenu); // pas d'espaces dans les declarations css $contenu = preg_replace("/\s}/ms","}",$contenu); // pas d'espaces dans les declarations css // passser les codes couleurs en 3 car si possible // uniquement si non precedees d'un [="'] ce qui indique qu'on est dans un filter(xx=#?...) $contenu = preg_replace(";([:\s,(])#([0-9a-f])(\\2)([0-9a-f])(\\4)([0-9a-f])(\\6)(?=[^\w\-]);i","$1#$2$4$6",$contenu); // supprimer les declarations vides $contenu = preg_replace(",(^|})([^{}]*){},Ums","$1",$contenu); $contenu = trim($contenu); return $contenu; } // Compacte du javascript grace a Dean Edward's JavaScriptPacker // utile pour prive/jquery.js par exemple // http://doc.spip.org/@compacte_js function compacte_js($flux) { // si la closure est demandee, on pourrait zapper cette etape // mais avec le risque, en localhost, de depasser 200ko et d'echec #if ($GLOBALS['meta']['auto_compress_closure'] == 'oui') # return $flux; if (!strlen($flux)) return $flux; include_spip('lib/JavascriptPacker/class.JavaScriptPacker'); $packer = new JavaScriptPacker($flux, 0, true, false); // en cas d'echec (?) renvoyer l'original if (!strlen($t = $packer->pack())) { spip_log('erreur de compacte_js'); return $flux; } return $t; } // Appelee par compacte_head() si le webmestre le desire, cette fonction // compacte les scripts js dans un fichier statique pose dans local/ // en entree : un html. // http://doc.spip.org/@compacte_head_js function compacte_head_js($flux) { $url_base = url_de_base(); $url_page = substr(generer_url_public('A'), 0, -1); $dir = preg_quote($url_page,',').'|'.preg_quote(preg_replace(",^$url_base,",_DIR_RACINE,$url_page),','); $scripts = array(); $flux_nocomment = preg_replace(",,Uims","",$flux); foreach (extraire_balises($flux_nocomment,'script') as $s) { if (extraire_attribut($s, 'type') === 'text/javascript' AND is_null(extraire_attribut($s, 'id')) # script avec un id : pas touche AND $src = extraire_attribut($s, 'src') AND !strlen(strip_tags($s)) AND ( preg_match(',^('.$dir.')(.*)$,', $src, $r) OR ( // ou si c'est un fichier $src = preg_replace(',^'.preg_quote(url_de_base(),',').',', '', $src) // enlever un timestamp eventuel derriere un nom de fichier statique AND $src2 = preg_replace(",[.]js[?].+$,",'.js',$src) // verifier qu'il n'y a pas de ../ ni / au debut (securite) AND !preg_match(',(^/|\.\.),', substr($src,strlen(_DIR_RACINE))) // et si il est lisible AND @is_readable($src2) ) )) { if ($r) $scripts[$s] = explode('&', str_replace('&', '&', $r[2]), 2); else $scripts[$s] = $src; } } if (list($src,$comms) = filtre_cache_static($scripts,'js')){ $compacte_ecrire_balise_script = charger_fonction('compacte_ecrire_balise_script',''); $scripts = array_keys($scripts); $flux = str_replace(reset($scripts), $comms .$compacte_ecrire_balise_script($src)."\n", $flux); $flux = str_replace($scripts,"",$flux); } return $flux; } // Appelee par compacte_head() si le webmestre le desire, cette fonction // compacte les feuilles de style css dans un fichier statique pose dans local/ // en entree : un html. // http://doc.spip.org/@compacte_head_css function compacte_head_css($flux) { $url_base = url_de_base(); $url_page = substr(generer_url_public('A'), 0, -1); $dir = preg_quote($url_page,',').'|'.preg_quote(preg_replace(",^$url_base,",_DIR_RACINE,$url_page),','); $css = array(); $flux_nocomment = preg_replace(",,Uims","",$flux); foreach (extraire_balises($flux_nocomment, 'link') as $s) { if (extraire_attribut($s, 'rel') === 'stylesheet' AND (!($type = extraire_attribut($s, 'type')) OR $type == 'text/css') AND is_null(extraire_attribut($s, 'name')) # css nommee : pas touche AND is_null(extraire_attribut($s, 'id')) # idem AND !strlen(strip_tags($s)) AND $src = preg_replace(",^$url_base,",_DIR_RACINE,extraire_attribut($s, 'href')) AND ( // regarder si c'est du format spip.php?page=xxx preg_match(',^('.$dir.')(.*)$,', $src, $r) OR ( // ou si c'est un fichier // enlever un timestamp eventuel derriere un nom de fichier statique $src2 = preg_replace(",[.]css[?].+$,",'.css',$src) // verifier qu'il n'y a pas de ../ ni / au debut (securite) AND !preg_match(',(^/|\.\.),', substr($src2,strlen(_DIR_RACINE))) // et si il est lisible AND @is_readable($src2) ) )) { $media = strval(extraire_attribut($s, 'media')); if ($media==='') $media='all'; if ($r) $css[$media][$s] = explode('&', str_replace('&', '&', $r[2]), 2); else $css[$media][$s] = $src; } } // et mettre le tout dans un cache statique foreach($css as $m=>$s){ // si plus d'une css pour ce media ou si c'est une css dynamique if (count($s)>1 OR is_array(reset($s))){ if (list($src,$comms) = filtre_cache_static($s,'css')){ $compacte_ecrire_balise_link = charger_fonction('compacte_ecrire_balise_link',''); $s = array_keys($s); $flux = str_replace(reset($s), $comms . $compacte_ecrire_balise_link($src,$m)."\n", $flux); $flux = str_replace($s,"",$flux); } } } return $flux; } // http://doc.spip.org/@filtre_cache_static function filtre_cache_static($scripts,$type='js'){ $nom = ""; if (!is_array($scripts) && $scripts) $scripts = array($scripts); if (count($scripts)){ $dir = sous_repertoire(_DIR_VAR,'cache-'.$type); $nom = $dir . md5(serialize($scripts)) . ".$type"; if ( $GLOBALS['var_mode']=='recalcul' OR !file_exists($nom) ) { $fichier = ""; $comms = array(); $total = 0; foreach($scripts as $script){ if (!is_array($script)) { // c'est un fichier $comm = $script; // enlever le timestamp si besoin $script = preg_replace(",[?].+$,",'',$script); if ($type=='css'){ $fonctions = array('urls_absolues_css'); if (isset($GLOBALS['compresseur_filtres_css']) AND is_array($GLOBALS['compresseur_filtres_css'])) $fonctions = $GLOBALS['compresseur_filtres_css'] + $fonctions; $script = appliquer_fonctions_css_fichier($fonctions, $script); } lire_fichier($script, $contenu); } else { // c'est un squelette $comm = _SPIP_PAGE . "=$script[0]" . (strlen($script[1])?"($script[1])":''); parse_str($script[1],$contexte); $contenu = recuperer_fond($script[0],$contexte); if ($type=='css'){ $fonctions = array('urls_absolues_css'); if (isset($GLOBALS['compresseur_filtres_css']) AND is_array($GLOBALS['compresseur_filtres_css'])) $fonctions = $GLOBALS['compresseur_filtres_css'] + $fonctions; $contenu = appliquer_fonctions_css_contenu($fonctions, $contenu, self('&')); } } $f = 'compacte_'.$type; $fichier .= "/* $comm */\n". $f($contenu) . "\n\n"; $comms[] = $comm; $total += strlen($contenu); } // calcul du % de compactage $pc = ($total?intval(1000*strlen($fichier)/$total)/10:0); $comms = "compact [\n\t".join("\n\t", $comms)."\n] $pc%"; $fichier = "/* $comms */\n\n".$fichier; // ecrire ecrire_fichier($nom,$fichier,true); // ecrire une version .gz pour content-negociation par apache, cf. [11539] ecrire_fichier("$nom.gz",$fichier,true); } // closure compiler ou autre super-compresseurs compresse_encore($nom, $type); } // Le commentaire detaille n'apparait qu'au recalcul, pour debug return array($nom, (isset($comms) AND $comms) ? "\n" : ''); } // experimenter le Closure Compiler de Google function compresse_encore (&$nom, $type) { # Closure Compiler n'accepte pas des POST plus gros que 200 000 octets # au-dela il faut stocker dans un fichier, et envoyer l'url du fichier # dans code_url ; en localhost ca ne marche evidemment pas if ( $GLOBALS['meta']['auto_compress_closure'] == 'oui' AND $type=='js' ) { lire_fichier($nom, $fichier); $dest = dirname($nom).'/'.md5($fichier).'.js'; if (!@file_exists($dest)) { include_spip('inc/distant'); $datas=array( 'output_format' => 'text', 'output_info' => 'compiled_code', 'compilation_level' => 'SIMPLE_OPTIMIZATIONS', // 'SIMPLE_OPTIMIZATIONS', 'WHITESPACE_ONLY', 'ADVANCED_OPTIMIZATIONS' ); if (strlen($fichier) < 200000) $datas['js_code'] = $fichier; else $datas['url_code'] = url_absolue($nom); $cc = recuperer_page('http://closure-compiler.appspot.com/compile', $trans=false, $get_headers=false, $taille_max = null, $datas, $boundary = -1); if ($cc AND !preg_match(',^\s*Error,', $cc)) { spip_log('Closure Compiler: success'); $cc = "/* $nom + Closure Compiler */\n".$cc; ecrire_fichier ($dest, $cc, true); ecrire_fichier ("$dest.gz", $cc, true); } else ecrire_fichier ($dest, '', true); } if (@filesize($dest)) $nom = $dest; } } function appliquer_fonctions_css_fichier($fonctions,$css) { if (!preg_match(',\.css$,i', $css, $r)) return $css; $url_absolue_css = url_absolue($css); // verifier qu'on a un array if (is_string($fonctions)) $fonctions = array($fonctions); $sign = implode(",",$fonctions); $sign = substr(md5("$css-$sign"), 0,8); $file = basename($css,'.css'); $file = sous_repertoire (_DIR_VAR, 'cache-css') . preg_replace(",(.*?)(_rtl|_ltr)?$,","\\1-f-" . $sign . "\\2",$file) . '.css'; if ((@filemtime($f) > @filemtime($css)) AND ($GLOBALS['var_mode'] != 'recalcul')) return $f; if ($url_absolue_css==$css){ if (strncmp($GLOBALS['meta']['adresse_site'],$css,$l=strlen($GLOBALS['meta']['adresse_site']))!=0 OR !lire_fichier(_DIR_RACINE . substr($css,$l), $contenu)){ include_spip('inc/distant'); if (!$contenu = recuperer_page($css)) return $css; } } elseif (!lire_fichier($css, $contenu)) return $css; $contenu = appliquer_fonctions_css_contenu($fonctions, $contenu, $css); // ecrire la css if (!ecrire_fichier($file, $contenu)) return $css; return $file; } function appliquer_fonctions_css_contenu($fonctions, &$contenu, $base) { foreach($fonctions as $f) if (function_exists($f)) $contenu = $f($contenu, $base); return $contenu; } function compresseur_embarquer_images_css($contenu, $source){ #$path = suivre_lien(url_absolue($source),'./'); $base = ((substr($source,-1)=='/')?$source:(dirname($source).'/')); return preg_replace_callback( ",url\s*\(\s*['\"]?([^'\"/][^:]*[.](png|gif|jpg))['\"]?\s*\),Uims", create_function('$x', 'return "url(\"".filtre_embarque_fichier($x[1],"'.$base.'")."\")";' ), $contenu); }