Page 1 sur 2

Eviter la répétition d'un tirage aléatoire

Posté : 31 mai 2012, 05:48
par kiwiz
Je sais afficher avec un ordre aléatoire un texte depuis ma base de données , cependant je n'arrive pas à trouver un moyen d’empêcher la répétition d'un même texte.
A travers un systeme de session, le visiteur clique sur suivant et les textes défilent aléatoirement sans se répéter.
Quelqu'un a t'il une idée? :)
<?php
session_start();
$_SESSION['pseudo'];

try
{
$pdo_options[PDO::ATTR_ERRMODE] = PDO::ERRMODE_EXCEPTION;
$bdd = new PDO('mysql:host=mysql51-57.perso;dbname=', '', '', $pdo_options);

$reponse = $bdd->query('SELECT * FROM textesaleatoire ORDER BY rand() LIMIT 1,1');
while ($donnees = $reponse->fetch())
{
<?
	

<table width="100%" border="1" class="arrondiombre">
		<tr>
		<td><?php echo $donnees['textes']; ?></td>
		</tr>
</table>
		

<?php
}  
$reponse->closeCursor();
}
catch(Exception $e)
{
die('Erreur : '.$e->getMessage());
}
?>

Re: Eviter la répétition d'un tirage aléatoire

Posté : 31 mai 2012, 06:48
par moogli
Salut,

Stock en session les id des choses déjà afficher et utilise le "in" de SQL pour faire une restriction.

Par exemple
select truc from machin where id not in (1,798,78) order by rand limit 1;

La fonction implode te sera utile ;)

@+

Re: Eviter la répétition d'un tirage aléatoire

Posté : 31 mai 2012, 14:37
par kny
Dans un premier temps je stockerais les résultats dans la session pour éviter les accès à la base.
Ensuite, plutôt que d'utiliser un rand sur ce tableau, une solution pourrait être d'utiliser un shuffle pour mélanger le tableau (une seule fois suffit), puis un shift pour enlever cette première pioche des suivantes et l'afficher à l'internaute.

Il y a un sujet similaire concernant le shuffle et le shift ici : php-debutant/plusieurs-images-aleatoires-t253741.html

Re: Eviter la répétition d'un tirage aléatoire

Posté : 31 mai 2012, 23:40
par kiwiz
Merci pour votre aide,
Je vais essayer avec les deux méthodes :)

Comment je pourrais faire pour stocker les id des textes déjà vu en session?

(ps: passer par les sessions plutôt que par la bdd évite le ralentissement du chargement de la page?)

Re: Eviter la répétition d'un tirage aléatoire

Posté : 01 juin 2012, 08:10
par moogli
Pour le os : ça dépend si ta requête prend 14s oui si elle n'est faite qu'une fois.

Mais si c'est le cas revoie ton système XD
Pour l'affichage y a peu de chance que tu ai besoin d'un volume de données si important qu'il ralentisse, significativement, le chargement de la page.

Généralement le problème d'image trop lourde, de multiple JS etc

Avec le plugin firebug (Firefox ou chrome) tu peux voir le temps de chargement de la page coté client et donc savoir ce qui prend le plus de temps.

Côté serveur il faut utiliser la fonction time pour calculer le temps que prennent les différentes parties de ton code (en gros faire une "inspection" de ton code). Certain outils propose ce type de chose.


@+

Re: Eviter la répétition d'un tirage aléatoire

Posté : 01 juin 2012, 17:53
par kiwiz
Pour insérer des info depuis la bdd à une session, je dois m'y prendre de cette manière la?
<?php
session_start();

function open()
{
	global $host,$user,$pass,$db,$connect;	
	$connect = mysql_connect($host, $user, $pass,1);
	$bdd = mysql_select_db($db,$connect);
	return $bdd;
}

	function read ($sid)
{
	$sql = "SELECT id FROM textealeatoire";
	$query = mysql_query($sql,$connect) or die (mysql_error());			
	$donnees = mysql_fetch_array($query);
		
	if(empty($donnees)) return FALSE;
	else return $donnees['id'];//
}
$_SESSION['id'] = $donnees['id'];
?>
Désolé ça dérive un peu du sujet principal.

