use Cli\Services\EnvironmentLoader;
use Cli\Services\MySqlRunner;
use Cli\Services\Paths;
+use FilesystemIterator;
use RecursiveDirectoryIterator;
use SplFileInfo;
use Symfony\Component\Console\Command\Command;
*/
protected function addFolderToZipRecursive(ZipArchive $zip, string $dirPath, string $targetZipPath): void
{
- $dirIter = new RecursiveDirectoryIterator($dirPath);
+ $dirIter = new RecursiveDirectoryIterator(
+ $dirPath,
+ FilesystemIterator::KEY_AS_PATHNAME | FilesystemIterator::CURRENT_AS_FILEINFO | FilesystemIterator::FOLLOW_SYMLINKS
+ );
$fileIter = new \RecursiveIteratorIterator($dirIter);
/** @var SplFileInfo $file */
foreach ($fileIter as $file) {
if (!$file->isDir()) {
- $zip->addFile($file->getPathname(), $targetZipPath . '/' . $fileIter->getSubPathname());
+ $zip->addFile($file->getRealPath(), $targetZipPath . '/' . $fileIter->getSubPathname());
}
}
}
static::getCliDirectory(),
];
- var_dump($directoriesToSearch);
-
foreach ($directoriesToSearch as $directory) {
if ($directory && static::isProbablyAppDirectory($directory)) {
return $directory;
-<?php
+<?php declare(strict_types=1);
namespace Cli\Services;
+use FilesystemIterator;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
/** @var RecursiveDirectoryIterator $files */
$files = new RecursiveIteratorIterator(
- new RecursiveDirectoryIterator($src, RecursiveDirectoryIterator::SKIP_DOTS),
+ new RecursiveDirectoryIterator($src, FilesystemIterator::SKIP_DOTS | FilesystemIterator::FOLLOW_SYMLINKS),
RecursiveIteratorIterator::SELF_FIRST
);
public static function delete(string $dir): void
{
$files = new RecursiveIteratorIterator(
- new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS),
+ new RecursiveDirectoryIterator($dir, FilesystemIterator::SKIP_DOTS | FilesystemIterator::FOLLOW_SYMLINKS),
RecursiveIteratorIterator::CHILD_FIRST
);
unlink($zipFile);
}
+ public function test_command_resolves_nested_symlinks()
+ {
+ $symDirs = ['storage/uploads/files', 'storage/uploads/images'];
+ exec('cp -r /var/www/bookstack /var/www/bookstack-symlink-backup');
+ mkdir('/symlinks');
+ foreach ($symDirs as $dir) {
+ $targetFile = str_replace('/', '-', $dir);
+ $code = 0;
+ $output = null;
+ exec("mkdir -p /var/www/bookstack-symlink-backup/{$dir}", $output, $code);
+ exec("mv /var/www/bookstack-symlink-backup/{$dir} /symlinks/{$targetFile}", $output, $code);
+ exec("ln -s /symlinks/{$targetFile} /var/www/bookstack-symlink-backup/{$dir}", $output, $code);
+ file_put_contents("/symlinks/{$targetFile}/test.txt", "Hello from $dir");
+ if ($code !== 0) {
+ $this->fail("Error when setting up symlinks");
+ }
+ }
+
+ chdir('/var/www/bookstack-symlink-backup');
+ $this->assertCount(0, glob('storage/backups/bookstack-backup-*.zip'));
+ $result = $this->runCommand('backup');
+ $result->assertSuccessfulExit();
+ $this->assertCount(1, glob('storage/backups/bookstack-backup-*.zip'));
+ $zipFile = glob('storage/backups/bookstack-backup-*.zip')[0];
+
+ $zip = new \ZipArchive();
+ $zip->open($zipFile);
+ foreach ($symDirs as $dir) {
+ $fileData = $zip->getFromName("{$dir}/test.txt");
+ $this->assertNotFalse($fileData);
+ $this->assertStringContainsString("Hello from {$dir}", $fileData);
+ }
+ $zip->close();
+
+ exec('rm -rf /symlinks');
+ exec('rm -rf /var/www/bookstack-symlink-backup');
+ }
+
}
\ No newline at end of file
$this->assertStringEqualsFile('/var/www/bookstack-symlink-restore/themes/test.txt', 'hello-themes');
exec('rm -rf /var/www/bookstack-symlink-restore');
+ exec('rm -rf /symlinks');
}
protected function buildZip(callable $builder): string