Diaporama généré par PHP sans MySQL à partir d'un dossier d'images

Répondre


Cette question est un moyen d’empêcher des soumissions automatisées de formulaires par des robots.
Smileys
:D :) :( :o :shock: :? 8-) :lol: :x :P :oops: :cry: :evil: :twisted: :roll: :wink: :!: :?: :idea: :arrow: :| :mrgreen: =D> #-o =P~ :^o :non: :priere: 8-|
Voir plus de smileys
  Revue du sujet
 

  Étendre la vue Revue du sujet : Diaporama généré par PHP sans MySQL à partir d'un dossier d'images

par sadeq » 12 sept. 2007, 13:32

Trés interessant, en effet =D>

par AB » 12 sept. 2007, 01:50

[Edit de Zeus] J'ai remis ton message original dans le message où tu était connecté ;)

J'avais bien compris. Si tu avais été légèrement plus diplomate, ou un peu moins catégorique, je n'aurais pas fait cette réponse :wink:

Enfin toujours est-il que pour en avoir le coeur net, j'ai fait quelques bench sur un tableau de 11120 éléments ("sdfrpgmdnr.png","gfhlgvtdyiy.gif","frtyuiopdeqf.jpg","treuuiopf.txt","qszertyf.doc" répétés).

Voici ma procédure de test (en local sur EasyPHP2):
$lettre = 'f';
$tab = array();
$moyenne = array();

for ($i=0; $i < 100; $i++)
{
$time_start = microtime(true);

    foreach ($tableau as $f)
		{
        //$nom = eregi_replace('\.[^.]*$', "", $f);
		//$nom = preg_replace('#\.[^.]*$#', "", $f);
		//$nom = substr($f,0,strrpos($f,'.'));
		//if(eregi("^$lettre.*", $f)) $tab[] = $f;
		//if(preg_match("#^$lettre.*#i", $f)) $tab[] = $f;
		//if(strpos(strtolower($f), strtolower($lettre)) === 0) $tab[] = $f;
		//(strpos(strtolower($f), strtolower($lettre)) === 0)? $tab[] = $f :'';
		} 
		
$time_end = microtime(true);
$time = $time_end - $time_start;
$moyenne[] = $time;
usleep(50000);
}

echo array_sum($moyenne)/count($moyenne);
et voici le résultat sur les trois premières lignes:

Image



Pour le reste, les résultats sont moins significatifs au niveau du temps d'exécution:
if(eregi("^$lettre.*", $f)) $tab[] = $f;// temps : 0.042
if(preg_match("#^$lettre.*#i", $f)) $tab[] = $f;// temps : 0.040
if(strpos(strtolower($f), strtolower($lettre)) === 0) $tab[] = $f;// temps : 0.034
preg est très légèrement plus rapide qu'eregi et consomme 2 à 3 % de ressources UC en moins.
La solution strpos, arrive légèrement en tête et elle offre l'avantage de consommer environ 6 à 10% de ressources UC en moins qu'eregi.


Concernant la dernière ligne pour la comparaison avec l'opérateur ternaire
(strpos(strtolower($f), strtolower($lettre)) === 0)? $tab[] = $f :''; //temps : 0.037 
pour une utilisation UC équivalente à la solution avec if

Le plus étonnant c'est que même
if(strpos(strtolower($f), strtolower($lettre)) === 0) $tab[] = $f; else $tab[] = $lettre;
conserve le même avantage par rapport à
$tab[] = (strpos(strtolower($f), strtolower($lettre)) === 0)? $f : $lettre;
tout en semblant consommer un chouilla moins de ressources UC
Dans ce test l'opérateur ternaire est donc toujours très légèrement en retard.

Conclusion:
- Le premier graphique donne amplement raison au manuel php (heureusement!). Quand on peut éviter les expressions régulières en les remplaçant par deux fonctions simples, y'a pas photo.
- Preg_match est non seulement plus rapide qu'ereg mais il consomme aussi moins de ressources.
- Quand il faut plus de deux fonctions, l'écart diminue et s'inverserait probablement dans des cas plus complexes.
- Moi qui avait lu que les opérateurs ternaires étaient plus rapides à l'exécution. Ben non, pas dans ce test du moins.


note: j'ai pris les regex tels qu'ils ont été écrits. En optimisant le regex pour rechercher la première lettre
if(preg_match("#^$lettre#i", $f)) $tab[] = $f;// temps = 0.038
pour une consommation ressource UC équivalente à la solution strpos

par sadeq » 07 sept. 2007, 09:24

