Les scripts à jéjé: Partage de la mémoire en php

fandecine

WRInaute passionné
Me voici de retour avec un autre script. Cette fois-ci, il s'agit de trouver une alternative aux cookies et aux variables de session pour stocker des informations relatives à un visiteur de votre site.

Les cookies s'acquitent généralement bien de cette tache, encore faut-il que votre visiteur les accepte (20% de mes visiteurs n'acceptent pas les cookies!)

Les variables de session sont également un bon moyen de conserver des variables d'une page à l'autre mais présentent deux inconvegnants:
- le nombre de sessions n'est pas ilimité
- le passage de variables de session dans l'url peut avoir de graves incidence sur la prise en compte de vos pages par les moteurs de recherche https://www.webrankinfo.com/dossiers/conseils/bon-referencement-php

php nous fournis une alternative avec la possibilité de créer des blocks mémoire partagées accessible à tout les script fonctionnant sur le serveur(gestion des droit d'accés identique à la gestion des droits d'accés fichier linux) grace à un identifiant.

L'exemple dont je donne les sources permet de stocker dans un file de 50 enregistrement, l'ip d'un visiteur et d'y assoicier une valeur de 0 à 9. Le timestamp correspondant à la date/heure de création ou de mise ajour de la valeur est également stocké ce qui permet de faire tourner la file de façon à ce que lorsque les 50 enregistrements sont utilisés, on écrase le plus ancien. (une manère pour obtenir dans un espace fini une capacité pseudo infinie de stockage si on la rapproche à la durée de vie de l'information)

Attention: c'est un exemple pour expliquer le mécanisme! à vous d'immaginer comment utiliser cette fonctionnalité.

Par exemple, sur le site de mon profil, je gere 4 onglets en DHTML sur la page d'accueil. Ce mécanisme me permet de mémoriser sur quel onglet de la page d'accueil était le visiteur afin de restituer le contenu de cet l'onglet lorsque l'internaute:
- revient sur page d'accueil
- utilise les bouton prec et suiv de son navigateur

Les autres utilisations étant disons... plus stratégiques, je n'en parlerais pas ici :wink: Mais je sais que les wrinautes ont beaucoup d'idées!

ce script permet d'initialiser le block de mémoire partagé:
Code:
<?php
			$enre=time()."-xxxx.xxxx.xxxx.xxxx-x"; //on génére la chaine de caractères par défaut
			$mem=""; // on initialise la variable mémoire
			for($i=0;$i<50;$i++) { // on initilise la variable mémoire avec 50 enregistrements
				$mem.=$enre;
				if($i!=49) $mem.=";"; // on sépare chaque enregistrement par le car ";" sauf en fin de mémoire
			}
			$shm_id = @shmop_open(0xf00, "c", 0644, strlen($mem)); // création du block mémoire partagé 
			if(!$shm_id) {  // on vérifie si la créatioon du block mémoire partagé a réussi
				echo "<div align=center>Erreur: Impossible de créer la mémoire partagée.</div><br>";
			} else {
				
				$shm_bytes_written = @shmop_write($shm_id, $mem, 0); // Ecriture dans le block de mémoire partagée
				echo "<div align=center>Création de la mémoire partagée.</div><br>";
			}

?>

celui-ci permet de détruire le block de mémoire partagée et libère la mémoire!
Code:
<?php
		$shm_id = @shmop_open(0xf00, "w", 0, 0); // création d'un handle pour notre block mémoire
		shmop_delete($shm_id); // destruction du block mémoire partagée
		echo 'block mémoire detruit';

?>
enfin, le script suivant permet de lire ( appel sans parametre dans l'url) ou d'écrire une valeur dans le bloc de mémoire partagée (appel avec le parametre Val=votrevaleur dans l'url methode GET):

Code:
<?php
		if(isset($_GET['Val'])) $Val=$_GET['Val']; //on récupére la valeur à écrire dans le block mémoire si elle existe
		$shm_id = @shmop_open(0xf00, "w", 0, 0); // on crée un handle pour acceder à notre block mémoire partagé
		if ($shm_id) { 					// le block mémoire partagé existe
			$ok=sem_get (0xf00); 		// demande de lecture du block mémoire partagée puis interdit l'acces au block mémoire partagé
			if(sem_acquire ($ok)) {     // l'accés au block mémoire est authorisé
				$shm_size=@shmop_size ($shm_id); // lecture de la taille du block mémoire partagée
				$tmp=substr(@shmop_read($shm_id, 0, $shm_size),0,16499); // lecture du block mémoire partagée
				$tab=split(";",$tmp); // création d'un tableau d'enregistrement à partir du block mémoire partégée
				$trouve=false;
				$mem=array();
				for($i=0;$i<50;$i++) {  // on récupére nos valeur du bloc mémoire partagé dans un tableau
					$val=split('-',$tab[$i]);
					$Enre=array ('time' => $val[0], 'ip' => $val[1], 'value' => $val[2]);
					$mem[$i]=$Enre;
					if(str_replace('*','',$Enre['ip'])==trim($_SERVER['REMOTE_ADDR'])) {  // on recherche si l'ip de l'internaute existe déjà
						$trouve=true;  // l'ip existe
						$mem[$i]['time']=time(); // on met la date à jour
						if(isset($_GET['Val'])) $mem[$i]['value']=$Val; // si valeur passée en paramétre, on la stocke
						$memvalue=$mem[$i]['value']; // on lit la valeur correspondant à l'ip de l'internaute
					}
				}
				sort($mem); // on trie notre tableau par date d'ancienneté
				if(!$trouve) {  // l'ip de l'internaute n'existe pas
					$mem[0]['time']=time(); // on stocke la date actuelle
					$mem[0]['ip']=trim($_SERVER['REMOTE_ADDR']); // on stocke l'ip de l'internaute
					if(isset($_GET['Val'])) $mem[0]['value']=$Val; else $mem[0]['value']=1; // ons stocke la valeur passée en paramètre ou 1 par défaut
					$memvalue=$mem[0]['value']; // on récupére la valeur associée à l'ip
				}
				$memwrite=""; // initialise une chaine vide
				for($i=0;$i<50;$i++) { // on reconstitue une chaine avec nos 50 enregistrements
					$memwrite.=$mem[$i]['time'].'-'.str_pad($mem[$i]['ip'],15,'*',STR_PAD_RIGHT).'-'.substr($mem[$i]['value'],0,1); // l'ip est complétée par "*" pour atteindre 15 caractères
					if($i!=$memsize-1) $memwrite.=';';
				}
				$shm_bytes_written = @shmop_write($shm_id, $memwrite, 0); // sauvegarde le block memoire partagé
				sem_release($ok);// autorise la lecture du block mémoire partagée
			}
		}
		echo $memvalue; // on affiche la valeur 'associée à l'ip de l'internaute
		exit(); // fin du script?>

Voila! J'utilise la mémoire partagée pour de nombreuses taches sur mes sites et cela fonctionne trés bien en consommant peu de ressources!
 

shrom

WRInaute impliqué
Juste 2 remarques:

1) l'identifiant est dans ce cas l'adresse IP du visiteur: dangereux si on a des visiteurs venant de AOL, Tiscali ... qui on la même IP à cause des proxy

2) la mémoire partagée n'est pas une alternative aux sessions, mais un autre moyen de stocker des informations.
 

fandecine

WRInaute passionné
shrom a dit:
Juste 2 remarques:

1) l'identifiant est dans ce cas l'adresse IP du visiteur: dangereux si on a des visiteurs venant de AOL, Tiscali ... qui on la même IP à cause des proxy

