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

I am using cgi-lib.pl in an application. I upload a file from my local windows machine and this file is saved on the unix machine to be used by the application.
I am trying to change over from cgi-lib.pl to CGI.pm. But when i do use CGI.pm and I upload any file from the local windows machine, my application now grabs the whole path of the file (example C:\docs\test.txt). It obviously omits the backslashes(\)used in the windows path for the file and the application ends up with a file called C:docstest.txt.

While using cgi-lib.pl this never happened. I used to get just the file name (example test.txt).
Whats the wayout?

Thanks for any help in advance.
Harpreet Singh

Replies are listed 'Best First'.
Re: CGI.pm help needed
by jarich (Curate) on May 22, 2002 at 04:47 UTC
    But when i do use CGI.pm and I upload any file from the local windows machine, my application now grabs the whole path of the file (example C:\docs\test.txt). It obviously omits the backslashes(\)used in the windows path for the file and the application ends up with a file called C:docstest.txt.

    I'm not sure what you're saying here. I think that you're saying that CGI.pm gives you the full filename eg "C:\docs\test.txt" and you just want "test.txt". Is that correct?

    Assuming that I'm right, you might consider using the File::Basename module that comes standard with Perl. So your script might have code that looks kinda like the following.

    use CGI; use File::Basename; my $cgi = new CGI; # $fullname is now a filehandle and a string # containing the uploaded filename. my $fullfilename = $cgi->upload("file"); my ($filename, $type) = split '\.', basename($fh);

    An example of how you might use the above is to add something like this below it:

    # untaint filename and type $filename =~ s/[^A-Za-z0-9_-]//g; $type =~ s/[^A-Za-z0-9_-]//g; # create a unique file in my desired $directory: my $i = 0; while(-e "$directory/$filename$i.$type") { $i++; } # this won't write over anything else. my $newfilename = "$directory/$filename$i.$type"; # Write contents of uploaded file to $directory open(FILE, "> $newfilename") or die "$!\n"; { local $/=""; my $uploaded = <$filename>; print FILE $uploaded; } close FILE or die "$!";
    Of course, you might want to be doing something else with your uploaded data, so go ahead.

    You might be tempted to do this another way. For example you could do this:

    my $fullfilename = $cgi->upload("file"); my $filename = reverse((split(/\//, reverse($fullfilename)))[0]);
    and then $filename would have everything beyond your last /. Of course TMTOWTDI. Keep in mind that the first solution I have offered is somewhat more portable though. ;)

    Hope this helps.

    jarich

    Update:added in " marks to make it compile. *blush*. Changed called to fileparse to basename and split as fileparse doesn't seem to work as expected in many cases. Added in taint checking for filename in example use.

Re: CGI.pm help needed
by bassplayer (Monsignor) on May 22, 2002 at 04:47 UTC
    CGI.pm is still definitely still the way to go. I'm sure anymonk who has used both can list 5 bad experiences with cgi-lib.pl for every setback experienced with CGI.pm. In this case, a little regular expression should do the trick. There are probably better ones than this, but how about:

    $filename =~ s/^.*\\//;

    This line strips unwanted path name stuff.

    $filename =~ s/[^\w.-]/_/g;

    This line inserts underscores instead of unwanted characters.

    Be sure to use the following attribute in your form tag:

    enctype="multipart/form-data"

    If you are still having any trouble, you should list out the code you are using. This will get you much quicker and more accurate responses to your queries.

    This might also be of interest to you.

    bassplayer