Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Script de telechargement qui ne tele charge pas tout !

12 réponses
Avatar
Vincent Verdon
Bonjour,

plutôt débutant en php (ma langue naturelle est le TCL ;-) ), je bute
sur un problème gênant :
j'ai créé un ensemble (modeste) de scripts dont le but est de gérer
l'accès à des répertoires sur un serveur web. Il s'agit en fait d'une
zone de téléchargement qui n'est pas en accès libre mais nécessite
d'être authentifié au préalable. Cette authentification est faite en
amont depuis un CMS (en l'occurence SPIP). Le pb est que certaines
personnes connectées ne perviennet pas à télécharger l'intégralité des
fichiers qu'elles souhaitent : les fichier se trouvent ainsi corrompus.
Je ne comprends pas pourquoi, et je n'ai jamais eu personnellement ce
problème quand je fais des essais ! Je suppose donc plusieurs choses :
1) C'est lié à l'OS de l'utilisateur (perso, j'utilise Linux) ;
2) C'est lié au fournisseur d'accès : le script est sur un site hébergé
chez Free et je suis moi-même chez Free.
3) Je programme bien mal, ce qui est fort possible.

Voici le morceau de script qui provoque le téléchargement. Vous
constaterez que j'ai essayé 2 fonctions différentes fpassthru et
readfile, mais cela donne le même résultat... Au passsage, j'ai
l'impression qu'en PHP il y a beaucoup de fonctions différentes qui
permettent d'arriver au résultat voulu : ça va être long à apprendre
tout ça !

--------------------
// on récupère les infos sur le fichier et on crée l'entête
$taille = filesize($fic);
$type_mime = def_mime_type($fic);
$f_nom = basename($fic);

//on ecrit l'entete
header('Content-Type: '.$type_mime);
header('Content-Length: '.$taille);
header('Content-Disposition: attachment; filename='.$f_nom);
header('Content-Transfer-Encoding: binary');

// on ouvre le fichier en lecture en mode binaire
//$file = @ fopen($fic, 'rb');
//if ($file) {
// on envoie le fichier
// fpassthru($file);
// on ecrit le log d'accès
// ecrire_log("acces au fichier $_GET[fic]");
//} else {
// echo "Il y a eu une erreur de chargement" ;
// ecrire_log("echec de l'acces au fichier $_GET[fic]");
//}

if(readfile("$fic")) {
ecrire_log("acces au fichier $_GET[fic]");
} else {
ecrire_log("echec de l'acces au fichier $_GET[fic]");
}
--------------------


Merci de votre aide
--
Amicalement, Vincent Verdon

10 réponses

1 2
Avatar
Antoine Polatouche
Le 15/08/2010 11:31, Vincent Verdon a écrit :

Le pb est que certaines
personnes connectées ne perviennet pas à télécharger l'intégralité des
fichiers qu'elles souhaitent : les fichier se trouvent ainsi corrompus.
Je ne comprends pas pourquoi, et je n'ai jamais eu personnellement ce
problème quand je fais des essais ! Je suppose donc plusieurs choses :
1) C'est lié à l'OS de l'utilisateur (perso, j'utilise Linux) ;
2) C'est lié au fournisseur d'accès : le script est sur un site hébergé
chez Free et je suis moi-même chez Free.
3) Je programme bien mal, ce qui est fort possible.



Une hypothèse à ajouter:
4) Le script php se termine sur un timeout et interrompt le téléchargement.
Avatar
Yop
Je ne comprends pas pourquoi, et je n'ai jamais eu personnellement ce
problème quand je fais des essais !



modifier php.ini (sous debian à /usr/local/lib/php5)
par exemple :
max_execution_time = 90 au lieu de 30
memory_limit = 32M au lieu de 8M
upload_max_filesize = 64M au lieu de 2M

optimiser les valeurs en fonction des besoins.

Y
Avatar
John GALLET
Bonjour,

Je répond uniquement en fonction des besoins de la question d'origine,
pour autant qu'on puisse changer ces valeurs chez free.fr, mais les
valeurs proposées sont tout à fait cohérentes dans le cadre général.

max_execution_time = 90 au lieu de 30


Ce sont des secondes CPU, donc là peu probable que ça change grand chose.

memory_limit = 32M au lieu de 8M


Mange pas de pain, mais chez free j'ai un doute de la possibilité.

upload_max_filesize = 64M au lieu de 2M


Pour du download, totalement inopérant.

a++;
JGA
Avatar
John GALLET
Bonjour,

