From 10954c386cacb270e4ae16837483120ca3406259 Mon Sep 17 00:00:00 2001 From: polo Date: Wed, 1 Sep 2021 23:35:42 +0200 Subject: albums --- controller/admin.php | 86 ++++++++++++++++---- controller/ckeditor.php | 124 ++++++++++++++++------------- controller/installation.php | 5 +- controller/visitor.php | 65 ++++++++++++--- index.php | 6 +- model/Classes.php | 190 +++++++++++++++++++++++++------------------- public/discographie.css | 14 +++- view/discographie.php | 51 ++++++++++-- view/melaine.php | 4 +- view/template.php | 2 +- 10 files changed, 362 insertions(+), 185 deletions(-) diff --git a/controller/admin.php b/controller/admin.php index 0abdb1c..2588d36 100644 --- a/controller/admin.php +++ b/controller/admin.php @@ -8,11 +8,9 @@ function melaineEdit($numArticle, $suppression) { $page_actuelle = "melaine"; - $Articles = new ArticlesManager; - - // contenu de la page - $Articles->setPage($page_actuelle); - $Articles->getFiles(); + // modèle + $Article = new OneArticle($page_actuelle); + $Article->makeFileList(); // nouvel article if($numArticle == 0) @@ -23,13 +21,13 @@ function melaineEdit($numArticle, $suppression) else { // nom de l'article ciblé (objet et session) - $Articles->findFileName($numArticle); - $_SESSION['nomFichier'] = $Articles->getFileName(); + $Article->findFileName($numArticle); + $_SESSION['nomFichier'] = $Article->getFileName(); // suppression if($suppression) { - $Articles->delete(); + $Article->delete(); header('Location: index.php?page=' . $page_actuelle); exit(); } @@ -37,15 +35,12 @@ function melaineEdit($numArticle, $suppression) else { $title = "Modifier un article"; - - // contenu envoyé à l'éditeur - $texte = $Articles->getOne(); + $texte = $Article->readOne(); // entrée de l'éditeur } } // pour l'affichage des articles - $Articles->reverseFilesArray(); - $articles = $Articles->getAll(); + $articles = array_reverse($Article->readAll()); // lourd // sécurisation du contenu pré-existant inséré dans l'éditeur if($numArticle >= 0 && !$suppression) @@ -73,13 +68,70 @@ function discoEdit($numArticle, $suppression) $title = "Discographie"; // modèle - $Albums = new AlbumsManager; - $texte = ''; + $Album = new OneArticle($page_actuelle); + $Album->makeFileList(); + + // nouvel album + if($numArticle == 0) + { + $title = "Ajouter un album"; + $texte = ''; + } + else + { + // nom de l'article ciblé (objet et session) + $Album->findFileName($numArticle); + $_SESSION['nomFichier'] = $Album->getFileName(); + + // suppression + if($suppression) + { + $Album->delete(); + header('Location: index.php?page=' . $page_actuelle); + exit(); + } + // modification + else + { + $title = "Modifier un album"; + $texte = $Album->readOne(); // entrée de l'éditeur + } + } + + $albums = array_reverse($Album->readAll()); // lourd + + // $albums contient un tableau de chaines JSON, + // on extrait de chacune 3 variables: titre, année, pochette // traitements PHP pour l'éditeur - require('controller/ckeditor.php'); // sécurisation du contenu pré-existant inséré dans l'éditeur - $texte = preparationCKeditor($numArticle, $texte); + if($numArticle >= 0 && !$suppression) + { + require('controller/ckeditor.php'); + $texte = preparationCKeditor($numArticle, $texte); + } + + // changer les chaines JSON en tableaux + $i = 0; + foreach($albums as $oneAlbum) + { + $albums[$i] = json_decode($oneAlbum, true); + $i++; + } + + // pour chaque album, détecter le fichier html + // si il y en a un, proposer un lien + // si non, ne fournir qu'un lien d'ancre pour la liste d'album + $titreAlbum = 'discographie'; + if(false) + { + $lienAlbum = $titreAlbum; + } + else + { + $lienAlbum = 'discographie#' . $titreAlbum; + } + //echo($lienAlbum); // morceaux en HTML à assembler // variable $editeurHTML, contient $texte diff --git a/controller/ckeditor.php b/controller/ckeditor.php index d25e5ac..2e72be2 100644 --- a/controller/ckeditor.php +++ b/controller/ckeditor.php @@ -44,35 +44,51 @@ function preparationCKeditor($numArticle, $texte) function submitCKeditor($nomFichier) { $page = $_GET['page']; - $contenu = $_POST['contenu']; // déjà fait mais on ne sait jamais if(!isset($_SESSION['admin']) || $_SESSION['admin'] != 1) { header('Location: index.php?page=' . $page . '&erreur=connexion'); + exit(); } - else + + // sécurité faille XSS avec htmLawed + $configHtmLawed = array( + 'safe'=>1, // protection contre les élements et attributs dangereux + 'elements'=>'h2, h3, h4, p, br, span, i, strong, u, mark, blockquote, li, ol, ul, a, figure, hr, img, figcaption, table, tbody, tr, td', // paramètre optionnel: les balises non indiquées sont supprimées + 'deny_attribute'=>'id', // gêner le JS hostile + // on garde 'class' et 'style' utilisés par le ckediteur + ); + $specHtmLawed = ''; // optionnel: faire qu'un certain élément puisse n'avoir que certains attributs + + // de l'éditeur + if(isset($_POST['contenu'])) // optionnel pour discographie { + $contenu = $_POST['contenu']; + // récupérer les liens multimedia //require("media.php"); //$contenu = mediaSubmit($contenu); - // sécurité faille XSS - $configHtmLawed = array( - 'safe'=>1, // protection contre les élements et attributs dangereux - 'elements'=>'h2, h3, h4, p, br, span, i, strong, u, mark, blockquote, li, ol, ul, a, figure, hr, img, figcaption, table, tbody, tr, td', // paramètre optionnel: les balises non indiquées sont supprimées - 'deny_attribute'=>'id', // gêner le JS hostile - // on garde 'class' et 'style' utilisés par le ckediteur - ); - $specHtmLawed = ''; // optionnel: faire qu'un certain élément puisse n'avoir que certains attributs + $contenu = htmLawed($contenu, $configHtmLawed, $specHtmLawed); + // supprimer espaces, tabulations et sauts de ligne en début et fin de chaine (pour l'entrée de l'éditeur) + $contenu = trim($contenu); + + // ne pas continuer si la variable est vide (javascript mal supporté ou utilisation de IE, bug?, erreur de l'utilisateur), risque perte de contenu !! + if($page != 'discographie' && $contenu == '') + { + header('Location: index.php?page=' . $page . '&erreur=contenu_vide'); + exit(); + } } + if($page == 'discographie') { $titre = $_POST['titre']; $annee = $_POST['annee']; $pochette = $_POST['pochette']; // une image - + // des formulaires simples $titre = htmLawed($titre, $configHtmLawed, $specHtmLawed); $titre = trim($titre); @@ -83,25 +99,6 @@ function submitCKeditor($nomFichier) // Album->imageUpload(); // test formats jpg, jpeg, png, gif, tiff // enregistrement du fichier - - // du ckeditor - $contenu = htmLawed($contenu, $configHtmLawed, $specHtmLawed); - $contenu = trim($contenu); - } - else // pages comme "melaine" - { - // ne pas continuer si la variable est vide (javascript mal supporté ou utilisation de IE, bug?, erreur de l'utilisateur), risque perte de contenu !! - if($contenu == '') - { - header('Location: index.php?page=' . $page . '&erreur=contenu_vide'); - } - else - { - // failles XSS - $contenu = htmLawed($contenu, $configHtmLawed, $specHtmLawed); - // supprimer espaces, tabulations et sauts de ligne en début et fin de chaine (pour l'entrée de l'éditeur) - $contenu = trim($contenu); - } } // lien sans http:// @@ -114,42 +111,61 @@ function submitCKeditor($nomFichier) // solution 2 (façon pop-up): fermer ce nouvel onglet avec echo ''; // pour faire passer par le .htaccess l'info comme quoi la page précédente comportait un éditeur ouvert... - //var_dump($titre, $annee, $pochette, $contenu); - //die(); - - // modèle - $Article = new ArticlesManager; - $Article->setPage($page); // enregistrement - if($_GET['article'] == 0) - { - $Article->create($contenu); - } - else - { - $Article->setFileName($nomFichier); - $Article->update($contenu); - } + // var_dump($titre, $annee, $pochette, $contenu); + // die(); + // modèle if($page == 'discographie') { - $Album = new AlbumsManager; + // on instancie avec l'enfant de OneArticle + $Album = new Album($page); - var_dump($_POST); - echo('
'); //var_dump($_GET['article']); - + //var_dump($_POST); + //exit(); + // enregistrement if($_GET['article'] == 0) { - // ERREUR, il faut le même nombre de paramètre pour une méthode du même nom - $Album->create($titre, $annee, $pochette); + // page disco + $Album->createVignette($titre, $annee, $pochette); + + // page détail de l'album + if(!empty($_POST['contenu'])) + { + $Album->create($contenu); + } + } + else + { + // page disco + $Album->updateVignette($titre, $annee, $pochette); + + // page détail de l'album + if(isset($_POST['contenu'])) + { + $Album->update($content); + } + } + } + // autres pages + else + { + $Article = new OneArticle($page); + + if($_GET['article'] == 0) + { + $Article->create($contenu); } else { - $Album->update($titre, $annee, $pochette); + $Article->setFileName($nomFichier); + $Article->update($contenu); } - die(); } -} \ No newline at end of file +} + +function cleanHTML($contenu) +{} diff --git a/controller/installation.php b/controller/installation.php index 42212f5..fc8c900 100644 --- a/controller/installation.php +++ b/controller/installation.php @@ -25,7 +25,7 @@ function installation() if(!file_exists(".htaccess")) { echo('

Le .htaccess semble absent ce qui rend le site vulnérable aux attaques, veuillez contacter l\'administrateur.

'); - // $contenu = "# redirection en cas d'erreur 404\nErrorDocument 404 http://" . $_SERVER['SERVER_NAME'] . "/" . $nomDuSite . "/erreur404.php\n# Interdire exploration du répertoire\nOptions All -Indexes"; + //$contenu = "# redirection en cas d'erreur 404\nErrorDocument 404 http://" . $_SERVER['SERVER_NAME'] . "/" . $nomDuSite . "/erreur404.php\n# Interdire exploration du répertoire\nOptions All -Indexes"; // $fichier = fopen('.htaccess', 'w'); // fputs($fichier, $contenu); // fclose($fichier); @@ -49,8 +49,7 @@ function installation() // - modifier ceux du dossier parent (nom du site) avec son client FTP à la mise en ligne chez l'hébergeur et ensuite remettre tout comme avant // le 0 devant signifie que le nombre est en octal - // changer cette valeur à la mise en production du site si le script d'upload des données est bon - $droitsDossiers = 0777; + $droitsDossiers = 0777; // mettre 0700 à la fin $listePages = array('melaine', 'discographie', 'concerts', 'presse', 'ateliers', 'liens', 'peinture', 'archives'); foreach ($listePages as $page) diff --git a/controller/visitor.php b/controller/visitor.php index 4f51dda..936eb35 100644 --- a/controller/visitor.php +++ b/controller/visitor.php @@ -33,18 +33,9 @@ function melaineVisitor() $title = "Mais qui est Melaine Favennec?"; // modèle - $Articles = new ArticlesManager; - $Articles->setPage($page_actuelle); - $Articles->getFiles(); - $Articles->reverseFilesArray(); - $articles = $Articles->getAll(); // lourd - - // vérification pour protéger les visiteurs - // normalement déjà faite dans submit.php, au cas où la base a été trafiquée - foreach ($Articles as $oneArticle) - { - $oneArticle = htmLawed($oneArticle); - } + $Articles = new AllArticles($page_actuelle); + $Articles->makeFileList(); + $articles = array_reverse($Articles->readAll()); // lourd // variables $css, $js, $header et $content require('view/melaine.php'); @@ -58,7 +49,55 @@ function discoVisitor() $title = "Discographie"; // modèle - $Albums = new AlbumsManager; + $Albums = new Album($page_actuelle); + $Albums->makeFileList(); + $albumsJSON = array_reverse($Albums->readAll()); // lourd + + // $albums est un tableau de chaines JSON, + // chacune renferme 3 variables: titre, année, pochette + + // changer les chaines JSON en tableaux + $i = 0; + foreach($albumsJSON as $oneAlbum) + { + $albumsJSON[$i] = json_decode($oneAlbum, true); + $i++; + } + + // on passe maintenant au contenu HTML + $albumNamesJSON = array_reverse($Albums->getFileNames()); + $Albums->setFormat('html'); + $Albums->makeFileList(); + $albumNamesHTML = array_reverse($Albums->getFileNames()); + + // pour chaque album, détecter le fichier html + // si il y en a un, proposer un lien
+ // si non, ne fournir qu'un lien d'ancre pour la liste d'album + $i = 0; + //print_r($albumNamesJSON); exit(); + + foreach($albumNamesJSON as $oneAlbum) + { + $chemin = pathinfo($oneAlbum); + $nomJSONsansExt = $chemin['filename']; + $chemin = pathinfo($albumNamesHTML[0]); + $nomHTMLsansExt = $chemin['filename']; + + // détecter un fichier du même nom + if(isset($nomJSONsansExt . '.html')) // c'est pas ça!! + { + //$lienAlbum[$i] = $titreAlbum; + } + else + { + //$lienAlbum[$i] = 'discographie#' . $oneAlbum[0]; + } + $i++; + } + //exit(); + + + //echo($lienAlbum); // variables $css, $js et $content require('view/discographie.php'); diff --git a/index.php b/index.php index dc5f3ba..b9989fd 100644 --- a/index.php +++ b/index.php @@ -54,12 +54,13 @@ require('controller/password.php'); installation(); - // traitement des POST du ckeditor // la fonction submitCKeditor n'affiche rien (controller/admin.php n'est pas utilisé) puis redirige sans GET if(isset($_SESSION['admin']) && $_SESSION['admin'] == 1 && isset($_GET['action']) && $_GET['action'] == 'submit' - && isset($_POST['contenu']) && $_POST['contenu'] != '') + // trois possibilités: on a un contenu HTML ou JSON ou les deux + && ((isset($_POST['contenu']) && $_POST['contenu'] != '') + || (isset($_POST['titre']) && isset($_POST['annee']) && isset($_POST['pochette'])))) { require('controller/ckeditor.php'); // traitement du POST require('lib/htmlawed/htmLawed.php'); // failles XSS @@ -119,7 +120,6 @@ else } - // page du site demandée if(isset($_GET['page'])) { diff --git a/model/Classes.php b/model/Classes.php index e574eeb..1349cd7 100644 --- a/model/Classes.php +++ b/model/Classes.php @@ -1,127 +1,137 @@ page = $page; + $this->time = time(); + if($this->page == 'discographie') + { + $this->format = 'json'; + } } - public function findFileName($numArticle) + // GET + public function getPage() { - $this->fileName = $this->files[$numArticle - 1]; + return($this->page); } - public function setFileName($nomFichier) + public function getNbArticles() { - $this->fileName = $nomFichier; + return($this->nbArticles); } - - // GET - public function getPage() + public function getFileNames() { - return($this->page); + return($this->files); } - public function getFileName() + // SET + public function setFormat($format) { - return($this->fileName); + $this->format = $format; } - - public function nbArticles() + + // tableaux des noms des fichiers + public function makeFileList() { - return($this->nbArticles); + $this->files = glob('data/' . $this->page . '/' . $this->format . '/*.' . $this->format); + //$this->files = glob('*.' . $this->format); } + /*public function makeFilePath() + {}*/ + // fonctions CRUD (create - read - update - delete) + + // create - // tableau des noms des articles - public function getFiles() + // read + public function readAll() { - if($this->page == '') + $i = 0; + $articles = array(); + foreach ($this->files as $oneFile) { - die("debug: la méthode setPage() doit être appelée avant getFiles()."); + $articles[$i] = file_get_contents($oneFile); + $i++; } + //print_r($articles); + return $articles; + } + + // update + + // delete +} + +// article créé ou ciblé pour modification/suppression +class OneArticle extends AllArticles +{ + private $fileName; // correspond à $_SESSION['nomFichier'] - $this->files = glob('data/' . $this->page . '/html/*.html'); + // GET + public function getFileName() + { + return($this->fileName); } - // ordre du tableau des noms de fichiers - public function reverseFilesArray() + // SET + public function setFileName($nomFichier) // modification { - $this->files = array_reverse($this->files); + $this->fileName = $nomFichier; } + public function findFileName($numArticle) // nouvel article + { + $this->fileName = $this->files[$numArticle - 1]; + } // fonctions CRUD (create - read - update - delete) - // ce sont les 4 opérations de base qu'un programme doit permettre pour être complet - + // create public function create($content) { - if($this->page == '') - { - die("debug: la méthode setPage() doit être appelée avant toute autre."); - } - - // nommer les fichiers avec le timestamp - // - trie par ordre chronologique + $format = 'html'; + + // nommer les fichiers avec le timestamp pour: + // - les trier par ordre chronologique // - rendre quasi impossible d'avoir deux fois le même nom (à la condition de gérer la "concurrence") - $nom_fichier = 'data/' . $this->page . '/html/' . time() . '.html'; + $nom_fichier = 'data/' . $this->page . '/' . $format . '/' . $this->time . '.' . $format; - $fichier = fopen($nom_fichier, 'w'); // w peut créer un fichier, si il existe déjà, il est effacé par le nouveau contenu + $fichier = fopen($nom_fichier, 'w'); // w pour créer ou écraser fputs($fichier, $content); fclose($fichier); chmod($nom_fichier, 0666); } // read - public function getNumber() - { - return $this->nbArticles; - } - - public function getOne() + public function readOne() { return(file_get_contents($this->fileName)); } - public function getAll() - { - //$this->getFiles(); - - $i = 0; - $articles = array(); - foreach ($this->files as $file) - { - $articles[$i] = file_get_contents($file); - $i++; - } - - //print_r($articles); - return $articles; - } - - public function getDate($fileNumber) + // pour afficher des dates + /*public function getDate($fileNumber) { // le 2è paramètre exclut le suffixe .html $timestamp = basename($this->files[$fileNumber], '.html'); return getdate($timestamp); - } + }*/ // update public function update($content) { - $file = fopen($this->fileName, 'w'); - // w peut créer un fichier, si il existe déjà, il est effacé par le nouveau contenu + $file = fopen($this->fileName, 'w'); // crée ou écrase fputs($file, $content); fclose($file); //chown($this->fileName, 'http'); @@ -135,39 +145,55 @@ class ArticlesManager } } -// note: les pros font de l'hydration -// le code du modèle est orienté objet et "refactorisé" d'une manière précise: -// on utilise un objet pour une chose (des articles, commentaires, etc), -// un objet article contiendrait ainsi tout le nécessaire pour lire, écrire ou modifier un article -// il y a pour ça un programme appelé "doctrine" (inclu dans symphony) qui est capable de lire une base de données et d'en écrire les objets PHP -class AlbumsManager extends ArticlesManager +class Album extends OneArticle { // variables - - // SET + //private $fileNameJSON; // même nom en .json + //protected $format = 'json'; // GET + // SET + // fonctions CRUD // create - //public function create($titre, $annee, $pochette) - public function create($content) - //public function create($content, $titre, $annee, $pochette) - {} + public function createVignette($titre, $annee, $pochette) + { + if($pochette != '') + { + // enregistrer le fichier + // retourner une erreur en cas d'échec de l'upload + } + + $albumJSON = json_encode([$titre, $annee, $pochette]); + + $nom_fichier = 'data/' . $this->page . '/' . $this->format . '/' . $this->time . '.' . $this->format; + + $fichier = fopen($nom_fichier, 'w'); // w pour créer ou écraser + fputs($fichier, $albumJSON); + fclose($fichier); + chmod($nom_fichier, 0666); + } // read public function read() {} // update - //public function update($titre, $annee, $pochette) - public function update($content) - //public function update($content, $titre, $annee, $pochette) + public function updateVignette($titre, $annee, $pochette) {} // delete public function delete() {} -} \ No newline at end of file +} + + + +// note: les pros font de l'hydration +// le code du modèle est orienté objet et "refactorisé" d'une manière précise: +// on utilise un objet pour une chose (des articles, commentaires, etc), +// un objet article contiendrait ainsi tout le nécessaire pour lire, écrire ou modifier un article +// il y a pour ça un programme appelé "doctrine" (inclu dans symphony) qui est capable de lire une base de données et d'en écrire les objets PHP \ No newline at end of file diff --git a/public/discographie.css b/public/discographie.css index ff622e9..cb0c9b5 100644 --- a/public/discographie.css +++ b/public/discographie.css @@ -90,6 +90,12 @@ input article { margin: 5px 0px; + width: 45%; +} + +.vignette +{ + width: 100%; } figure @@ -97,6 +103,10 @@ figure margin: 0px; display: inline-block; } +figure:hover +{ + border: 2px blue solid; +} figcaption { @@ -113,10 +123,10 @@ a display: inline-block; } -article a:hover +/*article a:hover { border: 2px blue solid; -} +}*/ a:hover figure figcaption diff --git a/view/discographie.php b/view/discographie.php index 4eb8e58..47ee377 100644 --- a/view/discographie.php +++ b/view/discographie.php @@ -48,12 +48,19 @@ ob_start();

Chronologie

-

Emoi des mots, MF chante Max Jacob (2012)

-

Kan Tri (2011)

-

Tri Men (2007)

-

Kan Tri (2003)

-

Hey ! Ho ! (2005)

-
+ +

()

+ +
@@ -64,7 +71,7 @@ if($_SESSION['admin'] == 1) { ?>

Ajouter un album

- +

- + +
Modifier l'article " . $j . "

"); - //echo("

Modification d'un article

"); + //echo("\n

Modifier l'article " . $j . "

"); + echo("

Modification d'un article

"); echo "\n"; echo($editeurHTML); // injection de template-editor.php diff --git a/view/template.php b/view/template.php index dad4e17..a14555d 100644 --- a/view/template.php +++ b/view/template.php @@ -71,7 +71,7 @@ if($_SESSION['admin'] == 1)

Vous êtes en mode administrateur. - + Options Déconnexion

-- cgit v1.2.3