Re: [RE-PHRASE] PHP ZIP Class

From: Date: Fri, 17 Jun 2005 08:16:37 +0000
Subject: Re: [RE-PHRASE] PHP ZIP Class
References: 1  Groups: php.general 
Request: Send a blank email to php-general+get-217122@lists.php.net to get a copy of this message
Jay Blanchard wrote:
I am in need of a PHP class or script or something that will allow me to
like Richard mentioned - exec out to the shell and zip there.... I wrote a little/simple class when I was bored, here you go, HIH - (sorry about the linewrapping) I use the class in backoffice setting and it is actually used to zip up PDF files, which is does just fine. (using zip on a RHES box) <?php /** * Zipper.class.php :: wrapper for the system command 'zip' *
 * @author      Jochem Maas <jochem@iamjochem.com>
 * @version     0.1
* @copyright Copyright 2003-2004 iamjochem * * $Header: include/class/core/Zipper.class.php,v 1.2 2005/04/12 11:36:21 jochem Exp $ */ abstract class Zipper {
    const ARC_RECURSE   = 0x1; // zip will recurse the from directory for files to include
    const ARC_APPEND    = 0x2; // zip will append to the given archive (if it exists), rather than overwrite
    const ARC_MOVE      = 0x4; // zip will delete the archived files upon success
    const ARC_TEST      = 0x8; // the generated cmdline will be returned as the first item of the output array instead of being called - useful for checking what will happen (before you do it!)
    /*
     * WARNING: $pattern is the UNESCAPED file pattern  to archive (defaults to './*')
     * DO NOT ALLOW USER INPUT IN HERE WITHOUT SANITATION (e.g. escapeshellargs() - bare in mind that
     * strings which are quoted in the strings will not have globbing performed, I say this
     * because that is exactly the result of performing escapeshellargs())
     *
     * e.g. "'./*.xml'" instead of "./*.xml"
     */
    static public function archiveData($fromdir, $todir, $filename, $pattern = '', $flags = self::ARC_RECURSE, &$output = null)
    {
        static $msgs;
        $fromdir    = realpath($fromdir);
        $todir      = realpath($todir);
        if (!is_dir($todir)) {
            $output = array('"to" dir - directory not found');
            return 19;
        }
        if (!is_dir($fromdir)) {
            $output = array('"from" dir - directory not found');
            return 19;
        }
        if (!self::checkforZIP()) {
            $output = array('zip - command not found');
            return -1;
        }
        /* could be localized via the Lang class */
        if (!isset($msgs)) {
            $msgs[  0 ] = 'normal; no errors or warnings detected.';
            $msgs[  2 ] = 'unexpected end of zip file.';
            $msgs[  3 ] = 'a  generic  error  in the zipfile format was detected.  Processing may have completed successfully anyway; some broken zipfiles created by other archivers have simple work-arounds.';
            $msgs[  4 ] = 'zip was unable to allocate memory for one or more buffers during program initialization.';
            $msgs[  5 ] = 'a severe error in the zipfile format was detected.  Processing probably failed immediately.';
            $msgs[  6 ] = 'entry too large to be split with zipsplit';
            $msgs[  7 ] = 'invalid comment format';
            $msgs[  8 ] = 'zip -T failed or out of memory';
            $msgs[  9 ] = 'the user aborted zip prematurely with control-C (or similar)';
            $msgs[ 10 ] = 'zip encountered an error while using a temp file';
            $msgs[ 11 ] = 'read or seek error';
            $msgs[ 12 ] = 'zip has nothing to do';
            $msgs[ 13 ] = 'missing or empty zip file';
            $msgs[ 14 ] = 'error writing to a file';
            $msgs[ 15 ] = 'zip was unable to create a file to write to';
            $msgs[ 16 ] = 'bad command line parameters';
            $msgs[ 18 ] = 'zip could not open a specified file to read';
        }
        /* check pattern - the pattern is meant to be expanded by the shell (not by the zip binary) */
        if (!($pattern = trim($pattern)) || $pattern == '.*') {
            $pattern = './*'; /* everything */
        }
        //$pattern = escapeshellarg($pattern);
        /* check flags */
        $flagStr = array();
        foreach(array(
                    self::ARC_RECURSE   => '-r',
                    self::ARC_APPEND    => '-u',
                    self::ARC_MOVE      => '-m',
                ) as $cnst => $flag)
        {
            if ($flags & $cnst) {
                $flagStr[] = $flag;
            }
        }
        $flagStr = count($flagStr) ? join(' ',$flagStr): '';
        $retval  = null;
        $cmd     = "cd {$fromdir}; zip -v -T {$flagStr} {$todir}/{$filename}.zip {$pattern}";
        if ($flags & self::ARC_TEST) {
            $output[] = $cmd;
        } else {
            @exec($cmd, $output, $retval);
            if ($retval > 0) {
                $output[] = '';
                if (isset($msgs[ $retval ])) {
                    $output[] = $msgs[ $retval ];
                } else {
                    $output[] = "\nunknown error [cmd: $cmd] (return: $retval)";
                }
            } else {
                $output[] = "\nfiles archived successfully to zip file (return: $retval)";
            }
        }
        return $retval;
    }
    /* checks for the zip executable (assumes its on the path)
     * the assumption is also made that the possible 'command not found' message
     * is output in english!
     */
    static private function checkforZIP()
    {
        static $check;
        $check = true;
        if (is_null($check)) {
            $output = $retval = null;
            @exec('zip -v', $output, $retval);
            if (!array($output) || !count($output)) {
                $check = false;
            } else {
                $check = stristr($output[ 0 ], 'command not found');
            }
        }
        return $check;
    }
}
designate a group of files to be zipped up, including PDF files, automagically. It must be compatible with WinZip as that is what the user will have access to. I have tried several things, a couple of classes, and some other tricks to no avail. There seems to be an issue with PDF's that I cannot figure out. The files are usually 1 byte too short when you try to open them after unzipping them, and are therefore corrupt. If anyone is aware of something would you please let me know? I am even willing at this point to add a couple of layers of abstraction to make this work as long as the process is relatively invisible to the end user. My desire is that it works like this; User clicks link [start automagic stuff] *whirring* //determine which files should go into archive *clicking* //put files in archive [/end automagic stuff] User presented with dialog box to save archive Any and all clues are appreciated.


« previous php.general (#217122) next »