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 :

Erreur au téléchargement de gros fichiers


Sujet :

Langage PHP

  1. #1
    Membre expérimenté Avatar de Jarodd
    Profil pro
    Inscrit en
    août 2005
    Messages
    845
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : août 2005
    Messages : 845
    Points : 1 678
    Points
    1 678
    Par défaut Erreur au téléchargement de gros fichiers
    Bonjour,

    J'ai un site hébergé sur un mutualisé, qui me permet de montrer à la famille des photos et des vidéos. J'ai une fonction qui leur permet de télécharger les éléments,, voici son code :

    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
     
    // $file est le chemin absolu du fichier : /path/to/file.ogv
    function file_download($file)
        {
            if( headers_sent() ) {      die('Headers Sent'); }
            if (!file_exists($file)) {  die('File not found'); }
            if (!is_file($file)) {      die('File not found'); }
            if(ini_get('zlib.output_compression')) ini_set('zlib.output_compression', 'Off'); // IE
            // Infos sur le fichier
            $len = filesize($file);
            $filename = basename($file);
            // $parts          = pathinfo($fullPath);
            // $file_extension = strtolower($parts["extension"]);
            $file_extension = strtolower(substr(strrchr($filename,"."),1));
     
            // Définit le Content-Type selon le type de fichier
            switch( $file_extension ) {
                case "avi"  : $ctype="video/x-msvideo"; break;
                case "doc"  : $ctype="application/msword"; break;
                case "exe"  : $ctype="application/octet-stream"; break;
                case "gif"  : $ctype="image/gif"; break;
                case "jpg"  :
                case "jpeg" : $ctype="image/jpg"; break;
                case "mp3"  : $ctype="audio/mpeg"; break;
                case "mp4"  : $ctype="video/mp4"; break;
                case "mpeg" :
                case "mpg"  :
                case "mpe"  : $ctype="video/mpeg"; break;
                case "mov"  : $ctype="video/quicktime"; break;
                case "ogv"  : $ctype="video/ogg"; break;
                case "pdf"  : $ctype="application/pdf"; break;
                case "png"  : $ctype="image/png"; break;
                case "ppt"  : $ctype="application/vnd.ms-powerpoint"; break;
                case "wav"  : $ctype="audio/x-wav"; break;
                case "xls"  : $ctype="application/vnd.ms-excel"; break;
                case "xlsx" : $ctype="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; break;
                case "zip"  : $ctype="application/zip"; break;
     
                // Ces extensions ne doivent pas être téléchargées
                case "php":
                case "htm":
                case "html":
                case "sql":		
                case "txt": die("<b>Cannot be used for ". $file_extension ." files!</b>"); break;
     
                default: $ctype="application/force-download";
            }
     
            // Ecriture du header
            header("Cache-Control: must-revalidate, no-cache, no-store"); // HTTP/1.1
            header("Cache-Control: private, post-check=0, pre-check=0", false); // IE
            header("Content-Description: File Transfer");
            header("Content-Disposition: attachment; filename=".$filename.";");
            header("Content-Length: ".$len);
            header("Content-Transfer-Encoding: binary");
            header("Content-Type: $ctype");
            header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Date dans le passé
            header("Last-Modified: " . gmdate( "D, d M Y H:i:s" ) . " GMT"); // Date GMT
            header("Pragma: no-cache"); 
            ob_clean();
            flush();
     
            // Download file
            readfile($file);
            die();
     
        }
    Les petits fichiers sont téléchargés sans problèmes. Mais s'ils font 140 Mo ou plus, je rencontre une erreur.

    Sous Chrome :
    Cette page Web est introuvable.
    Sous Firefox :
    Fichier introuvable

    Firefox ne peut trouver le fichier à l'adresse http://xxx.

    Vérifiez la syntaxe du nom de fichier (dont le respect des minuscules/majuscules) ;
    Vérifiez si le fichier n'a pas été déplacé, renommé ou supprimé.
    Opera lance le téléchargement, mais au final j'ai entre 0 et 20 octets...

    L'hébergement est en PHP 5.4.27. Le directive memory_limit est définie à 256M, je pense que c'est suffisant (et je ne sais pas si le poids du fichier joue dans la mémoire requise pour un script ?). Edit : je doute que ce soit ça qui bloque, car en local je suis à 128M et je peux tout télécharger, même les fichiers qui font plus de 140 Mo... J'espère que que ce n'est pas Apache qui bloque, car je n'ai pas la main

    Je cherche depuis un moment et je n'arrive pas à m'en sortir, j'espère que vous pourrez m'aider.

    Merci d'avance pour vorte aide.

  2. #2
    Responsable Systèmes


    Homme Profil pro
    Technicien maintenance
    Inscrit en
    août 2011
    Messages
    13 968
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Technicien maintenance
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : août 2011
    Messages : 13 968
    Points : 32 047
    Points
    32 047
    Par défaut
    Dans le php.ini tu as une directive upload_max_filesize
    En mutualisé, tu ne dois pas y avoir accès.
    Ma page sur developpez.com : http://chrtophe.developpez.com/ (avec mes articles)
    Mon article sur la création d'un système : http://chrtophe.developpez.com/tutoriels/minisysteme/
    Mon article sur le P2V : http://chrtophe.developpez.com/tutoriels/p2v/
    Consultez nos FAQ : Windows, Linux, Virtualisation

  3. #3
    Membre expérimenté Avatar de Jarodd
    Profil pro
    Inscrit en
    août 2005
    Messages
    845
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : août 2005
    Messages : 845
    Points : 1 678
    Points
    1 678
    Par défaut
    Cette directive est applicable si j'envoie un fichier sur le serveur (par un formulaire par exemple), non ?

    Ce n'est pas mon cas, je télécharge le fichier, je ne l'envoie pas.

  4. #4
    Expert éminent

    Homme Profil pro
    Développeur Web
    Inscrit en
    septembre 2010
    Messages
    5 099
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : septembre 2010
    Messages : 5 099
    Points : 9 801
    Points
    9 801
    Par défaut
    Bien possible que cela soit une limitation d'apache. Tu auras peut-être plus de précisions avec des spécialistes de l'administration serveur.

    Sinon (je doute que tu puisse régler ce problème sans avoir la main sur l'administration du serveur), reste la solution d'héberger tes vidéos dans une page privative youtube par exemple...

  5. #5
    Membre expérimenté Avatar de Jarodd
    Profil pro
    Inscrit en
    août 2005
    Messages
    845
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : août 2005
    Messages : 845
    Points : 1 678
    Points
    1 678
    Par défaut
    J'ai demandé le déplacement du sujet en section Apache (j'espère l'avoir fait au bon endroit).

  6. #6
    Membre habitué
    Profil pro
    Inscrit en
    novembre 2008
    Messages
    101
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : novembre 2008
    Messages : 101
    Points : 144
    Points
    144
    Par défaut
    Salut,

    Readfile ne peut pas poser de problème de mémoire, à moins que tu n'ai encore une compression de sortie active.

    Vérifies que ton buffer de sortie est bien désactivé avant le readfile.

  7. #7
    Membre expérimenté Avatar de Jarodd
    Profil pro
    Inscrit en
    août 2005
    Messages
    845
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : août 2005
    Messages : 845
    Points : 1 678
    Points
    1 678
    Par défaut
    Avant le readfile je fais :
    A priori c'est suffisant pour vider le tampon de sortie ?

  8. #8
    Membre habitué
    Profil pro
    Inscrit en
    novembre 2008
    Messages
    101
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : novembre 2008
    Messages : 101
    Points : 144
    Points
    144
    Par défaut
    Non, ce qu'il faut c'est éteindre la bufferisation de sortie, donc :


  9. #9
    Membre expérimenté Avatar de Jarodd
    Profil pro
    Inscrit en
    août 2005
    Messages
    845
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : août 2005
    Messages : 845
    Points : 1 678
    Points
    1 678
    Par défaut
    Malheureusement cela n'a rien changé

  10. #10
    Membre expérimenté Avatar de Jarodd
    Profil pro
    Inscrit en
    août 2005
    Messages
    845
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : août 2005
    Messages : 845
    Points : 1 678
    Points
    1 678
    Par défaut
    Mon hébergeur a fait quelques tests en regardant les logs, il m'a confirmé l'erreur au delà d'un certains poids de fichier (140Mo pour moi). Le changement de quelques directives php n'a rien changé.

    Il m'a dit quandn le problème se produit, il n'y avait aucun retour du site, juste une erreur 500. Avec une vidéo plus petite, on a bien un code 200.


  11. #11
    Modérateur
    Avatar de grunk
    Homme Profil pro
    Architecte Web / Android
    Inscrit en
    août 2003
    Messages
    6 202
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Architecte Web / Android
    Secteur : Industrie

    Informations forums :
    Inscription : août 2003
    Messages : 6 202
    Points : 17 748
    Points
    17 748
    Par défaut
    juste une erreur 500
    Ca veux dire soit un message d'erreur dans les logs PHP soit dans ceux d'apache qui devrait permettre de debuger.

    As tu essayer d'augmenter le temps d'execution ? peut être est ce le readfile qui est trop long ?
    Pry Framework php5 | N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  12. #12
    Membre expérimenté Avatar de Jarodd
    Profil pro
    Inscrit en
    août 2005
    Messages
    845
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : août 2005
    Messages : 845
    Points : 1 678
    Points
    1 678
    Par défaut
    L'admin a augmenté le max excution_time à 300, mais vu que la page tombe en erreur immédiatement, cela n'a rien changé.

    Que puis-je faire de mon côté pour débugguer le script ? J'ai repris celui indiqué sur la doc de php (readfile).

  13. #13
    Membre expérimenté Avatar de Jarodd
    Profil pro
    Inscrit en
    août 2005
    Messages
    845
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : août 2005
    Messages : 845
    Points : 1 678
    Points
    1 678
    Par défaut
    J'ai résolu le problème en remplaçant le readfile() par le code indiqué sur cet article, §4 (lisez-le en entier, il est très intéressant).

    Contrairement à ce que dit la doc PHP, il y a bien des soucis avec readfile() sur les fichiers volumineux ! Le web est plein d'exemples, notamment sur StackOverflow.

  14. #14
    Expert éminent

    Homme Profil pro
    Développeur Web
    Inscrit en
    septembre 2010
    Messages
    5 099
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : septembre 2010
    Messages : 5 099
    Points : 9 801
    Points
    9 801
    Par défaut
    Merci pour le retour Je me permet de recopier la solution pour qu'elle figure dans ce sujet instructif :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <?php
    set_time_limit(0);
    $file = @fopen($file_path,"rb");
    while(!feof($file))
    {
    	print(@fread($file, 1024*8));
    	ob_flush();
    	flush();
    }
    ?>

  15. #15
    Modérateur
    Avatar de grunk
    Homme Profil pro
    Architecte Web / Android
    Inscrit en
    août 2003
    Messages
    6 202
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Architecte Web / Android
    Secteur : Industrie

    Informations forums :
    Inscription : août 2003
    Messages : 6 202
    Points : 17 748
    Points
    17 748
    Par défaut
    Pour faire un poil de promo une classe qui gère les téléchargements de cette manière et qui en plus gère la reprise :
    https://github.com/grunk/Pry/blob/ma...load.class.php
    Pry Framework php5 | N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  16. #16
    Membre habitué
    Profil pro
    Inscrit en
    novembre 2008
    Messages
    101
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : novembre 2008
    Messages : 101
    Points : 144
    Points
    144
    Par défaut
    Citation Envoyé par ABCIWEB Voir le message
    Merci pour le retour Je me permet de recopier la solution pour qu'elle figure dans ce sujet instructif :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <?php
    set_time_limit(0);
    $file = @fopen($file_path,"rb");
    while(!feof($file))
    {
    	print(@fread($file, 1024*8));
    	ob_flush();
    	flush();
    }
    ?>
    Il est juste dommage que la bonne raison du fonctionnement ne soit pas souligné.

    "Readfile" n'y était pour rien, c'est juste qu'il avait une compression de sortie activée sur sa conf et que le readfile envoyait donc son flux dans un buffer (memoire php) et non directement dans la sortie standard.

    D'ailleurs la solution qu'il a trouvé prend bien soin de flusher le buffer à chaque itération car il n'as toujours pas désactivé sa bufferisation de sortie...

  17. #17
    Expert éminent

    Homme Profil pro
    Développeur Web
    Inscrit en
    septembre 2010
    Messages
    5 099
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : septembre 2010
    Messages : 5 099
    Points : 9 801
    Points
    9 801
    Par défaut
    Citation Envoyé par Yellu Voir le message
    Il est juste dommage que la bonne raison du fonctionnement ne soit pas souligné.

    "Readfile" n'y était pour rien, c'est juste qu'il avait une compression de sortie activée sur sa conf et que le readfile envoyait donc son flux dans un buffer (memoire php) et non directement dans la sortie standard.

    D'ailleurs la solution qu'il a trouvé prend bien soin de flusher le buffer à chaque itération car il n'as toujours pas désactivé sa bufferisation de sortie...
    Cela semble logique, mais suivant tes conseils, Jarodd avait pourtant tenté de faire un ob_end_clean() sans succès... Si donc Readfile n'y est pour rien cela veut dire que ob_end_clean() est inefficace dans certains contextes. Sinon comment aurait-il dû s'y prendre ?

  18. #18
    Membre habitué
    Profil pro
    Inscrit en
    novembre 2008
    Messages
    101
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : novembre 2008
    Messages : 101
    Points : 144
    Points
    144
    Par défaut
    Je crois qu'il était en mutualisé, on pourrait imaginer un verrouillage de cette désactivation.

    Il faudrait tester le retour de la fonction ob_end_clean.

    Ensuite il faudrait faire un ob_get_level pour voir combien de niveau peuvent eventuellement être encapsulés.

  19. #19
    Membre expérimenté Avatar de Jarodd
    Profil pro
    Inscrit en
    août 2005
    Messages
    845
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : août 2005
    Messages : 845
    Points : 1 678
    Points
    1 678
    Par défaut
    J'avais 2 niveaux d'imbrication.

    Je confirme que le ob_end_clean() n'a rien changé. La config a été vérifiée avec l'admin, il avait mis des valeurs très larges (même sur un mutu, j'ai un php.ini perso), et la compression de sortie était désactivée (voir mon premier post). En local, j'avais aussi le problème, j'avais aussi des valeurs de test assez élevées.

    La téléchargement fonctionnait pour des petits fichiers, mais plantait au delà d'une certaine limite. Il y avait donc bien un problème de buffer. Or les fonctions chargées de le vider n'ont jamais solutionné le problème. Donc a quoi cela peut-être dû, sinon un problème sur readfile() ? Pendant mes recherches j'ai trouvé pas mal de posts (notamment sur Stackoverflow, mais aussi des articles comme celui qui m'a aidé), qui la pointait du doigt.

  20. #20
    Membre expérimenté Avatar de Jarodd
    Profil pro
    Inscrit en
    août 2005
    Messages
    845
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : août 2005
    Messages : 845
    Points : 1 678
    Points
    1 678
    Par défaut
    Bonjour,

    J'ai encore un souci...

    Lors de la recherche de solution, l'admin de l'hébergeur a ajouté ceci dans le .htaccess du site :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    <FilesMatch \.php$>
    SetHandler application/x-httpd-php54
    </FilesMatch>
    Or, il se trouve que tout le site est soumis à identification, via un .htpasswd, sauf une seule page, le flux RSS, accessible directement. Le code qui gère cette authentification (avec l'exception pour une page) est celui-ci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    SetEnvIf Request_URI "/path/to/rss$" allowed_uri
    Order Deny,Allow
     
    AuthName "Veuillez vous identifier"
    AuthType Basic
    AuthUserFile "/path/to/.htpasswds/.htpasswd"
    Require valid-user
     
    #Allow valid-user
    Deny from all
    Allow from env=allowed_uri
    Satisfy any
    Problème : les deux directives ont l'air incompatibles ! Si j'active le SetHandler application/x-httpd-php54, les téléchargements de gros fichiers sont possibles, mais le flux RSS demande une authentification dans le client. Si je la désactive, je retrouve le problème initial pour les grosses vidéos...

    Je n'ai pas assez de connaissance en Apache et htaccess pour arriver à m'en sortir.

    Avez-vous une idée pour combiner les deux ? Merci d'avance.

Discussions similaires

  1. Nginx erreur 502 sur les gros fichiers
    Par Tlams dans le forum Administration système
    Réponses: 0
    Dernier message: 19/04/2014, 13h54
  2. Téléchargement de gros fichiers depuis un Servlet
    Par Simvetanylen dans le forum Servlets/JSP
    Réponses: 6
    Dernier message: 08/06/2011, 16h24
  3. [MySQL] Erreur de téléchargement forcé de fichier
    Par graymi dans le forum PHP & Base de données
    Réponses: 10
    Dernier message: 03/05/2011, 15h00
  4. Téléchargement de gros fichiers et segmentation
    Par SpaceFrog dans le forum Langage
    Réponses: 5
    Dernier message: 21/11/2009, 16h39
  5. Téléchargement de gros fichier avec IE
    Par amans dans le forum IE
    Réponses: 0
    Dernier message: 03/07/2009, 11h09

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