Temat o tyle aktualny, o ile tylko potrzeba nam uzupełnić ściąganie plików o ściąganie zbiorcze, ściąganie całego katalogu i tym podobnych. Cel już znamy, a przyczyna przed nami. „W locie” znaczy tyle, co skompresuj, prześlij i spraw by po archiwum nie było śladu w systemie. Na pewno znajdziecie w Internecie na ten temat wiele wywodów, prób rozwiązań, a nawet rozwiązań. Tyle tylko, że nie każde rozwiązanie można uznać za kompletne, a i niejedno nie działa. Takie uroki globalnej sieci – można wrzucić wszystko, nikt tego nie sprawdza, „cenzuruje” – wolność słowa.

ZipArchive

Za pewien wzór będzie nam służyć rozwiązanie podane przez Filipa Klara. Pozwala osiągnąć cel, ale być może jest to uwarunkowane systemem operacyjnym, a być może wersją PHP. Nie wnikam, ale przynajmniej sam, wykorzystując PHP 5.4.7 na systemie Windows 7, musiałem się zmierzyć z problemem przesyłania pustego archiwum. Dla jasności – archiwum miało zawierać pliki z określonego folderu, a jednak, wykorzystując opisaną na blogu Filipa metodą, otrzymywałem puste archiwum. Podobny problem miał także Krzysztof Szeremeta (patrz komentarze na w/w blogu) i nie otrzymał rozwiązania.

Muszę przyznać iż mimo przejrzenia niezliczonej treści w sieci, skutecznego rozwiązania nie mogłem znaleźć. Zatem trzeba było „wydumać” rozwiązanie samemu – czyli to, co tygryski lubią najbardziej 🙂

Po pewnym czasie i sprawdzeniu kilku pomysłów nastąpiło oświecenie – oświecenie podczas analizy funkcji scandir. Metoda ta zwraca tablicę z plikami, które znajdują się wewnątrz skanowanego katalogu. Ale tablica ta zawiera też bonus – wpisy [„..”, „.”] – znany z systemów Unix’owych. Oczyszczenie wyniku z tych wpisów pozwala cieszyć się efektem generowanego archiwum z oczekiwaną zawartością.

„W locie”

Stworzenie archiwum pod określoną nazwą i ścieżką to nic trudnego. Trzeba się jeszcze jego pozbyć po wysyłce. Nie ma być po nim śladu, bowiem:

  • nie ma konieczności przechowywania (nie jest to krytyczny zasób)
  • mamy ograniczoną przestrzeń dyskową i dbamy o porządek

Często takie założenia nam przyświecają i wówczas warto chwilkę skupić się na funkcji PHP: tempnam.

string tempnam ( string $dir , string $prefix )

Creates a file with a unique filename, with access permission set to 0600, in the specified directory. If the directory does not exist, tempnam() may generate a file in the system’s temporary directory, and return the full path to that file, including its name.

Tak stworzony plik (późniejszy plik archiwum) można po przesłaniu usunąć wykorzystując metodę unlink. Po kłopocie.

Przykład

$outputPath = 'Y:\Test';
$uploadPath = 'Wynik.zip'; 
 
$file = tempnam("tmp", "zip");
$zip = new ZipArchive();
$zip->open($file, ZipArchive::OVERWRITE);

$dir = scandir($outputPath);
if(!empty($dir)) {
    $dir = array_diff($dir, array('.', '..'));
    foreach($dir as $f) {
        if(file_exists($outputPath.DIRECTORY_SEPARATOR.$f)) {
            $zip->addFile($outputPath.DIRECTORY_SEPARATOR.$f, $f);
        }
    }
}
$zip->close();
 
if(file_exists($file)) {
    log('Download data from: '.$outputPath.'. Download by user: '.$userId); //filled $userId

    header('Content-Type: application/zip');
    header('Content-Disposition: attachment; filename='.basename($uploadPath));
    header('Content-Length: ' . filesize($file));
    readfile($file);
    unlink($file);
}
else {
    throw new Exception('Bad request'); //or http exception (400)
}

 
Pozdrawiam!