Archive :: Zip Can not create a Zip object in Perl

advertisements

I'm a newbie in Perl language programming. I cut & paste a short example from CPan official website (https://metacpan.org/pod/Net::FTP::RetrHandle), which lists the member names in a Zip file without downloading the whole thing. Please note that I changed the first line from "#!/usr/bin/perl" to "#!/root/localperl/bin/perl" because I want to use the newest Perl version 5.18.2.

#!/root/localperl/bin/perl

    use warnings;
    use strict;

    use Net::FTP;
    use Net::FTP::AutoReconnect;
    use Net::FTP::RetrHandle;
    use Archive::Zip;

    my $ftp = Net::FTP::AutoReconnect->new("ftp.info-zip.com", Debug => $ENV{DEBUG})
        or die "connect error\n";
    $ftp->login('anonymous','[email protected]')
        or die "login error\n";
    $ftp->cwd('/pub/infozip/unix/linux')
        or die "cwd error\n";
    my $fh = Net::FTP::RetrHandle->new($ftp,'unz551x-glibc.zip')
        or die "Couldn't get handle to remote file\n";
    my $zip = Archive::Zip->new($fh)
        or die "Couldn't create Zip object\n";
    foreach my $fn ($zip->memberNames())
    {
      print "unz551-glibc.zip: $fn\n";
    }

I gedit ".bash_profile", and add the following environmental variables for Perl specific version use:

PERL_BIN=$HOME/localperl/bin
PERL_LIB=$HOME/localperl/lib/5.18.2

export PATH=$PERL_BIN:$PERL_LIB:$PATH

[[email protected] ~]# echo $PATH

/root/localperl/bin:/root/localperl/lib/5.18.2:/usr/lib64/qt-3.3/bin:/usr/local/sbin:/usr/sbin:/sbin:/usr/local/bin:/usr/bin:/bin:/root/bin:/root/bin

We can check the active Perl version by running the following command:

[[email protected] ~]# perl -v

This is perl 5, version 18, subversion 2 (v5.18.2) built for x86_64-linux

Copyright 1987-2013, Larry Wall

Perl may be copied only under the terms of either the Artistic License or the GNU General Public License, which may be found in the Perl 5 source kit.

Complete documentation for Perl, including FAQ lists, should be found on this system using "man perl" or "perldoc perl". If you have access to the Internet, point your browser at http://www.perl.org/, the Perl Home Page.

When I execute the above-mentioned code snippets, it throws the following errors:

[[email protected] ~]# perl zipdown.pl

IO error: read failed : at /root/localperl/lib/5.18.2/Archive/Zip/Archive.pm line 705. Archive::Zip::Archive::_findEndOfCentralDirectory('Archive::Zip::Archive=HASH(0x1d55618)', 'Net::FTP::RetrHandle=HASH(0x1d55528)') called at /root/localperl/lib/5.18.2/Archive/Zip/Archive.pm line 607 Archive::Zip::Archive::readFromFileHandle('Archive::Zip::Archive=HASH(0x1d55618)', 'Net::FTP::RetrHandle=HASH(0x1d55528)', 'Net::FTP::RetrHandle=HASH(0x1d55528)') called at /root/localperl/lib/5.18.2/Archive/Zip/Archive.pm line 574 Archive::Zip::Archive::read('Archive::Zip::Archive=HASH(0x1d55618)', 'Net::FTP::RetrHandle=HASH(0x1d55528)') called at /root/localperl/lib/5.18.2/Archive/Zip/Archive.pm line 59 Archive::Zip::Archive::new('Archive::Zip::Archive', 'Net::FTP::RetrHandle=HASH(0x1d55528)') called at /root/localperl/lib/5.18.2/Archive/Zip.pm line 284 Archive::Zip::new('Archive::Zip', 'Net::FTP::RetrHandle=HASH(0x1d55528)') called at zipdown.pl line 19 Couldn't create Zip object

The error, which reads "Couldn't create Zip object", occurred on the line 19. I think for sure that this kind of error should not result from the simple official source code itself. So I provide the some concerned path and files for your reference:

