Mise en cache des pages php : mon alternative hérétique !

WRInaute accro
HERETIQUE TU ES ... HERETIQUE TU RESTES !

Ben oui, comme d'habitude, il faut que je me fasse les trucs à ma sauce :!: J'ai lu l'enorme topic épinglé sur le sujet ... ainsi que les multiples variantes et alternatives proposées sur des sites linkés par ce topic ... Interessant mais usant ... vu la taille du topic ...

Ce que j'en retiens est que la mise en cache de page entière ne me convient pas :

1 - Ca implique que seule la version visiteur non inscrits/connecté est "cachable" et que donc seuls les visiteurs non inscrits sont concernés (tant sur le plan vitesse pour eux que sur le plan décharge de la bdd par eux). Les membres inscrits eux auront un affichage plus lent et se traduiront par une charge supérieure ... Pas glop pas glop ...

2 - Qu'il vous vienne à l'idée d'ajouter une "*" sur un élément présent sur toutes les les pages (style un onglet de plus dans la barre de menu ou même n'importe quel element statiques dans les pages) et hop c'est tout votre cache (ou toutes le spages ayant en commun cet élément statique) qui devient obsolète et part à la benne ... et devra être regénéré (soit massivement soit petit a petit au gré des affichages de page).

3 - Il est des contextes (mutu) ou la place sur disque est aussi comptée et donc mettre l integralité de la page en cache revient a stocker 100000 fois (si le site fait 100000 pages) la meme entete, la meme barre de menu, le meme footer etc etc. Et au final on en vient a régénerer sur le disque une version statique du site ... alors que dans le meme temps on va pinailler dans la bdd entre INT et LONGINT !!!! Pas très cohérent.

Parce que sur le fond, la mise en cache à pour objectif principal si j'ai pas sauté une marche de soulager la charge serveur au niveau des sollicitations de la base de données et, accessoirement de profiter d'un affichage plus rapide des pages puisque pas / ou moins de requete sql et moins de code de fabrication des eléments de mises en page.

Ayant posé ces postulat, j'en suis venu a commencer a me poser la question "quelle partie des pages mérite d'être mise en cache" ... Plutot qu'un long discours, deux exemples concret avec 1 page a l'url fixe "index.php" et une autre page "rewritée".

La page index de mon www :

cache_index.png

Url pour la voir en real : http://www.qui-est-le-meilleur.com

Si je tiens compte des constat ci-dessus, j'en arrive a considérer :

