stany.ferer 1 год назад
Сommit
82e7abbca7

+ 1 - 0
.gitignore

@@ -0,0 +1 @@
+env.inc.php

+ 53 - 0
core/class/cms.class.php

@@ -0,0 +1,53 @@
+<?php
+
+class cms
+{
+    
+    static private function curl(string $_url, array $_array, $_debug = FALSE)
+    {
+        $ch = curl_init();
+
+        curl_setopt($ch, CURLOPT_URL, $_url);
+        curl_setopt($ch, CURLOPT_POST, true);
+        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($_array));
+        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+        curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
+
+        // Désactiver la vérification SSL (à ne pas utiliser en production)
+        if (ENVIRONNEMENT == "DEV") {
+            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
+        }
+
+        // Exécuter la requête et capturer les erreurs cURL
+        $response = curl_exec($ch);
+        if ($response === false) {
+            $curlError = curl_error($ch);
+            curl_close($ch);
+            return [
+                'status' => 'error',
+                'message' => 'cURL error: ' . $curlError
+            ];
+        }
+
+        // Fermer la session cURL
+        curl_close($ch);
+
+        // Décoder la réponse JSON
+        $responseData = json_decode($response, true);
+
+        if($_debug == TRUE){
+            core::print_r(["_url" => $_url, "_array" => $_array, "response" => $response]);
+        }
+
+        return $responseData;
+    }
+
+    static public function checkToken(string $_token)
+    {
+        $return = self::curl(
+            "https://" . DOMAIN_CMS . "/api/checkToken/",
+            ['token' => $_token]
+        );
+        return $return["status"] == "success" ? TRUE : FALSE;
+    }
+}

+ 94 - 0
core/class/core.class.php

@@ -0,0 +1,94 @@
+<?php
+
+class core
+{
+    public static function switch(){
+        if($_SERVER['REQUEST_METHOD'] === 'POST'){
+            if(isset($_POST["from"])){
+                if($_POST["from"] == "cse.invent" AND isset($_POST["token"])){
+                    include_once "../core/submit/record.jwt.php";
+                } elseif($_POST["from"] == "video.form.add") {
+                    include_once "../core/submit/video.add.php";
+                } elseif($_POST["from"] == "video.form") {
+                    include_once "../core/submit/video.edit.php";
+                } elseif($_POST["from"] == "video.cut") {
+                    include_once "../core/submit/video.cut.php";
+                } else {
+                    echo "Error : switch :. from else post";
+                    var_dump($_POST);
+                    exit();
+                }
+            } else {
+                echo "Error : switch :. from post";
+                exit();
+            }
+            
+        } elseif($_SERVER['REQUEST_METHOD'] === 'GET') { 
+        
+            if(isset($_GET["video"])){
+                include_once "../core/page/video.show.php";
+            } elseif(isset($_GET["preview"])){
+                include_once "../core/page/video.preview.php";
+            } elseif(isset($_GET["delete"])){
+                include_once "../core/submit/video.delete.php";
+            } else {
+                require_once "../core/controllers/session.php";
+                include_once "../core/page/_header.php";
+                if(empty($_GET["video"]) AND empty($_GET["preview"]) AND empty($_GET["edit"]) AND empty($_GET["cut"])){
+                    include_once "../core/page/videos.all.php";
+                } elseif(isset($_GET["edit"]) AND $_GET["edit"] == "add"){
+                    include_once "../core/page/video.form.add.php";
+                } elseif(isset($_GET["edit"]) AND $_GET["edit"] != "add"){
+                    include_once "../core/page/video.form.php";
+                } elseif(isset($_GET["cut"])){
+                    include_once "../core/page/video.cut.php";
+                } else {
+                    echo "Error : switch :. from get";
+                    exit();
+                }
+                include_once "../core/page/_footer.php";
+            }
+        } else {
+            echo "Error : switch";
+            exit();
+        }
+    }
+    
+    public static function print_r($_debug, int $_exit = NULL)
+    {
+        echo "<pre>";
+        if(is_array($_debug)) {
+            print_r($_debug);
+        } elseif(is_object($_debug)){
+            var_dump($_debug);
+        } else {
+            echo $_debug;
+        }
+        echo "</pre>";
+        ($_exit != NULL) ? exit() : NULL;
+    }
+
+    public static function formatDuration(float $seconds = NULL, string $type = NULL) {
+
+        if($seconds == NULL){
+            return NULL;
+        }
+
+        // Calculer les heures
+        $hours = floor($seconds / 3600);
+        
+        // Calculer les minutes restantes après avoir soustrait les heures
+        $minutes = floor(($seconds % 3600) / 60);
+        
+        // Calculer les secondes restantes après avoir soustrait les minutes
+        $remainingSeconds = $seconds % 60;
+        
+        // Retourner la durée formatée en "H:i:s"
+        if($type == ":"){
+            return sprintf("%02d:%02d:%02d", $hours, $minutes, $remainingSeconds);
+        } else {
+            return sprintf("%02dh %02dm %02ds", $hours, $minutes, $remainingSeconds);
+        }
+        
+    }
+}

+ 135 - 0
core/class/db.class.php

@@ -0,0 +1,135 @@
+<?php
+
+class db
+{
+    private static $dbh;
+    private static $error;
+    private static $stmt;
+
+    private static function connexion()
+    {
+        if (self::$dbh) {
+            return;
+        }
+
+        $dsn = "mysql:host=" . DB_HOST . ";dbname=" . DB_NAME;
+        $options = array(
+            PDO::ATTR_PERSISTENT => true,
+            PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
+        );
+
+        try {
+            self::$dbh = new PDO($dsn, DB_USER, DB_PASS, $options);
+        } catch (PDOException $e) {
+            self::$error = $e->getMessage();
+            throw new Exception(self::$error);
+        }
+    }
+
+    public static function version()
+    {
+        self::connexion();
+        return self::$dbh->getAttribute(PDO::ATTR_SERVER_VERSION);
+    }
+
+    public static function query(string $query)
+    {
+        self::connexion();
+        self::$stmt = self::$dbh->prepare($query);
+    }
+
+    public static function bind(string $param, $value = null, $type = null)
+    {
+        if (is_null($type)) {
+            switch (true) {
+                case is_int($value):
+                    $type = PDO::PARAM_INT;
+                    break;
+                case is_bool($value):
+                    $type = PDO::PARAM_BOOL;
+                    break;
+                case is_null($value):
+                    $type = PDO::PARAM_NULL;
+                    break;
+                default:
+                    $type = PDO::PARAM_STR;
+            }
+        }
+        self::$stmt->bindValue($param, $value, $type);
+    }
+
+    public static function execute()
+    {
+        self::connexion();
+        if (debug::isFile("sql")) {
+            ob_start();
+            $return = self::$stmt->execute();
+            self::$stmt->debugDumpParams();
+            $debugOutput = ob_get_clean();
+            return $return;
+        } else {
+            return self::$stmt->execute();
+        }
+    }
+
+    public static function resultset()
+    {
+        self::execute();
+        return self::$stmt->fetchAll(PDO::FETCH_ASSOC);
+    }
+
+    public static function single()
+    {
+        self::execute();
+        return self::$stmt->fetch(PDO::FETCH_ASSOC);
+    }
+
+    public static function rowCount()
+    {
+        return self::$stmt->rowCount();
+    }
+
+    public static function lastInsertId()
+    {
+        self::connexion();
+        return self::$dbh->lastInsertId();
+    }
+
+    public static function beginTransaction()
+    {
+        self::connexion();
+        return self::$dbh->beginTransaction();
+    }
+
+    public static function endTransaction()
+    {
+        self::connexion();
+        return self::$dbh->commit();
+    }
+
+    public static function cancelTransaction()
+    {
+        self::connexion();
+        return self::$dbh->rollBack();
+    }
+
+    public static function debugDumpParams()
+    {
+        self::connexion();
+        return self::$stmt->debugDumpParams();
+    }
+
+    public static function queryError()
+    {
+        self::connexion();
+        $qError = self::$dbh->errorInfo();
+        if (!is_null($qError[2])) {
+            echo $qError[2];
+        }
+    }
+
+    public static function getError()
+    {
+        return self::$error;
+    }
+}

