Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

ZipArchive::close() causes Internal Server Error

Status
Not open for further replies.

thenewa2x

Programmer
Dec 10, 2002
349
US
Hello.

I am trying to dynamically create an archive, save it, and output the results so that a browser and download the zip file. At the exact point where I call the close() method, an "Internal Server Error" occurs with nothing in the logs.

Here is the script:
Code:
<?php

    /**
    * Mukei Source Code Packager
    *
    * This script packages the latest version of the Mukei system into a
    * Zip file for developers to start downloading.  Hopefully they don't
    * use the source in a production environment yet!
    *
    * @package Packager
    * @version 0.1
    */

    // Zlib Not Installed?
    if ( !extension_loaded( "zlib" ) )
    {
        // Report problem.
        trigger_error( "Zlib must be installed in order to create the " .
                       "packages.",
                       E_USER_ERROR );
    }

    // Zip functions missing?
    if ( !function_exists( "zip_open" ) )
    {
        // Report problem.
        trigger_error( "Zip function, zip_open, does not exist even though " .
                       "zlib is loaded.",
                       E_USER_ERROR );
    }

    // ZipArchive class missing?
    if ( !class_exists( "ZipArchive" ) )
    {
        // Report problem.
        trigger_error( "ZipArchive class is missing even though zlib is " .
                       "loaded.",
                       E_USER_ERROR );
    }

    // Make global.
    global $sep;

    // Get file path seperator.
    $sep = ( substr( strtolower( PHP_OS ), 0, 3 ) === "win" )
         ? "\\"
         : "/";

    // Configure root directory.
    $root = $sep . make_path( array(
        'path', 'to', 'directory',
    ) );

    // Get current directory.
    $current = dirname( __FILE__ ) . $sep;

    // Make destination path.
    $to = $current . "latest.zip";

    // Get directories.
    $latest = scandir( $root );

    // Remove extras.
    array_shift( $latest );
    array_shift( $latest );

    // Get altest.
    $latest = make_path( array(
        $root, $latest[ count( $latest ) - 1 ],
    ) ) . $sep;

    // Get contents.
    $contents = scandir( $latest );

    // Remove extras.
    array_shift( $contents );
    array_shift( $contents );

    // Create an archive.
    $archive = new ZipArchive ( );

    // Escape root.
    $preg_root = "/^" . preg_quote( $latest, "/" ) . "/";

    // Create zip archive.
    if ( $archive->open( $to, ZipArchive::CREATE ) === true )
    {
        // Initialize iterator.
        $iterator = new RecursiveIteratorIterator  (
                    new RecursiveDirectoryIterator ( $latest ) );

        // Walk through contents.
        foreach ( $iterator as $key => $value )
        {
            // Get relative path.
            $relative = preg_replace( $preg_root,
                                      "",
                                      $key );

            // Add file.
            if ( $archive->addFile( realpath( $key ),
                                    "files/$relative" ) !== true )
            {
                // Close archive.
                $archive->close( );

                // Report fatal error.
                trigger_error( "Unable to add file, $key.",
                               E_USER_ERROR );
            }
        }

        // Close archive.
        if ( $archive->close( ) )
        {
            // Have host?
            if ( !empty( $_SERVER['HTTP_HOST'] ) )
            {
                // Archive exists?
                if ( file_exists( $to ) )
                {
                    // Send download headers.
                    header( "Content-type: application/x-zip-compressed" );
                    header( "Content-disposition: attachment; filename=\"" .
                            "files-" . date( "Ymd-His" ) . ".zip\"" );

                    // Open Zip file.
                    if ( $file = fopen( $to, "r" ) )
                    {
                        // Print as read.
                        while ( $data = fread( $file, 1024 ) )
                            print $data;

                        // Close Zip file.
                        fclose( $file );

                        // Quit.
                        exit( );
                    }
                }
            }
        }
    }

    // Still here?
    trigger_error( "Unable to generate latest Zip file.",
                   E_USER_ERROR );



    /**
    * Make Path
    *
    * @param  array  $parts Path parts.
    * @return string
    */
    function make_path ( $parts )
    {
        // Get global.
        global $sep;

        return( join( $sep, $parts ) );
    }
?>

 
I context testing and closing the zip file immediately after adding a single file produces the error.

 
Linux 2.6.17.11-grsechg
PHP 5.2.2 (PHPSuExec)
Zlib Compiled: v1.2.1.2
Zlib Linked: v1.2.3

 
must you use this class or would an alternative solution be adequate?
 
ok. and how do you derive the list of files that you wish to zip?
 
I scan a directory for the "latest" subdirectory. This latest sub directory is the last in the array returned from scandir() using the default sorting method. Then the contents of the directory is stored in a zip file called "latest.zip" which is stored in the same directory as the script. The paths in the zip file are all relative.

 
try this. pass the files in to the function in a numeric array.

Code:
function addToZip($zipFile, $filesToAdd){
 if (!is_array($filesToAdd)){
  die ("incorrect input");
 }
 //create temporary file name
 $file = tempnam('/tmp','zip_');
 
 //now compress the array to a list
 $fileList = '"'.implode('" "', $filesToAdd) . '"';
 $command = escapeshellcmd("zip $file $fileList");
 exec ($command);
 if (is_file($file) && is_readable($file)){
   header('Content-type: application/octet-stream');
   header('Content-Disposition: attachment; filename="$zipFile"');
   readfile($file);
   @unlink($file);
   exit();
 }
 
}
 
Thanks jpadie. I was able to progress and this is what I now have:

Code:
<?php

    // Set path.
    $path = "/path/to/directory";

    // Get latest.
    $latest = latest( $path );

    // Package file.
    $zip = package( $latest );

    // Dump zip file.
    dump( $zip );

    function latest ( $path = "" )
    {
        // Directory good?
        if ( is_dir( $path ) &&
             is_readable( $path ) )
        {
            // Scan directory.
            $contents = scandir( $path );

            // Get last directory.
            $last = array_pop( $contents );

            // Is a directory?
            if ( is_dir( $path . "/" . $last ) )
            {
                // Return path.
                return( $path . "/" . $last );
            }

            // Is not a directory?
            else
            {
                // Oh wtf?
                trigger_error( "Cannot locate latest code branch.",
                               E_USER_ERROR );
            }
        }

        // Not good?
        else
        {
            // Fatal error.
            trigger_error( "Code directory access denied.",
                           E_USER_ERROR );
        }
    }

    function package ( $path = "" )
    {
        // Create path.
        $zip  = basename( $path );
        $zip .= ".zip";

        // File exists?
        if ( file_exists( $zip ) )
        {
            // Return that file.
            return( $zip );
        }

        // File does not exist?
        else
        {
            // Create command.
            $cmd = "zip -q -j -r \"$zip\" \"$path\"";

            // Execute command.
            $res = system( $cmd );

            // Execute command.
            if ( empty( $res ) )
            {
                // Return zip path.
                return( $zip );
            }

            // Failed?
            else
            {
                // Fatal!!!
                trigger_error( "Unable to package code branch.",
                               E_USER_ERROR );
            }
        }
    }

    function dump ( $zip )
    {
        // File good?
        if ( is_file( $zip ) &&
             is_readable( $zip ) )
        {
            // Open the file.
            if ( $fp = fopen( $zip, "r" ) )
            {
                // Get file name.
                $file = basename( $zip );

                // Send headers.
                header( "Content-type: application/octet-stream" );
                header( "Content-Disposition: attachment; filename=\"$file\"" );

                // Pass thru it.
                fpassthru( $fp );

                // Close the file.
                fclose( $fp );
            }

            // Unable to open the file?
            else
            {
                // Fatal...
                trigger_error( "Unable to open package for download.",
                               E_USER_ERROR );
            }
        }

        // Filed naughty?
        else
        {
            // Fatal.
            trigger_error( "Packaged file missing.",
                           E_USER_ERROR );
        }
    }

?>

It works fine except that I can't seem to junk the paths. They're all absolute. I would just like the paths to begin at the directory that is being compressed.

 
i tried writing a script the other day to convert absolute to relative paths and reached a blank, got too messy.

you can flatten the zip file ignoring the directory structure through a switch. would that solve the issue?
 
I used the -j flag in the script above that would junk the path. Nothing changed.

 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top