Ecoutes AB, moi je n'ai rien contre ta solution ni les subtr() ni les strpos(). J'ai proposé les regExp en disant qu'elle sont simples et rapides à écrire. Et j'ai utilisé eregi() et preg_match() dans mes propositions pour des raisons d'exemple.

par AB » 06 sept. 2007, 17:46

   //Filrage : les fichiers commançant par la lettre recherchée
   if($f != "." && $f != ".." && is_file($rep.$f) && eregi("^$lettre.*", $f) ) { 
      //Stocke dans un tableau avant classement par ordre alphabétique
       $tableau[] = $f;  
      
   }//fin if
}//fin while
Là je ne comprend pas pourquoi tu testes $f != "." && $f != ".." puisqu'on teste si la première lettre commence par $lettre, ça devrait répondre faux si $f=='.' ou $f == ".." Y-a-t-il une autre explication ?

Je dis ça pour avertir notre ami jpsartre qu'en programmation il y a plusieurs façons de faire, mais il faut choisir la meilleure.
...
Merci donc AB pour ton apport enrichissant.
Très gros progrès diplomatiques :D

Je me préparais à répondre : pour faire des recherches un peu sophistiquées on emploie de préférence preg_match à ereg... Je dis ça pour avertir notre ami jpsartre qu'en programmation il y a plusieurs façons de faire, mais il faut choisir la meilleure...

Et concernant, la rapidité d'exécution, je vais pas me lancer dans des bench pour savoir si
$nom = eregi_replace('\.[^.]*$', "", $f);
est plus rapide d'exécution que
$nom = substr($fichier,0,strrpos($fichier,'.')) 
mais j'ai des gros doutes. Si quelqu'un pouvait m'éclairer sur ce point...

Et puis à force de défendre tes regex, tu as oublié de dire que mon script n'était pas approprié pour faire exactement ce que veux jpsartre puisque je ne cherchais qu'à afficher une liste de fichiers triée sans les extensions. Et comme il a besoin d'utiliser le fichier par la suite, il ne faut retirer l'extension qu'à la lecture du fichier, dans la boucle du tableau.
Ben oui, t'as oublié de parler de l'essentiel même si tu l'as fait dans ton code. Promis je toucherai plus à tes regex :wink: :lol:

par sadeq » 06 sept. 2007, 16:59

ok, pour le cas de l'extension j'ai confondu strpos de php avec d'autres langages. Mais pour la recherche de la lettre pourquoi chercher la position puisqu'on sait que c'est le début du mot. Le plus simple est d'utiliser $f[0] (sans les regExp)

C'est vrai que les RegExp sont un peu difficiles à appréhender mais c'est une occasion d'inciter à les utiliser.

Aussi, j'ai dit que ce sont deux façons de faire, le choix reste au lecteur. Merci donc AB pour ton apport enrichissant.

par AB » 06 sept. 2007, 15:57

Je ne suis pas tout à fait d'accord, l'expresion régulière (utilisant preg_match() ou ereg() ou eregi()) ou encore un test sur $f[0] est plus simple car le remplacer par un strpos() ne fait pas l'affaire puisqu'il cherche la lettre n'importe où dans le nom.
Oui, j'ai un peu trop le réflex (selon les indications du manuel php), d'éviter d'utiliser les regex quand on peut faire autrement pour des pb de performances.
Dans ce cas particulier, puisqu'il s'agit de trouver la première lettre, peut-être que les bench te donneraient raison (quoiqu'un nom de fichier n'est jamais long donc parcourir toute la chaine avec un strpos() ne doit pas être très pénalisant).
Et même remarque pour le cas de suppression de l'extension du fichier, se baser sur la position d'un point est faux car on peut avoir plusieurs points avant celui de l'extension.
Ben strrpos() ne cherche que la position du dernier point, donc c'est pas faux mais vrai. Sinon même remarque que précédemment, ça donne quoi au bench?

D'un point de vue "réponse à la demande de jpsartre" je ne sais pas si ta réponse concernant les regex est appropriée . Il apprend tout juste à faire et ordonner un tableau et tu lui parle régex...
Je me disais qu'on apprend les regex un peu après avoir commencé la notion des tableaux.

par jpsartre » 06 sept. 2007, 14:55

Super,

Je vais bien vous lire pour comprendre,

Un grand merci et à bientôt,

par sadeq » 06 sept. 2007, 13:27