+ 206 - 0
core/class/debug.class.php

@@ -0,0 +1,206 @@
+<?php
+
+class debug
+{
+    private static $logs = [];
+    private static $startTime;
+    private static $closeTime;
+
+    private static function typeFile(string $_string){
+        switch ($_string) {
+            case 'maintenance':
+                return ".lock-maintenance";
+                break;
+            case 'debug':
+                return ".active-debug";
+                break;
+            default:
+                return ".active-debug-".$_string;
+                break;
+        }
+    }
+    
+    public static function addFile(string $_string = NULL)
+    {
+        if($_string != NULL){
+            $myfile = fopen(DOCUMENT_ROOT . self::typeFile($_string), "w");
+            fclose($myfile);
+        }
+    }
+
+    public static function removeFile(string $_string = NULL)
+    {
+        if($_string != NULL){
+            unlink(DOCUMENT_ROOT . self::typeFile($_string));
+        }
+    }
+
+    public static function isFile(string $_string = NULL)
+    {
+        return file_exists(DOCUMENT_ROOT . self::typeFile($_string)) ? TRUE : FALSE;
+    }
+
+    public static function dump($var, $label = 'Dump', $echo = true)
+    {
+        // Start output buffering
+        ob_start();
+
+        echo "<pre class='debug-dump'>";
+        echo "<strong>" . $label . ":</strong> ";
+
+        // Convert array or object to string
+        if (is_array($var)) {
+            print_r($var);
+        } elseif (is_object($var)) {
+            echo self::objectToString($var);
+        } else {
+            var_dump($var);
+        }
+
+        echo "</pre>";
+
+        // Get the contents of the buffer
+        $output = ob_get_clean();
+
+        // If echo is true, print the output
+        if ($echo) {
+            echo $output;
+        } else {
+            return $output;
+        }
+    }
+
+    public static function objectToString($object, $_tab = NULL) {
+        ob_start();
+
+        $tab = "&nbsp;&nbsp;&nbsp;&nbsp;" . $_tab;
+        
+        echo "<span class='debug-console-capsule'>Object (" . get_class($object) . ")\n</span>";
+        echo $_tab . "<span class='debug-console-capsule'>{\n</span>";
+        
+        foreach (get_object_vars($object) as $property => $value) {
+            echo $tab . "<span class='debug-console-capsule'>[<span class='debug-console-key'>$property</span>] => </span>";
+            if (is_array($value)) {
+                echo self::arrayToString($value, $tab);
+            } elseif (is_object($value)) {
+                echo self::objectToString($value, $tab);
+            } else {
+                echo "<span class='debug-console-value'>" . var_export($value, true) . "</span>\n";
+            }
+        }
+        
+        echo $_tab . "<span class='debug-console-capsule'>}\n</span>";
+        
+        return ob_get_clean();
+    }
+
+
+
+    public static function arrayToString($array, $_tab = NULL)
+    {
+        ob_start();
+
+        $tab = "&nbsp;&nbsp;&nbsp;&nbsp;".$_tab;
+        
+        echo "<span class='debug-console-capsule'>Array\n</span>";
+        echo $_tab . "<span class='debug-console-capsule'>(\n</span>";
+        
+        foreach ($array as $key => $value) {
+            echo $tab . "<span class='debug-console-capsule'>[<span class='debug-console-key'>$key</span>] => </span>";
+            if (is_array($value)) {
+                echo self::arrayToString($value, $tab);
+            } elseif (is_object($value)) {
+                echo self::objectToString($value, $tab);
+            } else {
+                echo "<span class='debug-console-value'>" . var_export($value, true) . "</span>\n";
+            }
+        }
+        
+        echo $_tab . "<span class='debug-console-capsule'>)\n</span>";
+        
+        return ob_get_clean();
+    }
+
+    private static function variableToString($var, $label)
+    {
+        ob_start();
+        echo "$label: ";
+        if (is_array($var) || is_object($var)) {
+            print_r($var);
+        } else {
+            var_dump($var);
+        }
+        return ob_get_clean();
+    }
+
+    public static function getTraces(){
+        $return = "Trace : ";
+        
+        // Obtenir la trace d'exécution
+        $backtrace = debug_backtrace();
+        $nb = count($backtrace)-1;
+
+        for ($i=$nb; $i > 0; $i--) { 
+            $return .= ($i != 0) ? "[".$backtrace[$i]["function"]."] " : NULL;
+            $return .= str_replace(DOCUMENT_ROOT, '', $backtrace[$i]["file"]).":".$backtrace[$i]["line"];
+            $return .= ($i != 1) ? " >> " : NULL;
+        }
+
+        return $return;
+    }
+
+    public static function print_r(array $_array, int $_exit = NULL)
+    {
+        echo "<div>".debug::getTraces() . "</div>";
+        echo "<pre>";
+        print_r($_array);
+        echo "</pre>";
+        ($_exit != NULL) ? exit() : NULL;
+    }
+
+    public static function isHtml(string $_string) : bool 
+    {
+        $stripped_string = strip_tags($_string);
+        return $_string !== $stripped_string;
+    }
+
+    public static function generateHtmlContent($htmlContent)
+    {
+        $id = md5(microtime());
+        return <<<HTML
+                    <!DOCTYPE html>
+                    <html>
+                    <head>
+                        <title>Exécution de HTML</title>
+                        <style>
+                            .isolated-iframe {
+                                width: 100%;
+                                height: 300px;
+                                border: none;
+                            }
+                        </style>
+                    </head>
+                    <body>
+                        <iframe id="isolatedIframe-$id" class="isolated-iframe"></iframe>
+                        <script>
+                            var iframe = document.getElementById('isolatedIframe-$id');
+                            var doc = iframe.document || iframe.contentDocument || iframe.contentWindow.document;
+                            doc.open();
+                            doc.write(`{$htmlContent}`);
+                            doc.close();
+                        </script>
+                    </body>
+                    </html>
+                    HTML;
+    }
+
+    public static function startTimer()
+    {
+        self::$startTime = microtime(true);
+    }
+
+    public static function endTimer()
+    {
+        self::$closeTime = microtime(true) - self::$startTime;
+    }
+}

+ 240 - 0
core/class/fichier.class.php