/root/localperl/lib/5.18.2/Archive/(Extract.pm, Tar.pm, Zip.pm) /root/localperl/lib/5.18.2/Archive/Tar/(Constant.pm, File.pm) /root/localperl/lib/5.18.2/Archive/Zip/(Archive.pm, BufferedFileHandle.pm, DirectoryMember.pm, FAQ.pod, FileMember.pm, Member.pm, MemberRead.pm, MockFileHandle.pm, NewFileMember.pm, StringMember.pm, Tree.pm, ZipFileMember.pm)

/root/localperl/lib/5.18.2/Net/(Cmd.pm, Config.pm, Domain.pm, FTP.pm, hostent.pm, libnetFAQ.pod, netent.pm, Netrc.pm, NNTP.pm, Ping.pm, POP3.pm, protoent.pm, servent.pm, SMTP.pm, Time.pm) /root/localperl/lib/5.18.2/Net/FTP/(A.pm, AutoReconnect.pm, dataconn.pm, E.pm, I.pm, L.pm, RetrHandle.pm)

Worthy of mention is that Perl installer can't install the Zip module by default. Thus, I use "cpan" environment to install it independently as follows:

root# cpan
cpan> install Archive::Zip
cpan> quit
root#

In addition, in order to use Net::FTP::AutoReconnect and Net::FTP::RetrHandle modules, I download perl-Net-FTP-AutoReconnect-0.3-3.el6.noarch.rpm and perl-Net-FTP-RetrHandle-0.2-3.el6.noarch.rpm from http://pkgs.org/centos-6/epel-i386/perl-Net-FTP-AutoReconnect-0.3-3.el6.noarch.rpm.html and http://pkgs.org/centos-6/epel-i386/perl-Net-FTP-RetrHandle-0.2-3.el6.noarch.rpm.html links respectively, and install them one by one:

rpm -ivh perl-Net-FTP-AutoReconnect-0.3-3.el6.noarch.rpm
rpm -ivh perl-Net-FTP-RetrHandle-0.2-3.el6.noarch.rpm

It took me a whole day long to try all possible solutions as I my knowledge can reach. I now have nothing to do but turning to your Perl guru guys from SO for help. Thank you very much in advance!


Firstly, well done for figuring out how to set up a local copy of perl + libraries. However probably best not to do your learning with perl.

Secondly, although CPAN is "official" the packages you find on it are written by a wide range of people and the code is of varying quality. Net::FTP::RetrHandle is at version 0.2 and dates from 2006. That's doesn't mean it's bad code, just that it's not seen a lot of usage.

I tried the example and it failed just like with you.

Then I commented out the Archive::Zip code at the end and just used the filehandle to read data from the FTP server and save it to a file. That file seemed to be a valid ZIP archive so we know the basics are fine.

I then tried giving the Archive::Zip code an ordinary filehandle to work with. That was fine.

So - it's some interaction between the two. Looking at the Archive::Zip source-code the error occurred when it tried to read after seeking backwards from the end of the file. So - I had a look at the seek sub-routine in the Net::FTP::RetrHandle module. There I noticed you could set a debug environment variable, which I did.

export DEBUG=1
perl ftp_fh_test.pl
...
Net::FTP=GLOB(0x2e99ce8)<<< 250 Connected to /dsa0/infozip/pub/infozip/unix/linux.
Net::FTP=GLOB(0x2e99ce8)>>> PORT 192,168,1,43,226,125
Net::FTP=GLOB(0x2e99ce8)<<< 200 Port 226.125 at Host 80.229.41.160 accepted.
Net::FTP=GLOB(0x2e99ce8)>>> REST 155293
Net::FTP=GLOB(0x2e99ce8)<<< 500 I never heard of the REST command.  Try HELP.
IO error: read failed...

So - the FTP server doesn't recognise the "REST" command and so you can't seek via that server. Try a different FTP server.

You may also like perlbrew and local::lib as part of your development setup. Very useful for setting up local perl environments.