IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage PHP Discussion :

Conserver en cache côté client des images envoyer via readfile($filePath)


Sujet :

Langage PHP

  1. #1
    Membre confirmé Avatar de T`lash
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2007
    Messages
    381
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Saint-Pierre-Et-Miq.

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Biens de consommation

    Informations forums :
    Inscription : Septembre 2007
    Messages : 381
    Points : 519
    Points
    519
    Par défaut Conserver en cache côté client des images envoyer via readfile($filePath)
    Bonjour,

    J'ai réalisé une appli web dans laquelle de nombreuses images sont envoyées au client grâce à la fonction readfile($filePath) pour des raisons de confidentialité (il s'agit de miniatures de photos personnelles).

    Comme il peut y en avoir plusieurs centaines d'affichées en même temps et que certaines actions de l'utilisateur nécessite un rafraîchissement d'une partie de la page cela provoque de très nombreuses requêtes inutiles puisque ces miniatures correspondent chacune à une adresse unique et l'image associée à une adresse pourra être supprimée, mais jamais remplacée par une autre.

    Les adresses sont de la forme :

    http://www.domain.tld/download.php?F...mage&id=201&TN

    Et voici la fonction qui envoi le contenu des fichiers :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
        private static function sendFile($filePath = null){
            if ($filePath != null){
                if (file_exists($filePath)){
                    $finfo = new \finfo(\FILEINFO_MIME_TYPE);
                    $mimetype = $finfo->file($filePath);
                    if ($mimetype === false){
                        self::sendFile();
                        return false;
                    }
                    header('Content-Type: ' . $mimetype);
                    //header('Cache-Control: public, must-revalidate, max-age=3600');
                    //header("Last-Modified: " . gmdate("D, d M Y H:i:s", filemtime($filePath)) . " GMT", true, 304);
                    readfile($filePath);
                } else {
                    self::sendFile();
                    return false;
                }
            } else {
                header('Content-Type: image/png');
                readfile(PATH_IMAGES . DS . 'noimage.png');
            }
        }
    J'avais essayé avec les en-tête mis en commentaire, mais cela ne fonctionnait pas.

  2. #2
    Membre averti Avatar de demenvil
    Homme Profil pro
    Analyste développeur
    Inscrit en
    Avril 2009
    Messages
    195
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste développeur
    Secteur : Finance

    Informations forums :
    Inscription : Avril 2009
    Messages : 195
    Points : 389
    Points
    389
    Par défaut
    Salut !
    Je ne pense pas qu'en php tu puisses gérer le cache du client..

  3. #3
    Membre confirmé Avatar de T`lash
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2007
    Messages
    381
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Saint-Pierre-Et-Miq.

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Biens de consommation

    Informations forums :
    Inscription : Septembre 2007
    Messages : 381
    Points : 519
    Points
    519
    Par défaut
    On peux lui donner des instructions avec les headers, mais le truc c'est de savoir lesquels...

    J'ai trouvé qu'il fallait écraser certains en-têtes envoyés automatiquement par le serveur web.
    Donc faire un truc du genre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    header('Content-Type: ' . $mimetype);
    header('Content-Length: ' . filesize($filePath));
    header('Expires: ');
    header('Cache-Control: ');
    header('Pragma: ');
    //header('Last-Modified: ' . gmdate("D, d M Y H:i:s", filemtime($filePath)) . " GMT", true, 304);
    Le problème c'est que dès que je décommente la ligne "Last-Modified", le navigateur reçoit bien le code 304, mais pas du tout le contenu du fichier demandé.

  4. #4
    Membre confirmé Avatar de T`lash
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2007
    Messages
    381
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Saint-Pierre-Et-Miq.

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Biens de consommation

    Informations forums :
    Inscription : Septembre 2007
    Messages : 381
    Points : 519
    Points
    519
    Par défaut
    Et voilà !

    En cherchant de la doc sur le cache du navigateur et les en-têtes HTTP correspondant, je suis tombé sur cette page de la doc Symfony qui est très instructive même lorsque l'on utilise pas Symfony.

    À partir de ça j'ai pu développer une solution fonctionnelle pour mettre mes images en cache :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
        private static function sendFile($filePath = null){
            if ($filePath != null){
                if (file_exists($filePath)){
                    $finfo = new \finfo(\FILEINFO_MIME_TYPE);
                    $mimetype = $finfo->file($filePath);
                    if ($mimetype === false){
                        self::sendFile();
                        return false;
                    }
                    $fmtime = filemtime($filePath);
                    header('Expires: ');
                    header('Cache-Control: private, max-age=604800, must-revalidate');
                    header('Pragma: ');
                    header('ETag: "' . $fmtime . '"');
                    $headers = getallheaders();
                    if ((isset($headers['If-None-Match'])) && ($headers['If-None-Match'] == '"' . $fmtime . '"')){
                        header('Last-Modified: ' . gmdate("D, d M Y H:i:s", $fmtime) . " GMT", true, 304);
                    } else {
                        header('Content-Type: ' . $mimetype);
                        header('Content-Length: ' . filesize($filePath));
                        readfile($filePath);
                    }
                } else {
                    self::sendFile();
                    return false;
                }
            } else {
                header('Content-Type: image/png');
                readfile(PATH_IMAGES . DS . 'noimage.png');
            }
        }
    Si on regarde en détail les lignes qui nous intéressent (10-22), on a :

    • $fmtime = filemtime($filePath);
      Il s'agit simplement de conserver la date de modification du fichier car non en avons besoin à plusieures reprises.
    • header('Expires: ');
      Pour écraser la valeur existante.
    • header('Cache-Control: private, max-age=604800, must-revalidate');
      private désigne le cache du navigateur (pour ne pas conserver le fichier dans un cache partagé dans mon cas pour des raisons de confidentialité).
      max-age=604800 indique que le fichier doit être conservé une semaine (valeur en secondes).
      must-revalidate indique qu'il faut tout de même vérifier si le fichier n'a pas changé entre temps.
    • header('Pragma: ');
      Pour écraser la valeur existante.
    • header('ETag: "' . $fmtime . '"');
      L'en-tête Etag sert à donner un identifiant unique à une version d'un fichier. J'ai naturellement choisi la date de modification dans un cas aussi simple (la réponse ne dépend pas de l'état de l'application).
    • $headers = getallheaders();
      Alias de la fonction apache_request_headers(). Récupère les en-têtes de la requête.
      J'ai dû mettre à jour ma version de PHP en 5.4 car cette fonction n'est disponible qu'en exécution de PHP en tant que module apache avant PHP 5.4.
      Pour les versions antérieures, une astuce utilisant les RewriteRules (fichier .htaccess) est donnée en commentaire de cette page de la doc PHP.
    • if ((isset($headers['If-None-Match'])) && ($headers['If-None-Match'] == '"' . $fmtime . '"')){
      Si l'en-tête If-None-Match existe et contient la valeur précédemment envoyées via l'en-tête ETag.
    • header('Last-Modified: ' . gmdate("D, d M Y H:i:s", $fmtime) . " GMT", true, 304);
      On indique quand le fichier a été modifié pour la dernière fois, que cet en-tête doit écraser un en-tête de même type s'il existe, et que le code de réponse HTTP doit être 304 (Not Modified).
    • header('Content-Type: ' . $mimetype);
      header('Content-Length: ' . filesize($filePath));
      readfile($filePath);

      Sinon on envoi le type MIME du fichier, sa taille et son contenu.


    J'espère que cela pourra resservir à d'autres.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Comment puis-je recupérer des données envoyées via TCP
    Par pierrot10 dans le forum Général Python
    Réponses: 0
    Dernier message: 26/12/2014, 00h12
  2. [MySQL] associer une image à des données envoyées via un formulaire
    Par ironman06 dans le forum PHP & Base de données
    Réponses: 2
    Dernier message: 04/03/2012, 15h15
  3. Réponses: 11
    Dernier message: 25/02/2007, 01h56
  4. Empêcher la mise en cache des images
    Par oranoutan dans le forum Balisage (X)HTML et validation W3C
    Réponses: 6
    Dernier message: 15/02/2006, 11h49
  5. envoyer des images avec access
    Par dan664 dans le forum Access
    Réponses: 6
    Dernier message: 13/10/2005, 21h16

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo