2015-09-12 2 views
0

Я хочу создать zip-файл и скопировать все папки и файлы из каталога в него. Он успешно создан и содержит файлы и папки, но дерево файлов не сохраняется, все находится в корневом каталоге.Сохраните структуру папок при создании архива Zip

Мой каталог:

folder/ 
    test.txt 
    test2.txt 
test.php 

архив ZIP:

folder/ 
test.txt 
test2.txt 
test.php 

Это мой код:

public function createZipFromDir($dir, $zip_file) { 
    $zip = new ZipArchive(); 
    if(true !== $zip->open($zip_file, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE)) { 
     return false; 
    } 

    $this->zipDir($dir, $zip); 
    return $zip; 
} 

public function zipDir($dir, $zip) { 
    $dir = rtrim($dir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR; 
    $files = scandir($dir); 
    foreach($files as $file) { 
     if(in_array($file, array('.', '..'))) continue; 
     if(is_dir($dir . $file)) { 
      $zip->addEmptyDir($file); 
      $this->zipDir($dir . $file, $zip); 
     } else { 
      $zip->addFile($dir . $file, $file); 
     } 
    } 
} 

$zip = $this->createZipFromDir($rootPath, $archiveName); 

ответ

0

Вопрос заключается в том, что при создании папки или установить localname (второй аргумент addFile()) при добавлении файла в архив, вы используете только $file, поэтому все попадает в корень. Также необходимо предоставить иерархию файлов.

Теперь очевидным решением было бы использовать $dir.$file, но это будет работать только в папке, расположенной в том же каталоге, что и скрипт.

Мы на самом деле нужно следить за двух файловых деревьев:

  • реальное дерево, как она существует на машине
  • дерево архива, относительно пути, который мы хотим архивировать

Но так как один только подмножество других, мы можем легко отслеживать, что разделив реальный путь в два:

  • $dir, префикс, указывающий на оригинальный путь
  • $subdir, путь относительно $dir

При обращении к файлу на компьютере, мы используем $dir.$subdir и при обращении к файлу в архиве мы используем только $subdir. Это требует от нас адаптации zipDir(), чтобы отслеживать префикс, добавив к нему третий аргумент и слегка изменив вызов на zipDir() в createZipFromDir().

function createZipFromDir($dir, $zip_file) { 
    $zip = new ZipArchive(); 
    if(true !== $zip->open($zip_file, ZIPARCHIVE::CREATE | ZIPARCHIVE::OVERWRITE)) { 
     return false; 
    } 

    zipDir(
     // base dir, note we use a trailing separator from now on 
     rtrim($dir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR, 
     // subdir, empty on initial call 
     null, 
     // archive ref 
     $zip 
    ); 
    return $zip; 
} 

function zipDir($dir, $subdir, $zip) { 

    // using real path 
    $files = scandir($dir.$subdir); 

    foreach($files as $file) { 

     if(in_array($file, array('.', '..'))) 
      continue; 

     // check dir using real path 
     if(is_dir($dir.$subdir.$file)) { 

      // create folder using relative path 
      $zip->addEmptyDir($subdir.$file); 

      zipDir(
       $dir,        // remember base dir 
       $subdir.$file.DIRECTORY_SEPARATOR, // relative path, don't forget separator 
       $zip        // archive 
      ); 
     } 

     // file 
     else { 
      // get real path, set relative path 
      $zip->addFile($dir.$subdir.$file, $subdir.$file); 
     } 
    } 
} 

Этот код был протестирован и работает.

Смежные вопросы