source: spip-zone/_plugins_/less-css/trunk/lesscss_fonctions.php @ 66257

Last change on this file since 66257 was 66257, checked in by cedric@…, 7 years ago

Ne pas generer une erreur de compilation si la source .less est vide. L'indiquer simplement dans le fichier resultat

  • Property svn:executable set to *
File size: 5.7 KB
Line 
1<?php
2
3/**
4 * Compiler des styles inline LESS en CSS
5 *
6 * @param string $style
7 *   contenu du .less
8 * @param array $contexte
9 *   file : chemin du fichier compile
10 *          utilise en cas de message d'erreur, et pour le repertoire de reference des @import
11 * @return string
12 */
13function less_compile($style, $contexte = array()){
14        require_once 'lessphp/lessc.inc.php';
15
16        $import_dir = null;
17        if (isset($contexte['file']))
18                $import_dir = dirname($contexte['file']);
19
20        // le compilateur lessc compile le contenu
21        $less = new lessc();
22        if ($import_dir){
23                $import_dir = rtrim($import_dir,"/")."/";
24                $less->importDir = $import_dir;
25        }
26        try {
27                // avant compilation par less, remplacer les @import_spip par un @import+find_in_path
28                if (preg_match_all(",@import_spip\s+['\"]([^'\"]+)['\"],",$style,$matches,PREG_SET_ORDER)){
29                        if ($import_dir){
30                                // faker le chemin depuis le $import_dir
31                                $i = $import_dir."dummy";$base = "";
32                                while ($i AND ($i = dirname($i))!=".") {$base.="../";};
33                                $ide= explode('/',$import_dir);
34                                foreach($matches as $m){
35                                        if ($f=find_in_path($m[1])){
36                                                // calculer un chemin relatif propre avec le moins de ../ possible
37                                                $fe = explode("/",$f);
38                                                $be = explode("/",$base);
39                                                $l = min(count($ide),count($fe));
40                                                for($i=0;$i<$l;$i++){
41                                                        if (reset($fe)==$ide[$i]){
42                                                                array_shift($fe);
43                                                                array_shift($be);
44                                                        }
45                                                        else
46                                                                break;
47                                                }
48                                                $be = implode("/",$be);
49                                                $fe = implode("/",$fe);
50                                                $style = str_replace($m[0],"@import '$be$fe'",$style);
51                                        }
52                                }
53                        }
54                        else {
55                                spip_log('lessc @import_spip sans contexte de chemin','less'._LOG_ERREUR);
56                                erreur_squelette(
57                                        "LESS : @import_spip sans contexte de chemin"
58                                        . (isset($contexte['file'])?" fichier ".$contexte['file']:"")
59                                );
60                        }
61                }
62                $out = $less->parse($style);
63                return $out;
64        }
65        // en cas d'erreur, on retourne du vide...
66        catch (exception $ex) {
67                spip_log('lessc fatal error:'.$ex->getMessage(),'less'._LOG_ERREUR);
68                erreur_squelette(
69                        "LESS : Echec compilation"
70                        . (isset($contexte['file'])?" fichier ".$contexte['file']:"")
71                  . "<br />".$ex->getMessage()
72                );
73                return '';
74        }
75}
76
77/**
78 * Transformer du LESS en CSS
79 * Peut prendre en entree
80 * - un fichier .css ou .less :
81 *   [(#CHEMIN{messtyles.less.css}|less_css)]
82 *   la sortie est un chemin vers un fichier CSS
83 * - des styles inline,
84 *   pour appliquer dans une feulle less calculee :
85 *   #FILTRE{less_css}
86 *   la sortie est du style inline
87 *
88 * @param string $source
89 * @return string
90 */
91function less_css($source){
92        // Si on n'importe pas, est-ce un fichier ?
93        if (!preg_match(',[\s{}],', $source)
94          AND preg_match(',\.(less|css)$,i', $source, $r)
95          AND file_exists($source)) {
96                static $done = array();
97                // ne pas essayer de compiler deux fois le meme fichier dans le meme hit
98                // si on a echoue une fois, on echouera pareil
99                if (isset($done[$source])) return $done[$source];
100
101                $f = basename($source,$r[0]);
102                $f = sous_repertoire (_DIR_VAR, 'cache-less')
103                . preg_replace(",(.*?)(_rtl|_ltr)?$,","\\1-cssify-"
104                . substr(md5("$source-lesscss"), 0,4) . "\\2", $f, 1)
105                . '.css';
106
107                # si la feuille compilee est plus recente que la feuille source
108                # l'utiliser sans rien faire, sauf si recalcul explicite
109                if ((@filemtime($f) > @filemtime($source))
110                  AND (!defined('_VAR_MODE') OR _VAR_MODE != 'recalcul'))
111                        return $f;
112
113                if (!lire_fichier($source, $contenu))
114                        return $source;
115
116                # compiler le LESS si besoin (ne pas generer une erreur si source vide
117                if (!$contenu){
118                        $contenu = "/* Source $source : vide */\n";
119                }
120                else {
121                        $contenu = less_compile($contenu, array('file'=>$source));
122                }
123                // si erreur de compilation on renvoit un commentaire, et il y a deja eu un log
124                if (!$contenu){
125                        $contenu = "/* Compilation $source : vide */\n";
126                }
127
128                # passer la css en url absolue (on ne peut pas le faire avant, car c'est du LESS, pas des CSS)
129                $contenu = urls_absolues_css($contenu, $source);
130
131                // ecrire le fichier destination, en cas d'echec renvoyer la source
132                if (ecrire_fichier($f, $contenu, true))
133                        return $done[$source] = $f;
134                else
135                        return $done[$source] = $source;
136        }
137        $source = less_compile($source);
138        if (!$source)
139                return "/* Erreur compilation LESS : cf less.log */";
140        else
141                return $source;
142}
143
144
145/**
146 * injecter l'appel au compresseur sous la forme de filtre
147 * pour intervenir sur l'ensemble du head
148 * du squelette public
149 *
150 * @param string $flux
151 * @return string
152 */
153function lesscss_insert_head($flux){
154        $flux .= '<'
155                .'?php header("X-Spip-Filtre: '
156                .'cssify_head'
157                .'"); ?'.'>';
158        return $flux;
159}
160
161
162/**
163 * Attraper automatiquement toutes les .less ou .less.css du head
164 * les compiler, et les remplacer par leur css compilee
165 *
166 * @param string $head
167 * @return void
168 */
169function cssify_head($head){
170        $url_base = url_de_base();
171        $balises = extraire_balises($head,'link');
172        $files = array();
173        foreach ($balises as $s){
174                if (extraire_attribut($s, 'rel') === 'stylesheet'
175                        AND (!($type = extraire_attribut($s, 'type')) OR $type == 'text/css')
176                        AND $src = extraire_attribut($s, 'href')
177                        // format .less.css ou .less avec un eventuel timestamp ?123456
178                        AND preg_match(",\.(less\.css|less)(\?\d+)?$,",$src)
179                        AND $src = preg_replace(",\?\d+$,","",$src)
180                        AND $src = preg_replace(",^$url_base,",_DIR_RACINE,$src)
181                        AND file_exists($src))
182                        $files[$s] = $src;
183        }
184
185        if (!count($files))
186                return $head;
187
188        foreach($files as $s=>$lessfile){
189                $cssfile = less_css($lessfile);
190                $m = @filemtime($cssfile);
191                $s2 = inserer_attribut($s,"href","$cssfile?$m");
192                $head = str_replace($s, $s2, $head);
193        }
194       
195        return $head;
196}
197?>
Note: See TracBrowser for help on using the repository browser.