@@ -0,0 +1,240 @@
+<?php
+
+class fichier
+{
+    static public function add(array $file, array $form)
+    {
+        if ($file['error'] === UPLOAD_ERR_OK && !empty($file["tmp_name"])) {
+            $md5 = md5_file($file["tmp_name"]);
+            $hash = self::generateHash($file['name']);
+            $durationInSeconds = fichier::getVideoDuration($file["tmp_name"]);
+
+            if (copy($file["tmp_name"], "../video/" . $md5 . ".mp4")) {
+                db::query("INSERT INTO videos (title, titleTmp, type, size, duration, md5, hash, active, dateEvent, user) VALUES (:title, :titleTmp, :type, :size, :duration, :md5, :hash, :active, :dateEvent, :user)");
+                db::bind(':title', htmlspecialchars($form['videoName']));
+                db::bind(':titleTmp', htmlspecialchars($file['name']));
+                db::bind(':type', htmlspecialchars($file['type']));
+                db::bind(':size', (int)$file['size']);
+                db::bind(':duration', $durationInSeconds);
+                db::bind(':md5', $md5);
+                db::bind(':hash', $hash);
+                db::bind(':active', (int)$form['videoStatus']);
+                db::bind(':dateEvent', $form["dateEvent"]);
+                db::bind(':user', htmlspecialchars($_SESSION["USER"]["name"]));
+
+                try {
+                    db::execute();
+                    return $hash;
+                } catch (Exception $ex) {
+                    error_log($ex->getMessage()); // Log l'erreur pour un examen ultérieur
+                    return FALSE;
+                }
+            }
+        }
+        return FALSE;
+    }
+
+
+    static public function update(array $form)
+    {
+        db::query(" UPDATE videos SET 
+                        title = :title,
+                        dateEvent = :dateEvent,
+                        active = :active 
+                    WHERE id = :id");
+        db::bind(':title', $form["videoName"]);
+        db::bind(':dateEvent', $form["dateEvent"]);
+        db::bind(':active', $form["videoStatus"]);
+        db::bind(':id', $form["id"]);
+        db::execute();
+    }
+
+    static public function updateTime($_id, $_duration)
+    {
+        db::query(" UPDATE videos SET 
+                        duration = :duration 
+                    WHERE id = :id");
+        db::bind(':duration', $_duration);
+        db::bind(':id', $_id);
+        db::execute();
+    }
+
+    public static function delete(string $_md5 = NULL, string $_folderFiles = "../video/")
+    {
+        if (isset($_md5) and $_md5 != NULL and file_exists($_folderFiles . $_md5)) {
+            if (unlink($_folderFiles . $_md5 . ".mp4")) {
+                unlink($_folderFiles . $_md5 . ".jpg");
+                db::query("DELETE FROM videos WHERE md5 = :md5");
+                db::bind(':md5', $_md5);
+
+                try {
+                    db::execute();
+                    return TRUE;
+                } catch (Exception $ex) {
+                    return FALSE;
+                }
+            } else {
+                return FALSE;
+            }
+        } else {
+            return FALSE;
+        }
+    }
+
+    static public function getById(float $id)
+    {
+        db::query("SELECT "
+            . "*"
+            . "FROM videos "
+            . "WHERE id = :id");
+        db::bind(':id', $id);
+
+        try {
+            $return = db::single();
+            return $return;
+        } catch (Exception $ex) {
+            return FALSE;
+        }
+    }
+
+    static public function getByHash(string $hash)
+    {
+        db::query("SELECT "
+            . "*"
+            . "FROM videos "
+            . "WHERE hash = :hash");
+        db::bind(':hash', $hash);
+
+        try {
+            $return = db::single();
+            return $return;
+        } catch (Exception $ex) {
+            return FALSE;
+        }
+    }
+
+    static public function getAll()
+    {
+        db::query("SELECT "
+            . "*"
+            . "FROM videos ORDER BY id DESC");
+
+        try {
+            $return = db::resultset();
+            return $return;
+        } catch (Exception $ex) {
+            return FALSE;
+        }
+    }
+
+    static private function generateHash($string)
+    {
+        $timestamp = time();
+        $combined = $string . $timestamp;
+        $hashValue = hash('sha256', $combined);
+        return $hashValue;
+    }
+
+    static public function getVideoDuration($filePath)
+    {
+        $command = "ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 " . escapeshellarg($filePath);
+        $duration = shell_exec($command);
+        if ($duration) {
+            return trim($duration);
+        } else {
+            return NULL;
+        }
+    }
+
+    static public function generatePreview($_md5)
+    {
+        $videoPreview = "../video/" . $_md5 . ".jpg"; 
+        if (file_exists($videoPreview)) {
+            return ['success' => TRUE, 'file' => 'Le fichier existe déjà'];
+        }
+        
+        $time = "00:00:00";
+        $videoFile = "../video/" . $_md5 . ".mp4"; 
+
+        if (!file_exists($videoFile)) {
+            return ['success' => FALSE, 'error' => 'Le fichier vidéo n\'existe pas.'];
+        }
+
+        // Générer un nom unique pour le fichier de sortie
+        $outputFile = tempnam(sys_get_temp_dir(), 'preview_') . '.jpg';
+
+        // Commande FFmpeg pour faire une capture d'image
+        $command = "ffmpeg -i " . escapeshellarg($videoFile) 
+        . " -frames:v 1 -q:v 5 " . escapeshellarg($outputFile);
+
+        // Exécuter la commande FFmpeg
+        exec($command, $output, $return_var);
+
+        // Vérifier si la commande a réussi
+        if ($return_var === 0) {
+            $destinationFile = "../video/" . $_md5 . ".jpg";
+            if (copy($outputFile, $destinationFile)) {
+                unlink($outputFile);  // Supprimer le fichier temporaire
+                return ['success' => TRUE, 'file' => $destinationFile];
+            } else {
+                unlink($outputFile);  // Supprimer le fichier temporaire en cas d'échec
+                return ['success' => FALSE, 'error' => 'Erreur lors de la copie du fichier généré.'];
+            }
+        } else {
+            unlink($outputFile);  // Supprimer le fichier temporaire en cas d'échec
+            return ['success' => FALSE, 'error' => 'Erreur lors de l\'exécution de la commande FFmpeg.'];
+        }
+    }
+
+
+    static public function cut()
+    {
+        if ($_SERVER['REQUEST_METHOD'] == 'POST') {
+            // Validation basique des temps de début et de fin
+            $startTime = $_POST['startTime'];
+            $endTime = $_POST['endTime'];
+
+            // Vérifier que les temps sont au bon format (HH:MM:SS)
+            if (!preg_match('/^\d{2}:\d{2}:\d{2}$/', $startTime) || !preg_match('/^\d{2}:\d{2}:\d{2}$/', $endTime)) {
+                return ['success' => FALSE, 'error' => 'Format incorrect pour startTime ou endTime.'];
+            }
+
+            // Chemin sécurisé du fichier vidéo
+            $videoFile = "../video/" . basename($_POST['md5']) . ".mp4";
+
+            if (!file_exists($videoFile)) {
+                return ['success' => FALSE, 'error' => 'Le fichier vidéo n\'existe pas.'];
+            }
+
+            // Générer un nom unique pour le fichier de sortie
+            $outputFile = tempnam(sys_get_temp_dir(), 'cut_') . '.mp4';
+
+            // Commande FFmpeg pour découper la vidéo
+            $command = "ffmpeg -i " . escapeshellarg($videoFile)
+                . " -ss " . escapeshellarg($startTime)
+                . " -to " . escapeshellarg($endTime)
+                . " -force_key_frames 'expr:gte(t,n_forced*1)' -c copy -movflags +faststart "
+                . escapeshellarg($outputFile);
+
+            // Exécuter la commande FFmpeg
+            exec($command, $output, $return_var);
+
+            // Vérifier si la commande a réussi
+            if ($return_var === 0) {
+                $destinationFile = "../video/_" . basename($_POST['md5']. ".mp4");
+                if (copy($outputFile, $destinationFile)) {
+                    unlink($outputFile);  // Supprimer le fichier temporaire
+                    return ['success' => TRUE, 'file' => $destinationFile];
+                } else {
+                    unlink($outputFile);  // Supprimer le fichier temporaire en cas d'échec
+                    return ['success' => FALSE, 'error' => 'Erreur lors de la copie du fichier généré.'];
+                }
+            } else {
+                unlink($outputFile);  // Supprimer le fichier temporaire en cas d'échec
+                return ['success' => FALSE, 'error' => 'Erreur lors de l\'exécution de la commande FFmpeg.'];
+            }
+        } else {
+            return ['success' => FALSE, 'error' => 'Requête non autorisée.'];
+        }
+    }
+}

+ 60 - 0
core/class/video.class.php

@@ -0,0 +1,60 @@
+<?php
+
+class video
+{
+    static public function stream(array $file)
+    {
+        $filePath = "../video/".$file["md5"] . ".mp4";
+        
+        if (!file_exists($filePath)) {
+            header("HTTP/1.0 404 Not Found");
+            exit;
+        }
+
+        $fileSize = filesize($filePath);
+        $range = 0;
+        $length = $fileSize;
+
+        // Gestion des requêtes partielles (Range)
+        if (isset($_SERVER['HTTP_RANGE'])) {
+            $range = $_SERVER['HTTP_RANGE'];
+            $range = str_replace('bytes=', '', $range);
+            $range = explode('-', $range);
+            $start = intval($range[0]);
+
+            $end = isset($range[1]) && is_numeric($range[1]) ? intval($range[1]) : $fileSize - 1;
+
+            if ($start > $end || $end >= $fileSize) {
+                header("HTTP/1.1 416 Requested Range Not Satisfiable");
+                exit;
+            }
+
+            $length = $end - $start + 1;
+            header("HTTP/1.1 206 Partial Content");
+            header("Content-Range: bytes $start-$end/$fileSize");
+        } else {
+            $start = 0;
+            $end = $fileSize - 1;
+        }
+
+        // En-têtes HTTP pour le streaming
+        header("Content-Type: " . $file["type"]);
+        header("Content-Length: $length");
+        header("Accept-Ranges: bytes");
+
+        $fp = fopen($filePath, 'rb');
+        fseek($fp, $start);
+        $bufferSize = 1024 * 8;
+        $bytesSent = 0;
+
+        // Lecture de la vidéo par morceaux
+        while (!feof($fp) && ($bytesSent < $length)) {
+            $buffer = fread($fp, $bufferSize);
+            echo $buffer;
+            flush(); // Vide le tampon de sortie
+            $bytesSent += strlen($buffer);
+        }
+
+        fclose($fp);
+    }
+}

+ 9 - 0
core/controllers/header.php

@@ -0,0 +1,9 @@
+<?php
+
+setlocale(LC_TIME, 'fr_FR');
+date_default_timezone_set("Europe/Paris");
+
+spl_autoload_register(function ($class_name) {
+    (file_exists('../core/class/'.$class_name.'.class.php'))?	
+    require_once '../core/class/'.$class_name.'.class.php' : '';
+});

+ 6 - 0
core/controllers/session.php

@@ -0,0 +1,6 @@
+<?php 
+
+if(empty($_SESSION["USER"]["token"]) OR (isset($_SESSION["USER"]["token"]) AND !cms::checkToken($_SESSION["USER"]["token"]))){
+    header("Location: https://" . DOMAIN_CMS);
+    exit();
+} 

+ 1 - 0
core/maj/maj.sql

@@ -0,0 +1 @@
+ALTER TABLE `videos` ADD `duration` INT NULL AFTER `size`; 

+ 6 - 0
core/page/_footer.php

@@ -0,0 +1,6 @@
+
+<script src='https://cdn.jsdelivr.net/npm/@popperjs/core@2.9.2/dist/umd/popper.min.js'></script>
+<script src='https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js'></script>
+</body>
+
+</html>

+ 30 - 0
core/page/_header.php

@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<html lang="fr">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>CSE Invent : Vidéos streaming</title>
+    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.0/dist/css/bootstrap.min.css">
+    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
+    <link rel="stylesheet" href="/css/media.css">
+    <script src='https://code.jquery.com/jquery-3.5.1.slim.min.js'></script>
+</head>
+
+<body>
+
+    <header class="navbar sticky-top navbar-expand-sm navbar-dark flex-md-nowrap p-0 shadow" style="background-color:#0a71af;">
+        <div class="container-fluid">
+            <a href="/" class="navbar-brand" style="box-shadow: none; background-color:#0a71af;">CSE Invent : Vidéos streaming</a>
+            <div id="navbarCollapse" class="collapse navbar-collapse p-0" style="display: flex; justify-content: flex-end;">
+                <ul class="navbar-nav">
+                    <li class="nav-item dropdown">
+                        <a class="nav-link dropdown-toggle" href="#" id="navbarDropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><?php echo $_SESSION["USER"]["name"] ?></a>
+                        <div class="dropdown-menu" aria-labelledby="navbarDropdownMenuLink" style="left:unset; right:0;">
+                            <a href="/edit/add" class="dropdown-item"><button type="submit" class="btn btn-outline-success btn-sm"><i class="bi bi-file-earmark-arrow-up-fill"></i> Ajouter une vidéo</button></a>
+                            <a href="https://<?php echo DOMAIN_CMS ?>/submit.php?from=logout" class="dropdown-item"><button type="submit" class="btn btn-outline-danger btn-sm"><i class="bi bi-box-arrow-left"></i> Se déconnecter</button></a>
+                        </div>
+                    </li>
+                </ul>
+            </div>
+        </div>
+    </header>

+ 102 - 0
core/page/video.cut.php

@@ -0,0 +1,102 @@
+<?php
+$data = fichier::getByHash($_GET["cut"]);
+if (empty($data["md5"])) {
+  header("Location: /");
+  exit();
+}
+?>
+
+<nav aria-label="breadcrumb" class="ariane">
+  <ol class="breadcrumb" style="border-radius: 0 0 5px 5px; padding:5px 10px;">
+    <li class="breadcrumb-item"><a href="/">Toutes les vidéos</a></li>
+    <li class="breadcrumb-item active"><a href="/edit/<?php echo $data["hash"] ?>"><?php echo $data["title"] ?></a></li>
+    <li class="breadcrumb-item active" aria-current="page">Découper la vidéo</li>
+  </ol>
+</nav>
+
+<div class='container' style="position: relative;" onsubmit="return confirmCut()">
+  <!-- Lecteur vidéo -->
+  <video id="videoStream" style="width:100%; margin-bottom: 20px;" controls>
+    <source src="https://<?php echo DOMAIN_MEDIAS . "/video/" . $data["hash"] ?>" type='video/mp4'>
+    Votre navigateur ne supporte pas la balise vidéo.
+  </video>
+
+  <!-- Formulaire -->
+  <form id="cutForm" method="POST">
+    <input type="hidden" name="from" value="video.cut">
+    <input type="hidden" name="id" value="<?php echo $data["id"] ?>">
+    <input type="hidden" name="md5" value="<?php echo $data["md5"] ?>">
+    <input type="hidden" name="hash" value="<?php echo $data["hash"] ?>">
+
+    <!-- Champ Heure de début -->
+    <div class="form-group">
+      <label for="startTime">Heure de début (format HH:MM:SS) :</label>
+      <div class="input-group mb-3">
+        <div class="input-group-prepend">
+          <button type="button" class='btn btn-secondary' onclick="setStartTime()">Cliquez ici pour définir le début de la vidéo</button>
+        </div>
+        <input class='form-control' type="text" id="startTime" name="startTime" value="00:00:00" required>
+      </div>
+    </div>
+
+    <!-- Champ Heure de fin -->
+    <div class="form-group">
+      <label for="endTime">Heure de fin (format HH:MM:SS) :</label>
+      <div class="input-group mb-3">
+        <div class="input-group-prepend">
+          <button type="button" class='btn btn-secondary' onclick="setEndTime()">Cliquez ici pour définir la fin de la vidéo</button>
+        </div>
+        <input class='form-control' type="text" id="endTime" name="endTime" value="<?php echo core::formatDuration($data["duration"], ":") ?>" required>
+      </div>
+    </div>
+
+    <!-- Bouton soumettre -->
+    <button type="submit" class='btn btn-primary btn-lg'>Découper la Vidéo</button>
+  </form>
+</div>
+
+<script>
+  // Fonction pour convertir le temps en format HH:MM:SS
+  function formatTime(seconds) {
+    const h = Math.floor(seconds / 3600).toString().padStart(2, '0');
+    const m = Math.floor((seconds % 3600) / 60).toString().padStart(2, '0');
+    const s = Math.floor(seconds % 60).toString().padStart(2, '0');
+    return `${h}:${m}:${s}`;
+  }
+
+  // Fonction pour définir l'heure de début
+  function setStartTime() {
+    const video = document.getElementById('videoStream');
+    const startTimeField = document.getElementById('startTime');
+    startTimeField.value = formatTime(video.currentTime);
+  }
+
+  // Fonction pour définir l'heure de fin (avec une seconde ajoutée)
+  function setEndTime() {
+    const video = document.getElementById('videoStream');
+    const endTimeField = document.getElementById('endTime');
+
+    // Ajouter une seconde à la position actuelle
+    const endTimeWithExtraSecond = video.currentTime;
+
+    // Mettre à jour le champ avec le temps ajusté
+    endTimeField.value = formatTime(endTimeWithExtraSecond);
+  }
+
+  // Fonction pour afficher une confirmation avant la soumission du formulaire
+  function confirmCut() {
+    const startTime = document.getElementById('startTime').value;
+    const endTime = document.getElementById('endTime').value;
+
+    if(startTime === "00:00:00" && endTime === "<?php echo core::formatDuration($data["duration"], ":") ?>"){
+      window.location.href = "/edit/<?php echo $data["hash"] ?>";
+      return false;
+    }
+
+    // Message de confirmation personnalisé
+    const message = `Vous êtes sur le point de découper la vidéo car ce sera définitif.\n\nElle commencera à ${startTime} et se terminera à ${endTime}.\n\nVoulez-vous continuer ?`;
+
+    // Afficher la boîte de dialogue de confirmation
+    return confirm(message);
+  }
+</script>

+ 131 - 0
core/page/video.form.add.php

@@ -0,0 +1,131 @@
+<?php
+    $data = [];
+?>
+<nav aria-label="breadcrumb" class="ariane">
+    <ol class="breadcrumb" style="border-radius: 0 0 5px 5px; padding:5px 10px;">
+        <li class="breadcrumb-item"><a href="/">Toutes les vidéos</a></li>
+        <li class="breadcrumb-item active" aria-current="page"><?php echo isset($data["title"]) ? $data["title"] : "Ajouter une vidéo"; ?></li>
+    </ol>
+</nav>
+
+<div class='container' style="position: relative;">
+    <form method="post" id="uploadForm" enctype="multipart/form-data">
+        <input type="hidden" name="from" value="video.form.add">
+        <div class='form-group' id="progressBarBox" style="display:none;">
+            <span id="progressPercent">0%</span>
+            <progress id="progressBar" value="0" max="100" style="width: 100%; display: none;"></progress>
+        </div>
+        <div class='form-group SubmitElement'>
+            <label for='videoFile'>Charger la vidéo</label>
+            <div class='custom-file'>
+                <input type='file' name='videoFile' class='custom-file-input' id='videoFile' accept='video/*' required>
+                <label class='custom-file-label' for='videoFile'>Choisir un fichier</label>
+            </div>
+        </div>
+        <div class='form-group' id="previewFileName" style="display:none;">
+            <label for='selectedFileName'>Nom de la vidéo sélectionnée</label>
+            <input type='text' class='form-control' id='selectedFileName' readonly>
+        </div>
+        <div class='form-group SubmitElement'>
+            <label>Statut de la vidéo</label>
+            <div class='custom-control custom-radio'>
+                <input type='radio' id='activeStatus' name='videoStatus' class='custom-control-input' value='1' <?php echo ((isset($data["active"]) and $data["active"] == 1) or !isset($data["active"])) ? "checked" : NULL; ?>>
+                <label class='custom-control-label' for='activeStatus'>Accessible à tous</label>
+            </div>
+            <div class='custom-control custom-radio'>
+                <input type='radio' id='inactiveStatus' name='videoStatus' class='custom-control-input' value='0' <?php echo (isset($data["active"]) and $data["active"] == 0) ? "checked" : NULL; ?>>
+                <label class='custom-control-label' for='inactiveStatus'>Non accessible</label>
+            </div>
+        </div>
+        <div class='form-group'>
+            <label for='videoName'>Titre de la vidéo</label>
+            <input type='text' class='form-control' id='videoName' name="videoName" value="<?php echo isset($data["title"]) ? $data["title"] : NULL; ?>" required>
+        </div>
+        <div class='form-group'>
+            <label for='dateEvent'>Jour de l'évènement</label>
+            <input class='form-control' type="date" id="dateEvent" name="dateEvent" value="<?php echo isset($data["dateEvent"]) ? $data["dateEvent"] : NULL; ?>" required>
+        </div>
+        <div class='form-group SubmitElement'>
+            <button type='submit' class='btn btn-primary btn-lg'>Enregistrer la vidéo</button>
+        </div>
+    </form>
+</div>
+<style>
+    #progressBar {
+        height: 20px;
+    }
+
+    #progressPercent {
+        font-weight: bold;
+    }
+</style>
+<script>
+    document.getElementById('videoFile').addEventListener('change', function() {
+        var fileName = this.files[0].name;
+        document.getElementById('selectedFileName').value = fileName;
+        document.getElementById('previewFileName').style.display = 'block';
+    });
+
+    document.getElementById('uploadForm').addEventListener('submit', function(event) {
+        document.getElementById('progressBarBox').style.display = 'block';
+        var elements = document.getElementsByClassName('SubmitElement');
+
+        for (var i = 0; i < elements.length; i++) {
+            elements[i].style.display = 'none';
+        }
+        event.preventDefault();
+
+        var form = document.getElementById('uploadForm');
+        var fileInput = document.getElementById('videoFile');
+        var progressBar = document.getElementById('progressBar');
+        var progressPercent = document.getElementById('progressPercent');
+
+        progressBar.style.display = 'block';
+
+        var formData = new FormData(form);
+        var xhr = new XMLHttpRequest();
+
+        xhr.open('POST', '/edit/add', true);
+        xhr.upload.onprogress = function(event) {
+            if (event.lengthComputable) {
+                var percentComplete = (event.loaded / event.total) * 100;
+                progressBar.value = percentComplete;
+                progressPercent.textContent = Math.round(percentComplete) + '%';
+            }
+        };
+
+        xhr.onload = function() {
+            if (xhr.status === 200) {
+                try {
+                    // Récupérer la réponse JSON contenant l'ID
+                    var response = JSON.parse(xhr.responseText);
+                    var videoId = response.id;
+
+                    if (videoId) {
+                        // Rediriger vers /edit/ID avec l'ID récupéré
+                        window.location.href = "/edit/" + videoId;
+                    } else {
+                        alert("Erreur : ID non trouvé dans la réponse.");
+                        showElement();
+                    }
+                } catch (e) {
+                    alert("Erreur lors du traitement de la réponse.");
+                    showElement();
+                }
+            } else {
+                alert('Erreur lors du téléchargement.');
+                // progressBar.value = 0; // Réinitialiser la barre
+                // progressPercent.textContent = '0%';
+                showElement();
+            }
+        };
+        xhr.send(formData);
+    });
+
+    function showElement(){
+        var elements = document.getElementsByClassName('SubmitElement');
+        for (var i = 0; i < elements.length; i++) {
+            elements[i].style.display = 'block';
+        }
+    }
+</script>

