From 29e03697deaf4a2cd0f36d990596d9fbda990ebe Mon Sep 17 00:00:00 2001 From: David Beniamine <david.beniamine@tetras-libre.fr> Date: Tue, 7 Dec 2021 17:06:01 +0100 Subject: [PATCH] Fallback controller WIP --- config/routes/annotations.yaml | 4 + config/services.yaml | 4 + src/Controller/FallbackController.php | 370 ++++++++++++++++++++++++++ templates/legacy/legacy.html.twig | 21 ++ 4 files changed, 399 insertions(+) create mode 100644 src/Controller/FallbackController.php create mode 100644 templates/legacy/legacy.html.twig diff --git a/config/routes/annotations.yaml b/config/routes/annotations.yaml index e92efc5..1d3551d 100644 --- a/config/routes/annotations.yaml +++ b/config/routes/annotations.yaml @@ -2,6 +2,10 @@ controllers: resource: ../../src/Controller/ type: annotation +fallback: + resource: ../../src/Controller/FallbackController.php + type: annotation + kernel: resource: ../../src/Kernel.php type: annotation diff --git a/config/services.yaml b/config/services.yaml index 533ef58..1cf8a0e 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -21,3 +21,7 @@ services: # add more service definitions when explicit configuration is needed # please note that last definitions always *replace* previous ones +parameters: + app.legacy_url_external: '%env(LEGACY_URL_EXTERNAL)%' + app.legacy_url: '%env(LEGACY_URL)%' + app.legacy_external_prefix: '%env(LEGACY_EXTERNAL_PREFIX)%' diff --git a/src/Controller/FallbackController.php b/src/Controller/FallbackController.php new file mode 100644 index 0000000..bee13b3 --- /dev/null +++ b/src/Controller/FallbackController.php @@ -0,0 +1,370 @@ +<?php + +namespace App\Controller; + +use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\Routing\Annotation\Route; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\BinaryFileResponse; +use Symfony\Component\HttpFoundation\File\File; +use Symfony\Component\HttpFoundation\File\Exception\FileException; +use AppBundle\Entity\Capsule; +use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException; +use Symfony\Component\HttpFoundation\RedirectResponse; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; + +class FallbackController extends AbstractController +{ + /** + * @Route("/", name="get_legacy_resource_creation", methods={"POST"}) + * @Route("/{controller}", name="get_legacy_resource_creation_index", requirements={"controller" = "index.php"}) + */ + public function getCreationCapsuleAction(Request $request, $controller = null) + { + + // $_POST parameters + $capsuleName = $request->request->get('create'); + $capsulePass = $request->request->get('p'); + $capsuleLink = $this->sanitize($capsuleName); + + $this->denyAccessUnlessGranted('IS_AUTHENTICATED_REMEMBERED'); + $user = $this->getUser(); + + /* + // memorykall legacy affichera un message si champ vide + //bloquer les noms à null + if($capsuleName == null || $capsuleName == '') + { + // rediriger sur une page demandant un nom + return $this->redirectToRoute('missing_name'); + }*/ + +// TODO : the following code MUST be re-enabled with tuleap-51 +// // check if capsule exist in database +// $capByName = $this->getDoctrine() +// ->getManager() +// ->getRepository('AppBundle:Capsule') +// ->findOneByNom($capsuleName) +// ; +// $capByLink = $this->getDoctrine() +// ->getManager() +// ->getRepository('AppBundle:Capsule') +// ->findOneByLink($capsuleLink) +// ; +// if (!$capByName instanceof Capsule && !$capByLink instanceof Capsule) { +// $dateCreation = new \DateTime(); +// $cap = new Capsule(); +// $cap->setNom($capsuleName); +// $cap->setLink($capsuleLink); +// $cap->setEditionLink($capsuleLink.'/?p='.$capsulePass); +// $cap->setAutCrea($user); +// $cap->setDtCrea($dateCreation); +// $cap->setDtMaj($dateCreation); +// $cap->addEditeur($user); +// +// $em = $this->getDoctrine()->getManager(); +// $em->persist($cap); +// $em->flush(); +// } +// // si la capsule existe déjà memorkall legacy affichera un message capsule existe déjà + + $response = $this->transfertToLegacy($request); + return $response; + } + + + /** + * @Route("/", name="get_legacy_resource") + * @Route("/{controller}", name="get_legacy_resource", requirements={"controller" = ".+"}) + */ + public function getLegacyResourceAction(Request $request, $controller = null) + { + // $logger = $this->get('logger'); + // check if capsule edition (pôst or get) + if ($request->query->has('p') || $request->request->has('p')) { + $this->denyAccessUnlessGranted('IS_AUTHENTICATED_REMEMBERED'); + $user = $this->getUser(); + $pass = ''; + if ($request->query->has('p')) { + $pass = $request->query->get('p'); + } elseif ($request->request->has('p')) { + $pass = $request->request->get('p'); + } + $userId = $user->getId(); + // don't work properly with special char + //$link = rtrim($controller, "php/project.php"); + $link = str_replace("php/project.php", "", $controller); + $link = rtrim($link, "/"); + + +// TODO : the following code MUST be re-enabled with tuleap-51 +// // check if capsule exist in database +// $cap = $this->getDoctrine() +// ->getManager() +// ->getRepository('AppBundle:Capsule') +// ->getCapsuleByLink($link); +// if (!$cap instanceof Capsule) { +// // rediriger sur une page demandant si il est l'auteur de la capsule +// return $this->redirectToRoute('add_author', array('capsuleLink'=>$link, 'capsulePass'=> $pass)); +// } +// +// // if capsule exists, check if user can edit it +// $cap = $this->getDoctrine() +// ->getManager() +// ->getRepository('AppBundle:Capsule') +// ->getCapsuleByLinkAndUser($link, $userId); +// if (!$cap instanceof Capsule) { +// // rediriger sur une page lui demandant de contacter +// // l'administrateur de la capsule pour lui donner des droits +// return $this->redirectToRoute('no_edition_access'); +// } +// +// // if yes, continue +// $cap->setAutMaj($user); +// $cap->setDtMaj(new \DateTime()); +// +// $em = $this->getDoctrine()->getManager(); +// $em->persist($cap); +// $em->flush(); + } + + + if ($controller == null) { + //if no controller, this is index.php + return $this->redirectToRoute('get_legacy_resource', array('controller' => 'index.php')); + } + + // use iframe to enhance speed but not for creation + if (strpos($controller, 'legacy') !== 0) { + // relative path (to app/) of the legacy code (on the same filesystem) + //$path_to_legacy_code = $this->getParameter('kernel.root_dir'). + //$this->getParameter('legacy_root_dir'); + $originalController = $request->getPathInfo(); + $originalQueryString = $request->getQueryString(); + + $extension = strrchr($originalController, '.'); + if ($extension != '.html' && $extension != '.php' && $extension != false) { + //$url = "{$path_to_legacy_code}{$originalController}"; + $url = "{$originalController}"; + try { + $mime = $this->getMime($url, $extension); + $response = new BinaryFileResponse($url); + $response->headers->set('Content-Type', $mime ?: 'application/octet-stream'); + return $response; + } catch (FileNotFoundException $e) { + // try normal access by url + } + } + $separator = ''; + if (!$extension) { + $separator = '/'; + } + $url = "{$this->getParameter('app.legacy_url_external')}/" . + "{$originalController}{$separator}?{$originalQueryString}"; + $url = preg_replace('(^https?:\/\/[^/]+(:\d+)?)', '', $url); + $pattern = '/\/\//i'; + $url = preg_replace($pattern, '/', $url); + // $logger->info("Capsule iframe configuration for none index.php ", ['url' => $url]); + + return $this->render("legacy/legacy.html.twig", array( + 'url' => $url, + )); + } + + $response = $this->transfertToLegacy($request); + return $response; + } + + + private function transfertToLegacy(Request $request) + { + // relative path (to app/) of the legacy code (on the same filesystem) + //$path_to_legacy_code = $this->container->getParameter('kernel.root_dir'). + // $this->container->getParameter('legacy_root_dir'); + + $prefix = $this->getParameter('app.legacy_external_prefix'); + $originalController = preg_replace("@^$prefix@", '', $request->getPathInfo()); + $originalQueryString = $request->getQueryString(); + + //@TODO : delete on linux server + // $originalController = str_replace("/", "\\", $originalController); //windows + + $extension = strrchr($originalController, '.'); + if ($extension != '.html' && $extension != '.php' && $extension != false) { + #$url = "{$path_to_legacy_code}{$originalController}"; + $url = "{$originalController}"; + try { + $mime = $this->getMime($url, $extension); + $response = new BinaryFileResponse($url); + $response->headers->set('Content-Type', $mime ?: 'application/octet-stream'); + return $response; + } catch (FileNotFoundException $e) { + // try normal access by url + } + } + + $separator = ''; + if (!$extension) { + $separator = '/'; + } + $url = "{$this->getParameter('app.legacy_url')}{$originalController}{$separator}?{$originalQueryString}"; + + //open connection + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); + curl_setopt($ch, CURLOPT_HEADER, 0); + curl_setopt($ch, CURLOPT_VERBOSE, 1); + + // logs the connection (optional) + $stderr = fopen("{$this->getParameter('kernel.project_dir')}/log/curl.txt", "w"); + + if ($request->getMethod() == 'POST') { + $postParameters = $request->request->all(); + /*$postParametersString = ''; + foreach ($postParameters as $key => $value) { + $postParametersString .= $key . '=' . $value . '&'; + } + rtrim($postParametersString, '&');*/ + // upload file to transfer + if (isset($_FILES['fileToUpload'])) { + $data = array( + 'fileToUpload' => curl_file_create( + $_FILES['fileToUpload']['tmp_name'], + $_FILES['fileToUpload']['type'], + $_FILES['fileToUpload']['name'] + ) + ); + $postParameters = array_merge($postParameters, $data); + curl_setopt($ch, CURLOPT_HEADER, 1); + curl_setopt($ch, CURLOPT_BINARYTRANSFER, 1); + } + + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, $postParameters); + } + + curl_setopt($ch, CURLOPT_COOKIESESSION, 0); + curl_setopt($ch, CURLOPT_COOKIEFILE, 'cookies.txt'); + curl_setopt($ch, CURLOPT_COOKIEJAR, 'cookies.txt'); + + //execute post + $result = curl_exec($ch); + $contentType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE); + + if ($result === false) { + $mes = "Erreur - Page non trouvée : " . + sprintf(curl_error($ch)) . + ' - ' . sprintf(curl_errno($ch)); + curl_close($ch); + throw new NotFoundHttpException($mes); + } + curl_close($ch); + + $response = new Response($result); + $response->headers->set('Content-Type', $contentType); + return $response; + } + + + // Mime Type Checker + private function getMime($filename, $extension, $mode = 0) + { + + // mode 0 = full check + // mode 1 = extension check only + + $mime_types = array( + + 'txt' => 'text/plain', + 'htm' => 'text/html', + 'html' => 'text/html', + 'php' => 'text/html', + 'css' => 'text/css', + 'js' => 'application/javascript', + 'json' => 'application/json', + 'xml' => 'application/xml', + 'swf' => 'application/x-shockwave-flash', + 'flv' => 'video/x-flv', + + // images + 'png' => 'image/png', + 'jpe' => 'image/jpeg', + 'jpeg' => 'image/jpeg', + 'jpg' => 'image/jpeg', + 'gif' => 'image/gif', + 'bmp' => 'image/bmp', + 'ico' => 'image/vnd.microsoft.icon', + 'tiff' => 'image/tiff', + 'tif' => 'image/tiff', + 'svg' => 'image/svg+xml', + 'svgz' => 'image/svg+xml', + + // archives + 'zip' => 'application/zip', + 'rar' => 'application/x-rar-compressed', + 'exe' => 'application/x-msdownload', + 'msi' => 'application/x-msdownload', + 'cab' => 'application/vnd.ms-cab-compressed', + + // audio/video + 'mp3' => 'audio/mpeg', + 'qt' => 'video/quicktime', + 'mov' => 'video/quicktime', + + // adobe + 'pdf' => 'application/pdf', + 'psd' => 'image/vnd.adobe.photoshop', + 'ai' => 'application/postscript', + 'eps' => 'application/postscript', + 'ps' => 'application/postscript', + + // ms office + 'doc' => 'application/msword', + 'rtf' => 'application/rtf', + 'xls' => 'application/vnd.ms-excel', + 'ppt' => 'application/vnd.ms-powerpoint', + 'docx' => 'application/msword', + 'xlsx' => 'application/vnd.ms-excel', + 'pptx' => 'application/vnd.ms-powerpoint', + + + // open office + 'odt' => 'application/vnd.oasis.opendocument.text', + 'ods' => 'application/vnd.oasis.opendocument.spreadsheet', + ); + + if (null === $filename) { + throw new \InvalidArgumentException('File cannot be null.'); + } + + $ext = strtolower(str_replace('.', '', $extension)); + if (array_key_exists($ext, $mime_types)) { + return $mime_types[$ext]; + } + $file = new File((string) $filename, true); + if (!$file->isReadable()) { + throw new FileException('File must be readable.'); + } + $mime = $file->getMimeType(); + return $mime; + } + + // copy of function used by memorekall to calculate real project name ! + public static function sanitize($string, $force_lowercase = true, $anal = false) + { + $strip = array("~", "`", "!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "_", "=", "+", "[", "{", "]", + "}", "\\", "|", ";", ":", "\"", "'", "‘", "’", "“", "”", "–", "—", + "—", "–", ",", "<", ".", ">", "/", "?"); + $clean = trim(str_replace($strip, "", strip_tags($string))); + $clean = preg_replace('/\s+/', "-", $clean); + $clean = ($anal) ? preg_replace("/[^a-zA-Z0-9]/", "", $clean) : $clean ; + return ($force_lowercase) ? + (function_exists('mb_strtolower')) ? + mb_strtolower($clean, 'UTF-8') : + strtolower($clean) : + $clean; + } +} diff --git a/templates/legacy/legacy.html.twig b/templates/legacy/legacy.html.twig new file mode 100644 index 0000000..2bf7dbf --- /dev/null +++ b/templates/legacy/legacy.html.twig @@ -0,0 +1,21 @@ +{% extends 'layout.html.twig' %} + + + +{% block body %} + + <iframe src="{{ url }}" + style="width:100%;height:100%;top:0;left:0;position:absolute" + {# width="1200" + height="600" #} + + frameborder="0" + webkitallowfullscreen + mozallowfullscreen + allowfullscreen> + </iframe> + + + +{% endblock %} + -- GitLab