Je ne suis pas tout à fait d'accord, l'expresion régulière (utilisant preg_match() ou ereg() ou eregi()) ou encore un test sur $f[0] est plus simple car le remplacer par un strpos() ne fait pas l'affaire puisqu'il cherche la lettre n'importe où dans le nom.
L'expression régulière ou $f[0] cherchent seulement les noms qui commencent par la lettre. Ce qui est demandé.
Et même remarque pour le cas de suppression de l'extension du fichier, se baser sur la position d'un point est faux car on peut avoir plusieurs points avant celui de l'extension.

Je ne suis jamais d'accord pour l'usage de strpos() et substr() pour taiter un cas de recherche partielle ou de remplacement d'un critère partiel. Car tout simplement c'est le domaine des expressions régulières. Il faut donc utiliser le mieux qu'on peut les fonctions RegExp.

Par exemple,
//expReg pour les nom commençant par $lettre:
if ( preg_match('#^$lettre.*#', $f) ) {
   ... ici: touvé
}
ou
//nom commençant par $lettre:
$f = trim($f);
if ( $f && strtoupper($f[0]) == strtoupper($lettre) ) {
   ... ici: touvé
}
C'est simple, subtil et pratique.
//Pour écarter l'extension d'un fichier (cibler le dernier point)
$nom_sans_extension = eregi_replace('\.[^.]*$', "", $f);
Voilà, c'est aussi simple. le [^.]*$ s'assure que tous les caractères situés entre un point (\.) et la fin ($) du nom, ne contiennent pas de point. En l'occurence on cible vraimment l'extension.

Autre chose:
l'opérateur ternaire (?) n'est pas approprié car dans notre cas on ne veut pas affecter dans le cas de sinon. Et cet opérateur est souvent utilisé pour simplifier l'affectation conditionnelle dans une variable. Utiliser l'alternative if sans else est donc mieux approprié.

Je dis ça pour avertir notre ami jpsartre qu'en programmation il y a plusieurs façons de faire, mais il faut choisir la meilleure.

Comme ça par exemple: (pour continuer sur notre idée de départ)
<p><a href="?lettre=A">A</a>&nbsp;<a href="?lettre=B">B</a></p>
<hr>
<?php
//Initialiser la lettre de recherche
$lettre = isset($_GET["lettre"])?$_GET["lettre"]:"A"; // La lettre A par défaut 

//Lecture du dossier de recherche
$rep = "livre-d-or/";  
$dir = opendir($rep); 
while ($f = readdir($dir)) 
{ 
   //Filrage : les fichiers commançant par la lettre recherchée
   if($f != "." && $f != ".." && is_file($rep.$f) && eregi("^$lettre.*", $f) ) { 
      //Stocke dans un tableau avant classement par ordre alphabétique
       $tableau[] = $f;  
      
   }//fin if
}//fin while

//Affichage
if (count($tableau) > 0){
    //Tri naturel ignorant la casse
    natcasesort( $tableau );
    foreach ($tableau as $f){
        //nom sans extension
        $nom = eregi_replace('\.[^.]*$', "", $f);
        //Affichage
                echo "<p><a href=\"livre-d-or/".$f."\" target=\"afficheur\">".$nom."</a></p>";
    }
}
else echo "<p>Aucun artistre trouvé!</p>";
?> 
<iframe name="afficheur" width="100%" height="200"></iframe>

par jpsartre » 06 sept. 2007, 03:04

oui, oui, mais j'avais essayé d'adapter à ce que j'avais fait,
je vais essayer demain en partant du tien...

Dommage, ça partait bien...

par AB » 06 sept. 2007, 01:37

Si ce que tu souhaites faire est de lister tous les fichier d'un répertoire commençant par $_GET["lettre"] (en majuscule ou en minuscules) et en enlevant l'extension du fichier, le code précédent adapté à ton pb devrait donc donner:
$lettre = isset($_GET["lettre"])? $_GET["lettre"] : "A";
$rep = "livre-d-or/";

$list = opendir($rep);
  
  $tabfile = array();
  
  //liste tous les fichiers
  while ($fichier = readdir($list)) 
           {//s'ils commencent par $lettre (en majuscules ou en minucules)
           if (strpos(strtolower($fichier), strtolower($lettre)) === 0)
				{ 
				//Insère le nom des fichiers dans le tableau $tabfile après avoir enlevé tout ce qui se trouve après le dernier point.
				$tabfile[] = substr($fichier,0,strrpos($fichier,'.'));
           		}
	   }

  closedir($list);
  
  //tri du tableau par ordre alphabétique naturel
  natcasesort($tabfile);
  
  //lecture du tableau trié
  foreach($tabfile as $file)    
      {
      echo $file.'<br />';
        } 