+ 101 - 0
core/page/video.form.php

@@ -0,0 +1,101 @@
+<?php
+    $data = fichier::getByHash($_GET["edit"]);
+    if(empty($data["md5"])){
+        header("Location: /");
+        exit();
+    }
+
+    if($data["duration"] == NULL){
+        $durationInSeconds = fichier::getVideoDuration("../video/" . $data["md5"]);
+        fichier::updateTime($data["id"], $durationInSeconds);
+    }
+
+    fichier::generatePreview($data["md5"]);
+?>
+<nav aria-label="breadcrumb" class="ariane">
+    <ol class="breadcrumb" style="border-radius: 0 0 5px 5px; padding:5px 10px;">
+        <li class="breadcrumb-item"><a href="/">Toutes les vidéos</a></li>
+        <li class="breadcrumb-item active" aria-current="page"><?php echo isset($data["title"]) ? $data["title"] : "Ajouter une vidéo"; ?></li>
+    </ol>
+</nav>
+
+<div class='container' style="position: relative;">
+    <div class="btn-group" style="position: absolute; top: 10px; right: 10px; z-index: 10;">
+        <button type="button" class="btn btn-secondary" onclick="window.open('/cut/<?php echo $data["hash"] ?>', '_self')">
+            <i class="bi bi-scissors"></i>
+        </button>
+        <button type="button" class="btn btn-danger" onclick="confirmAction('<?php echo $data["md5"] ?>')">
+            <i class="bi bi-trash"></i>
+        </button>
+    </div>
+    <form method="post">
+        <input type="hidden" name="from" value="video.form">
+        <input type="hidden" name="id" value="<?php echo $data["id"] ?>">
+        <input type="hidden" name="hash" value="<?php echo $data["hash"] ?>">
+        <video id="videoStream" style="width:100%; margin-bottom: 20px;" controls>
+            <source id="videoSource" src="" type='video/mp4'>
+            Votre navigateur ne supporte pas la balise vidéo.
+        </video>
+        <div class="form-group">
+            <label for='videoLink'>Lien de la vidéo</label>
+            <input type="text" class="form-control" id='videoLink' value="https://<?php echo DOMAIN_MEDIAS . "/video/" . $data["hash"] ?>" readonly>
+        </div>
+        <div class='form-group' id="previewFileName" style="display:none;">
+            <label for='selectedFileName'>Nom de la vidéo sélectionnée</label>
+            <input type='text' class='form-control' id='selectedFileName' readonly>
+        </div>
+        <div class='form-group SubmitElement'>
+            <label>Statut de la vidéo</label>
+            <div class='custom-control custom-radio'>
+                <input type='radio' id='activeStatus' name='videoStatus' class='custom-control-input' value='1' <?php echo ((isset($data["active"]) and $data["active"] == 1) or !isset($data["active"])) ? "checked" : NULL; ?>>
+                <label class='custom-control-label' for='activeStatus'>Accessible à tous</label>
+            </div>
+            <div class='custom-control custom-radio'>
+                <input type='radio' id='inactiveStatus' name='videoStatus' class='custom-control-input' value='0' <?php echo (isset($data["active"]) and $data["active"] == 0) ? "checked" : NULL; ?>>
+                <label class='custom-control-label' for='inactiveStatus'>Non accessible</label>
+            </div>
+        </div>
+        <div class='form-group'>
+            <label for='videoName'>Titre de la vidéo</label>
+            <input type='text' class='form-control' id='videoName' name="videoName" value="<?php echo isset($data["title"]) ? $data["title"] : NULL; ?>" required>
+        </div>
+        <div class='form-group'>
+            <label for='dateEvent'>Jour de l'évènement</label>
+            <input class='form-control' type="date" id="dateEvent" name="dateEvent" value="<?php echo isset($data["dateEvent"]) ? $data["dateEvent"] : NULL; ?>" required>
+        </div>
+        <div class="form-group">
+            <label for='add'>Chargée le</label>
+            <input type="text" class="form-control" id='add' value="<?php echo $data["add"] ?>" readonly>
+        </div>
+        <div class="form-group">
+            <label for='add'>Durée de la vidéo</label>
+            <input type="text" class="form-control" value="<?php echo isset($data["duration"]) ? core::formatDuration($data["duration"]) : NULL; ?>" readonly>
+        </div>
+        <div class='form-group SubmitElement'>
+            <button type='submit' class='btn btn-primary btn-lg'>Enregistrer la vidéo</button>
+        </div>
+    </form>
+</div>
+
+<script>
+function confirmAction(md5) {
+    if (confirm("Êtes-vous sûr de vouloir supprimer cette vidéo ?")) {
+        window.open('/delete/' + md5, '_self');
+    }
+}
+
+window.onload = function() {
+    const video = document.getElementById('videoStream');
+    const source = document.getElementById('videoSource');
+    
+    // Ajouter un timestamp à l'URL pour éviter le cache
+    const videoUrl = 'https://<?php echo DOMAIN_MEDIAS . "/video/" . $data["hash"] ?>';
+    const newSrc = videoUrl + '?t=' + new Date().getTime();
+    
+    // Mettre à jour la source de la vidéo avec l'URL modifiée
+    source.src = newSrc;
+    
+    // Recharger et lire la vidéo
+    video.load();
+};
+</script>

