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 :

Intégrer des images en mode "flux" dans une page web


Sujet :

Langage PHP

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    105
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 105
    Points : 57
    Points
    57
    Par défaut Intégrer des images en mode "flux" dans une page web
    Bonjour

    J'ai des utilisateurs qui peuvent stocker des images dans leur espace perso.
    Les images sont dans des répertoires qui pour diverses raisons de sécurité et de confidentialité ne sont pas accessibles directement sur le web.

    L'architecture des dossiers de mon appli est

    application (répertoires non accessibles)
    >les scripts de l'appli
    >les dossiers d'images (repertoire non accessible)

    public (répertoire accessible)
    - index.php

    Comment alors puis-je afficher ces images dans une page web ?
    Quelle est la bonne méthode ?
    Puis-je insérer l'image en binaire dans la page ? Si oui comment
    est ce que je dois copier l'image temporairement dans un répertoire de public et avoir un script qui fait le ménage toute les 3 minutes ?

    Merci d'avance

  2. #2
    Membre averti
    Profil pro
    Inscrit en
    Janvier 2004
    Messages
    489
    Détails du profil
    Informations personnelles :
    Âge : 51
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Janvier 2004
    Messages : 489
    Points : 388
    Points
    388
    Par défaut
    Salut,

    J'avais fait ca sur un site.. mais un script qui t'affiche tes images.. c'est lourd, tres rapidement.. (pour peu que tu affiches des pages de navigation avec 20 / 30 images, quelques visiteurs simultanés et tu te retrouves avec beaucoup d'appels sur ton script d'affichage de médias)

    Pour le code, c'est ce genre la (cas d'une image):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    if (file_exists($filename))
    {
    	header("Content-Length: ".@filesize($filename));
    	header("Content-Transfer-Encoding: binary");
    	header("Content-Type: image/jpeg");
    	$fd = fopen($filename, "r");
    	while(!feof($fd))
    	{
    		echo fread($fd, filesize($filename));
    		flush();
    	}
    	fclose ($fd);
    }
    Enfin moi je te déconseille cette solution.. j'ai fini par refaire le site, en mettant les répertoires médias accessibles (en vérifiant bien les types/contenu des fichiers uploadés, bien sur).

    Et un petit détail, si tu utilise ce genre de scripts et que tu utilise une session, il faut absolument la fermer avant de lire ton fichier avec un

  3. #3
    Membre habitué
    Homme Profil pro
    Inscrit en
    Juin 2012
    Messages
    136
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations forums :
    Inscription : Juin 2012
    Messages : 136
    Points : 174
    Points
    174
    Par défaut
    Bonjour,
    Je garantie pas la validité de ma réponse, je suis pas sûr d'avoir compris la question.
    Je connais pas cette commande donc j'utiliserai une base de données.
    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
     
    <?php
    include('cnx-ilp.php');
     
    $sql2="select * from images";
    $sql3=$cnx->query($sql2);
    $sql4=$sql3->fetchAll();
    	$result=count($sql4);
    echo "$result image trouvée(s) : <br>";
     
    $sql0="select * from images";
    $sql1=$cnx->query($sql0);
    while ($rows=$sql1->fetch()) {
    	echo "<img style='width:150px;height:150px;' src='".$rows['image']."'/><br>";
    }
    Bon codage.

    En image : http://ilovephp.dedicom.eu/diapo/diapo.php

  4. #4
    Membre du Club
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    105
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 105
    Points : 57
    Points
    57
    Par défaut
    Merci pour vos réponses qui m'ont mis sur la piste.

    J'ai trouvé ca qui marche super

    Lire l'image et l'encoder et passer les données sans le src de l'image


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
       echo '<img src="data:image/png,'. rawurlencode(file_get_contents($monpath.$monfichier)).'">';
    Je ne sais pas si c'est OK au niveau des perfs mais je n'aurais pas bcp d'images a afficher, ni beaucoup d'utilisateurs concurents donc ca devrait aller.

  5. #5
    Expert éminent
    Avatar de Benjamin Delespierre
    Profil pro
    Développeur Web
    Inscrit en
    Février 2010
    Messages
    3 929
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Février 2010
    Messages : 3 929
    Points : 7 762
    Points
    7 762
    Par défaut
    Personnellement, j'aurais tout simplement utilisé un petit script PHP pour renvoyer le contenu binaire du fichier image après avoir bien entendu validé les droits de l'utilisateur qui souhaite la voir. Les performances ne sont pas réellement un problème surtout si tu envoies les headers de cache au client pour éviter que PHP doive systématiquement renvoyer l'image.

    Mettre le binaire de l'image directement dans le flux HTML n'est pas une bonne idée selon moi. Pourquoi ? Parce que toutes les ressources externes référencées dans un flux HTML sont chargées de manière asynchrone par des threads séparés par le navigateur. Concrètement, ça veux dire qu'avec ton système si une image mets 500ms à être téléchargée en binaire, ça viendra s'ajouter au temps nécessaire avant l'affichage de la page, donc pendant ce temps, l'internaute voit une belle page blanche.
    Donc il vaut toujours mieux servir le flux HTML et laisser les ressources se charger ensuite, sinon c'est le temps de chargement global de la page qui va en pâtir.
    De plus, tu ne peux pas utiliser le cache du navigateur dans ce cas, donc tu renvoies les images à chaque requête, donc tu augmente le traffic entre le client et le serveur web, ce qui n'est jamais une bonne chose.

    Voici concrêtement comment faire:
    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
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    <?php
    // attention: il faut éviter que la session ne désactive le cache (comportement par défaut) sinon tout ce
    // qu'on fait plus bas ne servira à rien
    session_cache_limiter("private_no_expire");
     
    // constate pratique pour activer / désactiver le log
    define("DEBUG_MODE", true);
     
    // on utilise des dates GMT pour éviter la confusion
    date_default_timezone_set('GMT');
     
    // on définit 'access.log' comme fichier de log
    ini_set('log_errors',      1);
    ini_set('error_log',       'access.log');
    ini_set('error_reporting', 0);
    ini_set('display_errors',  0);
     
    // ce script va contenir la fonction "check_permissions" (voir plus bas) et d'une manière générale la gestion des
    // droits
    require "auth.php";
     
    // si on n'a pas reçu le nom de fichier ou si ce dernier n'est pas dans notre repertoire 'img', on prétends que la
    // ressource n'est pas trouvée (http 404)
    if (!($filename = $_GET['filename']) || !is_file($file = dirname(__FILE__).'/img/'.$filename)) {
        header("HTTP/1.1 404 Not Found");
        exit;
    }
     
    // maintenant on vérifie que l'utilisateur à le droit d'accéder à cette ressource, si tel n'est pas le cas, on envoie
    // un forbidden (http 403), on va également vérifier que l'utilisateur ne cherche pas à obtenir le .htaccess
    if (!check_permissions($file) || preg_match('~\.htaccess~i', $filename)) {
        header("HTTP/1.1 403 Forbidden");
        exit;
    }
     
    // on regarde la date de dernière modification du fichier et on fait son MD5 pour l'ETAG
    $last_modified_time        = filemtime($file);
    $etag                      = md5_file($file);
     
    // on réccupère ces mêmes informations que nous a envoyé le navigateur
    $client_last_modified_time = $_SERVER['HTTP_IF_MODIFIED_SINCE'] ? trim($_SERVER['HTTP_IF_MODIFIED_SINCE']) : 0;
    $client_etag               = $_SERVER['HTTP_IF_NONE_MATCH']     ? trim($_SERVER['HTTP_IF_NONE_MATCH'])     : false;
     
    // dans tous les cas on envoie les headers Last-Modified et Etag
    header("Last-Modified: ".gmdate("D, d M Y H:i:s", $last_modified_time)." GMT");
    header("Etag: $etag");
     
    DEBUG_MODE && error_log("Requested $file");
     
    // si le navigateur à une version identique (même date ou même etag)
    if (strtotime($client_last_modified_time) == $last_modified_time || $client_etag == $etag) {
        DEBUG_MODE && error_log("Not modified");
        header("HTTP/1.1 304 Not Modified");
        exit;
    }
     
    // sinon, on détermine l'extension pour envoyer le bon header...
    preg_match('~\.(\w+)$~', $file, $matches);
    switch (strtolower($matches[1])) {
        case 'jpeg':
        case 'jpg':
            header("Content-Type: image/jpeg");
            break;
        case 'png':
            header("Content-Type: image/png");
            break;
        case 'gif':
            header("Content-Type: image/gif");
            break;
        default:
            header("Content-Type: application/octet-steam");
            break;
    }
     
    DEBUG_MODE && error_log("Serving $file");
     
    // ...et on balance le contenu du fichier
    header('Content-Length: ' . filesize($file));
    readfile($file);
    J'ai commenté pour que ce soit compréhensible. La logique est la suivante:
    1. le serveur demande une ressources (style 01.jpg)
    2. PHP commence par regarder si le fichier existe et si tel n'est pas le cas sort avec un status HTTP 404 (not found)
    3. ensuite, PHP vérifie que l'utilisateur loggé à les droits pour cette ressource (heureusement le navigateur nous a envoyé le token de session) et si tel n'est pas le cas, on sort avec un status HTTP 403 (forbidden)
    4. ensuite PHP créé un token (Etag) pour le fichier et détermine sa date de dernière mise à jour puis envoie ces deux informations au navigateur avec la fonction header, ces headers seront utilisés plus tard par le navigateur pour savoir si la ressource doit être rechargée
    5. enfin, on envoie le header pour le type (content-type) et le contenu du fichier

    Lors que le client va demander à nouveau la ressource, il va cette fois nous fournir l'etag et le last-modified qu'on lui envoyé la dernière fois, il ne nous reste qu'a les comparer avec ceux de notre fichier et s'ils sont identiques, on peut renvoyer directement le header 304 qui dit au navigateur que la ressource n'a pas changé et qu'il peut la prendre depuis son cache.

    Enfin, il ne reste qu'a mettre les attributs src des balises img comme suit:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <html>
    <head>
        <title>Demo</title>
    </head>
    <body>
        <img src="img.php?filename=18.jpg" />
        <img src="img.php?filename=19.jpg" />
        <img src="img.php?filename=21.jpg" />
    </body>
    </html>
    Simple non ?

    Pour des raisons pratiques, j'ai ajouté un petit log qui nous permet de voir ce qu'il se passe dans notre script. Lors du premier appel, on y trouve:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    [28-Aug-2012 13:43:31 UTC] Requested C:\wamp\www\sandbox\image-cache/img/19.jpg
    [28-Aug-2012 13:43:31 UTC] Serving C:\wamp\www\sandbox\image-cache/img/19.jpg
    [28-Aug-2012 13:43:31 UTC] Requested C:\wamp\www\sandbox\image-cache/img/18.jpg
    [28-Aug-2012 13:43:31 UTC] Serving C:\wamp\www\sandbox\image-cache/img/18.jpg
    [28-Aug-2012 13:43:31 UTC] Requested C:\wamp\www\sandbox\image-cache/img/21.jpg
    [28-Aug-2012 13:43:31 UTC] Serving C:\wamp\www\sandbox\image-cache/img/21.jpg
    Vu que c'est le premier appel, il n'y a pas de cache existant, on sert donc les images. Lors du deuxième appel, on y trouve:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    [28-Aug-2012 13:44:18 UTC] Requested C:\wamp\www\sandbox\image-cache/img/18.jpg
    [28-Aug-2012 13:44:18 UTC] Not modified
    [28-Aug-2012 13:44:18 UTC] Requested C:\wamp\www\sandbox\image-cache/img/19.jpg
    [28-Aug-2012 13:44:18 UTC] Not modified
    [28-Aug-2012 13:44:18 UTC] Requested C:\wamp\www\sandbox\image-cache/img/21.jpg
    [28-Aug-2012 13:44:18 UTC] Not modified
    Ce qui nous indique que cette fois, on a tout simplement envoyé le header 304 et qu'on s'est arrêté là.

    Je te mets un .zip avec les sources pour que tu puisse tester. Utilise Chrome pour regarder ce qu'il se passe quand tu lance index.html, avec F12 va dans Network, tu verra que les premiers appels sont résolus en 200 OK et que les suivants sont tous en 304 Not Modified.

    Pour aller plus loin, on aurait pu mettre directement img.php dans /img et utiliser les règles de réécriture d'URL pour tout faire passer par img.php. Ce qui rends la génération des liens encore plus facile.

    A toi de jouer.
    Fichiers attachés Fichiers attachés

  6. #6
    Membre habitué
    Homme Profil pro
    Inscrit en
    Juin 2012
    Messages
    136
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations forums :
    Inscription : Juin 2012
    Messages : 136
    Points : 174
    Points
    174
    Par défaut
    Excusez moi, mais j'ai 2 questions :
    Si c'est pas accessible par le web pourquoi vouloir les mettre dans une page web ?

    Pourquoi ne pas utiliser les sessions pour s'assurer des droit d'accès ?

  7. #7
    Membre du Club
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    105
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 105
    Points : 57
    Points
    57
    Par défaut
    Merci benjamin pour ton exemple très clair et très documenté.
    Effectivement c'est une bien meilleure méthode. Bien que dans mon cas la méthode employée pouvait suffire (peu d'images, peu de charge sur le serveur).
    Je vais essayer d'implémenter ça (j'utilise zendFramework alors ca va être un peu plus complexe mais ton exemple est super détaillé donc je pense y arriver)

    Merci encore d'avoir partagé ça !

    Pour Schim59, parfois tu as des images (par exemple mises en ligne par les utilisateurs) que tu ne veux pas mettre dans un répertoire public (tu ne veux pas que n'importe qui puisse y accéder) mais tu as besoin de pouvoir les afficher dans une page web (par exemple pour la montrer a l'utilisateur qui l'a mise en ligne).
    Dans ce cas tu ne peux pas simplement faire un <img src="images/toto.jpg">, il faut que tu gère les droits d'accès a l'image (ex ce que cet utilisateur a le droit de voir cette image) et comme tu as mis les images dans un répertoire protégé tu ne peux pas y accéder directement, il faut que tu les envoies au navigateur via un script.

  8. #8
    Membre expert Avatar de RunCodePhp
    Profil pro
    Inscrit en
    Janvier 2010
    Messages
    2 962
    Détails du profil
    Informations personnelles :
    Localisation : Réunion

    Informations forums :
    Inscription : Janvier 2010
    Messages : 2 962
    Points : 3 947
    Points
    3 947
    Par défaut
    Citation Envoyé par Schim59
    Excusez moi, mais j'ai 2 questions :
    Si c'est pas accessible par le web pourquoi vouloir les mettre dans une page web ?
    Il n'y a aucun malaise à vouloir comprendre les choses.
    Boubil n'a pas dit que les images ne soient pas accessible via une pages Web, il y souhaitait juste quelles ne le soient pas "directement".
    Il y a des sous-entendus dans ce "directement", et cela vient effectivement d'une certaine manière de structurer le site Web.

    A la base tout est une histoire de VirtualHost (ou VHost).
    Le virtualHost est (théoriquement) le répertoire où ce trouve le site Web, sont chemin (chemin physique) est défini dans le httpd.conf (pour Apache).

    Par défaut (sauf restriction particulière) tout fichier ce trouvant dans ce répertoire (le virtualhost) est accessible via HTTP, c'est à dire en saisissant une URL dans son navigateur.

    Admettons qu'on ait une arborescence comme celle-ci dessous, que j'estime la plus courante :
    /home/123456789/www -> On a défini ce répertoire www comme virtualhost.
    /home/123456789/www/images/public.jpg

    Le répertoire www étant accessible publiquement, et bien tout ce qui ce trouve dans celui-ci le sera tout autant.

    Si le nom du domaine est :domaine.com, et bien en saisissant : -http://www.domaine.com/images/public.jpg
    -> tout le monde pourra visualiser cette image.

    A ce stade, tout ceux qui ont quelques bases dans le Web savent cela.


    Maintenant (pure exemple) si on crée un nouveau répertoire au même niveau du www (on peu dire aussi, à coté), comme :
    /home/123456789/images_prive
    Et bien si on ne défini pas ce répertoire "image_prive" comme virtualhost, donc non lié/défini à un domaine (ou sous-domaine, peu importe), tout ce qui ce trouvera dedans sera inaccessible via une URL (ou HTTP), donc via un navigateur.
    En somme, comme "images_prive" ne se trouve pas dans le "www" mais en-dehors, impossible d'accéder à quoi que ce soit via "domaine.com" par exemple.

    Ceci dit, pas vraiment, et c'est là que ça devient intéressant.
    On peu récupérer le flux d'un des fichiers (le binaire) en Php et le renvoyer par le biais d'une autre page html.
    Donc ça peu se faire de manière "indirecte".
    En somme, le codeur/développeur ayant tous les droits dans /home/123456789/, il peu faire ce qu'il veux coté serveur, en Php entre autre.

    C'est ce que recherchait Boubil.
    Cependant, c'est un poil plus compliqué, sans compter que ça se complique encore plus si on souhaite optimiser tout ça car cela n'est pas sans incidence (voir le code et les explications de Benjamin).



    Citation Envoyé par Schim59
    Pourquoi ne pas utiliser les sessions pour s'assurer des droit d'accès ?
    Oui, les sessions sera très certainement utile dans le cas présent, mais ce n'est pas suffisant pour garantir la non accessibilité directe de certaines images qu'on qualifiera de privée.


    Voilà voilà, en espérant ne pas avoir été trop long.
    Win XP | WampServer 2.2d | Apache 2.2.21 | Php 5.3.10 | MySQL 5.5.20
    Si debugger, c'est supprimer des bugs, alors programmer ne peut être que les ajouter [Edsger Dijkstra]

  9. #9
    Membre habitué
    Homme Profil pro
    Inscrit en
    Juin 2012
    Messages
    136
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Nord (Nord Pas de Calais)

    Informations forums :
    Inscription : Juin 2012
    Messages : 136
    Points : 174
    Points
    174
    Par défaut
    Merci,

    Pour les sprécisions très intéressantes.

  10. #10
    Membre du Club
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    105
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 105
    Points : 57
    Points
    57
    Par défaut
    merci RunCodePhp pour ces explications très claires.

  11. #11
    Membre du Club
    Profil pro
    Inscrit en
    Décembre 2008
    Messages
    105
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2008
    Messages : 105
    Points : 57
    Points
    57
    Par défaut
    Bon, maintenant, j'ai la question inverse.
    Si j'ai le code source d'une page html qui contient

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    <img src="data:image/jpeg;base64,/9j/4AAQSkZJRgABAgEBLAEsAAD/4RR0RXhpZgAATU0AKgAAAAgABwESAAMAAAABAAEAAA......."/>
    Comment je fais pour récupérer les images et les enregistrer sur disque ?

  12. #12
    Expert éminent
    Avatar de Benjamin Delespierre
    Profil pro
    Développeur Web
    Inscrit en
    Février 2010
    Messages
    3 929
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Février 2010
    Messages : 3 929
    Points : 7 762
    Points
    7 762
    Par défaut
    Avec DOMDocument tu extrait la valeur des attributs src des noeuds cibles puis, en fonction du type mime exprimé par data: tu prends ce qui suit et éventuellement tu le décode, dans l'exemple avec base64_decode. Tu écris un fichier sur disque et c'est bon.

Discussions similaires

  1. Intégrer des documents word et pdf au milieu d'une page Web
    Par scude dans le forum EDI, CMS, Outils, Scripts et API
    Réponses: 1
    Dernier message: 12/09/2012, 09h45
  2. Utiliser des images stockées dans un dossier TMP dans une page web
    Par k o D dans le forum Développement Web en Java
    Réponses: 1
    Dernier message: 19/07/2010, 20h38
  3. Intégrer des scripts SHELL dans une page web
    Par abdellah 1 dans le forum Général Conception Web
    Réponses: 1
    Dernier message: 10/05/2010, 16h35
  4. Réponses: 3
    Dernier message: 15/05/2007, 09h28

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