简体   繁体   English

如何使用PHP创建ZIP文件并在用户下载后删除它?

[英]How to create a ZIP file using PHP and delete it after user downloads it?

I need to download images from other websites to my server. 我需要从其他网站下载图像到我的服务器。 Create a ZIP file with those images. 使用这些图像创建ZIP文件。 automatically start download of created ZIP file. 自动开始下载创建的ZIP文件。 once download is complete the ZIP file and images should be deleted from my server. 下载完成后,应从我的服务器中删除ZIP文件和图像。

Instead of automatic download, a download link is also fine. 而不是自动下载,下载链接也没关系。 but other logic remains same. 但其他逻辑仍然相同。

Well, you'll have to first create the zipfile, using the ZipArchive class. 好吧,你必须首先使用ZipArchive类创建ZipArchive

Then, send : 然后,发送:

  • The right headers, indicating to the browser it should download something as a zip -- see header() -- there is an example on that manual's page that should help 正确的标题,指示浏览器应该下载一些拉链 - 见header() - 该手册的页面上有一个例子应该有帮助
  • The content of the zip file, using readfile() zip文件的内容,使用readfile()

And, finally, delete the zip file from your server, using unlink() . 最后,使用unlink()从服务器中删除zip文件。


Note : as a security precaution, it might be wise to have a PHP script running automatically (by crontab, typically) , that would delete the old zip files in your temporary directory. 注意:作为安全预防措施,最好让PHP脚本自动运行(通常由crontab运行 ,这将删除临时目录中的旧zip文件。

This just in case your normal PHP script is, sometimes, interrupted, and doesn't delete the temporary file. 这是为了防止您的普通PHP脚本被中断,并且不会删除临时文件。

<?php 

Zip('some_directory/','test.zip');

if(file_exists('test.zip')){
    //Set Headers:
    header('Pragma: public');
    header('Expires: 0');
    header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
    header('Last-Modified: ' . gmdate('D, d M Y H:i:s', filemtime('test.zip')) . ' GMT');
    header('Content-Type: application/force-download');
    header('Content-Disposition: inline; filename="test.zip"');
    header('Content-Transfer-Encoding: binary');
    header('Content-Length: ' . filesize('test.zip'));
    header('Connection: close');
    readfile('test.zip');
    exit();
}

if(file_exists('test.zip')){
    unlink('test.zip');

}


function Zip($source, $destination)
{
    if (!extension_loaded('zip') || !file_exists($source)) {
        return false;
    }

    $zip = new ZipArchive();
    if (!$zip->open($destination, ZIPARCHIVE::CREATE)) {
        return false;
    }

    $source = str_replace('\\', '/', realpath($source));

    if (is_dir($source) === true)
    {
        $files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($source), RecursiveIteratorIterator::SELF_FIRST);

        foreach ($files as $file)
        {
            $file = str_replace('\\', '/', realpath($file));

            if (is_dir($file) === true)
            {
                $zip->addEmptyDir(str_replace($source . '/', '', $file . '/'));
            }
            else if (is_file($file) === true)
            {
                $zip->addFromString(str_replace($source . '/', '', $file), file_get_contents($file));
            }
        }
    }
    else if (is_file($source) === true)
    {
        $zip->addFromString(basename($source), file_get_contents($source));
    }

    return $zip->close();
}

?>

Other solution: Delete past files before creation new zip file: 其他解决方案:在创建新zip文件之前删除过去的文件:

    // Delete past zip files script
    $files = glob('*.zip'); //get all file names in array
    $currentTime = time(); // get current time
    foreach($files as $file){ // get file from array
        $lastModifiedTime = filemtime($file); // get file creation time

        // get how old is file in hours:
        $timeDiff = abs($currentTime - $lastModifiedTime)/(60*60);

        //check if file was modified before 1 hour:
        if(is_file($file) && $timeDiff > 1)
            unlink($file); //delete file
    }

Any idea how many zip file downloads get interrupted and need to be continued? 知道有多少zip文件下载被中断并需要继续吗?

If continued downloads are a small percentage of your downloads, you can delete the zip file immediately; 如果继续下载只占您下载的一小部分,您可以立即删除zip文件; as long as your server is still sending the file to the client, it'll remain on disk. 只要您的服务器仍在将文件发送到客户端,它就会保留在磁盘上。

Once the server closes the file descriptor, the file's reference count will drop to zero, and finally its blocks on disk will be released. 一旦服务器关闭文件描述符,文件的引用计数将降至零,最后将释放其磁盘上的块。

But, you might spent a fair amount of time re-creating zip files if many downloads get interrupted though. 但是,如果许多下载中断,您可能会花费相当多的时间重新创建zip文件。 Nice cheap optimization if you can get away with it. 很好的便宜优化, 如果你可以逃脱它。