2) la mémoire partagée n'est pas une alternative aux sessions, mais un autre moyen de stocker des informations.

Comme je le précise dans le post, ce n'est qu'un exemple! De plus le danger dépends des donnnées stockées (lorsque c'est juste le contexte d'une page, c'est pas grave)

Enfin, je précise bien qu'il existe d'autres moyens, dont les session, en renvoyant à un article sur les problèmes engendrés par les variables de session passées dans l'url.
 

shrom

WRInaute impliqué
fandecine a dit:
Comme je le précise dans le post, ce n'est qu'un exemple! De plus le danger dépends des donnnées stockées (lorsque c'est juste le contexte d'une page, c'est pas grave)

Ben si ton application mélange les données entre tous les utilisateurs AOL parce qu'ils ont la même IP, c'est quand même génant

D'ailleurs, le stockage en mémoire partagée peut très bien être utilisé avec les sessions.
 

fandecine

WRInaute passionné
ok shrom! L'exemple choisi n'est pas top! Mais le seul objectif de ce post et d'expliquer le mécanisme de mémoire partagé, c'est tout!
 

itsme

WRInaute impliqué
Me voici de retour avec un autre script. Cette fois-ci, il s'agit de trouver une alternative aux cookies et aux variables de session pour stocker des informations relatives à un visiteur de votre site.

C'est effectivement une technique peu connue (et peu utilisee) mais ce n'est qu'une technique de stockage parmis d'autres (base, fichier)...

... et en aucun cas une alternative.

Il ne faut pas confondre moyens et objectifs ;)
 

taybott

WRInaute discret
Je connaissais pas cet technique (encore bcp de choses a apprendre :roll: ) mais je crois qu'il y a des situations où ça peut être plus pratique d'utiliser ça!!
 

Tex

WRInaute occasionnel
le principal interet de la memoire partagée c'est de stocker des resultats de requetes ou des generations lourdes pour fournir un systeme de cache sans accés disque/bdd et donc instantané.

bravo a fandecine pour son exemple démonstratif, meme si pour stocker de simples variables les sessions restent quand meme la meilleure solution (bien evidemment il est preferable de les désactiver au passage des bots pour le referencement), mais le but ici etait de faire du proof of concept :)
 

