Aaron van Geffen
1b7e83e11e
This prevents edge cases where files are not found, while ensuring the archive does not contain the system directory hierarchy.
97 lines
2.4 KiB
PHP
97 lines
2.4 KiB
PHP
<?php
|
|
/*****************************************************************************
|
|
* Download.php
|
|
* Contains the code to download an album.
|
|
*
|
|
* Kabuki CMS (C) 2013-2019, Aaron van Geffen
|
|
*****************************************************************************/
|
|
|
|
class Download
|
|
{
|
|
public function __construct()
|
|
{
|
|
// Ensure we're logged in at this point.
|
|
$user = Registry::get('user');
|
|
if (!$user->isLoggedIn())
|
|
throw new NotAllowedException();
|
|
|
|
if (!isset($_GET['tag']))
|
|
throw new UserFacingException('No album or tag has been specified for download.');
|
|
|
|
$tag = (int)$_GET['tag'];
|
|
$album = Tag::fromId($tag);
|
|
|
|
if (isset($_SESSION['current_export']))
|
|
throw new UserFacingException('An export of "' . $tag->tag . '" is ongoing. Please try again later.');
|
|
|
|
// So far so good?
|
|
$this->exportAlbum($album);
|
|
exit;
|
|
}
|
|
|
|
private function exportAlbum(Tag $album)
|
|
{
|
|
$files = [];
|
|
|
|
$album_ids = array_merge([$album->id_tag], $this->getChildAlbumIds($album->id_tag));
|
|
foreach($album_ids as $album_id)
|
|
{
|
|
$iterator = AssetIterator::getByOptions(['id_tag' => $album_id]);
|
|
while ($asset = $iterator->next())
|
|
$files[] = join(DIRECTORY_SEPARATOR, [$asset->getSubdir(), $asset->getFilename()]);
|
|
}
|
|
|
|
$descriptorspec = [
|
|
0 => ['pipe', 'r'],
|
|
1 => ['pipe', 'w'],
|
|
];
|
|
|
|
$command = 'tar -cf - -C ' . escapeshellarg(ASSETSDIR) . ' --null -T -';
|
|
|
|
$proc = proc_open($command, $descriptorspec, $pipes, ASSETSDIR);
|
|
|
|
if(!$proc)
|
|
throw new UnexpectedValueException('Could not execute TAR command');
|
|
|
|
if(!$pipes[0])
|
|
throw new UnexpectedValueException('Could not open pipe for STDIN');
|
|
|
|
if(!$pipes[1])
|
|
throw new UnexpectedValueException('Could not open pipe for STDOUT');
|
|
|
|
$album_name = $album->tag;
|
|
|
|
header('Pragma: no-cache');
|
|
header('Content-Description: File Download');
|
|
header('Content-disposition: attachment; filename="' . $album_name . '.tar"');
|
|
header('Content-Type: application/octet-stream');
|
|
header('Content-Transfer-Encoding: binary');
|
|
|
|
foreach($files as $file)
|
|
fwrite($pipes[0], $file . "\0");
|
|
|
|
fclose($pipes[0]);
|
|
|
|
while($chunk = stream_get_contents($pipes[1], 4096))
|
|
echo $chunk;
|
|
|
|
fclose($pipes[1]);
|
|
|
|
proc_close($proc);
|
|
}
|
|
|
|
private function getChildAlbumIds($parent_id)
|
|
{
|
|
$ids = [];
|
|
|
|
$albums = Tag::getAlbums($parent_id, 0, PHP_INT_MAX, 'object');
|
|
foreach($albums as $album)
|
|
{
|
|
$ids[] = $album->id_tag;
|
|
$ids = array_merge($ids, $this->getChildAlbumIds($album->id_tag));
|
|
}
|
|
|
|
return $ids;
|
|
}
|
|
}
|