+ 19 - 0
core/page/video.preview.php

@@ -0,0 +1,19 @@
+<?php 
+
+if (isset($_GET['preview'])) {
+    $file = fichier::getByHash($_GET['preview']);
+    if($file != FALSE){
+        if($file['active'] == 1 OR isset($_SESSION["USER"]["token"])){
+            header("Content-Type: image/jpg");
+            readfile('../video/' . $file['md5'] . ".jpg", "r");
+            exit;
+        } else {
+            header("HTTP/1.1 403 Forbidden");
+            exit;
+        }
+    } else {
+        echo "Preview de la vidéo introuvable ou non spécifié.";
+    }
+} else {
+    echo "Aucun ID de vidéo spécifié.";
+}

+ 17 - 0
core/page/video.show.php

@@ -0,0 +1,17 @@
+<?php 
+
+if (isset($_GET['video'])) {
+    $file = fichier::getByHash($_GET['video']);
+    if($file != FALSE){
+        if($file['active'] == 1 OR isset($_SESSION["USER"]["token"])){
+            video::stream($file);
+        } else {
+            header("HTTP/1.1 403 Forbidden");
+            exit;
+        }
+    } else {
+        echo "Fichier vidéo introuvable ou non spécifié.";
+    }
+} else {
+    echo "Aucun ID de vidéo spécifié.";
+}

