Skip to content
Snippets Groups Projects
DownloadFileAction.php 3.5 KiB
Newer Older
  • Learn to ignore specific revisions
  • François Agneray's avatar
    François Agneray committed
    <?php
    
    /*
     * This file is part of Anis Server.
     *
     * (c) Laboratoire d'Astrophysique de Marseille / CNRS
     *
     * For the full copyright and license information, please view the LICENSE
     * file that was distributed with this source code.
     */
    declare(strict_types=1);
    
    namespace App\Action;
    
    use Psr\Http\Message\ServerRequestInterface as Request;
    use Psr\Http\Message\ResponseInterface as Response;
    use Doctrine\ORM\EntityManagerInterface;
    use Slim\Exception\HttpNotFoundException;
    use Nyholm\Psr7\Factory\Psr17Factory;
    
    /**
     * @author François Agneray <francois.agneray@lam.fr>
     * @package App\Action
     */
    final class DownloadFileAction extends AbstractAction
    {
        /**
         * Contains anis-server data path
         *
         * @var string
         */
        private $dataPath;
    
        /**
         * Contains settings to handle Json Web Token
         *
         * @var array
         */
        private $settings;
    
        /**
         * Create the classe before call __invoke to execute the action
         *
         * @param EntityManagerInterface $em       Doctrine Entity Manager Interface
         * @param string                 $dataPath Contains anis-server data path
         * @param array                  $settings Settings about token
         */
        public function __construct(EntityManagerInterface $em, string $dataPath, array $settings)
        {
            parent::__construct($em);
            $this->dataPath = $dataPath;
            $this->settings = $settings;
        }
    
        /**
         * `GET` Returns the file found
         *
         * @param  ServerRequestInterface $request  PSR-7 This object represents the HTTP request
         * @param  ResponseInterface      $response PSR-7 This object represents the HTTP response
         * @param  string[]               $args     This table contains information transmitted in the URL (see routes.php)
         *
         * @return ResponseInterface
         */
        public function __invoke(Request $request, Response $response, array $args): Response
        {
            if ($request->getMethod() === OPTIONS) {
                return $response->withHeader('Access-Control-Allow-Methods', 'GET, OPTIONS');
            }
    
            // Search the correct dataset with primary key
            $datasetName = $args['dname'];
            $dataset = $this->em->find('App\Entity\Dataset', $datasetName);
    
            // If dataset is not found 404
            if (is_null($dataset)) {
                throw new HttpNotFoundException(
                    $request,
                    'Dataset with name ' . $datasetName . ' is not found'
                );
            }
    
            // If dataset is private and authorization enabled
            if (!$dataset->getPublic() && boolval($this->settings['enabled'])) {
                $this->verifyDatasetAuthorization($request, $dataset->getName(), $this->settings['admin_role']);
            }
    
            // Search the file
    
            $filePath = $this->dataPath . $dataset->getFullDataPath() . DIRECTORY_SEPARATOR . $args['fpath'];
    
    François Agneray's avatar
    François Agneray committed
    
            // If the file not found 404
            if (!file_exists($filePath)) {
                throw new HttpNotFoundException(
                    $request,
                    'File with path ' . $args['fpath'] . ' is not found for the dataset ' . $datasetName
                );
            }
    
            // If the file found so stream it
            $psr17Factory = new Psr17Factory();
            $stream = $psr17Factory->createStreamFromFile($filePath, 'r');
    
            return $response->withBody($stream)
                ->withHeader('Content-Disposition', 'attachment; filename=' . basename($filePath) . ';')
                ->withHeader('Content-Type', mime_content_type($filePath))
                ->withHeader('Content-Length', filesize($filePath));
        }
    }