pics/controllers/Download.php
Aaron van Geffen 1b7e83e11e Let tar change working directory to assets directory.
This prevents edge cases where files are not found, while ensuring
the archive does not contain the system directory hierarchy.
2020-03-11 12:32:34 +01:00

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;
}
}