pics/controllers/Download.php
Aaron van Geffen 354e54a0af Limit album/tag downloading on a user basis.
This removes the limit of downloading albums only; tags are fine, too.

Now using UserFacingException for certain exceptions, as these are
displayed to the user.

Removing the inheritance of HTMLController, as we intend to output binary
data only.
2020-03-11 11:55:17 +01:00

103 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($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 --null -cf - -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;
}
}