- toute la partie haute (cadre violet) non cachable (du pur statique donc zero economie mysql).
- la partie centrale (cadre vert) tout a fait dans la cible (y a deux requetes sql a gratter) et l'affichage ets le meme que l'on soit visiteur ou memebre inscrit.
- la partie basse (cadre rouge) mérite analyse car elle me consomme elle aussi 2 requetes sql la bougresse ... sauf que ca bouge tellement tout le temps (dès qu'un membre se gratte le nez ca fait bouger un truc la dedans) que l'on passerait plus de temps a supprimer/recréer le cache qu'à l'exploiter ... donc on l'oublie.
- Reste tout en haut d el'ecran la mention du connecté/non connecté. Par definition on l'oublie puisque l'on veut du cache "tout terrain" : inscrit / non inscrit / bot sans distinction.

UNe page de type histo :

cache_histo.png

Url pour la voir en real : http://www.qui-est-le-meilleur.com/historique-2011-05-11.php

Si je choisi ce type de page, c'est que d'une part est elle simple dans son contenu (toujours plus facile dans le cadre d'explication ecrites) et que c'est une page avec paramètres et donc rewritée (contrairement a index.php ci-dessus). et cela a son importance pour la suite ... Mais non je plaisante : on se tappe royalement du rewriting (vou spouvez chager 10 fois vos régles dan sle htaccess sans impact sur la gestion du cache puisque ce ne sont pas des pages mais des "paquets de data" que l'on va mettre en cache ... et a qui on donne un petit nom deconnecté du rewriting (enfin en cohérence quand meme ...)

Selon la meme logique que ci-dessus on en vient a conclure que la seule partie cachable sera le cadre central (de toute façon c'est le seul qui consomme 1 requete mysql dans la page). En plus ce type de page a un gros avantage dans le cadre d'un cache : son cache est éternel ... puisque une fois une journée finie, ca ne bouge plus ...

Note : la on raisonne pour l'exempel sur une page qui consomme une micro requete sql et une seule donc l'impact sera faible mais le meme raisonnement s'applqiue sur un bloc necessitant quelques grosses requetes gourmandes avec jointure et tout et tout ...

MISE EN MUSIQUE

Bon ben ayant posé comme postulat que l'on ne gérait plus du cache de pages php mais du cache de morceau de pages, restait à le coder en essayant de mettre un place un truc facile a implanter avec un minimum de code (ma flemme est désormais bien connue donc autant y faire honneur) et offrant toute souplesse de choix pour chaque type de page ... Bref le beurre, les dihrams et la chamelière en prime ! Oui oui c'est une version locale que je viens d'inventer ...

Et finalement ca commence plutot bien puisque tout mon systeme de cache va reposer sur 5 petits script de 4 à 6 lignes ! Pourquoi faire plus si on peut faire moins ... Allez un peu de code lisible même par les phprank1 :

Cache_ecrire.php
Code:
<?php
	$cache_tampon = ob_get_contents();
	if(!is_dir($cache_dossier)) { mkdir ($cache_dossier); }
	$cache_ref = fopen ($cache_chemin, "w+");
	fputs ($cache_ref, $cache_tampon);
	fclose ($cache_ref);
?>
Ca va pas trop fatigué le chat ? nan nan ca va ...

Cache_lire.php
Code:
<?php
		$cache_dossier=$_SERVER["DOCUMENT_ROOT"].'/CACHE_'.$cache_version.'/';
		$cache_document=$cache_nom.$cache_param.'.php';
		$cache_chemin=$cache_dossier.$cache_document;
		if(file_exists($cache_chemin))
		{
			echo("."); // debug : signalement debut lu dans cache
			readfile($cache_chemin);
			echo(".."); // debug : signalement fin lu dans cache
			$cache_trouve=true;	
		}
		else { $cache_trouve=false; }
?>

Ouai là non plus pas de callosités sous les indexes !

Cache_detruire.php

Code:
<?php
		$cache_dossier=$_SERVER["DOCUMENT_ROOT"].'/CACHE_'.$cache_version.'/';
		$cache_document=$cache_nom.'.php';
		$cache_chemin=$cache_dossier.$cache_document;
		if(file_exists($cache_chemin))
		{
			echo("Suppression du cache : ".$cache_document."<br>");
			$cache_ouverture = opendir ($cache_dossier);
   			unlink ($cache_chemin);
  			closedir ($cache_ouverture);
		}
?>

Note : ici on peut choisir d'autres options (ne pas detruire mais réécrire vide), ou encore ne rien toucher à part ecraser le premier octet du document avec une "*" d'invalidation (ultra vite ecrit et vite testé ...). Perso en prod je pense que c'est cette option que je choisirai ... il suffira de changer la façon de tester dans cache_lire ...

Arrête zecat, tu frises la suractivité et l'usure prématurée du clavier ...

Cache_affiche.php

Code:
<?php
		include("cache_lire.php"); // on regarde si il existe et on l'affiche si oui
		if(!$cache_trouve) // si pas de cache trouvé
		{
			echo("<u>.</u>"); // debug : signalement debut fab cache
			ob_start(); // debut mise en tampon
				switch ($cache_nom)
				{
					case 'cache_aaaaaa_1':
						include("aaaaaa_cache_fab_1.php"); // fabrication morceau 1 de page aaaaaa
						break;


					case 'cache_bbbbbb_1':
						include("bbbbbb_cache_fab_1.php"); // fabrication cadre central page bbbbbb
						break;
				}

				include("cache_ecrire.php"); // on ecrit le cache sur disque
			ob_end_clean(); // arret mise en tampon
			echo($cache_tampon); // on affiche ce qu'on vient de fabriquer
			echo("<u>..</u>"); // debug : signalement fin fab cache
		}
?>
Houla vite une chaise longue ...

cache_impacter.php

Code:
<?php
	$cache_dossier=$_SERVER["DOCUMENT_ROOT"].'/CACHE_'.$cache_version.'/';
	if(is_dir($cache_dossier))
	{	
		$ouverture = opendir ($cache_dossier);
		echo("Impact cache : "); // echo de debug
		foreach($tab_cache_impact as $cache_document)
		{
			echo($cache_document."/"); // echo de debug
			$cache_chemin=$cache_dossier.$cache_document;
			if(file_exists($cache_chemin)) { unlink ($cache_chemin); }
		}
		closedir ($ouverture);
	}		
?>

Voila c'est tout. Toutes les routines sont en place.

MISE EN APPLICATION SUR LA PAGE INDEX.PHP

Son code (avant gestion cache) est simple (j'ai juste renommé les scripts pour la clarté mais c'est tout) :

Code:
<?php
	include ("entete.php");
	include ("menu.php");
                include ("presentation.php");
                include ("actus_ajouts.php");
                include ("cadre_qui.php");
	include("affiche_pied_haut.php");
?>

On a vu que la seule partie de la page qui nous intéresse au titre de la mise en cache est actus_ajouts ... je modifie donc cette page ainsi :

Code:
<?php
	include ("entete.php");
	include ("menu.php");
                include ("presentation.php");
               
                       $cache_nom="cache_index_1";
                       include("cache_affiche.php");

                include ("cadre_qui.php");
	include("affiche_pied_haut.php");
?>

et on mets actus_ajouts dans le switch de cache_affiche à la place de aaaaaa ..
(le premier case) :

Code:
case 'cache_index_1:
     include("actus_ajouts.php");

En gros je décide de donner un zouli petit nom à ce bloc et je l'appelle, notez l'originalité et la recherche "cache_index_1" (1 c'est parce que rien n'interdit d'avoir demain un autre bloc cache dans cette même page ... on le nommera surement ... cache_index_2 !

VOILA C'EST FINI ... OU PRESQUE ...

On lance désormais index.php sur notre navigateur ... cadre_affiche est lancé. il regarde si il a le nom demandé en stock (cache_index_1) ... Nada ! Donc il passe en mode "tampon" et execute le code normal "actus_ajouts.php" puis le balance sur le disque (cache_ecrire) et l'affiche normalement. Les encadrements par "." et ".." c'est juste pour voir les scripts agir en phase debug. On vient donc de génerer le cache du morceau voulu (que le visiteur soit un bot, un visiteur ou un inscrit). On pourra juste ajouter un if (gooogloubot) pas d'ecriture cache (histoire de travailler sa courbe dans GWT).

Maintenant votre voisine de palier arrive aussi sur cette page, ca execute cache_affiche, qui trouve le cache demandé et donc cache_lire lit et affiche le morceau voulu avec "readfile($cache_chemin);" et saute le reste.

Pour la page historique c'est le meme principe sauf que comme c'est une page avec un parametre en entrée le code devient :

La page avant :

Code:
<?php
	...

                include ("historique_liste.php");

                ...
?>

La page apres :

Code:
<?php
	...
                       $cache_param="_".date('Ymd');
                       $cache_nom="cache_historique_1";
                       include("cache_affiche.php");

                ...
?>

Vous noterez la seule différence avec la page index : on passe une valeur date du jour dans $cache_param (pas mis direct dans cache_nom pour que l'on reste dans un seul case au niveau du switch. Et le second switch de case_affiche :

Code:
case 'cache_historique_1':
     $date_histo=$cache_param;
     include ("historique_liste.php");

Voila nous disposons d'un systeme de cache permettant de couvrir les pages a url fixe et les pages avec paramètres ... en prenant en cache dans les pages le ou les paquets qui nous intéressent ...

PAS DE DUREE DE VIE A PRIORI

Ben non ! Un morceau en cache n'a aucune raison de sortir de sa cachette (ah c'est malin ...) tant qu'on le laisse dormir ... Certains caches seront éternels (cf historiques) et d'autres à durée de vie plus courte (cf index). Et donc toute la question est : qui va être autorisé à décider que tel morceau de cache est obsolète et doit mourir ... Et je reconnais que c'est la que ca devient un peu plus casse-machins à formaliser de façon aussi simple et tout terrain ... Enfin tout est relatif puisque c'est le script cache_impacter.php qui se chargera du truc ...

MISE A JOUR DU CACHE

Le principe est tout simplement pour chaque fonction (les post via formulaire en général) de se demander "quel(s) cache(s) cette action doit elle impacter" (impacter ca veut dire supprimer !).

J'ai donc un en validation de mon formulaire d'ajout de nouveaux prestataires un submit qui lance "prestataire_ajout_pos.php". Son allure est en gros (je saute les etapes de verif et l'enrobage de filtrage etc) :

Code:
<?php

include("sql_base_open.php");
     include("sql_prestataire_add.php");
include("sql_base_close.php");

?>

Cette fonction va avoir un impact sur le cache index et sur le cache histo du jour concerné ... je vais donc ajouter quelques lignes à mon script qui devient :

Code:
<?php

include("sql_base_open.php");
     include("sql_prestatire_add.php");
include("sql_base_close.php");

	// ----- tableau des impacts sur cache de la fonction ajouter prestataire
	$tab_cache_impact=array();
	$tab_cache_impact[]='cache_index_1.php'; // le cadre derniers ajouts
	$tab_cache_impact[]='cache_historique_1'.'_'.date('Ymd').'.php'; // la page histo du jour
	include("cache_impacter.php");
?>

Et donc dès lors qu'un utilisateur ajoute une fiche, cache_impacter va se charger de faire le menage ...

Note : j'ai mis la page histo juste pour la comprehension parce que en fait, dans ce cas particulier, je vais en amont tout simplement ne pas chercher de cache lorsque l'on affiche la page du jour courant ... donc aucun besoin d'impacter avec une saisie forcément dans le jour courant ...

Voila y a tout ...

LA VERSION DE CACHE

J'allais oublier ... Vous aurez noté que l'on range les caches non pas dans un dossier CACHE mais CACHE_V01 (si $cache_version a été initalisée avec "V01"). C'est tout simplement pour faciliter une opération de purge totale du cache (pour telle ou tele raison, peut importe).

Il suffit donc de changer la valeur de $cache_version en "V02" et tout le cahe se déroute vers un nouveau dossier (vide) CACHE_V02 ... Ce qui laisse tout loisirs de virer un peu plus tard sans stress le dossier CACHE_V01 en 2 clics via son cpanel par exemple ...



C'est tout chaud en cours de test (fonctionnel ... je vous aurais pas mis du code qui plante !) et donc si vous avez des remarques ou suggestions ... (y a surement des petites optimisations de code ou de méthodologie que j'ai sauté ....).

L'intéret : c'est tout léger, sans impact au niveau rewriting et très souple pour s'adapter à de multiples cas de figure en englobant des parties plus ou moins grande des pages dans les caches, tout en ne stockant pas de trop gros volumes sur le disque du serveur ... et ca se met en place en quelques minutes sans se poser de question : on pose les 5 scripts à la racine de son site et on peut commencer a "cacher" ses premier morceaux de page ... Enfin moi je le sens ainsi :wink:

Ouf je suis au bout du topic ... allez hop clic sur ENVOYER ! Faites pas gaffe aux fautes de frappes, vu la longueur ...
 
WRInaute accro
Sincèrement... j'ai lu que les dix premières lignes :) Perso j'ai un cache global dont je gère la réactualisation, et un cache spécifique (un champ dans une table) où la réactualisation est encore moins fréquente (liens internes)
 
WRInaute discret
hey sinon Zecat pourquoi tu te prends la tête, il y a un truc qui s’appelle ESI include et qui marche plutôt bien avec varnish !
http://www.varnish-cache.org/trac/wiki/ESIfeatures

je l'ai mis en place sur un site wordpress aveec pas mal de plugin (et pas forcément optimisé) et quand tu fais un bench tu gagne 4000% !!!
Bon une fois les vrais membres dessus ca change un peu, mais on a gagné quelques parts Gandi (4)...

Comment ca tu veux juste evoluer de rank php ^^
 
WRInaute impliqué
Disons qu'il faut différencier l'approche des pages caches.
1 - Les pages rarement consultés
2 - Les pages prisées

Pour le 1, à part si la page demande une chiée de requêtes qui écroulent le server durant 5s, aucun interêt du cache.

Pour le 2 :
- Les pages qui ne changent que très rarement.
- Les pages qui changent peu, mais ont gavé de requêtes.
- Les pages qui changent tout le temps et ont aussi gavé de requêtes.

C'est pas une solution, juste une direction de recherche. :)
 
WRInaute accro
mitchum a dit:
hey sinon Zecat pourquoi tu te prends la tête, il y a un truc qui s’appelle ESI include et qui marche plutôt bien avec varnish !
http://www.varnish-cache.org/trac/wiki/ESIfeatures

je l'ai mis en place sur un site wordpress aveec pas mal de plugin (et pas forcément optimisé) et quand tu fais un bench tu gagne 4000% !!!
Bon une fois les vrais membres dessus ca change un peu, mais on a gagné quelques parts Gandi (4)...

Comment ca tu veux juste evoluer de rank php ^^
J eme suis pas cassé le fion a ecrire un forum pour utiliser un truc pas écris by me pour la gestion du cache :mrgreen:
 
WRInaute accro
Au prochain épisode, Zecat vous réinventera un nouveau concept: La messagerie privée :D
 
WRInaute discret
et sinon pourquoi utiliser apache alors, un catpache c'est pas mieux ? ahah
quiestlemeilleurapprentiphp.com/zecat/motive-abloc/
:) :) :)
 
WRInaute accro
Ce topic en tête des reco ! Je ne penais pas que mes 5 petits scripts allaient plaire autant :wink:
 
WRInaute passionné
Bon, 2/3 trucs que je trouve moyen, tu fais par exemple sur chaque requête :
if (!is_dir(ton rep de cache...
Ca fait une lecture de disque pour rien (très performance killer si fort traffic au niveau des accès disque).
Tu fais la même chose sauf que au lieu de mettre sur le disque tu mets en RAM (memcache) et tu gagnes x100 pour la vitesse de cache/affichage ;)
 
WRInaute accro
Julia41 a dit:
Bon, 2/3 trucs que je trouve moyen, tu fais par exemple sur chaque requête :
if (!is_dir(ton rep de cache...
Ca fait une lecture de disque pour rien (très performance killer si fort traffic au niveau des accès disque).
Tu fais la même chose sauf que au lieu de mettre sur le disque tu mets en RAM (memcache) et tu gagnes x100 pour la vitesse de cache/affichage ;)
Merci julia, c'est exactement le type de suggestion que j'attendais de ce topic ... je vais intégrer la chose et refournir les 5 scripts adaptés (puisque manifestement certains les intègrent déjà ...). Et à part cela, tu dis 2/3 trucs .. tu peux developper svp.
 
WRInaute accro
bon j'ai un peu regardé memcache ... sauf que questions : zlib et les extentions PECL ... sur un mutu c'est toujours possible ?

et puis la on commence a sortir du schéma : je pose mes 5 scrips et 30s apres je me mets a "cacher" ... si le gars doit commencer a s'installer une floppée de trucs pas forcément acceptés par son mutu :roll: avec d'après ce que j'ai pu lire (en diagonale pour le moment) des probleme potentiel seloon la versiond e Debian etc etc ... bref on s'élogne du truc light "on pose on gere".
 
WRInaute accro
Zecat a dit:
Parce que sur le fond, la mise en cache à pour objectif principal si j'ai pas sauté une marche de soulager la charge serveur au niveau des sollicitations de la base de données et, accessoirement de profiter d'un affichage plus rapide des pages puisque pas / ou moins de requete sql et moins de code de fabrication des eléments de mises en page.

pour ce qui est de mon cas, j'ajoute une motivation importante a la mise en cache sur certains hébergement Mutu :

le nombre de fichier que l'on peu possiblement créer sur le filesystem. (j'ai un truc qui m'impose max 270 000 fichiers) Quid du site statique comprenant alors plus de 270 K pages (faut y aller je l'avoue), ou tout simplement quid de l'hébergement partagé par plusieurs sites qui finissent par générer beaucoup de fichiers.

Le cache type "Zecat" est aussi une réponse a cela, si on prend le temps de générer les fichiers avec plusieurs contenu dedans.

J'utilise donc un truc assez proche dans la phylosophie du code de zecat mais si mon parti a moi a été de "cacher" la globalité de mes pages, c'est surtout car j'avais un limitation en nombre de fichier. la combinaison des deux concepts (regroupement et cache de bloc sauce zecat) n'étant pas incompatible, j'apporte une idée qui peut compléter.

Le fichier concerné par le cache n'est pas calculé en fonction d'un param comme le fait zecat ($cache_document=$cache_nom.$cache_param.'.php';) mais en fonction d'une URL :

Code:
	$ucode = md5($_SERVER['REQUEST_URI']);
	$code = substr($ucode,0,4);
	$cacheFile = $_SERVER['DOCUMENT_ROOT'].'/cache/'.$cache_version.'/'.substr($code,0,1).'/'.substr($code,1,1).'/'.substr($code,2,1).'/'.substr($code,3,1).'/'.$code.'.php';

une arbo sur 4 niveau est donc crée pour le cache (donc 65536 dossier max) qui eux contiennent un fichier du type '12ab.php'

chaque fichier cache renferme alors le contenu sous forme d'une ou plusieurs variables par contenu -> $content['php'][$ucode] = '(... data en cache ...)';

ensuite un include du fichier cache + un test sur l'existante de la variable $content['php'][$ucode] premet de savoir si oui ou non le contenu a été caché et les cas échéant de l'afficher avec un echo.
A noter : cette technique permet au passage de "cacher" d'autres données du genre :

$content['dateRefresh'][$ucode] = '(... data en cache ...)'; // timestamp ou le fichier cache doit sauter.
$content['xml'][$ucode] = '(... data en cache ...)'; // version par exemple xml des données en cache
$content['mobile'][$ucode] = '(... data en cache ...)'; // version mobile de la page

etc ...
 
WRInaute impliqué
J'ai un sérieux doute dans ta conception de site. Tu réinventes tellement de truc que tu as même réinventé les fonctions …

Tu sais que les inclusions de fichier sont (sans cache opcode) consommateur en ressource ? Pour chaque inclusion, tu as un accès disque de fait couplé à une compilation par PHP. Tu devrais vraiment réapprendre à structurer ton code. Non seulement ce sera plus simple à gérer/maintenir, mais en plus, ce sera plus sécurisé (pas de variable qui traine par ci par là).

Exemple :
PHP:
<span class="syntaxdefault"><br /></span><span class="syntaxcomment">//<br />// Dans un fichier spécifique au cache que tu inclus au début de ton code<br />//<br /><br />// défini le répertoire racine du cache<br /></span><span class="syntaxdefault">define</span><span class="syntaxkeyword">(</span><span class="syntaxstring">'CACHE_DIR'</span><span class="syntaxkeyword">,</span><span class="syntaxdefault"> $_SERVER</span><span class="syntaxkeyword">[</span><span class="syntaxstring">"DOCUMENT_ROOT"</span><span class="syntaxkeyword">].</span><span class="syntaxstring">'/cache/'</span><span class="syntaxkeyword">);<br /><br /></span><span class="syntaxcomment">/**<br /> * Lit le contenu d'un cache s'il existe<br /> * @return bool|string<br /> */<br /></span><span class="syntaxdefault">function cache_lire</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">$id</span><span class="syntaxkeyword">)</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">{<br /></span><span class="syntaxdefault">    if </span><span class="syntaxkeyword">(</span><span class="syntaxdefault">file_exists</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">CACHE_DIR</span><span class="syntaxkeyword">.</span><span class="syntaxstring">'/'</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">$id</span><span class="syntaxkeyword">))</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">{<br /></span><span class="syntaxdefault">        return file_get_contents</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">CACHE_DIR</span><span class="syntaxkeyword">.</span><span class="syntaxstring">'/'</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">$id</span><span class="syntaxkeyword">);<br /></span><span class="syntaxdefault">    </span><span class="syntaxkeyword">}<br /></span><span class="syntaxdefault">    return false</span><span class="syntaxkeyword">;<br />}<br /><br /></span><span class="syntaxcomment">/**<br /> * Écrit le cache<br /> * @param string $id<br /> * @param string $content<br /> * @return bool<br /> */<br /></span><span class="syntaxdefault">function cache_ecrire</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">$id</span><span class="syntaxkeyword">,</span><span class="syntaxdefault"> $content</span><span class="syntaxkeyword">)</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">{<br /></span><span class="syntaxdefault">    if </span><span class="syntaxkeyword">(</span><span class="syntaxdefault">false </span><span class="syntaxkeyword">!==</span><span class="syntaxdefault"> file_put_contents</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">CACHE_DIR</span><span class="syntaxkeyword">.</span><span class="syntaxstring">'/'</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">$id</span><span class="syntaxkeyword">,</span><span class="syntaxdefault"> $content</span><span class="syntaxkeyword">))</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">{<br /></span><span class="syntaxdefault">        return true</span><span class="syntaxkeyword">;<br /></span><span class="syntaxdefault">    </span><span class="syntaxkeyword">}<br /></span><span class="syntaxdefault">    return false</span><span class="syntaxkeyword">;<br />}<br /><br /></span><span class="syntaxcomment">/**<br /> * Efface le cache<br /> * @param string $id<br /> * @return void<br /> */<br /></span><span class="syntaxdefault">function cache_effacer</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">$id</span><span class="syntaxkeyword">)</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">{<br /></span><span class="syntaxdefault">    unlink</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">CACHE_DIR</span><span class="syntaxkeyword">.</span><span class="syntaxstring">'/'</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">$id</span><span class="syntaxkeyword">);<br />}<br /><br /></span><span class="syntaxcomment">/**<br /> * Indique si le cache existe<br /> * @param string $id<br /> * @return bool<br /> */<br /></span><span class="syntaxdefault">function cache_existe</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">$id</span><span class="syntaxkeyword">)</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">{<br /></span><span class="syntaxdefault">    return file_exists</span><span class="syntaxkeyword">(</span><span class="syntaxdefault">CACHE_DIR</span><span class="syntaxkeyword">.</span><span class="syntaxstring">'/'</span><span class="syntaxkeyword">.</span><span class="syntaxdefault">$id</span><span class="syntaxkeyword">);<br />}<br /></span><span class="syntaxdefault"> </span>

PHP:
<span class="syntaxdefault"><br /></span><span class="syntaxcomment">// utilisation<br /><br />// du code HTML, on s'en fou de quoi (head, body, h1, etc.)<br /></span><span class="syntaxdefault">echo </span><span class="syntaxstring">'…'</span><span class="syntaxkeyword">;<br /><br /></span><span class="syntaxcomment">// on va mettre une partie en cache si pas déjà fait<br /></span><span class="syntaxdefault">if </span><span class="syntaxkeyword">(</span><span class="syntaxdefault">false </span><span class="syntaxkeyword">===</span><span class="syntaxdefault"> $partieEnCache </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> cache_lire</span><span class="syntaxkeyword">(</span><span class="syntaxstring">'id_de_cette_partie'</span><span class="syntaxkeyword">))</span><span class="syntaxdefault"> </span><span class="syntaxkeyword">{<br /></span><span class="syntaxdefault">    ob_start</span><span class="syntaxkeyword">();</span><span class="syntaxdefault"> </span><span class="syntaxcomment">// mise en tampon<br /></span><span class="syntaxdefault">    echo </span><span class="syntaxstring">'tout le bordel, tu peux y mettre des include si tu veux.'</span><span class="syntaxkeyword">;<br /></span><span class="syntaxdefault">    $partieEnCache </span><span class="syntaxkeyword">=</span><span class="syntaxdefault"> ob_get_contents</span><span class="syntaxkeyword">();</span><span class="syntaxdefault"> </span><span class="syntaxcomment">// récupération contenu et prêt pour affichage<br /></span><span class="syntaxdefault">    ob_end_clean</span><span class="syntaxkeyword">();</span><span class="syntaxdefault"> </span><span class="syntaxcomment">// désactive la mise en tampon<br /></span><span class="syntaxdefault">    cache_ecrire</span><span class="syntaxkeyword">(</span><span class="syntaxstring">'id_de_cette_partie'</span><span class="syntaxkeyword">,</span><span class="syntaxdefault"> $partieEnCache</span><span class="syntaxkeyword">);</span><span class="syntaxdefault"> </span><span class="syntaxcomment">// on n'oublie pas de sauvegarder<br /></span><span class="syntaxkeyword">}<br /></span><span class="syntaxdefault">echo $partieEnCache</span><span class="syntaxkeyword">;</span><span class="syntaxdefault"> </span><span class="syntaxcomment">// on affiche le contenu<br /></span><span class="syntaxdefault"> </span>

Ce n'est pas du code testé, et bien entendu c'est améliorable. Le but étant de te montrer une façon plus habile de la chose.
Et encore, je ne te parle pas de l'utilisation orienté objet :D (pas toujours utile, attention).

Bref, un fichier suffit amplement.
 
WRInaute accro
Oui je sais, c'est surement freudien ... je sais pas pourquoi mais je bloque sur les fonctions ... me rabattant sur les includes (utilisés comme des fonctions en fait) :roll: Faudra que je fasse mon coming out un de ces 4 :mrgreen:

Sinon pas de probleme de structuration, mon code est parfaitement organisé (en tout cas organisé pour etre hyper simpel a maintenir) :wink: mais callé par include !

Sinon sur le fond ca change rien à la demarche ... ca consommera juste encore moins :wink:

EDit : en analysant "la chose", je pense que mon aversion (in)consciente pour les fonctions doit être liée à une certaine flemmingite ... liée à la nécéssité avec les fonctions de propager les variables (ou les valeurs comme tu veux) de fonction en fonctions , de gérer les paramètres en retour et la non persistance des valeurs une fois sorti ... alors que l'include permet de se dégager de ces contraintes ... oui je sais je suis une flemmasse :mrgreen: et j'assume :mrgreen:

Note : j'avais déjà pressenti que l'include consommait un peu et dans des boucles importantes, je ne mets pas d'include mais du code direct ...
 
WRInaute accro
Blount a dit:
J'ai un sérieux doute dans ta conception de site. Tu réinventes tellement de truc que tu as même réinventé les fonctions …
+1

Zecat a dit:
Sinon pas de probleme de structuration, mon code est parfaitement organisé (en tout cas organisé pour etre hyper simpel a maintenir) :wink: mais callé par include !
C'est qd même presque de la programmation spaghetti, il ne manque plus que des goto et t'y es :mrgreen:
Une meilleure structure, serait plutôt le patron de conception MVC.
http://tahe.developpez.com/web/php/mvc/
http://julien-pauli.developpez.com/tutoriels/php/mvc-controleur/
 
WRInaute passionné
Zecat a dit:
Merci julia, c'est exactement le type de suggestion que j'attendais de ce topic ... je vais intégrer la chose et refournir les 5 scripts adaptés (puisque manifestement certains les intègrent déjà ...). Et à part cela, tu dis 2/3 trucs .. tu peux developper svp.
Pour les 2/3 trucs c'est surtout que :
pour un site lent avec peu de visites, d'accord c'est pas mal.
pour un site "pas trop lent" avec beaucoup de visites, je pense que le cache sera tueur de performance. Tu fais beaucoup trop d'accès disques. Si tu ne caches pas certains trucs (des requêtes SQL propre à un utilisateur connecté ou autre) les accès SQL vont pâtir de ces accès disques (une fois de plus je fais de la pub pour du Cache en RAM, mais bon ce n'est pas trop le sujet).
Ton :
Code:
if (false !== file_put_contents(CACHE_DIR.'/'.$id, $content)) {
Je le trouve un peu bizarre.

Ca je trouve ça nul
Code:
if (false === $partieEnCache = cache_lire('id_de_cette_partie'))
(surtout niveau lisibilité)

A noter aussi que j'avais fait quelques benchs il y a un moment sur d'autres fonctions pour tester l'existence d'un fichier avec du filemtime, readfile, stat, certaines étaient plus performantes que la tienne mais ça remonte et il me semble que PHP avait corrigé ce genre de fonctionnalités.

Bon, pareil pour :
define('CACHE_DIR', $_SERVER["DOCUMENT_ROOT"].'/cache/');
tu pourrais virer ce "document root" et mettre le "lieux" absolu à la main, ça éviterait de "read" une valeur serveur en plus.
C'est de la micro micro micro optimisation, mais si c'est ce que tu veux ça peut être pas mal ;)
 
WRInaute accro
Julia41 a dit:
Ton :
Code:
if (false !== file_put_contents(CACHE_DIR.'/'.$id, $content)) {
Je le trouve un peu bizarre.

Ca je trouve ça nul
Code:
if (false === $partieEnCache = cache_lire('id_de_cette_partie'))
(surtout niveau lisibilité)
Heu c'est pas dans mon code ça :roll: C'est Blount :wink:
 
WRInaute accro
Sinon sur les accès disques ... bien sur que ca fait des accès disque, c'est un cache sur disque :wink: (et pas en ram) mais bon :

1 file_exist et readfile pour lire
1 fput pour ecrire

C'est pas non plus monstrueux.

Et a priori, ca sera plus rapide et moins consommateur que le :

- open base, 1 ou 2 requetes sql, close base
- plus le code de mise en forme de la partie "cachée" (recuperation du ou des champs, boucle sur les lignes etc)

Mes premiers test sur un mutu (chez netavous), font apparaitre deja avec juste du cache qui couvre des blocs consommant à peine 1 ou 2 requetes simples en plus, une divison par environ 2 du temps global de generation de la page (j'ai pas encore mis en place un suivi fin du temps, juste au niveau global de la page).

En toute logique, si la partie cachée couvre un blocs consommant 5 ou 6 requetes, ca va être encore mieux puisque le temps de chargement du cache reste lui stable à contenu egal.

Après, effectivement se posera la question de la montée en charge et de "à quel moment les accès document sur disque vont provoquer un goulot d'étranglement". Je pense que le seuil est "relativement" lointain. Surtout que n'oublions pas le contexte : a priori on est sur du mutu donc on ne parle pas de sites à 30/50.000 visiteurs / jour ... La cible ici c'est plutot les sites faisant entre 500 et 5000 visiteurs jour (perso ca couvre 95 % de mes sites)

Sans compter que comme on est sur mutu, cache ou pas cache, optimisé ou pas optimisé, si on tombe sur un moment ou un clampin ecroule le mutu avec un requete de ouf ou une boucle sans fin, ca sera lent de toute façon ... mais au moins en période normale sur le mutu, on va au plus vite ...
 
WRInaute impliqué
J'ai pas tou lu pardon :)
Pour moi la solution la plus simple et la plus souple :
J'utilise plusieurs taches crons :
- une pour les données a actualiser toutes les 5 minutes
- une pour les données a actualiser toutes les 30 minutes
- une pour les données a actualiser toutes les heures
etc ...
- une pour les données a actualiser toutes les 24 heures

chaque tache cron fait toutes les requetes sql et ensuite je place ca dans une variable (genre $DATA_CACHE = array). j'écrit ca dans un fichier et basta. Au lieu de faire des requetes mysql je vais chercher mes données dans le $DATA_CACHE

l'avantage c'est que l'on peut modifier la présentation HTML sans raffraichir le cache.
 
Discussions similaires
Haut