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("~", "`", "!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "_", "=", "+", "[", "{", "]",
+            "}", "\\", "|", ";", ":", "\"", "'", "&#8216;", "&#8217;", "&#8220;", "&#8221;", "&#8211;", "&#8212;",
+            "—", "–", ",", "<", ".", ">", "/", "?");
+        $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