+ 144 - 0
core/page/videos.all.php

@@ -0,0 +1,144 @@
+<?php
+$videos = fichier::getAll();
+?>
+
+<nav aria-label="breadcrumb" class="ariane">
+    <ol class="breadcrumb" style="border-radius: 0 0 5px 5px; padding:5px 10px;">
+        <li class="breadcrumb-item">Toutes les vidéos</li>
+    </ol>
+</nav>
+
+<div class="container" style="margin-top:0;">
+    <div class="row mb-10">
+        <div class="col-md-6">
+            <input type="text" id="searchTitle" class="form-control" placeholder="Rechercher par titre...">
+        </div>
+        <div class="col-md-2">
+            <select id="searchMonth" class="form-control">
+                <option value="">Mois</option>
+                <option value="01">01 - Janvier</option>
+                <option value="02">02 - Février</option>
+                <option value="03">03 - Mars</option>
+                <option value="04">04 - Avril</option>
+                <option value="05">05 - Mai</option>
+                <option value="06">06 - Juin</option>
+                <option value="07">07 - Juillet</option>
+                <option value="08">08 - Août</option>
+                <option value="09">09 - Septembre</option>
+                <option value="10">10 - Octobre</option>
+                <option value="11">11 - Novembre</option>
+                <option value="12">12 - Décembre</option>
+            </select>
+        </div>
+        <div class="col-md-2">
+            <input type="number" id="searchYear" class="form-control" placeholder="Année" min="1900" max="2100">
+        </div>
+
+        <div class="col-md-2 text-end">
+            <button id="resetButton" class="btn btn-secondary">Réinitialiser</button>
+        </div>
+    </div>
+</div>
+
+<div class="container" style="margin-top:-30px;">
+    <?php
+
+    foreach ($videos as $video) {
+        fichier::generatePreview($video["md5"]);
+            echo '<div class="video-container big_topic" id="topic-big-' . $video["id"] . '">
+                    <div class="video-content">
+                        <img src="https://' . DOMAIN_MEDIAS . "/preview/" . $video["hash"] . '" alt="Preview" class="video-preview" style="width:350; height:auto;">
+                        <div class="video-details">
+                            <div class="actions">
+                                <div class="btn-group">
+                                    <button type="button" class="btn btn-outline-primary" onclick="window.open(\'/edit/' . $video["hash"] . '\', \'_self\')">
+                                        <i class="bi bi-pencil-square"></i>
+                                    </button>
+                                </div>
+                            </div>
+                            <div style="margin-top:-35px">
+                                <div class="video-title">' . $video["title"] . '</div>
+                                <div class="input-group mb-3">
+                                    <div class="input-group-prepend">
+                                        <span class="input-group-text">Lien</span>
+                                    </div>
+                                    <input type="text" class="form-control" value="https://' . DOMAIN_MEDIAS . "/video/" . $video["hash"] . '" style="background-color: #fff !important;" readonly>
+                                </div>
+                                <div class="video-info" style="text-align: right;">
+                                    Date : ' . $video["dateEvent"] . ' | Durée : ' . core::formatDuration($video["duration"]) . ' | Statut : ' . ($video["active"] == 1 ? "<span style='color:green'>Vidéo en ligne</span>" : "<span style='color:red'>Vidéo suspendue</span>") . '
+                                </div>
+                            </div>
+                        </div>
+                        
+                    </div>
+                </div>
+                ';
+            echo '<div class="video-container little_topic" id="topic-little-' . $video["id"] . '" onclick="showTopic(' . $video["id"] . ')">
+                    <div class="video-content">
+                        <div class="video-details">
+                            <div>
+                                <div class="video-title title-little">' . $video["title"] . '</div>
+                                <div class="video-info">
+                                    Date : ' . $video["dateEvent"] . ' | Durée : ' . core::formatDuration($video["duration"]) . ' | Statut : ' . ($video["active"] == 1 ? "<span style='color:green'>Vidéo en ligne</span>" : "<span style='color:red'>Vidéo suspendue</span>") . '
+                                </div>
+                            </div>
+                        </div>
+                        
+                    </div>
+                </div>
+                ';
+    }
+
+    ?>
+</div>
+
+<script>
+    document.getElementById('searchTitle').addEventListener('input', filterVideos);
+    document.getElementById('searchYear').addEventListener('input', filterVideos);
+    document.getElementById('searchMonth').addEventListener('change', filterVideos);
+    document.getElementById('resetButton').addEventListener('click', resetFilters);
+
+    function filterVideos() {
+        var searchTitle = document.getElementById('searchTitle').value.toLowerCase();
+        var searchYear = document.getElementById('searchYear').value;
+        var searchMonth = document.getElementById('searchMonth').value;
+
+        var videos = document.querySelectorAll('.video-container');
+
+        videos.forEach(function(video) {
+            var title = video.querySelector('.video-title').textContent.toLowerCase();
+            var dateText = video.querySelector('.video-info').textContent.toLowerCase();
+
+            // Extraire la date (format attendu : 'Date : YYYY-MM-DD')
+            var videoDateMatch = dateText.match(/date\s*:\s*(\d{4})-(\d{2})/i); // Extrait YYYY-MM
+            var videoYear = videoDateMatch ? videoDateMatch[1] : '';
+            var videoMonth = videoDateMatch ? videoDateMatch[2] : '';
+
+            // Vérifier si le titre, l'année et le mois correspondent à la recherche
+            var titleMatch = title.includes(searchTitle) || searchTitle === '';
+            var yearMatch = videoYear === searchYear || searchYear === '';
+            var monthMatch = videoMonth === searchMonth || searchMonth === '';
+
+            if (titleMatch && yearMatch && monthMatch) {
+                video.style.display = ''; // Afficher la vidéo si elle correspond aux critères
+            } else {
+                video.style.display = 'none'; // Masquer sinon
+            }
+        });
+    }
+
+    function resetFilters() {
+        document.getElementById('searchTitle').value = '';
+        document.getElementById('searchYear').value = '';
+        document.getElementById('searchMonth').value = '';
+        filterVideos(); // Réinitialiser le filtre
+    }
+
+    function showTopic(id){
+        $(".little_topic").show();
+        $(".big_topic").hide();
+        filterVideos();
+        $("#topic-little-" + id).hide();
+        $("#topic-big-" + id).show();
+    }
+</script>