amont depuis un CMS (en l'occurence SPIP). Le pb est que certaines
personnes connectées ne perviennet pas à télécharger l'intégralité des
fichiers qu'elles souhaitent : les fichier se trouvent ainsi corrompus.



Chez moi, spip et le safe mode font mauvais ménage. Bien vérifier qu'il
n'est pas activé.

Remarque: free.fr a pendant longtemps eu des versions de PHP "tripotées"
à leur sauce, avec parfois des comportements peu intuitifs, les anciens
savent de quoi je parle avec mail()... Aujourd'hui, je ne sais pas.

Voici le morceau de script qui provoque le téléchargement. Vous
constaterez que j'ai essayé 2 fonctions différentes fpassthru et
readfile, mais cela donne le même résultat...


C'est normal, sauf boucle infinie, du moment que la section qui envoie
les données est correcte, le fonctionnement dépend de l'habillage.

Au passsage, j'ai l'impression qu'en PHP il y a beaucoup de fonctions différentes qui
permettent d'arriver au résultat voulu : ça va être long à apprendre
tout ça !



L'API est en effet très riche, avec des choses très utiles ou des
aberrations caractérisées (par exemple la fonction qui donne l'heure de
lever et coucher du soleil selon les coordonnées LAT/LONG, je pense
qu'elle aurait pu aller dans PEAR ou PECL...)

--------------------
// on récupère les infos sur le fichier et on crée l'entête



Oui mais non: si les headers sont déjà partis on est morts. Donc un
script qui fait du download doit nécessairement:
1) commencer en PREMIERE LIGNE et SANS caractère quel qu'il soit avant
<?php par :
<?php
ob_start();

Variante: activer ceci par défaut dans php.ini ou par htaccess.

Ensuite avant de construire le contenu du résultat, on vire tout ce qui
a pu aller dans le buffer par un :
ob_clean();
Et *maintenant* on peut commencer à mettre des résultats dans le buffer:
$taille = filesize($fic);
$type_mime = def_mime_type($fic);
$f_nom = basename($fic);

//on ecrit l'entete


Perso je le fais après traitement des éventuelles erreurs mais peu
importe, ça doit fonctionner.

header('Content-Type: '.$type_mime);
header('Content-Length: '.$taille);
header('Content-Disposition: attachment; filename='.$f_nom);
header('Content-Transfer-Encoding: binary');



Perso je n'ai jamais utilisé que deux headers: le content type par
exemple ci-dessous pour un csv, et le disposition à l'identique.

header("Content-Type: text/csv; charset=iso-8859-1;");
header("Content-disposition: attachment; filename=$file_name");


// on ouvre le fichier en lecture en mode binaire
//$file = @ fopen($fic, 'rb');
//if ($file) {
// on envoie le fichier
// fpassthru($file);


Penser à fermer le $file. On peut aussi utiliser fileexists() au lieu du
fopen() si on ne s'en sert pas derrière comme avec readfile().

// on ecrit le log d'accès
// ecrire_log("acces au fichier $_GET[fic]");
//} else {
// echo "Il y a eu une erreur de chargement" ;
// ecrire_log("echec de l'acces au fichier $_GET[fic]");
//}
if(readfile("$fic")) {
ecrire_log("acces au fichier $_GET[fic]");
} else {
ecrire_log("echec de l'acces au fichier $_GET[fic]");
}



Du moment que le même script sans le header machin affiche bien en
données pures ce qu'il faut, ce n'est pas là que se trouve le problème.

Attention au _GET[fic] qui écrit dans un log: si je peux appeler en http
le fichier de log en question alors je peux exécuter du code sur ton
serveur en remplissant $_GET['fic'] par du code php.

Enfin, si on utilise un buffer, on peut laisser php le flusher ou le
forcer, par habitude j'utilise:
ob_flush();
exit();
pour tout forcer explicitement, mais ob_end_flush() ou rien du tout
devraient fonctionner.

Un autre exemple dans le manuel:
http://fr2.php.net/manual/en/function.readfile.php


HTH
JGA
Avatar
Dominique Ottello
John GALLET écrivait :

> memory_limit = 32M au lieu de 8M
Mange pas de pain, mais chez free j'ai un doute de la possibilité.


Chez free, c'est déjà à 32M. Suffit de faire un phpinfo() :
memory_limit 32M 32M
Avatar
Pierre Maurette
Vincent Verdon, le 15/08/2010 a écrit :
Bonjour,

plutôt débutant en php (ma langue naturelle est le TCL ;-) ), je bute sur un
problème gênant :
j'ai créé un ensemble (modeste) de scripts dont le but est de gérer l'accès à
des répertoires sur un serveur web. Il s'agit en fait d'une zone de
téléchargement qui n'est pas en accès libre mais nécessite d'être authentifié
au préalable. Cette authentification est faite en amont depuis un CMS (en
l'occurence SPIP). Le pb est que certaines personnes connectées ne perviennet
pas à télécharger l'intégralité des fichiers qu'elles souhaitent : les
fichier se trouvent ainsi corrompus. Je ne comprends pas pourquoi, et je n'ai
jamais eu personnellement ce problème quand je fais des essais ! Je suppose
donc plusieurs choses :
1) C'est lié à l'OS de l'utilisateur (perso, j'utilise Linux) ;
2) C'est lié au fournisseur d'accès : le script est sur un site hébergé chez
Free et je suis moi-même chez Free.
3) Je programme bien mal, ce qui est fort possible.



