août
9
2009

Headers – Compression CSS

Bonjours, je commence une série d’articles pour vous montrer la solution mise en place pour compresser les en-têtes de votre site.

Attention, pour le moment la solution n’est pas encore 100% fonctionnelle, à l’heure où j’écris ces lignes, sur le site je fonctionne encore avec le Zend_Cache utilisant les fichiers. En local, je travail avec Zend_Cache utilisant le cache APC. Certains problèmes me sont apparus avec les fichiers et ils ont disparus avec APC.

Donc tout d’abord je vais vous présenter le filtre que j’utilise pour compresser le contenu de mes fichiers CSS, ensuite je vous présente la méthode utilisée pour récupérer dans mon layout tous les appels à mes styles et pour finir comment je fais croire qu’il y a qu’un seul fichier CSS.

Attention: dans les exemples que je vais vous montrer, je vais faire appel à la classe App_Cache. Cette classe est donnée dans le livre Zend Framework – Bien développer en php.

Tout d’abord, pour compresser le contenu des fichiers CSS j’utilise le filtre présent ci-dessous. Il permet de supprimer toutes les tabulations, espaces en trop, commentaires présents dans le fichier.

 PHP |  copy code |? 
01
/**
02
 * Filtre servant à compresser des données CSS lors de la mise en cache par exemple.
03
 * 
04
 * Supprime les espaces en trop, les commentaires et met tout sur une seule ligne.
05
 * 
06
 * @author Throrin
07
 *
08
 */
09
class App_Filter_CssCompressor implements Zend_Filter_Interface 
10
{
11
	public function filter($value) 
12
	{
13
		$value = preg_replace('!/\*[^*]*\*+([^/][^*]*\*+)*/!', '', $value);
14
	    $value = str_replace(array("\r\n", "\r", "\n", "\t", '  '), '', $value);
15
	    $value = str_replace('{ ', '{', $value);
16
	    $value = str_replace(' }', '}', $value);
17
	    $value = str_replace('; ', ';', $value);
18
	    $value = str_replace(', ', ',', $value);
19
	    $value = str_replace(' {', '{', $value);
20
	    $value = str_replace('} ', '}', $value);
21
	    $value = str_replace(': ', ':', $value);
22
	    $value = str_replace(' ,', ',', $value);
23
	    $value = str_replace(' ;', ';', $value);
24
 
25
	    return $value;
26
	}
27
}

Ensuite, nous devons commencer par rajouter certaines lignes dans la partie contenant tous nos appels au CSS. Pour ce faire j’utilise la fonction ob_start() de PHP permettant de stocker ce qui suit dans un buffer et je le récupère avec la fonction ob_get_contents(). Pour finir à la suite de sa je ferais appel aux actions qui serviront à stocker le tout dans le cache grâce à la fonction $this->action().

 HTML |  copy code |? 
01
<?php
02
ob_start();
03
?>
04
 
05
<link rel="stylesheet" href="<?php echo $this->baseUrl();?>/styles/unstyle.css" type="text/css" media="screen" /><
06
<?php
07
//autres fiches CSS
08
?>
09
 
10
<?php echo $this->headScript()."\n"; ?>
11
 
12
<script type="text/javascript" src="<?php echo $this->baseUrl();?>/scripts/unscript.js"></script>
13
<?php
14
//autres fiches JS
15
?>
16
 
17
<?php echo $this->jQuery()->addStylesheet($this->baseUrl().'/styles/jquery-ui-1.7.2.custom.css')
18
						->setUiLocalPath($this->baseUrl().'/scripts/jquery-ui-1.7.2.custom.min.js')
19
	         			->setLocalPath($this->baseUrl().'/scripts/jquery-1.3.2.min.js')."\n"; ?>
20
 
21
<?php 
22
	$output = ob_get_contents();
23
	$css = $this->action('compresscss', 'header', 'compress', array('contenu' => $output));
24
	ob_end_clean();
25
?>

Voilà pour ici, maintenant on s’attaque à notre contrôleur qui va parcourir le contenu du buffer pour récupérer le lien vers chaque CSS. Ensuite il va lire le contenu des CSS, le compresser grâce à notre filtre et envoyer son contenu en cache. Pour éviter de répéter cette action assez lourde à chaque appel de l’action, on testera si le cache a bien été créé.

 PHP |  copy code |? 
