<?php
declare(strict_types=1);
/*
* This file is part of eSales Media SinglereisenBundle
*
* (c) Benjamin Roth
*
* @license proprietary
*/
namespace vonRotenberg\MemberfilesBundle\Controller\Frontend\ContentElement;
use Contao\BackendTemplate;
use Contao\Config;
use Contao\ContentModel;
use Contao\Controller;
use Contao\CoreBundle\Controller\ContentElement\AbstractContentElementController;
use Contao\CoreBundle\ServiceAnnotation\ContentElement;
use Contao\Environment;
use Contao\File;
use Contao\FilesModel;
use Contao\FrontendUser;
use Contao\Image;
use Contao\Input;
use Contao\StringUtil;
use Contao\System;
use Contao\Template;
use Doctrine\DBAL\Connection;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Contracts\Translation\TranslatorInterface;
use vonRotenberg\MemberfilesBundle\Model\SecureDownloadsModel;
/**
* @ContentElement(SecureDownloadsController::TYPE, category="files")
*/
class SecureDownloadsController extends AbstractContentElementController
{
public const TYPE = 'secure_downloads';
/** @var Connection */
protected $db;
protected $User;
public function __construct(Connection $db)
{
$this->db = $db;
$this->User = FrontendUser::getInstance();
}
public function __invoke(Request $request, ContentModel $model, string $section, array $classes = null): Response
{
if (System::getContainer()->get('contao.routing.scope_matcher')->isBackendRequest($request)) {
return $this->getBackendWildcard($model);
}
return parent::__invoke($request, $model, $section, $classes); // TODO: Change the autogenerated stub
}
protected function getResponse(Template $template, ContentModel $model, Request $request): Response
{
// The module is only accessible for authenticated members
if (!System::getContainer()->get('contao.security.token_checker')->hasFrontendUser())
{
return new Response('',403);
}
// Handle file requests
if (
($path = Input::get('file', true)) !== null
&& ($File = FilesModel::findByPath($path)) !== null
&& ($SecFile = $SecFile = SecureDownloadsModel::findBy(["uuid = ?"],[$File->uuid])) !== null
)
{
if ($SecFile->pid == $this->User->id)
{
$this->db->update('tl_member_secureDownloads', ['opened' => time()], ['id' => $SecFile->id]);
Controller::sendFileToBrowser($path);
} else {
return new Response('',403);
}
}
// Get member files for authenticated user
$strLocale = $request->getLocale();
$allowedDownload = StringUtil::trimsplit(',', strtolower(\Config::get('allowedDownload')));
$UserFiles = $this->db->executeQuery("SELECT uuid FROM tl_member_secureDownloads WHERE pid = ?",[$this->User->id]);
// Return if there are no files
if ($UserFiles->rowCount() < 1)
{
return new Response();
}
$arrUuid = $UserFiles->fetchFirstColumn();
if (($objFiles = FilesModel::findMultipleByUuids($arrUuid)) === null)
{
return new Response();
}
while ($objFiles->next())
{
// Continue if the files has been processed or does not exist
if (isset($files[$objFiles->path]) || !file_exists(TL_ROOT . '/' . $objFiles->path))
{
continue;
}
// Single files
$SecureFile = SecureDownloadsModel::findBy(["uuid = ?"],[$objFiles->uuid]);
if ($objFiles->type == 'file')
{
$File = new File($objFiles->path);
if (!in_array($File->extension, $allowedDownload) || preg_match('/^meta(_[a-z]{2})?\.txt$/', $File->basename))
{
continue;
}
$arrMeta = $objFiles->current()->getMetaData($strLocale);
if (empty($arrMeta))
{
if ($model->metaIgnore)
{
continue;
}
elseif (($arrMeta = $objFiles->current()->getMetaData('en')) === null || $arrMeta === null)
{
$arrMeta = [];
}
}
// Use the file name as title if none is given
if (empty($arrMeta['title']))
{
$arrMeta['title'] = StringUtil::specialchars($File->basename);
}
$strHref = Environment::get('request');
// Remove an existing file parameter (see #5683)
if (preg_match('/(&(amp;)?|\?)file=/', $strHref))
{
$strHref = preg_replace('/(&(amp;)?|\?)file=[^&]+/', '', $strHref);
}
$strHref .= ((Config::get('disableAlias') || strpos($strHref, '?') !== false) ? '&' : '?') . 'file=' . System::urlEncode($objFiles->path);
// Add the image
$files[$objFiles->path] = array
(
'id' => $objFiles->id,
'uuid' => $objFiles->uuid,
'name' => $File->basename,
'title' => StringUtil::specialchars(sprintf($GLOBALS['TL_LANG']['MSC']['download'], $File->basename)),
'link' => $arrMeta['title'] ?? '',
'caption' => $arrMeta['caption'] ?? '',
'href' => $strHref,
'filesize' => System::getReadableSize($File->filesize, 1),
'icon' => Image::getPath($File->icon),
'mime' => $File->mime,
'meta' => $arrMeta,
'extension' => $File->extension,
'path' => $File->dirname,
'mtime' => $File->mtime,
'opened' => ($SecureFile !== null ? $SecureFile->opened : 0)
);
$auxDate[] = $File->mtime;
}
// Folders
else
{
$objSubfiles = FilesModel::findByPid($objFiles->uuid);
if ($objSubfiles === null)
{
continue;
}
while ($objSubfiles->next())
{
// Skip subfolders
if ($objSubfiles->type == 'folder')
{
continue;
}
$File = new File($objSubfiles->path);
if (!in_array($File->extension, $allowedDownload) || preg_match('/^meta(_[a-z]{2})?\.txt$/', $File->basename))
{
continue;
}
$arrMeta = $objSubfiles->current()->getMetaData($strLocale);
if (empty($arrMeta))
{
if ($model->metaIgnore)
{
continue;
}
elseif (($arrMeta = $objSubfiles->current()->getMetaData('en')) === null || $arrMeta === null)
{
$arrMeta = [];
}
}
// Use the file name as title if none is given
if (empty($arrMeta['title']))
{
$arrMeta['title'] = StringUtil::specialchars($File->basename);
}
$strHref = Environment::get('request');
// Remove an existing file parameter (see #5683)
if (preg_match('/(&(amp;)?|\?)file=/', $strHref))
{
$strHref = preg_replace('/(&(amp;)?|\?)file=[^&]+/', '', $strHref);
}
$strHref .= ((Config::get('disableAlias') || strpos($strHref, '?') !== false) ? '&' : '?') . 'file=' . System::urlEncode($objSubfiles->path);
// Add the image
$files[$objSubfiles->path] = array
(
'id' => $objSubfiles->id,
'uuid' => $objSubfiles->uuid,
'name' => $File->basename,
'title' => StringUtil::specialchars(sprintf($GLOBALS['TL_LANG']['MSC']['download'], $File->basename)),
'link' => $arrMeta['title'] ?? '',
'caption' => $arrMeta['caption'] ?? '',
'href' => $strHref,
'filesize' => System::getReadableSize($File->filesize, 1),
'icon' => Image::getPath($File->icon),
'mime' => $File->mime,
'meta' => $arrMeta,
'extension' => $File->extension,
'path' => $File->dirname,
'opened' => ($SecureFile !== null ? $SecureFile->opened : 0)
);
$auxDate[] = $File->mtime;
}
}
}
// Sort array
switch ($model->sortBy)
{
default:
case 'name_asc':
uksort($files, 'basename_natcasecmp');
break;
case 'name_desc':
uksort($files, 'basename_natcasercmp');
break;
case 'date_asc':
array_multisort($files, SORT_NUMERIC, $auxDate, SORT_ASC);
break;
case 'date_desc':
array_multisort($files, SORT_NUMERIC, $auxDate, SORT_DESC);
break;
case 'random':
shuffle($files);
break;
}
$template->files = array_values($files);
return $template->getResponse();
}
protected function getBackendWildcard(ContentModel $element): Response
{
$href = $this->container->get('router')->generate(
'contao_backend',
['do' => 'themes', 'table' => 'tl_module', 'act' => 'edit', 'id' => $element->id]
);
$name = $this->container->get('translator')->trans('FMD.'.$this->getType().'.0', [], 'contao_modules');
$template = new BackendTemplate('be_wildcard');
$template->wildcard = '### '.strtoupper($name).' ###';
$template->id = $element->id;
$template->link = $element->name;
$template->href = $href;
return new Response($template->parse());
}
public static function getSubscribedServices(): array
{
$services = parent::getSubscribedServices();
$services['translator'] = TranslatorInterface::class;
return $services;
}
}