Re: Eviter la répétition d'un tirage aléatoire

Posté : 02 juin 2012, 12:54
par Ryle
La question la plus importante pour savoir quelle méthode utiliser, c'est combien de textes as-tu en base qui peuvent être affichés (aujourd'hui et d'ici à 5 ans). Car placer 20 textes de ta base en session peut rester raisonnable, en mettre 2000 l'est beaucoup moins et il vaut mieux faire une requête à la demande.

Pour mettre tes id en session, autant profiter de la requête qui affiche ton texte. Lorsque tu affiches le résultat, tu en profites pour stocker l'id dans ta session, cela évite de le faire en double (surtout que là, l'id que tu vas récupérer ne correspondra peut être pas au texte qui sera affiché).

Quant à l'enregistrement en session, il faut utiliser un tableau pour stocker chaque id consulté, sinon tu vas écraser l'id précédent à chaque fois :)

En gros ton code doit :
- chercher un texte au hasard, dont l'id n'est pas dans ceux déjà passés et stockés dans le tableau en session
- afficher le texte retourné
- stocker l'id du texte retourné dans le tableau en session

Re: Eviter la répétition d'un tirage aléatoire

Posté : 04 juin 2012, 11:50
par kiwiz
Merci pour l'aide apporté, je penses avoir mis toutes les données nécessaire, cependant l'id finit encore par retombé.
Auriez-vous une idée de la marche à suivre pour que ce code réussisse?
Je ne vois pas l'élément qui manque afin de réussir.

Code : Tout sélectionner

<?php session_start(); try { $pdo_options[PDO::ATTR_ERRMODE] = PDO::ERRMODE_EXCEPTION; $bdd = new PDO('mysql:host=mysql51-57.perso;dbname=', '', '', $pdo_options); $reponse = $bdd->query('SELECT id FROM textealeatoire WHERE id != "'.$_SESSION['id'].'" ORDER BY rand() LIMIT 1,1'); if (isset($_SESSION['id'])) { $_SESSION['id'] = array(); } while ($donnees = $reponse->fetch()) { $_SESSION['id'][] = $donnees['id']; echo $donnees['id']; } $reponse->closeCursor(); } catch(Exception $e) { die('Erreur : '.$e->getMessage()); } ?>

Re: Eviter la répétition d'un tirage aléatoire

Posté : 04 juin 2012, 14:42
par Ryle
Ta variable $_SESSION['id'] est un tableau qui va contenir chacun des id tirés au hasard. Pour pouvoir l'utiliser dans ta requête SQL il faut faire appel à la fonction implode() qui va transformer ce tableau en chaine d'id séparés par des virgules. Tu pourras alors l'utiliser avec l'opérateur IN de ta requête SQL :
... WHERE id NOT IN (" . implode(',' , $_SESSION['id']) . ") ...
Ensuite, tu as une petite erreur au niveau de ton test isSet() : en effet, tu tests si le tableau d'id est défini et si c'est bien le cas, tu le déclares comme étant un nouveau tableau. En fait, c'est le contraire qu'il te faut, tu ne dois le déclarer comme nouveau tableau que s'il n'est pas défini :)

Et logiquement il te retournera tes id un par un de façon aléatoire jusqu'à ce qu'il n'y ai plus de résultat en base (il faudra alors peut être prévoir de remettre à zéro ton tableau pour recommencer, ou mettre un message pour dire que ça y est, l'utilisateur a tout vu :))

Re: Eviter la répétition d'un tirage aléatoire

Posté : 04 juin 2012, 23:24
par kiwiz
J'ai ajouté l'implode et modifier le isset.
Cependant les id affichés reviennent
<?php
session_start();
 