Le 2 n'est pas impossible. Il y a plusieurs années, chez Free
également, il m'était impossible d'uploader sans erreur - fichiers
manquants - en une fois dès que ça dépassait quelques fichiers et / ou
une arborerscence simplissime, en utilisant tout bêtement les bons
clients FTP du moment. Mais j'étais en RTC.
J'avais résolu le problème en zippant l'arborescence et en uploadant
cette archive. Je n'avais ensuite plus qu'à décompresser sur le site, à
l'aide d'un script PHP. J'utilisais soit pclzip, soit des fonctions de
PEAR, il semble que j'avais choisi le premier. J'avais également
préparé l'inverse, c'est à dire compresser une arborescence sur le
serveur, je ne sais plus pouirquoi, peut-être simplement pour ne pas
mourir idiot.

Aujourd'hui, je n'ai plus trop de problème. ADSL, moins d'uploads
massifs - je n'ai plus de sites de photos -, utilisation de Dreamweaver
puis aujourd'hui Eclipse - Aptana. Ceci dit il m'arrive dans Eclipse de
devoir télécharger à nouveau quelques fichiers. En fait, il y a en FTP
(FTPS, etc.) des régressions dans Aptana Studio depuis queqlues mois.

--
Pierre Maurette
Avatar
Vincent Verdon
Bonsoir,

Le 16/08/2010 19:04, Yop a écrit :
Je ne comprends pas pourquoi, et je n'ai jamais eu personnellement ce
problème quand je fais des essais !



modifier php.ini (sous debian à /usr/local/lib/php5)
par exemple :
max_execution_time = 90 au lieu de 30
memory_limit = 32M au lieu de 8M
upload_max_filesize = 64M au lieu de 2M

optimiser les valeurs en fonction des besoins.

Y



Bien entendu, le serveur étant chez Free, je n'ai pas la main sur la
config !


--
Amicalement, Vincent Verdon
Avatar
Vincent Verdon
Bonsoir,

Le 16/08/2010 19:44, John GALLET a écrit :
Bonjour,

amont depuis un CMS (en l'occurence SPIP). Le pb est que certaines
personnes connectées ne perviennet pas à télécharger l'intégralité des
fichiers qu'elles souhaitent : les fichier se trouvent ainsi corrompus.



Chez moi, spip et le safe mode font mauvais ménage. Bien vérifier qu'il
n'est pas activé.



Oui, mais dans ce cas, je devrais moi-même rencontrer ces problèmes lors
d'essais de téléchargements.



--------------------
// on récupère les infos sur le fichier et on crée l'entête



Oui mais non: si les headers sont déjà partis on est morts. Donc un
script qui fait du download doit nécessairement:
1) commencer en PREMIERE LIGNE et SANS caractère quel qu'il soit avant
<?php par :
<?php
ob_start();



J'ai expérimenté ça : j'ai déjà cherché un bon moment où était l'erreur
alors qu'il s'agissait d'un caractère non visible en tête du fichier
(avant le premier <?php) : un coup du changement d'encodage d'une
machine à l'autre !


Ensuite avant de construire le contenu du résultat, on vire tout ce qui
a pu aller dans le buffer par un :
ob_clean();
Et *maintenant* on peut commencer à mettre des résultats dans le buffer:
$taille = filesize($fic);
$type_mime = def_mime_type($fic);
$f_nom = basename($fic);



//on ecrit l'entete


Perso je le fais après traitement des éventuelles erreurs mais peu
importe, ça doit fonctionner.

header('Content-Type: '.$type_mime);
header('Content-Length: '.$taille);
header('Content-Disposition: attachment; filename='.$f_nom);
header('Content-Transfer-Encoding: binary');



Perso je n'ai jamais utilisé que deux headers: le content type par
exemple ci-dessous pour un csv, et le disposition à l'identique.

header("Content-Type: text/csv; charset=iso-8859-1;");
header("Content-disposition: attachment; filename=$file_name");

} else {
ecrire_log("echec de l'acces au fichier $_GET[fic]");
}



Attention au _GET[fic] qui écrit dans un log: si je peux appeler en http
le fichier de log en question alors je peux exécuter du code sur ton
serveur en remplissant $_GET['fic'] par du code php.



En fait au paravant je fais des tests pour être certain que les données
sont bien le nom d'un fichier valide et pas autre chose.