01
class Compress_HeaderController extends Zend_Controller_Action
02
{	
03
	public function compresscssAction()
04
	{
05
		$css = App_Cache::get('csssite');
06
 
07
		if(!$css) {
08
			$cssoffset = $this->_request->getParam('contenu');
09
 
10
			//on récupère tous les fichiers CSS
11
			preg_match_all('/link rel="stylesheet" href="(.*?)"/', $cssoffset, $matches);
12
			$i = 0;
13
			$n = count($matches[1]);
14
			$contenucss = '';
15
			//on parcour le tableau des fichiers CSS
16
			while($i < $n) 
17
			{
18
				$lienscss = str_replace('//', '/', $_SERVER['DOCUMENT_ROOT']."/zendtuto18/public"); //lien absolu vers votre dossier public
19
				$liens = str_replace('/test18', '', $matches[1][$i]);
20
				$handle = fopen($lienscss.$liens,'r');
21
				$contenucss .= fread($handle, filesize($lienscss.$liens));
22
				$i++;
23
			}
24
                        $filtrecss = new App_Filter_CssCompressor();
25
			$contenucss = $filtrecss->filter($contenucss);
26
 
27
			App_Cache::set($contenucss, 'csssite');
28
		}
29
	}
30
}

Voilà pour le contrôleur. Le problème c’est qu’il faut bien dire quel CSS on affiche. C’est pourquoi dans la vue de cette action vous allez mettre juste cette ligne:

 HTML |  copy code |? 
1
<link rel="stylesheet" href="<?php echo $this->baseUrl();?>/styles/style.css" type="text/css" media="screen" />
2

Maintenant il y a une question qui vous brûle les levres et qui doit être: « Qu’est-ce que ce fichier style.css? ». Ce fichier est en fait un lien vers notre action d’affichage. Pour ce faire nous devons créer la règle de réécriture présente ci-dessous (htaccess et zend_route).

.htaccess :

 Apache configuration |  copy code |? 
1
RewriteRule ^(.*)styles/style.css$ /compress/header/css [L]

bootstrap.php dans l’action _initRoute() :

 PHP |  copy code |? 
1
$router->addRoute(
2
    'manageCSS',
3
    new Zend_Controller_Router_Route('styles/style.css', array('module' => 'compress', 'controller'=>'header','action'=>'css'))
4
);

Voilà, cette règle a été nécessaire pour pas casser tous les liens relatifs présents dans les fichiers CSS. Ensuite il ne vous reste plus qu’à créer cette action dans le contrôleur header afin d’afficher le style:

 PHP |  copy code |? 
01
public function cssAction()
02
{
03
		$this->_helper->layout()->disableLayout();
04
		$this->_helper->viewRenderer->setNoRender(true);
05
		$css = App_Cache::get('css');
06
 
07
		$this->getResponse()->setHeader("Content-type","text/css; charset: UTF-8");
08
		$this->getResponse()->setHeader("Cache-Control","must-revalidate");
09
		$offset = 60 * 60 ;
10
		$ExpStr = gmdate("D, d M Y H:i:s",time() + $offset) . " GMT";
11
		$this->getResponse()->setHeader("Expires: ", $ExpStr);
12
		echo $css;
13
}

Après ceci tout devrai fonctionner comme sur des roulettes. Pour la partie JS tout est à peu près de ce genre. Seules quelques étapes supplémentaires sont nécessaires pour tout récupérer. J’espère que cet article vous aura permi de trouver une méthode pour compresser vos styles. Par contre évitez de l’utiliser pour un site necessitant un fichier CSS différent par pages. Effectivement en cache vous aurez que le contenu des css inclus dans la première page.

Articles Connexes

A propos de l'Auteur: Benjamin Besse

Je suis Analyste Développeur chez Goomeo et je suis passioné par tout ce qui touche aux technologies du Web. J'ai commencé par apprendre l'utilisation du Framework Zend et j'ai continué naturellement via Android. Le tout seulement avec les bases acquises en DUT et Licence professionnelle Informatique.

Laisser un commentaire

Mots-Clefs