try
{
    $pdo_options[PDO::ATTR_ERRMODE] = PDO::ERRMODE_EXCEPTION;
 $bdd = new PDO('mysql:host=mysql51-57.perso;dbname=', '', '', $pdo_options);
 $reponse = $bdd->query('SELECT id FROM gage WHERE id NOT IN ("' . implode(',', $_SESSION['id']) . '") ORDER BY rand() LIMIT 1,1');

 
if (!isset($_SESSION['id'])) {
    $_SESSION['id'] = array();
    }
    while ($donnees = $reponse->fetch()) {
 $_SESSION['id'][] = $donnees['id'];
 echo $donnees['id'];
    }
    $reponse->closeCursor();
 }
catch(Exception $e)
{
die('Erreur : '.$e->getMessage());
}
 ?>

Re: Eviter la répétition d'un tirage aléatoire

Posté : 05 juin 2012, 13:33
par Ryle
Ta requête sql n'est pas bonne, tu as des apostrophes en trop dans le IN. La syntaxe a obtenir est : " id NOT IN (2,7,5) " alors que actuellement tu génères " id NOT IN ('2,7,5') ". Du coup mysql vérifie que ton id n'a pas la valeur de cette chaine plutôt que chacune des valeurs qui la constitue :)

Re: Eviter la répétition d'un tirage aléatoire

Posté : 07 juin 2012, 16:12
par Invité
Lorsque j'enlève les guillemets ou apostrophes il y a une erreur de syntaxe qui apparait.

Re: Eviter la répétition d'un tirage aléatoire

Posté : 07 juin 2012, 23:52
par Ryle
En fait, il y a deux choses à gérer... il faut effectivement enlever les guillemets qui sont en trop dans ta requête, mais également traiter le cas où tu n'as pas encore d'id en session pour éviter d'avoir un IN () qui sera incorrect. Il faut donc construire ta requête ainsi, avant de l'exécuter :
$sql = 'SELECT id FROM gage ';
if (isset($_SESSION['id']))
  $sql.= ' WHERE id NOT IN (' . implode(',', $_SESSION['id']) . ')';
$sql.= ' ORDER BY rand() LIMIT 1,1';
$reponse = $bdd->query($sql);

Re: Eviter la répétition d'un tirage aléatoire

Posté : 08 juin 2012, 09:49
par Mazarini
Après un certain nombre d'affichage (10,50 ou plus) il faudrait prévoir d'autoriser les répétitions et donc de supprimer le premier élément (voir fonction array_shift). Ca te permettra de limiter ta requete SQL à pas trop d'id.
<?PHP
$_SESSION['id'][] = $donnees['id'];  
if (count($_SESSION['id'] > 50) { $_SESSION['id'] = array_shift($_SESSION['id']); }
?>

Re: Eviter la répétition d'un tirage aléatoire

Posté : 08 juin 2012, 16:59
par kiwiz
Plus aucune erreur ne s'affiche merci!
L'id se stock bien mais n’empêche pas la répétition.
(ps: array_shift supprimerai à partir du premier id stocker?)
<?php
session_start();
 
try
{
    $pdo_options[PDO::ATTR_ERRMODE] = PDO::ERRMODE_EXCEPTION;
	$bdd = new PDO('mysql:host=mysql51-57.perso;dbname=', '', '', $pdo_options);
 
if 		(!isset($_SESSION['id']))	{
		$_SESSION['id'] = array();
		$reponse = $bdd->query('SELECT id FROM base ORDER BY rand() LIMIT 1,1');
		while ($donnees = $reponse->fetch()) 	{
		$_SESSION['id'][] = $donnees['id'];
		echo $donnees['id'];
												}
									} 
else 	{
		$reponse = $bdd->query('SELECT id FROM base WHERE id NOT IN ("' . implode(',', $_SESSION['id']) . '") ORDER BY rand() LIMIT 1,1');
		}
		while ($donnees = $reponse->fetch()) 	{
		$_SESSION['id'][] = $donnees['id'];
		echo $donnees['id'];
												}
    $reponse->closeCursor();
}
catch(Exception $e)
{
die('Erreur : '.$e->getMessage());
}
 ?>