forked from Public/pics
		
	
		
			
				
	
	
		
			123 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			123 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
/*****************************************************************************
 | 
						|
 * Download.php
 | 
						|
 * Contains the code to download an album.
 | 
						|
 *
 | 
						|
 * Kabuki CMS (C) 2013-2019, Aaron van Geffen
 | 
						|
 *****************************************************************************/
 | 
						|
 | 
						|
class Download extends HTMLController
 | 
						|
{
 | 
						|
	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 UnexpectedValueException('Must specify an album to download');
 | 
						|
 | 
						|
		$tag = (int)$_GET['tag'];
 | 
						|
		$album = Tag::fromId($tag);
 | 
						|
 | 
						|
		if($album->kind !== 'Album')
 | 
						|
			throw new UnexpectedValueException('Specified tag does not correspond to an album');
 | 
						|
 | 
						|
		//Yes TOCTOU but it does not need to be perfect.
 | 
						|
		$lock_file = join('/', [sys_get_temp_dir(), 'pics-export.lock']);
 | 
						|
		if(!file_exists($lock_file))
 | 
						|
		{
 | 
						|
			try
 | 
						|
			{
 | 
						|
				$fp = fopen($lock_file, 'x');
 | 
						|
 | 
						|
				if(!$fp)
 | 
						|
					throw new UnexpectedValueException('Could not open lock-file');
 | 
						|
 | 
						|
				$this->exportAlbum($album);
 | 
						|
			}
 | 
						|
			finally
 | 
						|
			{
 | 
						|
				fclose($fp);
 | 
						|
				unlink($lock_file);
 | 
						|
			}
 | 
						|
		}
 | 
						|
		else
 | 
						|
			throw new UnexpectedValueException('Another export is busy, please try again later');
 | 
						|
 | 
						|
		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;
 | 
						|
	}
 | 
						|
}
 |