<?php
namespace App\PromemoriaBundle\Controller;
use Pimcore\Db;
use Pimcore\File;
use Pimcore\Tool;
use Pimcore\Model\User;
use Pimcore\Security\User\User as UserAdmin;
use Pimcore\Model\Asset;
use Pimcore\Tool\Session;
use Pimcore\Event\AdminEvents;
use Pimcore\Tool\Authentication;
use Pimcore\Controller\FrontendController;
use Pimcore\Bundle\AdminBundle\Controller\Admin;
use Pimcore\Controller\Configuration\ResponseHeader;
use Pimcore\Event\Admin\Login\LoginCredentialsEvent;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\StreamedResponse;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBagInterface;
class ApiController extends FrontendController
{
/**
* @Route("/promemoria/api/login", methods={"POST"})
* @param Request $request
*
* @return JsonResponse
*/
public function login(Request $request)
{
$response = new Response();
$response->setStatusCode(401);
$data = json_decode($request->getContent());
if (!empty($data->username) && !empty($data->password)) {
$credentials = [
'username' => $data->username,
'password' => $data->password
];
$event = new LoginCredentialsEvent($request, $credentials);
try {
$this->dispatcher->dispatch(AdminEvents::LOGIN_CREDENTIALS, $event);
} catch (\Throwable $th) {
}
$pimcoreUser = Authentication::authenticatePlaintext($data->username, $data->password);
if ($pimcoreUser) {
return Session::useSession(function (AttributeBagInterface $adminSession) use ($pimcoreUser) {
$user = new UserAdmin($pimcoreUser);
Session::regenerateId();
$adminSession->set('user', $pimcoreUser);
$adminSession->set('2fa_required', true);
return $this->json(['ok' => true, 'user' => array(
'id' => $pimcoreUser->getId(),
'firstname' => $pimcoreUser->getFirstname(),
'lastname' => $pimcoreUser->getLastname(),
'email' => $pimcoreUser->getEmail(),
'roles' => $user->getRoles()
)]);
});
}
}
return $response;
}
/**
* @Route("/promemoria/api/logout", methods={"POST", "GET"})
*
* @return JsonResponse
*/
public function logout()
{
return $this->redirectToRoute('pimcore_admin_logout');
}
/**
* @Route("/promemoria/api/get-audio-thumbnail", methods={"GET"})
*
* @param Request $request
*
* @return BinaryFileResponse
*/
public function getAudioThumbnail(Request $request)
{
$tmpfname = tempnam("/tmp", "audio.png");
file_put_contents($tmpfname, file_get_contents("https://dummyimage.com/170x170/3e3e3e/ffffff.png&text=%20audio%20"));
$response = new BinaryFileResponse($tmpfname);
$this->addThumbnailCacheHeaders($response);
return $response;
}
/**
* @Route("/promemoria/api/get-image-thumbnail", methods={"GET"})
*
* @param Request $request
*
* @return BinaryFileResponse|StreamedResponse
*/
public function getImageThumbnail(Request $request)
{
$id = $request->get('id');
if(!$this->checkHash($id)){
$response = new Response();
$response->setStatusCode(401);
return $response;
}
$image = Asset\Image::getById(intval($id));
$thumb = $this->getThumb($image, $request->get('version', 'thumbnail'));
return $this->responseThumbnail($thumb);
}
/**
* @Route("/promemoria/api/get-video-thumbnail", methods={"GET"})
*
* @param Request $request
*
* @return BinaryFileResponse|StreamedResponse
*/
public function getVideoThumbnail(Request $request)
{
$id = $request->get('id');
if(!$this->checkHash($id)){
$response = new Response();
$response->setStatusCode(401);
return $response;
}
$video = Asset\Video::getById(intval($id));
$thumb = $video->getImageThumbnail(Asset\Image\Thumbnail\Config::getPreviewConfig());
return $this->responseThumbnail($thumb);
}
/**
* @Route("/promemoria/api/get-document-thumbnail", methods={"GET"})
*
* @param Request $request
*
* @return BinaryFileResponse|StreamedResponse
*/
public function getDocumentThumbnail(Request $request)
{
$id = $request->get('id');
if(!$this->checkHash($id)){
$response = new Response();
$response->setStatusCode(401);
return $response;
}
$document = Asset\Document::getById(intval($id));
$thumb = new Asset\Document\ImageThumbnail($document, Asset\Image\Thumbnail\Config::getPreviewConfig(), 1);
return $this->responseThumbnail($thumb);
}
/**
* @Route("/promemoria/api/get-video-preview", methods={"GET"})
*
* @param Request $request
*
* @return BinaryFileResponse
*/
public function getVideoPreview(Request $request)
{
$response = new Response();
$response->setStatusCode(400);
$id = $request->get('id');
if(!$this->checkHash($id)){
$response->setStatusCode(401);
return $response;
}
$asset = Asset::getById(intval($id));
if(!empty($asset) && $asset->getType()=='video'){
$thumbnail = $asset->getThumbnail(Asset\Video\Thumbnail\Config::getPreviewConfig(), ['mp4']);
$storagePath = $asset->getRealPath() . '/' . preg_replace('@^' . preg_quote($asset->getPath(), '@') . '@', '', urldecode($thumbnail['formats']['mp4']));
$storage = \Pimcore\Tool\Storage::get('thumbnail');
if ($storage->fileExists($storagePath)) {
$fs = $storage->fileSize($storagePath);
$stream = $storage->readStream($storagePath);
return new StreamedResponse(function () use ($stream) {
fpassthru($stream);
}, 200, [
'Content-Type' => 'video/mp4',
'Content-Length' => $fs,
'Accept-Ranges' => 'bytes',
]);
} else {
$response->setStatusCode(204);
}
}
return $response;
}
/**
* @param Response $response
*/
protected function responseThumbnail($thumb)
{
$stream = $thumb->getStream();
if ($stream) {
$response = new StreamedResponse(function () use ($stream) {
fpassthru($stream);
}, 200, [
'Content-Type' => 'image/' . $thumb->getFileExtension(),
]);
} else {
$pathparts = pathinfo($thumb->getAsset()->getFilename());
$ext = isset($pathparts["extension"]) ? $pathparts["extension"] : 'image';
$tmpfname = tempnam("/tmp", "image.png");
file_put_contents($tmpfname, file_get_contents("https://dummyimage.com/300x300/3e3e3e/ffffff.png&text=%20{$ext}%20"));
$response = new BinaryFileResponse($tmpfname);
}
$this->addThumbnailCacheHeaders($response);
return $response;
}
/**
* @Route("/promemoria/api/download-as-zip", methods={"GET"})
*
* @param Request $request
*
* @return BinaryFileResponse
*/
public function downloadAsZip(Request $request)
{
$name = $request->get('name', '');
$version = $request->get('version', 'original');
$watermarked = $request->get('watermarked', 0);
$zipName = ($name ?: 'collection-' . time()) . '.zip';
$zipFile = tempnam("/tmp", $zipName);
$zip = new \ZipArchive();
$zipState = $zip->open($zipFile, \ZipArchive::CREATE);
$selectedIds = $request->get('selectedIds', '');
if (strlen($selectedIds) > 0 && $zipState === true) {
$conditionFilters = [];
$selectedIds = explode(',', $selectedIds);
$ids = [];
foreach ($selectedIds as $id) {
if(!$this->checkHash($id)){
$response = new Response();
$response->setStatusCode(401);
return $response;
}
$ids[] = intval($id);
}
$conditionFilters[] = 'id IN (' . implode(',', $ids) . ')';
$conditionFilters[] .= "type != 'folder'";
$condition = implode(' AND ', $conditionFilters);
$assetList = new Asset\Listing();
$assetList->setCondition($condition);
$assetList->setOrderKey('LENGTH(path) ASC, id ASC', false);
$assetList->setOffset((int)$request->get('offset'));
$assetList->setLimit((int)$request->get('limit'));
foreach ($assetList->load() as $a) {
if (!$a instanceof Asset\Folder) {
if($a instanceof Asset\Image){
$a = $this->getThumb($a, $watermarked ? $version : "no_watermark", $version === 'original');
}
if ($a instanceof Asset\Image\Thumbnail) {
$dir_prefix = '/var/www/html/public/var/tmp/thumbnails';
$pathReference = $a->getPathReference();
//serve per generare la thumb nel caso non esista
$fileContent = Tool\Storage::get('thumbnail')->read($pathReference['storagePath']);
$path = urldecode($a->getPath());
} else {
$dir_prefix = '/var/www/html/public/var/assets';
$path = $a->getRealFullPath();
}
$zip->addFile($dir_prefix.$path, basename($path));
}
}
$zip->close();
$response = new BinaryFileResponse($zipFile);
$response->headers->set('Content-Type', 'application/zip');
$response->setContentDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT, $zipName);
$response->deleteFileAfterSend(true);
return $response;
}
return $this->json(['error' => true]);
}
/**
* @Route("/promemoria/api/getShortToken", methods={"GET"})
* @param Request $request
*
* @return JsonResponse
*/
public function getShortToken(Request $request)
{
$response = new Response();
$response->setStatusCode(400);
$db = \Pimcore\Db::get();
$jwtToken = $request->get('jwtToken');
$this->clearExpiredShortUrls();
if (!empty($jwtToken)) {
$generatedToken = substr(md5(uniqid(mt_rand(), true)), 0, 8);
$db->insert('promemoria_shorturl', [
'jwtToken' => $jwtToken,
'shortToken' => $generatedToken
]);
return $this->json(['shortToken' => $generatedToken]);
}
return $response;
}
/**
* @Route("/promemoria/api/getJwtToken", methods={"GET"})
* @param Request $request
*
* @return JsonResponse
*/
public function getJwtToken(Request $request)
{
$response = new Response();
$response->setStatusCode(400);
$db = \Pimcore\Db::get();
$shortToken = $request->get('shortToken');
$this->clearExpiredShortUrls();
if (!empty($shortToken)) {
$res = $db->fetchRow("SELECT jwtToken FROM promemoria_shorturl WHERE shortToken = " . $db->quote($shortToken));
return $this->json(['jwtToken' => $res['jwtToken']]);
}
return $response;
}
/**
* @Route("/promemoria/api/changePassword", methods={"POST"})
* @param Request $request
*
* @return JsonResponse
*/
public function changePassword(Request $request)
{
$response = new Response();
$response->setStatusCode(401);
$data = json_decode($request->getContent());
$newPassword = $data->password;
$pimcoreUser = Authentication::authenticateSession();
if(empty($pimcoreUser)){
return $response;
}
if (!empty($pimcoreUser) && !empty($newPassword)) {
$pimcoreUser->setPassword(Authentication::getPasswordHash($pimcoreUser->getUsername(), $newPassword));
$pimcoreUser->save();
return $this->json(['message' => 'Password changed']);
}
return $response;
}
/**
* @Route("/promemoria/api/getUserList", methods={"POST"}))
* @param Request $request
*
* @return JsonResponse
*/
public function getUserList(Request $request)
{
$pimcoreUser = Authentication::authenticateSession();
if(empty($pimcoreUser)){
$response = new Response();
$response->setStatusCode(401);
return $response;
}
$db = \Pimcore\Db::get();
$query = <<<QUERY
SELECT u.id as user_id, u.name as user_name, u.firstname as fname, u.lastname as lname, u.email, r.id as role_id, r.name as role
FROM users u
INNER JOIN users r ON u.type = 'user' and u.roles = r.id and u.roles != '' and u.active = 1
order by u.name asc
QUERY;
return $this->json(['users' => $db->executeQuery($query)->fetchAll()]);
}
/**
* @Route("/promemoria/api/getRoleList", methods={"POST"}))
* @param Request $request
*
* @return JsonResponse
*/
public function getRoleList(Request $request)
{
$pimcoreUser = Authentication::authenticateSession();
if(empty($pimcoreUser)){
$response = new Response();
$response->setStatusCode(401);
return $response;
}
$db = \Pimcore\Db::get();
$query = <<<QUERY
SELECT u.id as role_id, u.name as name
FROM users u
WHERE
u.type = 'role'
order by u.name asc
QUERY;
return $this->json(['roles' => $db->executeQuery($query)->fetchAll()]);
}
/**
* @Route("/promemoria/api/upsertUser", methods={"POST"})
* @param Request $request
*
* @return JsonResponse
*/
public function upsertUser(Request $request)
{
$pimcoreUser = Authentication::authenticateSession();
if(empty($pimcoreUser)){
$response = new Response();
$response->setStatusCode(401);
return $response;
}
$userAdmin = new UserAdmin($pimcoreUser);
if(!in_array("ROLE_PIMCORE_ADMIN", $userAdmin->getRoles())
&& !in_array("ROLE_MANAGER", $userAdmin->getRoles())){
$response = new Response();
$response->setStatusCode(401);
return $response;
}
$data = json_decode($request->getContent());
$user = new User();
if(!empty($data->user_id)){
$user = User::getById($data->user_id);
}
$user->setParentid(0);
$user->setUsername($data->user_name);
$user->setFirstname($data->fname);
$user->setLastname($data->lname);
$user->setEmail($data->email);
$user->setActive($data->active);
$user->setLanguage("it");
$user->setContentLanguages("it,en");
if(!empty($data->password)){
$user->setPassword(Authentication::getPasswordHash($data->user_name, $data->password));
}
$user->setRoles($data->role_id);
$user->save();
return $this->json(['message' => 'User updated']);
}
/**
* @Route("/promemoria/api/deleteUser", methods={"POST"})
* @param Request $request
*
* @return JsonResponse
*/
public function deleteUser(Request $request)
{
$pimcoreUser = Authentication::authenticateSession();
if(empty($pimcoreUser)){
$response = new Response();
$response->setStatusCode(401);
return $response;
}
$data = json_decode($request->getContent());
$user = User::getById($data->user_id);
$userAdmin = new UserAdmin($user);
if(in_array("ROLE_PIMCORE_ADMIN", $userAdmin->getRoles())){
$response = new Response();
$response->setStatusCode(401);
return $response;
}
$user->delete();
return $this->json(['message' => 'User deleted']);
}
/**
* @Route("/promemoria/api/buca", methods={"POST"})
* @param Request $request
*
* @return JsonResponse
*/
public function buca(Request $request)
{
$token = $request->get("token");
$config = \App\PromemoriaBundle\PromemoriaBundle::getConfig();
if(!empty($config["googleRecaptchaSecretKey"]) && !empty($token)){
$verifyResponse = file_get_contents('https://www.google.com/recaptcha/api/siteverify?secret=' . $config["googleRecaptchaSecretKey"] . '&response=' . $token);
$responseData = json_decode($verifyResponse);
if (!$responseData->success || $responseData->score < 0.5) {
$response = new Response();
$response->setStatusCode(401);
return $response;
}
$email = $request->get("email");
$pimcoreUsername = empty($email) ? "website" : $email;
$pimcoreId = 0;
}else{
$pimcoreUser = Authentication::authenticateSession();
if(empty($pimcoreUser)){
$email = $request->get("email");
if(empty($email)){
$response = new Response();
$response->setStatusCode(401);
return $response;
}else{
$pimcoreUsername = $email;
$pimcoreId = 0;
}
}else{
$pimcoreUsername = $pimcoreUser->getUsername();
$pimcoreId = $pimcoreUser->getId();
}
}
// crezione folder utente se non esiste
$parentBuca = "/Buca/";
$parentPath = $parentBuca . $pimcoreUsername;
$parentAsset = \Pimcore\Model\Asset::getByPath($parentPath);
if(!$parentAsset){
$parent = \Pimcore\Model\Asset::getByPath($parentBuca);
$parentAsset = $this->createFolder($pimcoreUsername, $parent->getId(), 'asset');
}
$parentObject = \Pimcore\Model\DataObject::getByPath($parentPath);
if(!$parentObject){
$parent = \Pimcore\Model\DataObject::getByPath($parentBuca);
$parentObject = $this->createFolder($pimcoreUsername, $parent->getId());
}
// creazione oggetto e media
$separatore = "$";
$classe = "\Pimcore\Model\DataObject\\" . $request->get("class");
$fields = json_decode($request->get("fields"), TRUE);
$obj = new $classe();
$obj->setParentId($parentObject->getId());
foreach ($fields as $key => $typeField) {
$fieldDefiniton = $obj->getClass()->getFieldDefinition($key);
$type = $fieldDefiniton ? $fieldDefiniton->getFieldtype() : "localizedfield";
$type = strpos($key, $separatore) !== FALSE ? "block" : $type;
if(in_array($typeField,["file","image"])){
$files = $request->files->get($key);
$metadati = $request->get($key . "Metadati");
if(!empty($files)){
$isMultiple = is_array($files);
$files = $isMultiple ? $files : [$files];
if(!empty($metadati)){
$metadati = $isMultiple ? $metadati : [$metadati];
}
$values = [];
if($typeField === "image"){
foreach ($files as $index => $file) {
$advancedImage = new \Pimcore\Model\DataObject\Data\Hotspotimage();
$metadatis = !empty($metadati) && !empty($metadati[$index]) ? json_decode($metadati[$index], TRUE) : [];
$advancedImage->setImage($this->createAsset($parentAsset, $file, "image", $metadatis));
$values[] = $advancedImage;
}
$values = new \Pimcore\Model\DataObject\Data\ImageGallery($values);
}else{
foreach ($files as $index => $file) {
$values[] = $this->createAsset($parentAsset, $file);
}
}
$obj->{"set" . ucfirst($key)}($isMultiple ? $values : $values[0]);
}
}else {
$val = $request->get($key);
if(!empty($val)){
switch($typeField){
case "link":
$link = new \Pimcore\Model\DataObject\Data\Link();
$link->setText("Link");
$link->setPath($val);
$val = $link;
break;
case 'date':
$val = \Carbon\Carbon::createFromFormat('Y-m-d', $val);
break;
}
switch($type){
case "video":
$video = new \Pimcore\Model\DataObject\Data\Video();
$video->setType("youtube");
$video->setData($val);
$result = preg_match("/(?<=v=)[a-zA-Z0-9-]+(?=&)|(?<=v\/)[^&]+(?=\?)|(?<=v=)[^&]+|(?<=youtu.be\/)[^&]+/", $val, $matches);
if($result){
$video->setType("youtube");
$video->setData($matches[0]);
}
$result = preg_match("/(?<=vimeo.com\/)[^&]+/", $val, $matches);
if($result){
$video->setType("vimeo");
$video->setData($matches[0]);
}
$obj->{"set" . ucfirst($key)}($video);
break;
case "block":
list ($keyContainer, $keyMeta) = explode($separatore, $key);
$metadata = [];
$metadata[$keyMeta] = new \Pimcore\Model\DataObject\Data\BlockElement($keyMeta, $typeField, $val);
$obj->{"set" . ucfirst($keyContainer)}([$metadata]);
break;
case "localizedfield":
$obj->{"set" . ucfirst($key)}($val, 'it');
break;
case "multiselect":
$obj->{"set" . ucfirst($key)}([$val]);
break;
default:
$obj->{"set" . ucfirst($key)}($val);
break;
}
if($key === 'dcTitle'){
$obj->setKey(\Pimcore\Model\Element\Service::getValidKey($val, 'object'));
}
}
}
}
$obj->setUserOwner($pimcoreId);
$obj->setUserModification($pimcoreId);
$obj->save();
$tags = $request->get("tags");
if(!empty($tags)){
\Pimcore\Model\Element\Tag::setTagsForElement('object', $obj->getId(), array_map(function($id){
return \Pimcore\Model\Element\Tag::getById($id);
}, $tags));
}
return $this->json(["status" => true ]);
}
/**
* @Route("/promemoria/api/bucaSelect", methods={"POST"})
* @param Request $request
*
* @return JsonResponse
*/
public function bucaSelect(Request $request)
{
$pimcoreUser = Authentication::authenticateSession();
if(empty($pimcoreUser)){
$response = new Response();
$response->setStatusCode(401);
return $response;
}
$data = json_decode($request->getContent());
$classe = "\Pimcore\Model\DataObject\\" . $data->class;
$obj = new $classe();
$fieldDefiniton = $obj->getClass()->getFieldDefinition($data->field);
return $this->json($fieldDefiniton->getOptions());
}
/**
* @Route("/promemoria/api/bucaTags", methods={"POST"})
* @param Request $request
*
* @return JsonResponse
*/
public function bucaTags(Request $request)
{
$pimcoreUser = Authentication::authenticateSession();
if(empty($pimcoreUser)){
$response = new Response();
$response->setStatusCode(401);
return $response;
}
$data = json_decode($request->getContent());
$tagList = new \Pimcore\Model\Element\Tag\Listing();
$tagList->setCondition("parentId = ?", $data->parentId);
$tagList->setOrderKey("id");
$tags = [];
foreach ($tagList->load() as $tag) {
$tags[] = [
"id" => $tag->getId(),
"label" => $tag->getName()
];
}
return $this->json($tags);
}
/**
* @Route("/promemoria/api/check-email", methods={"POST"}))
* @param Request $request
*
* @return JsonResponse
*/
public function checkEmail(Request $request)
{
$response = new Response();
$response->setStatusCode(400);
$data = json_decode($request->getContent());
if(empty($data->email)){
return $response;
}
$user = false;
$entries = new \Pimcore\Model\User\Listing();
$entries->setLimit(1);
$entries->setCondition("email LIKE ?", [$data->email]);
foreach ($entries as $entry) {
$user = $entry;
return $this->json([
'status' => true
]);
}
return $response;
}
/**
* @Route("/promemoria/api/change-reset-password", methods={"POST"}))
* @param Request $request
*
* @return JsonResponse
*/
public function changeResetPassword(Request $request)
{
$response = new Response();
$response->setStatusCode(400);
$data = json_decode($request->getContent());
if(empty($data->email) || empty($data->password)){
return $response;
}
$entries = new \Pimcore\Model\User\Listing();
$entries->setLimit(1);
$entries->setCondition("email LIKE ?", [$data->email]);
foreach ($entries as $entry) {
$user = $entry;
$user->setPassword(Authentication::getPasswordHash($user->getUsername(), $data->password));
$user->save();
return $this->json([
'status' => true
]);
}
return $response;
}
/* PRIVATE */
private function clearExpiredShortUrls()
{
$db = \Pimcore\Db::get();
$db->deleteWhere('promemoria_shorturl', 'insertDate < NOW() - INTERVAL 1 WEEK');
}
private function createFolder($name, $parent, $type = 'object'){
$folder = $type === 'object' ? new \Pimcore\Model\DataObject\Folder() : new \Pimcore\Model\Asset\Folder();
$folder->setParentId($parent);
$type === 'object' ? $folder->setKey($name) : $folder->setFilename($name);
$folder->save();
return $folder;
}
private function createAsset($parentAsset, $file, $type="", $metadati = []){
$newAsset = $type ? new \Pimcore\Model\Asset\Image() : new \Pimcore\Model\Asset();
$newAsset->setFilename($this->checkFileAndRename($parentAsset->getFullPath(), $file->getClientOriginalName()));
$newAsset->setData(file_get_contents($file->getPathname()));
$newAsset->setParent($parentAsset);
if(!empty($metadati)){
foreach ($metadati as $key => $value) {
$newAsset->addMetadata($key, "input", $value);
}
}
$newAsset->save();
return $newAsset;
}
private function checkFileAndRename($parentPath, $filename){
$path_parts = pathinfo($filename);
$i = 1;
while(\Pimcore\Model\Asset::getByPath($parentPath . "/" . $filename)){
$filename = $path_parts['filename'] . "_$i." . $path_parts['extension'];
$i++;
}
return $filename;
}
private function getThumb($image, $type, $original=false){
$thumb = $this->getThumbnail($image, "watermarked_" . $type);
if(!$thumb || empty($thumb->getConfig())) {
$thumb = $this->getThumbnail($image, $type);
}
if(!$thumb || empty($thumb->getConfig())){
if($original) return $image;
$thumb = $this->getThumbnail($image, Asset\Image\Thumbnail\Config::getPreviewConfig());
}
return $thumb;
}
private function getThumbnail($image, $type){
try{
return $image->getThumbnail($type);
}catch(\Exception $err){
return null;
}
}
private function addThumbnailCacheHeaders(Response $response)
{
$lifetime = 300;
$date = new \DateTime('now');
$date->add(new \DateInterval('PT' . $lifetime . 'S'));
$response->setMaxAge($lifetime);
$response->setPublic();
$response->setExpires($date);
$response->headers->set('Access-Control-Allow-Origin', '*');
}
private function checkHash($id){
list($id, $hash) = explode("-", $id);
return $hash === substr(md5($id . md5(getenv("dotenv_suffix"))), 0, 8);
}
}