kiat has asked for the wisdom of the Perl Monks concerning the following question:

Hi monks,

I'm totally clueless to the behaviour of the following two pieces of somewhat similar code to upload files to the server:

# code 1 use CGI; my $q = new CGI; my $file = $q->param("upfile"); # $file set to 'C:\images\apple.gif'; # $img_str set to 'apple.gif' my ($img_str) = ($file =~ /.*\\(.*\.(gif|jpg))/); open(OUT,">C:/tmp/$img_str") or die; binmode $file; binmode OUT; my $buffer = ''; while (read($file, $buffer, 1024)) { print OUT $buffer; } close(OUT); # end of use CGI # code 2 use CGI qw(:standard); my $file = param('upfile'); # $file set to 'C:\\images\\apple.gif'; my ($img_str) = ($file =~ /.*\\(.*\.(gif|jpg))/); open(OUT,">C:/tmp/$img_str"); binmode $file; # This line is not present in code 1 with use CGI open(FH,"$file"); binmode FH; binmode OUT; my $buffer = ''; while (read(FH, $buffer, 1024)) { print OUT $buffer; } close(OUT);
The differences are as follows:

1) With use CGI, the name of $file is 'C:\images\apple.gif'. With use CGI qw(:standard), the name of $file is 'C:\\images\\apple.gif'. That is, an additional '\'.

2) With use CGI qw(:standard), there is a need to open (and read) the contents of $file. There's no need for that with use CGI.

Can someone please enlighten me on the differences?

Great thanks in advance :)

Update: As pointed by jeffa, I made a mistake with (2). There's no need to open (and read) the contentsof $file.

Update2: I'm not quite surely actually. Sometimes it works sometimes it doesn't :(

Update3: Stupid me. No need for that read...:) code2 below is a modified version of the one above.

# code 2 use CGI qw(:standard); use File::Basename; my $file = $q->param('upfile') || ''; my $img_str = basename($file); open(OUT,">C:/tmp/$img_str"); binmode $file; binmode OUT; my $buffer = ''; while (read($file, $buffer, 1024)) { print OUT $buffer; } close(OUT);

Replies are listed 'Best First'.
Re: use CGI vs use CGI qw(:standard)
by jeffa (Bishop) on Apr 19, 2004 at 14:48 UTC

    I am not sure about #1 ... i wish i had time to look into it, but i have other work to do. #2, however is simply not true. Here is code that works for me:

    use CGI qw(:standard); use File::Basename; my $PATH = '/path/to/dir/to/store/files'; if (param('go')) { my $handle = upload('the_file'); my $name = param('the_file'); fileparse_set_fstype('MSDOS') if $name =~ /\\/; $name = basename($name); open OUT, '>', "$PATH/$name" or die "can't open file $name: $!"; print OUT while <$handle>; }
    Hope this helps ...

    jeffa

    L-LL-L--L-LL-L--L-LL-L--
    -R--R-RR-R--R-RR-R--R-RR
    B--B--B--B--B--B--B--B--
    H---H---H---H---H---H---
    (the triplet paradiddle with high-hat)
    
      Thanks, jeffa!

      You're right, (2) is not true. I commented out that particular line and it still works. But it's puzzling because the first time I commented it out, the image didn't show on the web page. It only showed on sebsequent uploadings.

      I had been running the code without that 'open(FH, $file)' line and I swore it didn't work for almost an hour when I was at it. I double-checked the folder where it was supposed to go to and although the file was created, the image wasn't properly saved. That was when I added the 'open(FH, $file)' line and then the image was rightly created, which puzzled me.

Re: use CGI vs use CGI qw(:standard)
by bradcathey (Prior) on Apr 19, 2004 at 14:51 UTC
    Sorry kiat, I can't answer technically what is happening, but though use CGI is a bit noisier, it is safer and I've stopped using the use CGI qw(:standard) altogether, based on Ovid's popular tutorial that has a great explanation about the two methods.

    —Brad
    "A little yeast leavens the whole dough."
      Thanks, Brad!

      I changed it to 'use CGI'.

      There were problems at first because in my code I had lines such as 'print header' and 'my $action = param('query'). I think those caused the script to die. I changed the former to 'print $q->header' and the latter to '$action = $q->param('query') and the script works like before. cheers :)

        As Ovid points out in one portion of the tutorial.. one of the problems with use CGI qw(:standard); is namespace. The functions imported via the  :standard type would invalidate functions of the same name in the local file.

        Grygonos
Re: use CGI vs use CGI qw(:standard)
by Anonymous Monk on Apr 19, 2004 at 19:37 UTC

    As an aside, $file =~ /.*\\(.*\.(gif|jpg))/ is a bad way to get the filename. Unless this will be used on an intranet where only Windows operating systems will be able to access the script, your script will not do what you want if someone on a *nux or mac machine accesses the script. You should use one of the file0related modules to grab the name instead:

    use File::Basename; my $file = $q->param('upfile') || ''; $file = basename($file);
      Thanks, I saw that in jeffa's code too. Will change it right away :)
Re: use CGI vs use CGI qw(:standard)
by iburrell (Chaplain) on Apr 20, 2004 at 05:34 UTC
    Number 1 is a comment. The comment in the second one is wrong. It is a confusion between escape backslash in double quoted strings (and regex) and single backslash in single quoted strings.

    As someone else mentioned, you should not be matching the backslash in the regex. Other platforms (or possibly some browsers on Windows) use other directory separators. Also, that regular expression allows some unsafe characters in the matched string.

    # $file set to "C:\\images\\apple.gif" # $file set to 'C:\images\apple.gif';