Here's how I've been able to do it in the past. 以下是我过去的表现。 This code assumes you've written the files to a path specified by the $path variable. 此代码假定您已将文件写入$path变量指定的$path You might have to deal with some permissions issues on your server configuration with using php's exec 您可能必须使用php的exec处理服务器配置上的一些权限问题

 // write the files you want to zip up
file_put_contents($path . "/file", $output);

// zip up the contents
chdir($path);
exec("zip -r {$name} ./");

$filename = "{$name}.zip";

header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.urlencode($filename));
header('Content-Transfer-Encoding: binary');

readfile($filename);

Enable your php_curl extension; 启用php_curl扩展名; (php.ini),Then use the below code to create the zip. (php.ini),然后使用下面的代码创建zip。 create a folder class and use the code given below: 创建一个文件夹类并使用下面给出的代码:

<?php 
    include("class/create_zip.php");
    $create_zip     =   new create_zip();
    //$url_path,$url_path2 you can use your directory path
            $urls = array(
                 '$url_path/file1.pdf',         
                 '$url_path2/files/files2.pdf'
                 ); // file paths 


            $file_name      =   "vin.zip";   // zip file default name
            $file_folder    =   rand(1,1000000000); // folder with random name
            $create_zip->create_zip($urls,$file_folder,$file_name);  
            $create_zip->delete_directory($file_folder);  //delete random folder 

            if(file_exists($file_name)){
             $temp = file_get_contents($file_name);     
             unlink($file_name); 
            }       

            echo $temp;

    ?>

create a folder class and use the code given below: 创建一个文件夹类并使用下面给出的代码:

<?php

    class create_zip{

        function create_zip($urls,$file_folder,$file_name){

            header('Content-Type: application/octet-stream'); 
            header('Content-Disposition: attachment; filename='.$file_name); 
            header('Content-Transfer-Encoding: binary');

                $mkdir  =   mkdir($file_folder); 

                $zip    = new ZipArchive;
                $zip->open($file_name, ZipArchive::CREATE); 

                foreach ($urls as $url)
                {
                     $path=pathinfo($url);     
                     $path = $file_folder.'/'.$path['basename'];
                     $zip->addFile($path);     
                     $fileopen = fopen($path, 'w');     
                     $init = curl_init($url);     
                     curl_setopt($init, CURLOPT_FILE, $fileopen);     
                     $data = curl_exec($init);     
                     curl_close($init);     
                     fclose($fileopen); 
                } 

                $zip->close();


            }

            function delete_directory($dirname) 
            {
                if (is_dir($dirname))
                $dir_handle = opendir($dirname); 
                if (!$dir_handle)
                return false;
                    while($file = readdir($dir_handle))
                    {
                        if ($file != "." && $file != "..") 
                        {
                            if (!is_dir($dirname."/".$file))             
                            unlink($dirname."/".$file);          
                            else            
                            delete_directory($dirname.'/'.$file);           
                        }    
                    }
                closedir($dir_handle);    
                rmdir($dirname);    
                return true; 
            }



    }

    ?>

I went there looking for a similar solution, and after reading the comments found this turnover : before creating your zip file in a dedicated folder (here called 'zip_files', delete all zip you estimate being older than a reasonable time (I took 24h) : 我去那里寻找类似的解决方案,并在阅读评论后发现这个营业额:在专用文件夹中创建你的zip文件之前(这里称为'zip_files',删除你估计比合理时间早的所有邮政编码(我花了24小时) :

$dossier_zip='zip_files';   
    if(is_dir($dossier_zip))
        {
        $t_zip=$dossier_zip.'/*.zip'; #this allow you to let index.php, .htaccess and other stuffs...
        foreach(glob($t_zip) as $old_zip)
            {
            if(is_file($old_zip) and filemtime($old_zip)<time()-86400)
                {
                unlink($old_zip);
                }
            }

        $zipname=$dossier_zip.'/whatever_you_want_but_dedicated_to_your_user.zip';
        if(is_file($zipname))
            {
            unlink($zipname); #to avoid mixing 2 archives
            }

        $zip=new ZipArchive;
#then do your zip job

By doing so, after 24h you only have the last zips created, user by user. 通过这样做,在24小时后,您只能按用户创建最后一个拉链。 Nothing prevents you for doing a clean by cron task sometimes, but the problem with the cron task is if someone is using the zip archive when the cron is executed it will lead to an error. 没有什么能阻止你有时通过cron任务进行清理,但是cron任务的问题是如果有人在执行cron时使用zip存档会导致错误。 Here the only possible error is if someone waits 24h to DL the archive. 这里唯一可能的错误是如果有人等待24小时到存档的DL。

Firstly, you download images from webiste 首先,您从网站下载图像

then, with the files you have downloaded you creatae zipfile (great tute) 然后,你下载的文件你creatae zipfile (伟大的tute)

finally you sent this zip file to browser using readfile and headers (see Example 1) 最后你使用readfile和headers将这个zip文件发送到浏览器(参见例1)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM