[mini tuto]Fonction récursive AJAX pour éviter les timeout PHP

Répondre
Partager Rechercher
Hoi,

Prenons l'exemple bien connu de création de vignettes par php. Le problème de ce genre de chose est que si il y a beaucoup de photos à traiter, nous allons dépasser les 30 secondes fatidiques d'exécution.

Pour améliorer les choses, on peut passer par l'ajax pour exécuter cette fonction.Le message d'erreur apparaîtra dans un div de la page principale. C'est un peu mieux pour l'utilisateur qu'une page blanche avec le message d'erreur.

Ceci est bien beau mais l'idéal serait de ne pas avoir de message d'erreur du tout.

La solution est de créer une fonction ajax récursive qui va envoyer une requête au script php autant de fois qu'il y a de photos à traiter.

En pratique, comment ça marche ?

Le script php

Code PHP:

<?php
// cest deux premières lignes sont extrêmement importantes pour IE, sinon, celui-ci met en cache le résultat précédent !!
// la troisième étant juste la pour éviter un conflit enter l'utf-8 et l'iso.
header("Cache-Control: no-cache, must-revalidate"); // HTTP/1.1
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); // Date in the past
header('Content-type: text/html; charset=iso-8859-1'); 
$dir='./images';
chdir($dir);
$dir=".";
$handle=opendir($dir);
$i=0;
while (
false !== ($file readdir($handle)))
 {
   if (!(
is_dir($file)) AND ($file!="Thumbs.db") AND ($file!="error_log") AND ($file!=".ftpquota") AND (!file_exists($dir.'/small/'.$file)))
  {
$fichier $dir.'/'.$file;
    if(!
file_exists($_SERVER['DOUMENT_ROOT']."/admin/photos_ftp/images/small/".$file))
    {
    if (
$image = @imagecreatefromjpeg($fichier))
    {
    
$width imagesx($image) ;
    
$height imagesy($image) ;
    
$new_height 150;
    
$new_width $new_height $width $height;
    
$thumb imagecreatetruecolor($new_width,$new_height);
    
imageAntiAlias($thumb,true);
    
imageCopyResampled($thumb,$image,0,0,0,0,$new_width,$new_height,$width,$height);
    
ImageJPEG($thumb$dir.'/small/'.$file);
    
chmod($dir.'/small/'.$file,0666);
    
imagedestroy($image);
    
$i++;
    echo 
'<br />image '.$file.' créée !';
    }
    else
    {echo 
'Echec de création de l\'image <strong>'.$file.'</strong><br />Effacez ce fichier du dossier et recommencez';die();}
    break;
    }
  }
 }
if (
$i == 0)
 echo 
'Toutes les photos ont été traitées';
?>
C'est assez basique. Il cherche juste une vignette non-crée, il la crée et sort de la boucle.
Le terme "créée" est important, il va être utilisé comme contrôle par le script javascript.

Le code html basique :

Code HTML:
<style type="text/css">
#resultat {
	border:           1px solid black;
	background-color: #CCDDFF;
	height:           200px;
	overflow:         auto;
}
</style>";
ici l'important est le overflow : auto; pour suivre l'évolution du script
Code HTML:
<span  onclick=\"makeRequest('small.php')\">Faire les vignettes</span>";
<div id='resultat'></div>
Rien de bien compliqué ici, on peut aussi appliquer un style genre
cursor: pointer;
text-decoration: underline;
dans notre css.

Bon maintenant, les choses sérieuses :

Code HTML:
<script type="text/javascript" language="javascript">

function makeRequest(url)
{

                http_request = false;

                if (window.XMLHttpRequest) { // Mozilla, Safari,...
                    http_request = new XMLHttpRequest();
                    if (http_request.overrideMimeType) {
                        http_request.overrideMimeType('text/xml');
                    }
                } else if (window.ActiveXObject) { // IE
                    try {
                        http_request = new ActiveXObject("Msxml2.XMLHTTP");
                    } catch (e) {
                        try {
                        http_request = new ActiveXObject("Microsoft.XMLHTTP");
                        } catch (e) {}
                    }
                }

                if (!http_request) {
                    alert('Giving up :( Cannot create an XMLHTTP instance');
                    return false;
                }
                http_request.onreadystatechange = function() {
		if (http_request.readyState == 4) {
                    if (http_request.status == 200) {
                        document.getElementById('resultat').innerHTML += http_request.responseText+'<br />'; // on écrit le résultat dans le div
			document.getElementById('resultat').scrollTop = document.getElementById('resultat').scrollHeight; //juste pour se retrouver en bas
                        if (http_request.responseText.indexOf('créée') != -1) // Si le terme 'créée' est renvoyé par php
				{

				makeRequest(url) // Récursivité : On repart dans la fonction 
				}
                    } else {
                        alert('There was a problem with the request.');
                    }
                 }
                }
                http_request.open('/GET', url, true);
                http_request.send(null);

}
</script>
La syntaxe "http_request.onreadystatechange = function() {" est très importante.
Ca marche comme ça et pas autrement.
ou alors http_request.onreadystatechange = MaFunction;
mais alors, pas d'argument autorisé.


Donc globalement, que fait donc tout ça ?

Au clic sur 'Faire les vignettes' javascript va envoyer une requête asynchrone au script small.php
celui-ci va générer une et une seule vignette si possible.
Si le résultat est ok -> il envois, par un echo "xxxx créée"
Par ce mot clé, javascript envoit une nouvelle requête à small.php
Et ceci, jusqu'à temps que small.php envois autre chose, comme "Echec de création de l'image..." ou "Toutes les photos ont été traitées"
A ce moment, javascript stoppe sa récursivité.

Résultat : toutes les vignettes ont été crées, parfois en plus d'une minute sans timeout et l'utilisateur peut voir le résultat de sa requête dans le div.
Citation :
Publié par Empoisonneur
Et c'est à quel moment que l'on pense que pour afficher une galerie de quelques dizaines de photos par X utilisateurs simultanés, on écroule complètement le serveur ?

jamais.
Les vignettes sont crées une et une seule fois par l'admin du site, pas par les visiteurs
Personnelement je préfère limiter le nombre de vignette par page ce qui offre une meilleur lisibilité et un temps d'exécution correct.

Ceci dit: tres bon tuto ^^
Citation :
Publié par KROGOTH
..
Mais enfin, il faut un peu comprendre ce qui est écrit.
Ce script ne sert pas à afficher des vignettes mais d'en créer sans timeout php
On aurait pu prendre un tout autre exemple ...
Dans ce cas demander une confirmation toute les n vignettes créées ^^

Oui je sais que ce tuto s'applique a beaucoup d'autres choses et c'est l'occasion de s'intéresser a ajax plutôt que d'utiliser des bidouilles avec php et javascript ^^
Code:
if(http_request.responseText.indexOf('créée') != -1)
{
    makeRequest(url);
}
Ici j'aurais ajouté un timeout histoire que le serveur ne travaille pas en boucle ( la GD n'est pas ce qu'il y a de plus léger avec les couleurs vraies, l'anticrénelage et le ré-échantillonage ).

Code:
if(http_request.responseText.indexOf('créée') != -1)
{
    setTimeout('makeRequest("' + url + '")', 1000); // ~ une requête / seconde
}
Sinon innerHTML est une mauvaise habitude à mettre de côté. Il vaut mieux utiliser les méthodes du document. DOM Builder est une classe javascript qui rend leur utilisation aisée.
Répondre

Connectés sur ce fil

 
1 connecté (0 membre et 1 invité) Afficher la liste détaillée des connectés