On peut faire l'économie de deux accolades (mais Zeus va me foudroyer car c'est moins lisible) :)
$lettre = isset($_GET["lettre"])? $_GET["lettre"] : "A";
$rep = "livre-d-or/";

$list = opendir($rep);
  
  $tabfile = array();
  
  //liste tous les fichiers
  while ($fichier = readdir($list)) 
           {//s'ils commencent par $lettre (en majuscules ou en minucules), insère le nom des fichiers dans le tableau $tabfile après avoir enlevé tout ce qui se trouve après le dernier point.
           (strpos(strtolower($fichier), strtolower($lettre)) === 0)? $tabfile[] = substr($fichier,0,strrpos($fichier,'.')) : '';
            }

  closedir($list);
  
  //tri du tableau par ordre alphabétique naturel
  natcasesort($tabfile);
  
  //lecture du tableau trié
  foreach($tabfile as $file)    
      {
      echo $file.'<br />';
        }
J'ai enlevé le preg_match car il n'était pas absolument nécessaire et tu auras bien d'autres occasions d'apprendre son fonctionnement :wink:
Tu vois qu'il n'y avait pas beaucoup de code à adapter 8-)

par AB » 06 sept. 2007, 00:35

Evidemment, pour que cela fonctionne il faut indiquer le chemin d'un répertoire pour $dossier. Pour lister ton répertoire PHOTO par exemple (si PHOTO est au même niveau que ton script) :
$dossier = 'PHOTO';

$list = opendir($dossier);
  
  $tabfile = array();
  
  while ($fichier = readdir($list)) 
           {// lit les fichiers et les insère dans le tableau $tabfile
           ($fichier != "." && $fichier != "..")? $tabfile[] = $fichier : '' ;
           }
  closedir($list);
  
  //tri du tableau
  natcasesort($tabfile);
  
  //lecture du tableau trié
  foreach($tabfile as $file)    
      {
      echo $file.'<br />';
        } 

par jpsartre » 06 sept. 2007, 00:13

J'ai essayé et j'ai eu soit une page vide, soit les noms qui se répétaient plusieurs fois chacun sans être classés.
J'y retourne

par AB » 06 sept. 2007, 00:06

Sur le principe, par exemple pour afficher les fichiers d'un dossier par ordre alphabétique
 $list = opendir($dossier);
  
  $tabfile = array();
  
  while ($fichier = readdir($list)) 
           {// lit les fichiers et les insère dans le tableau $tabfile
           ($fichier != "." && $fichier != "..")? $tabfile[] = $fichier : '' ;
           }
  closedir($list);
  
  //tri du tableau
  natcasesort($tabfile);
  
  //lecture du tableau trié
  foreach($tabfile as $file)    
	  {
	  echo $file.'<br />';
  	  }

par jpsartre » 05 sept. 2007, 23:37

J'ai bien compris la logique de la manoeuvre mais impossible d'y arriver, le code n'est pourtant pas bien long et j'ai essayé dans tous les sens...

Alors pour l'instant j'en suis là :
$lettre = isset($_GET["lettre"])?$_GET["lettre"]:"A"; // La lettre A par défaut 
$rep = "livre-d-or/";  
$dir = opendir($rep); 
while ($f = readdir($dir)) 
{ 
   if(is_file($rep.$f)) { 
 
   // Enlève l'extension
$fichier = $f; 
$position = strrpos($fichier,'.'); 
if($position !== false) 
   $sans = substr($fichier,0,$position);
   if ( preg_match("#^$lettre.*#", $f) ) { 
      // Stocke dans un tableau avant classement par ordre alphabétique
         echo "<p><a href=\"livre-d-or/".$f."\">".$sans."</a></p>"; 
	  
	  }
  }

} 
Je n'arrive pas à adapter à mon code. Si tu peux encore m'aider...
Pas évident à saisir ces tableaux. En fait je me perds dans les variables...

Et quoi que je fasse je n'ai pas de message d'erreur pour m'aider, soit rien ne se passe, soit les noms affichés sont remplacés par des 1 mais jamais dans l'ordre alphabétique....

Et merci pour le natsort(); car j'utilise effectivement des images qui se terminent par des nméros étant donné que certains artistes ont plusieurs photos. Mais pas évident tout cela...

par AB » 05 sept. 2007, 23:35

Dans le tri de ton tableau utilise plutôt natsort();
ça te rendra service si certaines de tes images sont terminées par un nombre