Le téléchargement de gros fichiers de manière fiable en PHP
J'ai un script php sur un serveur pour envoyer des fichiers à des récipiendaires: on obtient un unique lien et puis, ils peuvent télécharger des fichiers volumineux. Il y a parfois un problème avec le transfert et le fichier est corrompu ou ne se termine jamais. Je me demande si il ya une meilleure façon d'envoyer de gros fichiers
Code:
$f = fopen(DOWNLOAD_DIR.$database[$_REQUEST['fid']]['filePath'], 'r');
while(!feof($f)){
print fgets($f, 1024);
}
fclose($f);
J'ai vu des fonctions telles que
http_send_file
http_send_data
Mais je ne sais pas si ils vont travailler.
Quelle est la meilleure façon de résoudre ce problème?
Ce qui concerne
erwing
- Une partie de ce problème pourrait être résolu en appuyant
Range
en-têtes, afin que les navigateurs peuvent les mettre en pause et reprendre les téléchargements. Voici une question traitant de la: stackoverflow.com/questions/157318/... - Jetez aussi un oeil à ceci et ceci AFIN de réponses.
- Voir ici -- stackoverflow.com/questions/47827768/...
Vous devez vous connecter pour publier un commentaire.
Si vous envoyez vraiment de gros fichiers et s'inquiètent de l'impact que cela va avoir, vous pouvez utiliser le x-sendfile en-tête.
De l'OSQ aide-xsendfile-with-apache-php, un howto blog.adaniels.nl : comment-je-php-x-sendfile/
Meilleure solution serait de s'appuyer sur lighty ou apache, mais si en PHP, je voudrais utiliser La POIRE est HTTP_Download (pas besoin de réinventer la roue, etc.), a quelques fonctionnalités intéressantes, comme:
Voir intro/utilisation docs.
De segmentation des fichiers est la manière la plus rapide /la plus simple méthode en PHP, si vous ne pouvez pas ou ne voulez pas faire usage de quelque chose d'un peu plus professionnel comme cURL,
mod-xsendfile
sur Apache ou certains un script dédié.Porté à partir de richnetapps.com /NeedBee. Testé sur 200 MO de fichiers, sur lequel
readfile()
est mort, même avec de mémoire maximale autorisée limite fixée à1G
, qui est cinq fois plus que la taille du fichier téléchargé.BTW: j'ai testé également sur les fichiers
>2GB
, mais PHP ne réussi à écrire la première2GB
de fichier et puis a éclaté à la connexion. Des fonctions associées au fichier (fopen, fread, fseek) utilise des INT, si vous atteignez la limite de2GB
. Ci-dessus mentionné solutions (c'est à diremod-xsendfile
) semble être la seule option dans ce cas.MODIFIER: vous Faire 100% que votre fichier est enregistré dans
utf-8
. Si vous omettez que, les fichiers téléchargés seront corrompus. C'est, parce que ces solutions utiliseprint
de pousser morceau d'un fichier dans un navigateur.reafile
déjà des "morceaux".readfile
doc vous vois aucune mention au sujet de segmentation? Où? Il n'y a qu'une mention concernant défini par l'utilisateurreadfile_chunked
fonction, dont le code source a l'air... presque exactement comme dans l'exemple ci-dessus. Vérifier, avant de faire état de vos affirmations fausses!readfile()
sur des fichiers volumineux, meurt sur le côté client -- navigateur de terminaison de connexion, qui prend trop de temps, pas sur des problèmes de mémoire. Sireadfile()
est colmatage des fichiers, alors il est probable qu'il le fait pour juste la lecture du fichier sur le serveur, mais il envoie tout de même fichier entier comme un réponse à la requête. Et ce qui meurt sur la plupart des navigateurs. De segmentation dans ma solution cause de télécharger le fichier des réponses multiples et permet navigateur pour gérer les téléchargements de fichiers de grandes dimensions.Pour le téléchargement de fichiers de la manière la plus simple je pense, serait de placer le fichier dans un emplacement temporaire et de leur donner une URL unique qu'ils peuvent télécharger via HTTP.
Dans le cadre de génération de ces liens, vous pouvez également supprimer des fichiers de plus de X heures.
Créer un lien symbolique vers le fichier et de faire le lien de téléchargement point le lien symbolique. Ensuite, lorsque l'utilisateur clique sur le lien DL, ils vont obtenir le téléchargement d'un fichier à partir du fichier réel, mais nommé à partir du lien symbolique. Il ne prend que quelques millisecondes pour créer le lien symbolique et est mieux que d'essayer de copier le fichier vers un nouveau nom et de la télécharger à partir de là.
Par exemple:
C'est ce que j'ai fait parce que Go Daddy kills que le script en cours d'exécution au bout de 2 minutes 30 secondes....cela empêche que le problème et le cache le fichier réel.
Vous pouvez ensuite configurer une tâche CRON pour supprimer les liens symboliques à intervalles réguliers....
L'ensemble de ce processus sera ensuite envoyer le fichier dans le navigateur et il n'a pas d'importance combien de temps il fonctionne car il n'est pas un script.
Nous avons été à l'aide de cette dans un couple de projets et il fonctionne très bien, donc loin:
Quand je l'ai fait dans le passé, j'ai utilisé ceci:
Ces 3 lignes de code qui fera tout le travail de la télécharger readfile() sera diffuser l'intégralité du fichier spécifié pour le client, et assurez-vous de définir une infinité de limite de temps que vous pourriez être en cours d'exécution hors du temps avant que le fichier est terminé en streaming.
readfile
fonction ne pas diffuser n'importe quoi. Il essaie juste de lire tout le fichier en mémoire et de les jeter ensemble dans un navigateur. Cette mourra sur quoi que ce soit de plus de 100 MO. Et il va mourir "brutalement", c'est à dire pas de message d'erreur, seul l'utilisateur télécharge une page HTML avec une erreur sur épuisant de mémoire, au lieu d'un vrai fichier. Pour de vrai, le streaming de fichiers volumineux que vous avez à mettre en œuvre quelque chose de plus sophistiqué que ces trois lignes. Par exemple, le fichier de chunking. Voir mon exemple ci-dessous.Si vous utilisez lighttpd comme un serveur web, une alternative pour les téléchargements sécurisés serait d'utiliser ModSecDownload. Il a besoin de configuration du serveur, mais vous laisserez au serveur de gérer le téléchargement lui-même à la place du script PHP.
Générer l'URL de téléchargement ressembleraient à ça (prises à partir de la documentation), et il pourrait bien sûr être généré uniquement pour les utilisateurs autorisés:
Bien sûr, en fonction de la taille des fichiers, à l'aide de
readfile()
tel que proposé par Unkwntech est excellent. Et à l'aide de xsendfile proposé par garrow est une autre bonne idée également pris en charge par Apache.Je ne suis pas sûr que ce soit une bonne idée pour les gros fichiers. Si le thread pour votre télécharger le script s'exécute jusqu'à ce que l'utilisateur a fini de le télécharger, et vous utilisez quelque chose comme Apache, à seulement 50 ou plusieurs téléchargements simultanés pourrait provoquer une panne de votre serveur, car Apache n'est pas conçu pour s'exécuter un grand nombre de long-threads en cours d'exécution en même temps. Bien sûr je peux me tromper, si l'apache fil en quelque sorte se termine et le téléchargement se trouve dans un tampon quelque part alors que le téléchargement progresse.
J'ai utilisé de l'extrait de code suivant trouvé dans les commentaires de l'php entrée de manuel pour readfile:
J'ai eu le même problème,
mon problème a été résolu par l'ajout de cette avant de commencer la session
session_cache_limiter('none');
C'est testé sur des fichiers d'une taille de 200 MO sur un serveur qui a une mémoire de 256 mo de limite.