예제 #1
0
 /**
  * @param $directory
  *  The directory to extract the files to.
  * @return bool
  * @throws \BackupMigrate\Core\Exception\BackupMigrateException
  */
 private function extractAllToDirectory($directory)
 {
     clearstatcache();
     // Read a header block
     while (strlen($block = $this->archive->readBytes(512)) != 0) {
         $header = $this->readHeader($block);
         if (!$header) {
             return false;
         }
         if ($header['filename'] == '') {
             continue;
         }
         // Check for potentially malicious files (containing '..' etc.).
         if ($this->maliciousFilename($header['filename'])) {
             throw new BackupMigrateException('Malicious .tar detected, file %filename. Will not install in desired directory tree', ['%filename' => $header['filename']]);
         }
         // ignore extended / pax headers
         if ($header['typeflag'] == 'x' || $header['typeflag'] == 'g') {
             $this->archive->seekBytes(ceil($header['size'] / 512));
             continue;
         }
         // Add the destination directory to the path.
         if (substr($header['filename'], 0, 1) == '/') {
             $header['filename'] = $directory . $header['filename'];
         } else {
             $header['filename'] = $directory . '/' . $header['filename'];
         }
         // If the file already exists, make sure we can overwrite it.
         if (file_exists($header['filename'])) {
             // Cannot overwrite a directory with a file.
             if (@is_dir($header['filename']) && $header['typeflag'] == '') {
                 throw new BackupMigrateException('File %filename already exists as a directory', ['%filename' => $header['filename']]);
             }
             // Cannot overwrite a file with a directory.
             if (@is_file($header['filename']) && !@is_link($header['filename']) && $header['typeflag'] == "5") {
                 throw new BackupMigrateException('Directory %filename already exists as file', ['%filename' => $header['filename']]);
             }
             // Cannot overwrite a read-only file.
             if (!is_writeable($header['filename'])) {
                 throw new BackupMigrateException('File %filename already exists and is write protected', ['%filename' => $header['filename']]);
             }
         }
         // Extract a directory
         if ($header['typeflag'] == "5") {
             if (!$this->createDir($header['filename'])) {
                 throw new BackupMigrateException('Unable to create directory %filename', ['%filename' => $header['filename']]);
             }
         } else {
             if (!$this->createDir(dirname($header['filename']))) {
                 throw new BackupMigrateException('Unable to create directory for %filename', ['%filename' => $header['filename']]);
             }
             // Symlink
             if ($header['typeflag'] == "2") {
                 if (@file_exists($header['filename'])) {
                     @unlink($header['filename']);
                 }
                 if (!@symlink($header['link'], $header['filename'])) {
                     throw new BackupMigrateException('Unable to extract symbolic link: %filename', ['%filename' => $header['filename']]);
                 }
             } else {
                 // Open the file for writing.
                 if (($dest_file = @fopen($header['filename'], "wb")) == 0) {
                     throw new BackupMigrateException('Error while opening %filename in write binary mode', ['%filename' => $header['filename']]);
                 }
                 // Write the file.
                 $n = floor($header['size'] / 512);
                 for ($i = 0; $i < $n; $i++) {
                     $content = $this->archive->readBytes(512);
                     fwrite($dest_file, $content, 512);
                 }
                 if ($header['size'] % 512 != 0) {
                     $content = $this->archive->readBytes(512);
                     fwrite($dest_file, $content, $header['size'] % 512);
                 }
                 @fclose($dest_file);
                 // Change the file mode, mtime
                 @touch($header['filename'], $header['mtime']);
                 if ($header['mode'] & 0111) {
                     // make file executable, obey umask
                     $mode = fileperms($header['filename']) | ~umask() & 0111;
                     @chmod($header['filename'], $mode);
                 }
                 clearstatcache();
                 // Check if the file exists.
                 if (!is_file($header['filename'])) {
                     throw new BackupMigrateException('Extracted file %filename does not exist. Archive may be corrupted.', ['%filename' => $header['filename']]);
                 }
                 // Check the file size
                 $file_size = filesize($header['filename']);
                 if ($file_size != $header['size']) {
                     throw new BackupMigrateException('Extracted file %filename does not have the correct file size. File is %actual bytes (%expected bytes expected). Archive may be corrupted', ['%filename' => $header['filename'], '%expected' => (int) $header['size'], (int) '%actual' => $file_size]);
                 }
             }
         }
     }
     return true;
 }