+ 30 - 0
core/submit/record.jwt.php

@@ -0,0 +1,30 @@
+<?php
+
+// Vérifier si la méthode est POST
+if ($_SERVER['REQUEST_METHOD'] === 'POST') { 
+    // Vérifier la présence de l'en-tête "Referer"
+    if (isset($_SERVER['HTTP_REFERER'])) {
+        // Récupérer l'URL de référence (Referer)
+        $referer = $_SERVER['HTTP_REFERER'];
+        $allowed_referer = "https://" . DOMAIN_CMS . "/";
+
+        // Comparer le "Referer" avec l'URL autorisée
+        if ($referer === $allowed_referer) {
+            $_SESSION["USER"]["token"] = $_POST["token"];
+            $_SESSION["USER"]["name"] = $_POST["name"];
+            header("Location: https://" . DOMAIN_MEDIAS);
+            exit();
+        } else {
+            // Le "Referer" ne correspond pas à l'URL autorisée
+            http_response_code(403); // Code HTTP 403 Forbidden
+            echo "Accès refusé.";
+        }
+    } else {
+        // Si le "Referer" n'est pas défini, refuser également la requête
+        http_response_code(403); // Code HTTP 403 Forbidden
+        echo "Accès refusé. Aucun referer détecté.";
+    }
+} else {
+    // Si la méthode n'est pas POST, refuser la requête
+    http_response_code(405); // Code HTTP 405 Method Not Allowed
+}

+ 12 - 0
core/submit/video.add.php

@@ -0,0 +1,12 @@
+<?php 
+
+if(isset($_FILES["videoFile"]["tmp_name"])){
+    $idVideo = fichier::add($_FILES["videoFile"], $_POST);
+    if($idVideo != FALSE) {
+        echo json_encode(['id' => $idVideo]);
+        exit();
+    }
+} else {
+    header("Location: /");
+    exit();
+}

+ 21 - 0
core/submit/video.cut.php

