2009-08-28 4 views
5

Mon application Web fonctionne sur Apache mod_perl en utilisant CGI :: Application. Je veux fournir un téléchargement d'un fichier généré. Dans le passé (avant que nous utilisions mod_perl et CGI :: App) j'ai juste spoulé un fichier csv à STDOUT comme il a été généré. Maintenant, je prends un peu plus de raffinement - créer une feuille de calcul Excel en utilisant Spreadsheet :: WriteExcel - et je n'arrive pas à l'imprimer depuis la poignée de fichier.Comment puis-je fournir un téléchargement de fichier temporaire en utilisant mod_perl et CGI :: Application?

sub export_list { 
    my $self = shift; 

    binmode(STDOUT); 
    my $str; 
    open my $fh, '>', \$str; 
    my $workbook = Spreadsheet::WriteExcel->new($fh); 
    my $worksheet = $workbook->add_worksheet(); 

    $worksheet->write_col(0,0, ['some','data','here']); 
    warn $str; 
    return $str; 
} 

La sortie est simplement une réponse vide et l'avertissement est également vide.

La méthode que j'utilise pour écrire la feuille de calcul dans un handle de fichier est à peu près tout droit sortie du documentation, donc je suppose que le problème est dû à une certaine noobery CGI :: App de ma part. Les méthodes suggérées par la documentation pour les handles de fichiers et mod_perl se sont révélées plutôt infructueuses. Je suppose que je devrais mentionner que je cours sous Windows, et que ma solution de contournement actuelle est de créer un fichier et de fournir à l'utilisateur un lien vers celui-ci. Cela pose plus de problèmes, cependant, en ce qui concerne l'effacement du répertoire et quand le faire, ainsi que l'authentification pour l'accès aux fichiers générés.

Suggestions? Critique cinglante?

Répondre

4

Vous ne devriez pas avoir à jouer avec STDOUT; CGI-App devrait gérer cela correctement pour vous sous le capot. Vous devrez peut-être également fermer le handle de fichier avant d'essayer d'envoyer les données. Cependant, il semble que vous ne définissiez pas un type de contenu correct pour les données Excel. Pour toute autre chose que text/html, vous devrez le définir manuellement. Essayez quelque chose comme ceci:

sub export_list { 
    my $self = shift; 

    my $str; 
    open my $fh, '>', \$str or die "Can't open to var: $!"; 
    my $workbook = Spreadsheet::WriteExcel->new($fh); 
    my $worksheet = $workbook->add_worksheet(); 

    $worksheet->write_col(0,0, ['some','data','here']); 

    $workbook->close; 
    close $fh; 

    warn $str; 

    $self->header_add(-type => 'application/vnd.ms-excel'); 
    return $str; 

}

Vous pouvez également être intéressé par CGI::Application::Plugin::Stream

+0

Ouais je suppose que la fermeture du handle de fichier le force à vider la variable afin que je puisse le retourner. En outre, j'ai dû ajouter '-attachment => 'filename.xls'' à l'en-tête ou firefox ne pouvait pas savoir quoi faire avec le fichier. Je vais regarder dans CGI :: A :: P :: Stream, mais les fichiers que nous faisons ne devraient pas être assez gros pour importer. Merci! – wes

3

Vous souhaitez fermer le classeur. Aussi fermer le descripteur de fichier:

warn "length 1=".length($str); 
$workbook->close(); 
close($fh) or die "error on close: $!"; 
warn "length 2=".length($str); 

length 1=0 at wx.pl line 16. 
length 2=5632 at wx.pl line 19. 
4

Au lieu de créer la feuille de calcul tout en mémoire, vous devez soit l'écrire dans un fichier et diffusez le leur lorsque vous avez terminé (en utilisant CGI::Application::Plugin::Stream aide ici, mais vous aurez toujours besoin de le nettoyer par la suite, mais vraiment chaque application web devrait avoir un répertoire temporaire qui périodiquement nettoyé) ou l'imprimer lorsque vous le créez (ce qui signifie que le FH STDIN au lieu qui pourrait être plus difficile sous mod_perl ou peut pas être).

Et n'oubliez pas de fermer votre classeur lorsque c'est fait.

Questions connexes