2009-09-18 7 views
1

J'essaie d'utiliser un script CGI pour accepter et enregistrer un fichier à partir d'un programme qui utilise un HTTP POST pour envoyer un fichier zip.Pourquoi mon fichier .zip est-il corrompu après un téléchargement de fichier HTTP?

Dans la section MIME de l'en-tête HTTP, il ressemble à ceci:

Content-Disposition: form-data; name="el_upload_file_0"; filename="BugReport.zip";\r\n 
Content-Type: application/octet-stream\r\n\r\n 

Dans mon code CGI J'utilise ceci:

use CGI; 
use strict; 
my $cgi = CGI->new; 
my $upload_file = $cgi->upload('el_upload_file_0'); 
my $time = time; 

my $filename = "/tmp/$time.zip"; 
open TMP, ">$filename"; 
binmode TMP; 
while (<$upload_file>) { 
    print TMP $_; 
} 
close TMP; 

Le fichier qui ne cesse de se sauvé est en quelque sorte se corrompre et n'est pas un fichier zip valide. La requête HTTP est envoyée par une application C# et il est possible qu'elle envoie un fichier zip corrompu, mais j'en doute. Y a-t-il quelque chose que je puisse faire pour résoudre d'autres problèmes?

Répondre

3

Quelle est la différence entre le fichier que vous avez téléchargé et le fichier que vous avez enregistré? Regardez une décharge hexagonale de chacun.

Je sais que cela semble stupide, mais en essayant simplement de copier le fichier que vous essayez de télécharger sur le serveur sans utiliser le script CGI. Pouvez-vous encore décompresser là-bas? De même, pouvez-vous prendre le fichier téléchargé du serveur, le copier sur votre ordinateur client et le décompresser?

À quoi ressemble le reste de l'en-tête HTTP? Changez-vous les jeux de caractères ou quoi que ce soit?

Je ne soupçonne pas de problème avec les traductions de fichiers puisque CGI devrait déjà régler cela pour vous. Donc, une fois que quelqu'un dit "devrait", vous devez vérifier à nouveau :). Il y a une ligne dans CGI.pm qui détecte automatiquement les systèmes qui ont besoin de binmode, donc je ne pense pas que vous en ayez besoin sur $upload_file. Cependant, peut-être CGI.pm se trompe pour vous:

$needs_binmode = $OS=~/^(WINDOWS|DOS|OS2|MSWin|CYGWIN|NETWARE)/; 

Vous pourriez essayer de régler la variable réelle juste pour vous assurer que:

use CGI; 
$CGI::needs_binmode = 1; 
5

Vous lisez dans une ligne de fichier .zip par ligne, ce qui est une grosse erreur. Les lignes ne sont pertinentes que pour les fichiers texte, après tout. Lire le tout en un seul coup, ou si vous devez, le faire en morceaux de taille raisonnable. Dans cet exemple, il est en cours de lecture en morceaux 1024 octets, mais vous pouvez facilement utiliser une valeur beaucoup plus grande, comme 16MB (1 < < 24) ou ce qui semble approprié:

my $data; 
while (read($upload_file, $data, 1024)) 
{ 
    print TMP, $data; 
} 
0

Le « \ r \ n » s ' dans l'en-tête pourrait être un indice. Le fichier de sortie contient-il des séquences "\ r \ n"? Pouvez-vous/devez-vous faire un binmode sur le handle de fichier $upload_file?

Questions connexes