Suede

WRInaute passionné
Juste une question :
Dans ton cas, tu utilises l'IP pour identifier à quel visiteurs appartient la pile. Comme dit précédemment, l'IP n'est pas forcément une bonne méthode donc il faudra un autre identifiant pour identifier ton visiteur. Par exemple, un identifiant de session...
amha ta méthode est plutot complementaire des sessions pour stocker des données que tu ne peux peut-etre pas stocker avec les identifiants de sessions (?).

François
 

fandecine

WRInaute passionné
En fait, je crois que j'ai vraiment mal choisi l'exemple, mais je pouvais pas faire trop long!

Tous les exemples que vous donnez sont valables bien entendu.

Mais, maintenent, imaginez que vous souhaitez afficher sur une page d'un annuaire, le nombre de visite d'un site. La solution classique (requette Mysql sur la BDD) présente deux inconvegnants:
- consommation de ressources
- rends innopérant et innutile la mise en cache de la pages (voir mon premier script)

Par conte, vous pouvez creer un tableau en memoire partage avec l'id du lien et le nombre de fois qu'il a été cliqué. C'est rapide et econnome en ressources et vous permet de mettre la page en cache. Ensuite, il suffit de faire un cron qui une fois/jour consolide votre BDD avec les resultats de la mémoire partagés et reinitialise la mémoire partagée.
 

pedouille

WRInaute discret
Je trouve que c'est un bon moyen de se passer des sessions et des cookies. Il a déjà bien maché le travail, il reste à trouver un moyen d'identifier un utilisateur de façon unique. On pourrait imaginer un algorithme qui ne se base pas uniquement sur l'adresse ip, mais sur d'autres paramètres pour identifier de façon stable.

Sinon, il faudrait également mettre toute la soupe dans une belle classe, avec des fonctions simples de lecture / écriture, et là, je crois que tu tiens une bonne alternative.
 

ZBoy

Nouveau WRInaute
Salut à tous,

Je viens de découvrir ce post car je cherchais le meilleur moyen de mettre à disposition des données partagées à tous mes visiteurs. En fait, je suis en train de créer un jeu en PHP, et je trouvais ça lourd que chaque utilisateur lance l'instanciation redondante de tous les objets utiles ( l' écran de jeu, les ennemis, les autres joueurs, les objets au sols, etc...) alors que ce sont les MEMES pour tous les joueurs qui se trouvent au meme endroit.

J'avais pensé d'abord à la méthodes qui consiste à fixer un identifiant de session choisi (qui devient par là une session commune) et d'y enregistrer mes objets/variables: inconvénient je pense la mémoire vive utilisée puis apparemment aussi un mécanisme de blocage de session par PHP au bout d'un moment. Bref

Pour l'instant j'étais parti sur du cache en XML de mes objets, l'affichage de données reviendrai à afficher ces XML, la modification de données à mettre à jour la base de données puis dans la foulée le/les fichiers de cache concernés.

Ca me paraissait pas trop mal niveau performance PHP et MySQL, mais cette discussion m'a vraiment interpelé je ne connaissait vraiment pas ce système : les données sont donc bien sur le disque et pas en mémoire vive? Dans ce cas là, la lecture/ecriture dans ce/ces fichiers n'est-t-elle pas nettement plus lente que l'accès à la base? Et enfin (!), y'a-t-il une restriction dans Apache pour cette option où serait-ele active sur n'importe quel hébergement PHP?

C'était long! Merci d'avance!

ZBoy
 

Discussions similaires

Haut