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

Hi,

If I have a filehandle, how can I get at the filename? What I really want it to do is give me the name when I treat is as a string, like a CGI upload filehandle. I don't seem to be able to find anything about this from google, but I'm not really sure what I should be looking for. Can someone point me in the right direction?

Thanks, Cxx

just found this via google: > Is there a way to get the filename from an open filehandle >that has been passed to another package? No. There may not even *be* a filename.

So can I amend my question: I'm trying to test some code that would normally take an uploaded (CGI) filehandle and use it's file extension to guess if it's an archive and unpack it appropriately. I want to be able to test it directly, so how do I create an object that mimics the behaviour of cgi filehandles?

Thanks again.

Replies are listed 'Best First'.
Re: filenames from filehandles
by chromatic (Archbishop) on Jun 23, 2004 at 19:18 UTC

    I'd rather check the MIME type of the file with File::MMagic or similar to decide whether it's an archive. Filenames come from the client so I distrust them.

    Your subclass looks reasonable if you can trust the client, though.

      That is EXACTLY what I've been looking for!

      Thanks for your help guys

      Cass xx

Re: filenames from filehandles
by theorbtwo (Prior) on Jun 23, 2004 at 19:44 UTC

    I agree with chromatic -- don't trust the client. The ability to upload .zip files named .jpg has been used to upload warez various places. In the general case, though...

    if ($^O eq 'linux' and -d /proc) { $procpath=fileno($fh); $filename=readlink($procpath); $filename=undef unless -e $filename; }

    note that this is linux-specific, though there is a similar proc on many unixes.


    Warning: Unless otherwise stated, code is untested. Do not use without understanding. Code is posted in the hopes it is useful, but without warranty. All copyrights are relinquished into the public domain unless otherwise stated. I am not an angel. I am capable of error, and err on a fairly regular basis. If I made a mistake, please let me know (such as by replying to this node).

      $procpath=fileno($fh);
      should be
      $procpath='/proc/self/fd/'.fileno($fh);

      Also, your directory test is missing quotes.

      my $filename; if (defined(my $fileno = fileno($fh))) { if ($^O eq 'linux') { my $procpath = "/proc/self/fd/$fileno"; $filename = readlink($procpath); $filename = undef unless -e $filename; } }
Re: filenames from filehandles
by CassJ (Sexton) on Jun 23, 2004 at 16:09 UTC
    Hmm, I've come up with a solution that works, but I don't know if it's a good way of doing it. Comments please?
    package fakeCGIFile; use base IO::File; my %filenames; sub new { my $class = shift; my $filename = shift; my $self = $class->SUPER::new("<$filename"); $filenames{fileno($self)} = $filename; bless($self,$class); } use overload '""'=>sub { my $self = shift; my $filename = $filenames{fileno($self)}; return $filename; };