web-dev-qa-db-ja.com

PHPを使用してZipファイルを作成し、ユーザーがダウンロードした後にそれを削除する方法は?

他のウェブサイトからサーバーに画像をダウンロードする必要があります。それらの画像でZipファイルを作成します。作成されたZipファイルのダウンロードを自動的に開始します。ダウンロードが完了すると、Zipファイルと画像がサーバーから削除されます。

自動ダウンロードの代わりに、ダウンロードリンクでもかまいません。しかし、他のロジックは同じままです。

18
Joby Joseph

ZipArchive クラスを使用して、まずzipファイルを作成する必要があります。

次に、送信します:

  • 正しいヘッダー。ブラウザに何かをZipとしてダウンロードする必要があることを示します-header()を参照してください-例があります役立つはずのそのマニュアルのページ
  • readfile() を使用したZipファイルの内容

最後に、 unlink() を使用して、サーバーからZipファイルを削除します。


注:セキュリティ上の予防措置として、PHPスクリプトを自動的に実行する(crontabによって、通常は)]にすると、一時ディレクトリにある古いZipファイル。

これは、通常のPHPスクリプトが時々中断され、一時ファイルが削除されない場合に備えてです。

22
Pascal MARTIN
<?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();
}

?>
14
Mahesh Ambig

どのくらいの数のZipファイルのダウンロードが中断され、続行する必要があるか考えていますか?

ダウンロードの継続がダウンロードのごく一部である場合は、Zipファイルをすぐに削除できます。サーバーがファイルをクライアントに送信している限り、ディスクに残ります。

サーバーがファイル記述子を閉じると、ファイルの参照カウントがゼロになり、最後にディスク上のブロックが解放されます。

ただし、多くのダウンロードが中断された場合、Zipファイルの再作成にかなりの時間を費やす可能性があります。ニースの安価な最適化ifあなたはそれでうまくいくことができます。

3
sarnold

その他の解決策:新しい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
    }
3
Intacto

これが私が過去にそれを行うことができた方法です。このコードは、$path変数で指定されたパスにファイルを書き込んだことを前提としています。 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);
2
Eric Conner

Php_curl拡張機能を有効にします。 (php.ini)、次に以下のコードを使用してZipを作成します。フォルダークラスを作成し、以下のコードを使用します。

<?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;

    ?>

フォルダークラスを作成し、以下のコードを使用します。

<?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; 
            }



    }

    ?>
1

私は同様の解決策を探してそこに行き、コメントを読んだ後、このターンオーバーを見つけました:専用フォルダーにZipファイルを作成する前に(ここでは「Zip_files」と呼ばれます)、妥当な時間より古いと推定されるすべてのZipを削除します(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

そうすることで、24時間後にユーザーごとに最後のzipのみが作成されます。 cronタスクによるクリーンアップを妨げるものはありませんが、cronタスクの問題は、誰かがcronの実行時にZipアーカイブを使用している場合にエラーが発生することです。ここで唯一考えられるエラーは、誰かがアーカイブを24時間待つDLである場合です。

0
Romain Bel