PHP ZIP file download

后端 未结 7 1224
一生所求
一生所求 2020-12-17 05:51

Here is a code which downloads attachment files from the an imap server. Almost all file types (pdf, doc, xls, etc) are being downloaded correctly, where as some zip files g

相关标签:
7条回答
  • 2020-12-17 06:20

    I didn't see anyone mention this yet, but try removing the Content-Length header when download ZIP files. I had this exact same problem and it worked for

    0 讨论(0)
  • 2020-12-17 06:20

    This is really good for big file download. User will be receiving file immediately. Maybe zip will be correct too this way.

        if(file_exists($filename) && is_readable($filename) && file_exists($filename)){
                 header("Content-Disposition: attachment; filename=".basename(str_replace(' ', '_', $filename)));
                 header("Content-Type: application/force-download");
                 header("Content-Type: application/octet-stream");
                 header("Content-Type: application/download");
                 header("Content-Description: File Transfer");
                 header("Content-Length: " . filesize($filename));
                 flush(); // this doesn't really matter.
    
                 $fp = fopen($filename, "r");
                 while (!feof($fp))
                 {
                     echo fread($fp, 65536);
                     flush(); // this is essential for large downloads
                 }
                 fclose($fp);
             exit;
        }
    
    0 讨论(0)
  • 2020-12-17 06:21

    Script for downloading files in zip format: zip.php

    <?php
    
    /**
    * Zip file creation class.
    * Makes zip files.
    *
    * Last Modification and Extension By :
    *
    *  Hasin Hayder
    *  HomePage : www.hasinme.info
    *  Email : countdraculla@gmail.com
    *  IDE : PHP Designer 2005
    *
    *
    * Originally Based on :
    *
    *  http://www.zend.com/codex.php?id=535&single=1
    *  By Eric Mueller <eric@themepark.com>
    *
    *  http://www.zend.com/codex.php?id=470&single=1
    *  by Denis125 <webmaster@atlant.ru>
    *
    *  a patch from Peter Listiak <mlady@users.sourceforge.net> for last modified
    *  date and time of the compressed file
    *
    * Official ZIP file format: http://www.pkware.com/appnote.txt
    *
    * @access  public
    */
    class zipfile
    {
        /**
         * Array to store compressed data
         *
         * @var  array    $datasec
         */
        var $datasec      = array();
    
        /**
         * Central directory
         *
         * @var  array    $ctrl_dir
         */
        var $ctrl_dir     = array();
    
        /**
         * End of central directory record
         *
         * @var  string   $eof_ctrl_dir
         */
        var $eof_ctrl_dir = "\x50\x4b\x05\x06\x00\x00\x00\x00";
    
        /**
         * Last offset position
         *
         * @var  integer  $old_offset
         */
        var $old_offset   = 0;
    
    
        /**
         * Converts an Unix timestamp to a four byte DOS date and time format (date
         * in high two bytes, time in low two bytes allowing magnitude comparison).
         *
         * @param  integer  the current Unix timestamp
         *
         * @return integer  the current date in a four byte DOS format
         *
         * @access private
         */
        function unix2DosTime($unixtime = 0) {
            $timearray = ($unixtime == 0) ? getdate() : getdate($unixtime);
    
            if ($timearray['year'] < 1980) {
                $timearray['year']    = 1980;
                $timearray['mon']     = 1;
                $timearray['mday']    = 1;
                $timearray['hours']   = 0;
                $timearray['minutes'] = 0;
                $timearray['seconds'] = 0;
            } // end if
    
            return (($timearray['year'] - 1980) << 25) | ($timearray['mon'] << 21) | ($timearray['mday'] << 16) |
                    ($timearray['hours'] << 11) | ($timearray['minutes'] << 5) | ($timearray['seconds'] >> 1);
        } // end of the 'unix2DosTime()' method
    
        /**
         *
         * Function to force the download of the archive as soon as it is created
         *
         * @param archiveName string - name of the created archive file
         * @access public
         * @return ZipFile via Header
         */
        public function forceDownload($archiveName) {
            if(ini_get('zlib.output_compression')) {
                ini_set('zlib.output_compression', 'Off');
            }
    
            // Security checks
            if( $archiveName == "" ) {
                echo "<html><title>Public Photo Directory - Download </title><body><BR><B>ERROR:</B> The download file was NOT SPECIFIED.</body></html>";
                exit;
            }
            elseif ( ! file_exists( $archiveName ) ) {
                echo "<html><title>Public Photo Directory - Download </title><body><BR><B>ERROR:</B> File not found.</body></html>";
                exit;
            }
    
            header("Pragma: public");
            header("Expires: 0");
            header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
            header("Cache-Control: private",false);
            header("Content-Type: application/zip");
            header("Content-Disposition: attachment; filename=".basename($archiveName).";" );
            header("Content-Transfer-Encoding: binary");
            header("Content-Length: ".filesize($archiveName));
            readfile("$archiveName");
        }
    
        /**
         * Adds "file" to archive
         *
         * @param  string   file contents
         * @param  string   name of the file in the archive (may contains the path)
         * @param  integer  the current timestamp
         *
         * @access public
         */
        function addFile($data, $name, $time = 0)
        {
            $name     = str_replace('\\', '/', $name);
    
            $dtime    = dechex($this->unix2DosTime($time));
            $hexdtime = '\x' . $dtime[6] . $dtime[7]
                      . '\x' . $dtime[4] . $dtime[5]
                      . '\x' . $dtime[2] . $dtime[3]
                      . '\x' . $dtime[0] . $dtime[1];
            eval('$hexdtime = "' . $hexdtime . '";');
    
            $fr   = "\x50\x4b\x03\x04";
            $fr   .= "\x14\x00";            // ver needed to extract
            $fr   .= "\x00\x00";            // gen purpose bit flag
            $fr   .= "\x08\x00";            // compression method
            $fr   .= $hexdtime;             // last mod time and date
    
            // "local file header" segment
            $unc_len = strlen($data);
            $crc     = crc32($data);
            $zdata   = gzcompress($data);
            $zdata   = substr(substr($zdata, 0, strlen($zdata) - 4), 2); // fix crc bug
            $c_len   = strlen($zdata);
            $fr      .= pack('V', $crc);             // crc32
            $fr      .= pack('V', $c_len);           // compressed filesize
            $fr      .= pack('V', $unc_len);         // uncompressed filesize
            $fr      .= pack('v', strlen($name));    // length of filename
            $fr      .= pack('v', 0);                // extra field length
            $fr      .= $name;
    
            // "file data" segment
            $fr .= $zdata;
    
            // "data descriptor" segment (optional but necessary if archive is not
            // served as file)
            $fr .= pack('V', $crc);                 // crc32
            $fr .= pack('V', $c_len);               // compressed filesize
            $fr .= pack('V', $unc_len);             // uncompressed filesize
    
            // add this entry to array
            $this -> datasec[] = $fr;
    
            // now add to central directory record
            $cdrec = "\x50\x4b\x01\x02";
            $cdrec .= "\x00\x00";                // version made by
            $cdrec .= "\x14\x00";                // version needed to extract
            $cdrec .= "\x00\x00";                // gen purpose bit flag
            $cdrec .= "\x08\x00";                // compression method
            $cdrec .= $hexdtime;                 // last mod time & date
            $cdrec .= pack('V', $crc);           // crc32
            $cdrec .= pack('V', $c_len);         // compressed filesize
            $cdrec .= pack('V', $unc_len);       // uncompressed filesize
            $cdrec .= pack('v', strlen($name) ); // length of filename
            $cdrec .= pack('v', 0 );             // extra field length
            $cdrec .= pack('v', 0 );             // file comment length
            $cdrec .= pack('v', 0 );             // disk number start
            $cdrec .= pack('v', 0 );             // internal file attributes
            $cdrec .= pack('V', 32 );            // external file attributes - 'archive' bit set
    
            $cdrec .= pack('V', $this -> old_offset ); // relative offset of local header
            $this -> old_offset += strlen($fr);
    
            $cdrec .= $name;
    
            // optional extra field, file comment goes here
            // save to central directory
            $this -> ctrl_dir[] = $cdrec;
        } // end of the 'addFile()' method
    
    
        /**
         * Dumps out file
         *
         * @return  string  the zipped file
         *
         * @access public
         */
        function file()
        {
            $data    = implode('', $this -> datasec);
            $ctrldir = implode('', $this -> ctrl_dir);
    
            return
                $data .
                $ctrldir .
                $this -> eof_ctrl_dir .
                pack('v', sizeof($this -> ctrl_dir)) .  // total # of entries "on this disk"
                pack('v', sizeof($this -> ctrl_dir)) .  // total # of entries overall
                pack('V', strlen($ctrldir)) .           // size of central dir
                pack('V', strlen($data)) .              // offset to start of central dir
                "\x00\x00";                             // .zip file comment length
        } // end of the 'file()' method
    
    
        /**
         * A Wrapper of original addFile Function
         *
         * Created By Hasin Hayder at 29th Jan, 1:29 AM
         *
         * @param array An Array of files with relative/absolute path to be added in Zip File
         *
         * @access public
         */
        function addFiles($files /*Only Pass Array*/)
        {
            foreach($files as $file)
            {
            if (is_file($file)) //directory check
            {
                $data = implode("",file($file));
                        $new_file = $this->prefix_name.end(explode('/', $file));
                        $this->addFile($data, $new_file);
                    }
            }
        }
    
        /**
         * A Wrapper of original file Function
         *
         * Created By Hasin Hayder at 29th Jan, 1:29 AM
         *
         * @param string Output file name
         *
         * @access public
         */
        function output($file)
        {
            $fp=fopen($file,"w");
            fwrite($fp,$this->file());
            fclose($fp);
        }
    
    
    
    } // end of the 'zipfile' class
    ?>
    

    Example usage:

    <?php
    
    include_once('zip.php');
    
    $zip_file = 'my_files.zip'; // name for downloaded zip file
    
    $ziper = new zipfile();
    $ziper->prefix_name = 'folder/'; // here you create folder which will contain downloaded files
    $ziper->addFiles($files_to_zip);  // array of files
    $ziper->output($zip_file); 
    $ziper->forceDownload($zip_file);
    @unlink($zip_file);
    
    ?>
    
    0 讨论(0)
  • 2020-12-17 06:28
    It Worked For Me. It Download My .Zip File. But, you have to provide the full path of File, where it is located.
    For ex: My File is inside assets/upload Folder. Attach name of that file with this location. You will download it without any problem.
    
    $FilePaths='assets/Upload/'.$FileName; //Give proper file path with file name.
    
    download_file($FilePaths);
    
    function download_file( $fullPath )
    {
      if( headers_sent() )
        die('Headers Sent');
    
    
      if(ini_get('zlib.output_compression'))
        ini_set('zlib.output_compression', 'Off');
    
    
      if( file_exists($fullPath) )
      {
    
        $fsize = filesize($fullPath);
        $path_parts = pathinfo($fullPath);
        $ext = strtolower($path_parts["extension"]);
    
        switch ($ext) 
        {
          case "pdf": $ctype="application/pdf"; break;
          case "exe": $ctype="application/octet-stream"; break;
          case "zip": $ctype="application/zip"; break;
          case "doc": $ctype="application/msword"; break;
          case "xls": $ctype="application/vnd.ms-excel"; break;
          case "ppt": $ctype="application/vnd.ms-powerpoint"; break;
          case "gif": $ctype="image/gif"; break;
          case "png": $ctype="image/png"; break;
          case "jpeg":
          case "jpg": $ctype="image/jpg"; break;
          default: $ctype="application/force-download";
        }
    
        header("Pragma: public"); 
        header("Expires: 0");
        header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
        header("Cache-Control: private",false); 
        header("Content-Type: $ctype");
        header("Content-Disposition: attachment; filename=\"".basename($fullPath)."\";" );
        header("Content-Transfer-Encoding: binary");
        header("Content-Length: ".$fsize);
        ob_clean();
        flush();
        readfile( $fullPath );
    
      } 
      else
        die('File Not Found');
    
    }
    

    For more info, Check this File Download

    0 讨论(0)
  • 2020-12-17 06:32

    You're very close to the solution! I found the way to solve this was to remove the Content-type header all together and let the browser figure out that this was a .zip file. Remove the Content-Type and it should work as needed.

    // Remove this line 
    header('Content-Type: '. $type .'/'. $subtype);
    

    In my console (Chrome) I was receiving a strange message(s) saying:

    Resource interpreted as Document but transferred with MIME type application/octet-stream:

    Resource interpreted as Document but transferred with MIME type application/zip:

    When I removed the MIME Type (Content-type header) the .zip stopped giving me an error and worked normally.

    The most basic download script for making the .zip to work looked like this at the end: (note: You can still add more headers for caching and such)

    <?php
        header("Content-Disposition: attachment; filename=\"".$Filename."\"");
        header("Content-Length: ".filesize($Filename));
        readfile($Filename);
    ?>
    

    Edited

    Your .zip's will also run into problems if the browser is reading extra spaces. You can prevent the extra spaces at the end of the readfile() by adding exit(); but you'll want to make sure you don't have any spaces at the start of the file. This is particularly common when dealing with frameworks (especially your own). A little trick: If you include all the functions, configs and classes before your buffer starts outputting HTML, view your source code. At the start there will be a space before the .

    0 讨论(0)
  • 2020-12-17 06:34

    The culprit was imap_base64. It was not decoding the data correctly. I replaced it with base64_decode as follows and the code worked fine.

    $body = base64_encode($data);
    
    0 讨论(0)
提交回复
热议问题