@@ -0,0 +1,21 @@
+<?php 
+
+if(isset($_POST["from"]) AND $_POST["from"] == "video.cut"){
+    require_once "../core/controllers/session.php";
+    $execute = fichier::cut();
+
+    if($execute["success"] == TRUE){
+        unlink("../video/" . $_POST['md5']. ".mp4");
+        rename("../video/_" . $_POST['md5']. ".mp4", "../video/" . $_POST['md5']. ".mp4");
+        $durationInSeconds = fichier::getVideoDuration("../video/" . $_POST["md5"]. ".mp4");
+        fichier::updateTime($_POST["id"], $durationInSeconds);
+    } else {
+        core::print_r($execute);
+        exit();
+    }
+    header("Location: /edit/".$_POST["hash"]);
+    exit();
+} else {
+    header("Location: /");
+    exit();
+}

+ 11 - 0
core/submit/video.delete.php

@@ -0,0 +1,11 @@
+<?php 
+
+if(isset($_GET["delete"])){
+    require_once "../core/controllers/session.php";
+    fichier::delete($_GET["delete"]);
+    header("Location: /");
+    exit();
+} else {
+    header("Location: /");
+    exit();
+}

+ 7 - 0
core/submit/video.edit.php

@@ -0,0 +1,7 @@
+<?php 
+
+if(isset($_POST["from"])){
+    fichier::update($_POST);
+    header("Location: /edit/".$_POST["hash"]);
+    exit();
+}

+ 77 - 0
env.inc.template.php

@@ -0,0 +1,77 @@
+<?php
+
+// DEVELOPPEMENT
+define("URL_DEV_MEDIA", "local.media.cse-invent.com");
+define("URL_DEV_CMS", "local.cms.cse-invent.com");
+
+define("URL_DEV", array(
+    URL_DEV_MEDIA,
+    URL_DEV_CMS
+));
+
+// RECETTE
+define("URL_R7_MEDIA", "local.media.cse-invent.com");
+define("URL_R7_CMS", "r7.cms.cse-invent.com");
+
+define("URL_R7", array(
+    URL_R7_MEDIA,
+    URL_R7_CMS
+));
+
+// PRE-PRODUCTION
+define("URL_PREPROD_MEDIA", "pp.media.cse-invent.com");
+define("URL_PREPROD_CMS", "pp.cms.cse-invent.com");
+
+define("URL_PREPROD", array(
+    URL_PREPROD_MEDIA,
+    URL_PREPROD_CMS
+));
+
+// PRODUCTION
+define("URL_PROD_MEDIA", "media.cse-invent.com");
+define("URL_PROD_CMS", "cms.cse-invent.com");
+
+define("URL_PROD", array(
+    URL_PROD_MEDIA,
+    URL_PROD_CMS
+));
+
+if (in_array($_SERVER['HTTP_HOST'], URL_DEV))
+{
+    define("ENVIRONNEMENT", "DEV"); 
+    define("DOMAIN_MEDIAS", URL_DEV_MEDIA);
+    define("DOMAIN_CMS", URL_DEV_CMS);
+
+    define("DOCUMENT_ROOT", "/Users/stanyferer/Sites/cms.cse-invent.com/html/");
+
+    define("DB_HOST", "localhost");
+    define("DB_USER", "root");
+    define("DB_PASS", "root");
+    define("DB_NAME", "local.media.cse-invent.com");
+} 
+elseif (in_array($_SERVER['HTTP_HOST'], URL_PREPROD))
+{
+    define("ENVIRONNEMENT", "PREPROD"); 
+    define("DOMAIN_MEDIAS", URL_PREPROD_MEDIA);
+    define("DOMAIN_CMS", URL_PREPROD_CMS);
+
+    define("DOCUMENT_ROOT", "/var/www/pp.medias/");
+
+    define("DB_HOST", "localhost");
+    define("DB_USER", "");
+    define("DB_PASS", "");
+    define("DB_NAME", "");
+}
+elseif (in_array($_SERVER['HTTP_HOST'], URL_PROD))
+{
+    define("ENVIRONNEMENT", "PROD");
+    define("DOMAIN_MEDIAS", URL_PROD_MEDIA);
+    define("DOMAIN_CMS", URL_PROD_CMS);
+
+    define("DOCUMENT_ROOT", "/var/www/medias/");
+
+    define("DB_HOST", "localhost");
+    define("DB_USER", "");
+    define("DB_PASS", "");
+    define("DB_NAME", "");
+}

+ 8 - 0
public/.htaccess

@@ -0,0 +1,8 @@
+RewriteEngine On
+RewriteBase /
+
+RewriteRule ^video/(.*)$ /?video=$1 [L,NC,QSA,NS]
+RewriteRule ^preview/(.*)$ /?preview=$1 [L,NC,QSA,NS]
+RewriteRule ^edit/(.*)$ /?edit=$1 [L,NC,QSA,NS]
+RewriteRule ^cut/(.*)$ /?cut=$1 [L,NC,QSA,NS]
+RewriteRule ^delete/(.*)$ /?delete=$1 [L,NC,QSA,NS]

+ 115 - 0
public/css/media.css

@@ -0,0 +1,115 @@
+body {
+    background-color: #f8f9fa;
+}
+
+.ariane {
+    width: 1140px;
+    margin-bottom: 10px;
+    margin-right: auto;
+    margin-left: auto;
+}
+
+.container {
+    width: 1200px;
+    margin-top: 30px;
+    margin-bottom: 50px;
+    padding: 30px;
+    background-color: white;
+    border-radius: 5px;
+    box-shadow: 0 0 20px rgba(0, 0, 0, 0.1);
+}
+
+h1 {
+    color: #007bff;
+    margin-bottom: 30px;
+}
+
+.form-group label {
+    font-weight: bold;
+}
+
+.btn-primary {
+    width: 100%;
+    margin-top: 20px;
+}
+
+.video-container {
+    border: 1px solid #ddd;
+    border-radius: 5px;
+    box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
+    background-color: #f9f9f9;
+    margin-bottom: 10px;
+    overflow: hidden;
+    transition: max-height 0.3s ease;
+}
+.video-content {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    padding: 15px;
+}
+.video-details {
+    display: flex;
+    flex-direction: column;
+    justify-content: flex-start; /* Aligne le contenu en haut */
+    flex-grow: 1;
+}
+.video-info {
+    font-size: 0.9em;
+    color: #666;
+    width: 100%;
+}
+.video-title {
+    font-size: 1.2em;
+    font-weight: bold;
+    margin: 5px 0 10px 0;
+}
+.title-little {
+    margin: 0 !important;
+}
+.actions {
+    display: flex;
+    flex-direction: row-reverse;
+    margin-top: -5px;
+}
+.actions .btn {
+    margin-left: 5px;
+}
+.video-preview {
+    width: 200px;
+    height: 113px;
+    object-fit: cover;
+    margin-right: 10px;
+}
+
+/*
+ * Navbar
+ */
+
+.navbar-brand {
+    padding-top: .75rem;
+    padding-bottom: .75rem;
+    font-size: 1rem;
+    background-color: rgba(0, 0, 0, .25);
+    box-shadow: inset -1px 0 0 rgba(0, 0, 0, .25);
+}
+
+.navbar .navbar-toggler {
+    top: .25rem;
+    right: 1rem;
+}
+
+.navbar .form-control {
+    padding: .75rem 1rem;
+    border-width: 0;
+    border-radius: 0;
+}
+
+.big_topic{
+    display: none;
+}
+
+.little_topic:hover{
+    background-color: #dbf3fa;
+    cursor: ns-resize;
+}

+ 0 - 0
public/css/text.css


BIN
public/favicon.ico


+ 14 - 0
public/index.php

@@ -0,0 +1,14 @@
+<?php
+
+session_start();
+
+/*
+error_reporting(E_ALL);
+ini_set("display_errors", 1);
+*/
+
+require_once "../env.inc.php";
+require_once "../core/controllers/header.php";
+core::switch();
+
+?>

+ 0 - 0
video/index.html