Enfin, si on utilise un buffer, on peut laisser php le flusher ou le
forcer, par habitude j'utilise:
ob_flush();
exit();
pour tout forcer explicitement, mais ob_end_flush() ou rien du tout
devraient fonctionner.



Je teste un ob_flush et on verra ce que cela donne.

--
Merci de ton aide, amicalement, Vincent Verdon
Avatar
Web Dreamer
Vincent Verdon a écrit ce dimanche 15 août 2010 11:31 dans
<4c66fb7f$0$2043$ :

Bonjour,

plutôt débutant en php (ma langue naturelle est le TCL ;-) ), je bute
sur un problème gênant :
j'ai créé un ensemble (modeste) de scripts dont le but est de gérer
l'accès à des répertoires sur un serveur web. Il s'agit en fait d'une
zone de téléchargement qui n'est pas en accès libre mais nécessite
d'être authentifié au préalable. Cette authentification est faite en
amont depuis un CMS (en l'occurence SPIP). Le pb est que certaines
personnes connectées ne perviennet pas à télécharger l'intégralité des
fichiers qu'elles souhaitent : les fichier se trouvent ainsi corrompus.
Je ne comprends pas pourquoi, et je n'ai jamais eu personnellement ce
problème quand je fais des essais ! Je suppose donc plusieurs choses :
1) C'est lié à l'OS de l'utilisateur (perso, j'utilise Linux) ;



Je donne des accès au téléchargement à de "gros" fichiers à des clients, et
j'ai déjà rencontré ceci qui est lié à leur OS:

IE6 ne télécharge pas plus de 2Go (4Go pour IE7).

Donc par ex. une image iso de distrib linux en téléchargement (pouvant faire
4,7Go) se verra tronquée (donc corrompue) à 2 Go (ou 4).
Seul IE8 n'a plus cette limite.
De plus, il existe des utilisateurs Windows qui on upgradé au file du
temps... et gardés un disque avec une partition FAT32... qui ne supporte pas
plus de 4Go "par fichier". Et parfois ils utilisent ce disque comme cible
pour le téléchargement...
J'en ai eu d'autres essayant de sauvegarder une image iso téléchargée sur un
clé USB de 8 Go pensant que ça irait, mais les clés USB de 8Go sont souvent
en FAT32... et un fichier unique ne peut dépasser 4Go.

Donc je ne sais pas la taille des fichiers que tu laisses en téléchargement,
mais si ils sont gros, tu as cette limitation décrite ci-dessus pour les
utilisateurs de Windows.

Donc ce que tu peux faire coté PHP, c'est de détecter le butineur du client
(avec $_SERVER['HTTP_USER_AGENT'] ou get_browser() ) et en fonction,
"griser" (et inactiver) les liens affichés vers les fichiers de taille non
supportés et ajouter un lien proposant le téléchargement d'un autre
navigateur avec un message explicite expliquant l'impossibilité de leur
navigateur actuel à télécharger un tel fichier.:

if (filesize('fichier.iso') > $browserlimit)
{
...ton code qui affiche le lien spécial...
}
else
{
... ton code qui affiche le lien normalement...
}

où $browserlimit a été initialisé à une certaine valeur en fonction de
$_SERVER['HTTP_USER_AGENT']
De tête je ne sais plus ce que donne IE, j'en ai pas sous la main :-) donc
je peux pas te donner le code "de mémo", mais un bête if() ou switch() (et
case ) suffit et pour les autres butineurs tu initialise $browserlimit à une
GROSSE valeur)

Par contre... tu ne peut pas détecter la partition où le client va
sauvegarder son fichier... (du moins pas avec PHP, sauf a détecter dans le
$_SERVER['HTTP_USER_AGENT'] une version de win9x qui ne serra QUE en FAT32,
mais ceux qui utilisent encore un tel OS non-mis à jour sont suicidaires)
mais détecter le browser est déjà une épine du pied de retiré.

--
Web Dreamer
Avatar
Vincent Verdon
Bonsoir,

Le 27/08/2010 13:46, Web Dreamer a écrit :

Je donne des accès au téléchargement à de "gros" fichiers à des clients, et
j'ai déjà rencontré ceci qui est lié à leur OS:

IE6 ne télécharge pas plus de 2Go (4Go pour IE7).



Le problème semble bien être celui que j'avais imaginé : Free limite le
téléchargement en php s'il n'est pas notre fournisseur d'accès. J'ai
fais l'expérience depuis chez moi (aucun problème) puis depuis un autre
accès non Free et là je suis presqu'inmanquablement coupé en milieu de
téléchargement, en général au bout de 2Mo mais parfois plus. Les
fichiers à télécharger font environ 5 Mo (c'est pourtant pas beaucoup
!). Je suis très loin des 2Go...


--
Amicalement, Vincent Verdon
1 2