diff options
| -rw-r--r-- | controller/admin.php | 51 | ||||
| -rw-r--r-- | controller/ckeditor.php | 44 | ||||
| -rw-r--r-- | controller/visitor.php | 54 | ||||
| -rw-r--r-- | imageAJAX.php | 100 | ||||
| -rw-r--r-- | index.php | 29 | ||||
| -rw-r--r-- | model/Classes.php | 26 | ||||
| -rw-r--r-- | model/Image.php | 59 | ||||
| -rw-r--r-- | public/discographie.css | 32 | ||||
| -rw-r--r-- | public/donnees_hors_editeur.css | 4 | ||||
| -rw-r--r-- | public/melaine.css | 1 | ||||
| -rw-r--r-- | view/album.php | 2 | ||||
| -rw-r--r-- | view/discographie.php | 4 | ||||
| -rw-r--r-- | view/template-formulaires.php | 22 |
13 files changed, 214 insertions, 214 deletions
diff --git a/controller/admin.php b/controller/admin.php index 3c2b613..ba6fd83 100644 --- a/controller/admin.php +++ b/controller/admin.php | |||
| @@ -98,11 +98,6 @@ function discoEdit($numArticle, $suppression) | |||
| 98 | } | 98 | } |
| 99 | } | 99 | } |
| 100 | 100 | ||
| 101 | $albumsJSON = array_reverse($Album->readAll()); // lourd | ||
| 102 | |||
| 103 | // $albums contient un tableau de chaines JSON, | ||
| 104 | // on extrait de chacune 3 variables: titre, année, pochette | ||
| 105 | |||
| 106 | // traitements PHP pour l'éditeur | 101 | // traitements PHP pour l'éditeur |
| 107 | // sécurisation du contenu pré-existant inséré dans l'éditeur | 102 | // sécurisation du contenu pré-existant inséré dans l'éditeur |
| 108 | if($numArticle >= 0 && !$suppression) | 103 | if($numArticle >= 0 && !$suppression) |
| @@ -111,44 +106,58 @@ function discoEdit($numArticle, $suppression) | |||
| 111 | $texte = preparationCKeditor($numArticle, $texte); | 106 | $texte = preparationCKeditor($numArticle, $texte); |
| 112 | } | 107 | } |
| 113 | 108 | ||
| 114 | // changer les chaines JSON en tableaux | 109 | |
| 110 | // contenu de tous les fichiers JSON (= tableau de chaines) | ||
| 111 | $albumsJSON = $Album->readAll(); | ||
| 112 | // noms des fichiers JSON | ||
| 113 | $albumNamesJSON = $Album->getFileList(); | ||
| 114 | |||
| 115 | // changer les chaines JSON en tableaux: titre, année, pochette | ||
| 115 | $i = 0; | 116 | $i = 0; |
| 117 | $annees = array(); | ||
| 116 | foreach($albumsJSON as $oneAlbum) | 118 | foreach($albumsJSON as $oneAlbum) |
| 117 | { | 119 | { |
| 118 | $albumsJSON[$i] = json_decode($oneAlbum, true); | 120 | $albumsJSON[$i] = json_decode($oneAlbum, true); |
| 121 | |||
| 122 | // ajout des noms des fichiers JSON | ||
| 123 | $albumsJSON[$i][3] = $albumNamesJSON[$i]; | ||
| 124 | $annees[$i] = $albumsJSON[$i][1]; | ||
| 119 | $i++; | 125 | $i++; |
| 120 | } | 126 | } |
| 127 | // tri d'un tableau multidimensionnel | ||
| 128 | array_multisort($annees, $albumsJSON); | ||
| 121 | 129 | ||
| 122 | // on passe maintenant au contenu HTML | 130 | // on passe maintenant au contenu HTML |
| 123 | $albumNamesJSON = array_reverse($Album->getFileNames()); | ||
| 124 | $Album->setFormat('html'); | 131 | $Album->setFormat('html'); |
| 125 | $Album->makeFileList(); | 132 | $Album->makeFileList(); |
| 126 | $albumNamesHTML = array_reverse($Album->getFileNames()); | 133 | $albumNamesHTML = $Album->getFileList(); |
| 127 | 134 | ||
| 128 | // lien vers le HTML ou ancre? | 135 | // lien vers le HTML ou ancre? |
| 129 | // pour chaque album, détecter le fichier html | 136 | // pour chaque album, détecter le fichier html |
| 130 | // si non, ne fournir qu'un lien d'ancre pour la liste d'album | 137 | // si non, ne fournir qu'un lien d'ancre pour la liste d'album |
| 131 | $i = 0; | 138 | $i = 0; |
| 132 | $avecLien = []; | 139 | $avecLien = []; |
| 133 | foreach($albumNamesJSON as $oneAlbum) | 140 | foreach($albumsJSON as $oneAlbum) |
| 134 | { | 141 | { |
| 135 | // nom sans extension | 142 | // nom sans extension |
| 136 | $chemin = pathinfo($oneAlbum); | 143 | $chemin = pathinfo($oneAlbum[3]); |
| 137 | $nomJSONsansExt = $chemin['filename']; | 144 | $nomJSONsansExt = $chemin['filename']; |
| 138 | $chemin = pathinfo($albumNamesHTML[0]); | ||
| 139 | 145 | ||
| 140 | // détection | 146 | // au cas où la discographie ne contient aucun html |
| 141 | if(file_exists($chemin['dirname'] . '/' . $nomJSONsansExt . '.html')) | 147 | if(!empty($albumNamesHTML)) |
| 142 | { | 148 | { |
| 143 | $lienAlbum[$i] = 'album&album_code=' . $nomJSONsansExt . '&album_name=' . $albumsJSON[$i][0]; | 149 | if(file_exists('data/discographie/html/' . $nomJSONsansExt . '.html')) |
| 144 | $avecLien[$i] = true; | 150 | { |
| 151 | $lienAlbum[$i] = 'album&album_code=' . $nomJSONsansExt . '&album_name=' . $albumsJSON[$i][0]; | ||
| 152 | $avecLien[$i] = true; | ||
| 153 | } | ||
| 154 | else | ||
| 155 | { | ||
| 156 | $lienAlbum[$i] = 'discographie#' . $albumsJSON[$i][0]; | ||
| 157 | $avecLien[$i] = false; | ||
| 158 | } | ||
| 159 | $i++; | ||
| 145 | } | 160 | } |
| 146 | else | ||
| 147 | { | ||
| 148 | $lienAlbum[$i] = 'discographie#' . $albumsJSON[$i][0]; | ||
| 149 | $avecLien[$i] = false; | ||
| 150 | } | ||
| 151 | $i++; | ||
| 152 | } | 161 | } |
| 153 | 162 | ||
| 154 | // morceaux en HTML Ã assembler | 163 | // morceaux en HTML Ã assembler |
diff --git a/controller/ckeditor.php b/controller/ckeditor.php index 2e72be2..d07f2a2 100644 --- a/controller/ckeditor.php +++ b/controller/ckeditor.php | |||
| @@ -87,7 +87,7 @@ function submitCKeditor($nomFichier) | |||
| 87 | { | 87 | { |
| 88 | $titre = $_POST['titre']; | 88 | $titre = $_POST['titre']; |
| 89 | $annee = $_POST['annee']; | 89 | $annee = $_POST['annee']; |
| 90 | $pochette = $_POST['pochette']; // une image | 90 | $pochette = $_FILES['upload']['name']; |
| 91 | 91 | ||
| 92 | // des formulaires simples | 92 | // des formulaires simples |
| 93 | $titre = htmLawed($titre, $configHtmLawed, $specHtmLawed); | 93 | $titre = htmLawed($titre, $configHtmLawed, $specHtmLawed); |
| @@ -95,36 +95,8 @@ function submitCKeditor($nomFichier) | |||
| 95 | $annee = htmLawed($annee, $configHtmLawed, $specHtmLawed); | 95 | $annee = htmLawed($annee, $configHtmLawed, $specHtmLawed); |
| 96 | $annee = trim($annee); | 96 | $annee = trim($annee); |
| 97 | 97 | ||
| 98 | // pochette | ||
| 99 | // Album->imageUpload(); | ||
| 100 | // test formats jpg, jpeg, png, gif, tiff | ||
| 101 | // enregistrement du fichier | ||
| 102 | } | ||
| 103 | |||
| 104 | // lien sans http:// | ||
| 105 | // un clic sur un lien dans l'éditeur affiche une infobulle montrant l'adresse cible du lien si celle-ci a déjà été précisée | ||
| 106 | // il est possible de cliquer sur ce lien, ce qui ouvre un onglet avec le site demandé | ||
| 107 | // toutefois si cette adresse est de type "domaine.fr" (sans http:// devant), le navigateur ne va pas rechercher un site mais un fichier comme si mon adresse était de type file:///fichier | ||
| 108 | // tomber ainsi sur une page d'erreur est déroutant: | ||
| 109 | // "ai-je perdu le texte que j'étais en train de taper?"" | ||
| 110 | // solution 1 (mauvaise): activer la redirection en cas d'erreur 404 dans le .htaccess | ||
| 111 | // solution 2 (façon pop-up): fermer ce nouvel onglet avec echo '<SCRIPT>javascript:window.close()</SCRIPT>'; | ||
| 112 | // pour faire passer par le .htaccess l'info comme quoi la page précédente comportait un éditeur ouvert... | ||
| 113 | |||
| 114 | |||
| 115 | // enregistrement | ||
| 116 | // var_dump($titre, $annee, $pochette, $contenu); | ||
| 117 | // die(); | ||
| 118 | |||
| 119 | // modèle | ||
| 120 | if($page == 'discographie') | ||
| 121 | { | ||
| 122 | // on instancie avec l'enfant de OneArticle | 98 | // on instancie avec l'enfant de OneArticle |
| 123 | $Album = new Album($page); | 99 | $Album = new Album($page); |
| 124 | |||
| 125 | //var_dump($_GET['article']); | ||
| 126 | //var_dump($_POST); | ||
| 127 | //exit(); | ||
| 128 | 100 | ||
| 129 | // enregistrement | 101 | // enregistrement |
| 130 | if($_GET['article'] == 0) | 102 | if($_GET['article'] == 0) |
| @@ -132,7 +104,7 @@ function submitCKeditor($nomFichier) | |||
| 132 | // page disco | 104 | // page disco |
| 133 | $Album->createVignette($titre, $annee, $pochette); | 105 | $Album->createVignette($titre, $annee, $pochette); |
| 134 | 106 | ||
| 135 | // page détail de l'album | 107 | // page de l'album |
| 136 | if(!empty($_POST['contenu'])) | 108 | if(!empty($_POST['contenu'])) |
| 137 | { | 109 | { |
| 138 | $Album->create($contenu); | 110 | $Album->create($contenu); |
| @@ -143,7 +115,7 @@ function submitCKeditor($nomFichier) | |||
| 143 | // page disco | 115 | // page disco |
| 144 | $Album->updateVignette($titre, $annee, $pochette); | 116 | $Album->updateVignette($titre, $annee, $pochette); |
| 145 | 117 | ||
| 146 | // page détail de l'album | 118 | // page de l'album |
| 147 | if(isset($_POST['contenu'])) | 119 | if(isset($_POST['contenu'])) |
| 148 | { | 120 | { |
| 149 | $Album->update($content); | 121 | $Album->update($content); |
| @@ -167,5 +139,15 @@ function submitCKeditor($nomFichier) | |||
| 167 | } | 139 | } |
| 168 | } | 140 | } |
| 169 | 141 | ||
| 142 | // lien sans http:// | ||
| 143 | // un clic sur un lien dans l'éditeur affiche une infobulle montrant l'adresse cible du lien si celle-ci a déjà été précisée | ||
| 144 | // il est possible de cliquer sur ce lien, ce qui ouvre un onglet avec le site demandé | ||
| 145 | // toutefois si cette adresse est de type "domaine.fr" (sans http:// devant), le navigateur ne va pas rechercher un site mais un fichier comme si mon adresse était de type file:///fichier | ||
| 146 | // tomber ainsi sur une page d'erreur est déroutant: | ||
| 147 | // "ai-je perdu le texte que j'étais en train de taper?"" | ||
| 148 | // solution 1 (mauvaise): activer la redirection en cas d'erreur 404 dans le .htaccess | ||
| 149 | // solution 2 (façon pop-up): fermer ce nouvel onglet avec echo '<SCRIPT>javascript:window.close()</SCRIPT>'; | ||
| 150 | // pour faire passer par le .htaccess l'info comme quoi la page précédente comportait un éditeur ouvert... | ||
| 151 | |||
| 170 | function cleanHTML($contenu) | 152 | function cleanHTML($contenu) |
| 171 | {} | 153 | {} |
diff --git a/controller/visitor.php b/controller/visitor.php index 239c139..a5bf538 100644 --- a/controller/visitor.php +++ b/controller/visitor.php | |||
| @@ -51,49 +51,62 @@ function discoVisitor() | |||
| 51 | // modèle | 51 | // modèle |
| 52 | $AllAlbums = new Album($page_actuelle); | 52 | $AllAlbums = new Album($page_actuelle); |
| 53 | $AllAlbums->makeFileList(); | 53 | $AllAlbums->makeFileList(); |
| 54 | $albumsJSON = array_reverse($AllAlbums->readAll()); // lourd | ||
| 55 | 54 | ||
| 56 | // $albums est un tableau de chaines JSON, | 55 | // contenu de tous les fichiers JSON (= tableau de chaines) |
| 57 | // chacune renferme 3 variables: titre, année, pochette | 56 | $albumsJSON = $AllAlbums->readAll(); |
| 57 | // noms des fichiers JSON | ||
| 58 | $albumNamesJSON = $AllAlbums->getFileList(); | ||
| 58 | 59 | ||
| 59 | // changer les chaines JSON en tableaux | 60 | // changer les chaines JSON en tableaux: titre, année, pochette |
| 60 | $i = 0; | 61 | $i = 0; |
| 62 | $annees = array(); | ||
| 61 | foreach($albumsJSON as $oneAlbum) | 63 | foreach($albumsJSON as $oneAlbum) |
| 62 | { | 64 | { |
| 63 | $albumsJSON[$i] = json_decode($oneAlbum, true); | 65 | $albumsJSON[$i] = json_decode($oneAlbum, true); |
| 66 | $annees[$i] = $albumsJSON[$i][1]; | ||
| 67 | |||
| 68 | // ajout des noms des fichiers JSON | ||
| 69 | $albumsJSON[$i][3] = $albumNamesJSON[$i]; | ||
| 70 | |||
| 64 | $i++; | 71 | $i++; |
| 65 | } | 72 | } |
| 73 | // tri d'un tableau multidimensionnel | ||
| 74 | array_multisort($annees, $albumsJSON); | ||
| 66 | 75 | ||
| 67 | // on passe maintenant au contenu HTML | 76 | // on passe maintenant au contenu HTML |
| 68 | $albumNamesJSON = array_reverse($AllAlbums->getFileNames()); | ||
| 69 | $AllAlbums->setFormat('html'); | 77 | $AllAlbums->setFormat('html'); |
| 70 | $AllAlbums->makeFileList(); | 78 | $AllAlbums->makeFileList(); |
| 71 | $albumNamesHTML = array_reverse($AllAlbums->getFileNames()); | 79 | $albumNamesHTML = $AllAlbums->getFileList(); |
| 72 | 80 | ||
| 73 | // lien vers le HTML ou ancre? | 81 | // lien vers le HTML ou ancre? |
| 74 | // pour chaque album, détecter le fichier html | 82 | // pour chaque album, détecter le fichier html |
| 75 | // si non, ne fournir qu'un lien d'ancre pour la liste d'album | 83 | // si non, ne fournir qu'un lien d'ancre pour la liste d'album |
| 76 | $i = 0; | 84 | $i = 0; |
| 77 | $avecLien = []; | 85 | $avecLien = []; |
| 78 | foreach($albumNamesJSON as $oneAlbum) | 86 | $linkDiscoChrono = []; |
| 87 | foreach($albumsJSON as $oneAlbum) | ||
| 79 | { | 88 | { |
| 80 | // nom sans extension | 89 | // nom sans extension |
| 81 | $chemin = pathinfo($oneAlbum); | 90 | $chemin = pathinfo($oneAlbum[3]); |
| 82 | $nomJSONsansExt = $chemin['filename']; | 91 | $nomJSONsansExt = $chemin['filename']; |
| 83 | $chemin = pathinfo($albumNamesHTML[0]); | ||
| 84 | 92 | ||
| 85 | // détection | 93 | // au cas où la discographie ne contient aucun html |
| 86 | if(file_exists($chemin['dirname'] . '/' . $nomJSONsansExt . '.html')) | 94 | if(!empty($albumNamesHTML)) |
| 87 | { | 95 | { |
| 88 | $lienAlbum[$i] = 'album&album_code=' . $nomJSONsansExt . '&album_name=' . $albumsJSON[$i][0]; | 96 | if(file_exists('data/discographie/html/' . $nomJSONsansExt . '.html')) |
| 89 | $avecLien[$i] = true; | 97 | { |
| 98 | $lienAlbum[$i] = 'album&album_code=' . $nomJSONsansExt . '&album_name=' . $albumsJSON[$i][0]; | ||
| 99 | $avecLien[$i] = true; | ||
| 100 | $linkDiscoChrono[$i] = 'linkChrono'; // css | ||
| 101 | } | ||
| 102 | else | ||
| 103 | { | ||
| 104 | $lienAlbum[$i] = 'discographie#' . $albumsJSON[$i][0]; | ||
| 105 | $avecLien[$i] = false; | ||
| 106 | $linkDiscoChrono[$i] = 'noLinkChrono'; // css | ||
| 107 | } | ||
| 108 | $i++; | ||
| 90 | } | 109 | } |
| 91 | else | ||
| 92 | { | ||
| 93 | $lienAlbum[$i] = 'discographie#' . $albumsJSON[$i][0]; | ||
| 94 | $avecLien[$i] = false; | ||
| 95 | } | ||
| 96 | $i++; | ||
| 97 | } | 110 | } |
| 98 | 111 | ||
| 99 | // variables $css, $js et $content | 112 | // variables $css, $js et $content |
| @@ -102,6 +115,7 @@ function discoVisitor() | |||
| 102 | require('view/template.php'); | 115 | require('view/template.php'); |
| 103 | } | 116 | } |
| 104 | 117 | ||
| 118 | // page d'un album | ||
| 105 | function album($albumCode, $albumName) | 119 | function album($albumCode, $albumName) |
| 106 | { | 120 | { |
| 107 | $page_actuelle = 'discographie'; | 121 | $page_actuelle = 'discographie'; |
diff --git a/imageAJAX.php b/imageAJAX.php deleted file mode 100644 index 0831986..0000000 --- a/imageAJAX.php +++ /dev/null | |||
| @@ -1,100 +0,0 @@ | |||
| 1 | <?php | ||
| 2 | // imageAJAX.php | ||
| 3 | // | ||
| 4 | // le problème pour écrire ce fichier est qu'il est impossible d'afficher le contenu des variables avec "echo" ou "var_dump" | ||
| 5 | // puisqu'on reste toujours sur la même page, il y a heureusement au moins deux manières de faire autrement: | ||
| 6 | // - avec les outils de développement du navigateur (utiliser firefox ou chromium/chrome mais pas les autres) | ||
| 7 | // - écrire les données dans un fichier de log | ||
| 8 | |||
| 9 | // ce fichier est autonome vis-à -vis du reste du code PHP et sert uniquement à traiter les requêtes AJAX, | ||
| 10 | // il reçoit un POST du "simple upload adapter", un plugin du ckeditor qui sert faire de l'AJAX | ||
| 11 | // ce POST est une image et s'appelle 'upload', c'est à dire le tableau $_FILES['upload'] | ||
| 12 | // à la fin on retournera une chaine de caractères avec "echo" et au format json (parce que c'est ce que demande le client) | ||
| 13 | |||
| 14 | // avec firefox, faire un clic droit dans la page et cliquer sur examiner l'élément, ou faire Ctrl + Maj + i | ||
| 15 | // une fois dans les outils de dev, aller dans la section "Réseau", et ensuite essayer d'uploader un fichier | ||
| 16 | // de nombreuses infos sur la dernière requête envoyée apparaissent: | ||
| 17 | // fichier = imageAJAX.php | ||
| 18 | // initiateur = ckeditor.js | ||
| 19 | // état = code HTTP (200 = ok, 400 = erreur dans l'adresse du fichier .php, 500 = erreur interne au serveur) | ||
| 20 | // méthode = POST | ||
| 21 | // les onglets "En-têtes", "Requête" et "Réponse" donnent d'autres infos: | ||
| 22 | // l'onglet "Requête" affiche name="upload", | ||
| 23 | // l'onglet "Réponse" montre tout le tableau $_FILES si le PHP comporte l'instruction: $upload = var_dump($_FILES); | ||
| 24 | |||
| 25 | // pour que le ckeditor arrête de renvoyer une erreur, j'ai donc dû: | ||
| 26 | // - passer du code 500 au code 200, ce qui nécessite d'écrire quelque chose avec "echo", "var_dump", "print_r", etc | ||
| 27 | // - et que la chaine écrite avec PHP soit au format json, ce qu'on obtient avec la fonction json_encode' | ||
| 28 | |||
| 29 | // nous souhaitons bien sûr enregistrer le fichier et renvoyer une chaine json utilisable par le ckeditor | ||
| 30 | // nous devons donc autoriser les bons dossiers en écriture, dont celui des fichiers temporaires du système d'exploitation | ||
| 31 | // et renvoyer cette chaîne en json: | ||
| 32 | //{ | ||
| 33 | // "url": "chemin/images/foo.jpg" | ||
| 34 | //} | ||
| 35 | |||
| 36 | // debuggage | ||
| 37 | /*print_r($_FILES); | ||
| 38 | $upload = array( | ||
| 39 | 'name' => $_FILES['upload']['name'], | ||
| 40 | 'type' => $_FILES['upload']['type'], | ||
| 41 | 'tmp_name' => $_FILES['upload']['tmp_name'], | ||
| 42 | 'error' => $_FILES['upload']['error'], | ||
| 43 | 'size' => $_FILES['upload']['size'] | ||
| 44 | ); | ||
| 45 | print_r($upload);*/ | ||
| 46 | |||
| 47 | session_start(); | ||
| 48 | // et une backdoor de fermée! | ||
| 49 | if(!isset($_SESSION['admin']) || $_SESSION['admin'] != 1 || !isset($_FILES['upload']) || empty($_FILES['upload'])) | ||
| 50 | { | ||
| 51 | header('Location: index.php?erreur=imageajax'); | ||
| 52 | } | ||
| 53 | |||
| 54 | // get envoyé avec le javascript | ||
| 55 | $page = $_GET['page']; | ||
| 56 | |||
| 57 | // déjà fait dans installation.php | ||
| 58 | if(!file_exists('data/' . $page . '/images')) | ||
| 59 | { | ||
| 60 | mkdir('data/' . $page . '/images', 0777); | ||
| 61 | chmod('data/' . $page . '/images', 0777); | ||
| 62 | } | ||
| 63 | |||
| 64 | // taille en Mo à adapter au serveur (2Mo est la valeur par défaut dans le php.ini) | ||
| 65 | $tailleMax = 2000000; | ||
| 66 | $erreur = ''; | ||
| 67 | |||
| 68 | // traitement et enregistrement de l'image | ||
| 69 | if (isset($_FILES['upload']) AND $_FILES['upload']['error'] == 0) // 0 signifie ok | ||
| 70 | { | ||
| 71 | if ($_FILES['upload']['size'] <= $tailleMax ) | ||
| 72 | { | ||
| 73 | $infos = pathinfo ($_FILES['upload']['name']); | ||
| 74 | $extension = $infos['extension']; | ||
| 75 | $extautorisées = array('jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'tiff'); | ||
| 76 | // on prend la même liste que celle côté javascript, le SVG est bloqué pour raison de sécurité (javascript à l'intérieur) | ||
| 77 | if (in_array ($extension, $extautorisées)) | ||
| 78 | { | ||
| 79 | move_uploaded_file ($_FILES['upload']['tmp_name'], 'data/' . $page . '/images/' . $_FILES['upload']['name']); | ||
| 80 | chmod('data/' . $page . '/images/' . $_FILES['upload']['name'], 0666); | ||
| 81 | } | ||
| 82 | else{$erreur = 'mauvais format, veuillez utiliser une image comportant un de ces formats: jpg ou jpeg, png, gif, bmp, webp, tiff<br />le format svg n\'est pas supporté';} | ||
| 83 | } | ||
| 84 | else{$erreur = 'fichier trop lourd';} | ||
| 85 | } | ||
| 86 | else{$erreur = $_FILES['upload']['error'];} | ||
| 87 | /* les erreurs retournées avec $_FILES['upload']['error']: | ||
| 88 | 0 pas d'erreur | ||
| 89 | 1 taille du fichier supérieure à la valeur de upload_max_filesize dans le fichier php.ini (par défaut = 2 MO) | ||
| 90 | 2 taille du fichier supérieure à la valeur de MAX_FILE_SIZE dans le formulaire HTML | ||
| 91 | 3 fichier partiellement téléchargé | ||
| 92 | 4 pas de fichier du tout | ||
| 93 | 6 pas de dossier temporaire pour mettre le fichier | ||
| 94 | 7 echec de l'écriture sur le DD | ||
| 95 | 8 envoi arrêté par une extension de PHP mais on ne nous dit pas pourquoi => diagnostic avec la fonction phpinfo() */ | ||
| 96 | |||
| 97 | // nouveau chemin à renvoyer en format json | ||
| 98 | $chemin = '{"url": "data/' . $page . '/images/' . $_FILES['upload']['name'] . '"}'; | ||
| 99 | //echo json_encode($chemin); | ||
| 100 | echo $chemin; | ||
| @@ -54,13 +54,31 @@ require('controller/password.php'); | |||
| 54 | installation(); | 54 | installation(); |
| 55 | 55 | ||
| 56 | 56 | ||
| 57 | // traitement des requêtes AJAX | ||
| 58 | if(isset($_GET['action']) && isset($_GET['page']) && $_GET['action'] == 'upload_image') | ||
| 59 | { | ||
| 60 | // et une backdoor de fermée! | ||
| 61 | if(!isset($_SESSION['admin']) || $_SESSION['admin'] != 1 || !isset($_FILES['upload']) || empty($_FILES['upload'])) | ||
| 62 | { | ||
| 63 | header('Location: index.php?erreur=image_ajax'); | ||
| 64 | } | ||
| 65 | else | ||
| 66 | { | ||
| 67 | require('model/Image.php'); | ||
| 68 | // paramètre "true" parce qu'on reçoit une requête AJAX | ||
| 69 | $Image = new Image(true); | ||
| 70 | $Image->upload(); | ||
| 71 | } | ||
| 72 | exit; // arrêt ici !! | ||
| 73 | } | ||
| 74 | |||
| 57 | // traitement des POST du ckeditor | 75 | // traitement des POST du ckeditor |
| 58 | // la fonction submitCKeditor n'affiche rien (controller/admin.php n'est pas utilisé) puis redirige sans GET | 76 | // la fonction submitCKeditor est "autonome", elle n'affiche rien puis redirige sans GET |
| 59 | if(isset($_SESSION['admin']) && $_SESSION['admin'] == 1 | 77 | if(isset($_SESSION['admin']) && $_SESSION['admin'] == 1 |
| 60 | && isset($_GET['action']) && $_GET['action'] == 'submit' | 78 | && isset($_GET['action']) && $_GET['action'] == 'submit' |
| 61 | // trois possibilités: on a un contenu HTML ou JSON ou les deux | 79 | // trois possibilités: on a un contenu HTML ou JSON ou les deux |
| 62 | && ((isset($_POST['contenu']) && $_POST['contenu'] != '') | 80 | && ((isset($_POST['contenu']) && $_POST['contenu'] != '') |
| 63 | || (isset($_POST['titre']) && isset($_POST['annee']) && isset($_POST['pochette'])))) | 81 | || (isset($_POST['titre']) && isset($_POST['annee'])))) |
| 64 | { | 82 | { |
| 65 | require('controller/ckeditor.php'); // traitement du POST | 83 | require('controller/ckeditor.php'); // traitement du POST |
| 66 | require('lib/htmlawed/htmLawed.php'); // failles XSS | 84 | require('lib/htmlawed/htmLawed.php'); // failles XSS |
| @@ -94,11 +112,7 @@ if(isset($_GET['action']) && isset($_GET['page'])) | |||
| 94 | } | 112 | } |
| 95 | } | 113 | } |
| 96 | 114 | ||
| 97 | // le site comporte deux modes: | 115 | // contrôleur des pages en mode visiteur (= lecture uniquement) |
| 98 | // le mode visiteur en "lecture seule" utilisant le contrôleur visitor.php | ||
| 99 | // le mode admin avec droits en "écriture" utilisant le contrôleur admin.php | ||
| 100 | |||
| 101 | // contrôleur des pages en mode visiteur | ||
| 102 | // appelé tout le temps parce que certaines pages (accueil, menu) n'ont pas de version "admin" => à améliorer | 116 | // appelé tout le temps parce que certaines pages (accueil, menu) n'ont pas de version "admin" => à améliorer |
| 103 | require('controller/visitor.php'); | 117 | require('controller/visitor.php'); |
| 104 | 118 | ||
| @@ -111,6 +125,7 @@ if(isset($_GET['page']) && $_GET['page'] != 'menu') | |||
| 111 | // contrôleur des pages en mode admin | 125 | // contrôleur des pages en mode admin |
| 112 | if(isset($_SESSION['admin']) && $_SESSION['admin'] == 1) | 126 | if(isset($_SESSION['admin']) && $_SESSION['admin'] == 1) |
| 113 | { | 127 | { |
| 128 | // contrôleur en mode admin (= lecture/écriture) | ||
| 114 | require('controller/admin.php'); | 129 | require('controller/admin.php'); |
| 115 | } | 130 | } |
| 116 | else | 131 | else |
diff --git a/model/Classes.php b/model/Classes.php index 1846ce3..97a137a 100644 --- a/model/Classes.php +++ b/model/Classes.php | |||
| @@ -31,7 +31,7 @@ class AllArticles | |||
| 31 | { | 31 | { |
| 32 | return($this->nbArticles); | 32 | return($this->nbArticles); |
| 33 | } | 33 | } |
| 34 | public function getFileNames() | 34 | public function getFileList() |
| 35 | { | 35 | { |
| 36 | return($this->files); | 36 | return($this->files); |
| 37 | } | 37 | } |
| @@ -154,21 +154,27 @@ class Album extends OneArticle | |||
| 154 | { | 154 | { |
| 155 | // variables | 155 | // variables |
| 156 | //private $fileNameJSON; // même nom en .json | 156 | //private $fileNameJSON; // même nom en .json |
| 157 | //protected $format = 'json'; | ||
| 158 | 157 | ||
| 159 | // GET | 158 | // GET |
| 160 | 159 | ||
| 161 | // SET | 160 | // SET |
| 162 | 161 | ||
| 163 | // fonctions CRUD | 162 | // fonctions CRUD |
| 164 | |||
| 165 | // create | 163 | // create |
| 166 | public function createVignette($titre, $annee, $pochette) | 164 | public function createVignette($titre, $annee, $pochette) |
| 167 | { | 165 | { |
| 166 | $this->format = 'json'; | ||
| 167 | |||
| 168 | if($pochette != '') | 168 | if($pochette != '') |
| 169 | { | 169 | { |
| 170 | // enregistrer le fichier | 170 | // télécharger la pochette |
| 171 | // retourner une erreur en cas d'échec de l'upload | 171 | require('model/Image.php'); |
| 172 | $Image = new Image(false); | ||
| 173 | $Image->upload(); | ||
| 174 | |||
| 175 | /*$erreur = $Image->getError(); | ||
| 176 | if(!empty($erreur)) | ||
| 177 | {}*/ | ||
| 172 | } | 178 | } |
| 173 | 179 | ||
| 174 | $albumJSON = json_encode([$titre, $annee, $pochette]); | 180 | $albumJSON = json_encode([$titre, $annee, $pochette]); |
| @@ -192,12 +198,4 @@ class Album extends OneArticle | |||
| 192 | // delete | 198 | // delete |
| 193 | public function delete() | 199 | public function delete() |
| 194 | {} | 200 | {} |
| 195 | } | 201 | } \ No newline at end of file |
| 196 | |||
| 197 | |||
| 198 | |||
| 199 | // note: les pros font de l'hydration | ||
| 200 | // le code du modèle est orienté objet et "refactorisé" d'une manière précise: | ||
| 201 | // on utilise un objet pour une chose (des articles, commentaires, etc), | ||
| 202 | // un objet article contiendrait ainsi tout le nécessaire pour lire, écrire ou modifier un article | ||
| 203 | // 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/model/Image.php b/model/Image.php new file mode 100644 index 0000000..0070b70 --- /dev/null +++ b/model/Image.php | |||
| @@ -0,0 +1,59 @@ | |||
| 1 | <?php | ||
| 2 | // model/Image.php | ||
| 3 | |||
| 4 | class Image | ||
| 5 | { | ||
| 6 | private const MAX_WEIGHT = 2000000; // taille max des images (par défaut 2Mo dans php.ini) | ||
| 7 | private $page; | ||
| 8 | private $ajax = false; | ||
| 9 | private $erreur = ''; | ||
| 10 | |||
| 11 | public function __construct($ajax) | ||
| 12 | { | ||
| 13 | // get envoyé avec le javascript | ||
| 14 | $this->page = $_GET['page']; | ||
| 15 | $this->ajax = $ajax; | ||
| 16 | } | ||
| 17 | |||
| 18 | // GET | ||
| 19 | public function getError() | ||
| 20 | { | ||
| 21 | return($this->erreur); | ||
| 22 | } | ||
| 23 | |||
| 24 | public function upload() | ||
| 25 | { | ||
| 26 | |||
| 27 | // traitement et enregistrement de l'image | ||
| 28 | if (isset($_FILES['upload']) AND $_FILES['upload']['error'] == 0) // 0 signifie ok | ||
| 29 | { | ||
| 30 | if ($_FILES['upload']['size'] <= self::MAX_WEIGHT) | ||
| 31 | { | ||
| 32 | $infos = pathinfo($_FILES['upload']['name']); | ||
| 33 | $extension = $infos['extension']; | ||
| 34 | $extautorisées = array('jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'tiff'); | ||
| 35 | // on prend la même liste que celle côté javascript, le SVG est bloqué pour raison de sécurité (javascript à l'intérieur) | ||
| 36 | if (in_array($extension, $extautorisées)) | ||
| 37 | { | ||
| 38 | move_uploaded_file($_FILES['upload']['tmp_name'], 'data/' . $this->page . '/images/' . $_FILES['upload']['name']); | ||
| 39 | chmod('data/' . $this->page . '/images/' . $_FILES['upload']['name'], 0666); | ||
| 40 | } | ||
| 41 | else{$this->erreur = 'mauvais format, veuillez utiliser une image comportant un de ces formats: jpg ou jpeg, png, gif, bmp, webp, tiff<br />le format svg n\'est pas supporté';} | ||
| 42 | } | ||
| 43 | else{$this->erreur = 'fichier trop lourd';} | ||
| 44 | } | ||
| 45 | else | ||
| 46 | { | ||
| 47 | $this->erreur = $_FILES['upload']['error']; | ||
| 48 | } | ||
| 49 | |||
| 50 | // retour des rêquetes AJAX | ||
| 51 | if($this->ajax) | ||
| 52 | { | ||
| 53 | // nouveau chemin à renvoyer en format json | ||
| 54 | $chemin = '{"url": "data/' . $this->page . '/images/' . $_FILES['upload']['name'] . '"}'; | ||
| 55 | //echo json_encode($chemin); | ||
| 56 | echo $chemin; | ||
| 57 | } | ||
| 58 | } | ||
| 59 | } \ No newline at end of file | ||
diff --git a/public/discographie.css b/public/discographie.css index adf5ac0..8b050db 100644 --- a/public/discographie.css +++ b/public/discographie.css | |||
| @@ -39,7 +39,8 @@ aside div | |||
| 39 | /*padding: 5px;*/ | 39 | /*padding: 5px;*/ |
| 40 | display: none; | 40 | display: none; |
| 41 | z-index: 1; /* placer le menu déroulant au dessus */ | 41 | z-index: 1; /* placer le menu déroulant au dessus */ |
| 42 | background-color: #9fa8d0; | 42 | /*background-color: #9fa8d0;*/ |
| 43 | background-color: #a4afd4; | ||
| 43 | } | 44 | } |
| 44 | 45 | ||
| 45 | #chronologie p | 46 | #chronologie p |
| @@ -47,6 +48,29 @@ aside div | |||
| 47 | margin: 8px; | 48 | margin: 8px; |
| 48 | } | 49 | } |
| 49 | 50 | ||
| 51 | #chronologie p a:visited | ||
| 52 | { | ||
| 53 | color: blue; | ||
| 54 | } | ||
| 55 | #chronologie p a:hover | ||
| 56 | { | ||
| 57 | color: black; | ||
| 58 | } | ||
| 59 | |||
| 60 | .linkChrono | ||
| 61 | { | ||
| 62 | text-decoration: none; | ||
| 63 | } | ||
| 64 | .linkChrono:hover | ||
| 65 | { | ||
| 66 | text-decoration: underline; | ||
| 67 | } | ||
| 68 | .noLinkChrono | ||
| 69 | { | ||
| 70 | text-decoration: none; | ||
| 71 | color: black; | ||
| 72 | } | ||
| 73 | |||
| 50 | /* PC uniquement, pour les smartphones prévoir un clic | 74 | /* PC uniquement, pour les smartphones prévoir un clic |
| 51 | => :checked et une checkbox | 75 | => :checked et une checkbox |
| 52 | => ou la balise select qui crée un menu déroulant */ | 76 | => ou la balise select qui crée un menu déroulant */ |
| @@ -129,11 +153,17 @@ a:hover figure figcaption | |||
| 129 | text-decoration: underline; | 153 | text-decoration: underline; |
| 130 | } | 154 | } |
| 131 | 155 | ||
| 156 | |||
| 132 | /* page dédiée à un album */ | 157 | /* page dédiée à un album */ |
| 133 | #albumHTML | 158 | #albumHTML |
| 134 | { | 159 | { |
| 135 | width: 100%; | 160 | width: 100%; |
| 136 | } | 161 | } |
| 162 | .linkAlbumHTML | ||
| 163 | { | ||
| 164 | color: blue; | ||
| 165 | } | ||
| 166 | |||
| 137 | 167 | ||
| 138 | @media screen and (min-width: 700px) | 168 | @media screen and (min-width: 700px) |
| 139 | { | 169 | { |
diff --git a/public/donnees_hors_editeur.css b/public/donnees_hors_editeur.css index 8619938..fdb12b5 100644 --- a/public/donnees_hors_editeur.css +++ b/public/donnees_hors_editeur.css | |||
| @@ -26,13 +26,13 @@ input[type="checkbox"]:checked{border: none; background: #26ab33;} | |||
| 26 | .table td{border: 1px grey solid; padding: 7px; min-width: 30px;} | 26 | .table td{border: 1px grey solid; padding: 7px; min-width: 30px;} |
| 27 | td p{margin: 0px;} | 27 | td p{margin: 0px;} |
| 28 | 28 | ||
| 29 | .image{margin: 0px 0px 0px 5px; text-align: center; display: inline-block;} | 29 | .image{margin: 0px; text-align: center; display: inline-block;} |
| 30 | .image img{max-width: 630px;} | 30 | .image img{max-width: 630px;} |
| 31 | .image-style-side{float: right;} | 31 | .image-style-side{float: right;} |
| 32 | .image-style-side img{max-width: 315px;} | 32 | .image-style-side img{max-width: 315px;} |
| 33 | .image>figcaption{padding: 7px; text-align: center; font-size: small; background-color: #f0f0f0;} | 33 | .image>figcaption{padding: 7px; text-align: center; font-size: small; background-color: #f0f0f0;} |
| 34 | 34 | ||
| 35 | .boutonArticle{clear: both;} | 35 | .boutonArticle{clear: both; padding: 10px 0px;} |
| 36 | article:after{content: ""; display: block; clear: both;} | 36 | article:after{content: ""; display: block; clear: both;} |
| 37 | 37 | ||
| 38 | iframe{min-width: 400px; min-height: 300px; max-width: 1200px; max-height: 900px;} \ No newline at end of file | 38 | iframe{min-width: 400px; min-height: 300px; max-width: 1200px; max-height: 900px;} \ No newline at end of file |
diff --git a/public/melaine.css b/public/melaine.css index 9736147..f7faf99 100644 --- a/public/melaine.css +++ b/public/melaine.css | |||
| @@ -22,7 +22,6 @@ figure | |||
| 22 | } | 22 | } |
| 23 | .boutonArticle | 23 | .boutonArticle |
| 24 | { | 24 | { |
| 25 | padding-bottom: 20px; | ||
| 26 | border-bottom: 1px black solid; | 25 | border-bottom: 1px black solid; |
| 27 | } | 26 | } |
| 28 | .boutonArticle a | 27 | .boutonArticle a |
diff --git a/view/album.php b/view/album.php index 39d180a..921efaf 100644 --- a/view/album.php +++ b/view/album.php | |||
| @@ -30,6 +30,6 @@ ob_start(); | |||
| 30 | <?= $album ?> | 30 | <?= $album ?> |
| 31 | </article> | 31 | </article> |
| 32 | 32 | ||
| 33 | <p><a href="index.php?page=discographie" >Retour à la discographie</a></p> | 33 | <p><a class="linkAlbumHTML" href="index.php?page=discographie" >Retour à la discographie</a></p> |
| 34 | <?php | 34 | <?php |
| 35 | $content = ob_get_clean(); | 35 | $content = ob_get_clean(); |
diff --git a/view/discographie.php b/view/discographie.php index fcb788f..19e982b 100644 --- a/view/discographie.php +++ b/view/discographie.php | |||
| @@ -55,7 +55,7 @@ foreach($albumsJSON as $oneAlbum) | |||
| 55 | // mettre une adresse lorsqu'un fichier html existe | 55 | // mettre une adresse lorsqu'un fichier html existe |
| 56 | // si il n'existe pas, mettre une ancre vers l'endroit sur la page | 56 | // si il n'existe pas, mettre une ancre vers l'endroit sur la page |
| 57 | ?> | 57 | ?> |
| 58 | <p><a href="index.php?page=<?= $lienAlbum[$i] ?>" ><?= $oneAlbum[1] ?>: <?= $oneAlbum[0] ?></a></p> | 58 | <p><a class="<?= $linkDiscoChrono[$i] ?>" href="index.php?page=<?= $lienAlbum[$i] ?>" ><?= $oneAlbum[1] ?> <?= $oneAlbum[0] ?></a></p> |
| 59 | <?php | 59 | <?php |
| 60 | $i++; | 60 | $i++; |
| 61 | } | 61 | } |
| @@ -106,8 +106,6 @@ foreach($albumsJSON as $oneAlbum) | |||
| 106 | <?php | 106 | <?php |
| 107 | } | 107 | } |
| 108 | ?> | 108 | ?> |
| 109 | |||
| 110 | |||
| 111 | <figure> | 109 | <figure> |
| 112 | <img class="vignette" src="data/discographie/images/<?= $oneAlbum[2] ?>" alt="" > | 110 | <img class="vignette" src="data/discographie/images/<?= $oneAlbum[2] ?>" alt="" > |
| 113 | <figcaption><?= $oneAlbum[0] ?><br><?= $oneAlbum[1] ?></figcaption> | 111 | <figcaption><?= $oneAlbum[0] ?><br><?= $oneAlbum[1] ?></figcaption> |
diff --git a/view/template-formulaires.php b/view/template-formulaires.php index 7eb1bb5..391f729 100644 --- a/view/template-formulaires.php +++ b/view/template-formulaires.php | |||
| @@ -24,9 +24,9 @@ ob_start(); | |||
| 24 | <label for="titre" >Titre</label> | 24 | <label for="titre" >Titre</label> |
| 25 | <input type="text" name="titre" required ><br /> | 25 | <input type="text" name="titre" required ><br /> |
| 26 | <label for="annee" >Année</label> | 26 | <label for="annee" >Année</label> |
| 27 | <input type="text" name="annee" ><br /> | 27 | <input type="text" name="annee" required ><br /> |
| 28 | <label for="pochette" >Pochette du disque (jpg ou png)</label> | 28 | <label for="pochette" >Pochette du disque (jpg ou png)</label> |
| 29 | <input type="file" name="pochette" > | 29 | <input type="file" name="upload" > |
| 30 | <br /><br /> | 30 | <br /><br /> |
| 31 | <?php | 31 | <?php |
| 32 | $inputsAlbum = ob_get_clean(); | 32 | $inputsAlbum = ob_get_clean(); |
| @@ -37,7 +37,7 @@ ob_start(); | |||
| 37 | ?> | 37 | ?> |
| 38 | 38 | ||
| 39 | <div class="conteneur_article" > | 39 | <div class="conteneur_article" > |
| 40 | <form action="index.php?page=<?= $page_actuelle ?>&article=<?= $numArticle ?>&action=submit" method="post" > | 40 | <form action="index.php?page=<?= $page_actuelle ?>&article=<?= $numArticle ?>&action=submit" method="post" enctype="multipart/form-data" > |
| 41 | <?php | 41 | <?php |
| 42 | if($page_actuelle == 'discographie') | 42 | if($page_actuelle == 'discographie') |
| 43 | { | 43 | { |
| @@ -154,13 +154,12 @@ if($page_actuelle == 'discographie') | |||
| 154 | // "url": "https://example.com/images/foo.jpg" | 154 | // "url": "https://example.com/images/foo.jpg" |
| 155 | //} | 155 | //} |
| 156 | // cette url sert à deux choses: | 156 | // cette url sert à deux choses: |
| 157 | // - à télécharger l'image avant de la placer dans l'éditeur | 157 | // - à télécharger immédiatement l'image envoyée pour la placer dans l'éditeur |
| 158 | // - écrire le HTML qu'on enregistrera ensuite | 158 | // - à inclure l'adresse de l'image dans le HTML produit par l'éditeur |
| 159 | // en effet, le fichier est téléchargé sur le serveur avant de revenir dans l'éditeur comme un téléchargement classique | ||
| 160 | simpleUpload: { | 159 | simpleUpload: { |
| 161 | uploadUrl: 'imageAJAX.php?page=<?= $page_actuelle ?>', | 160 | uploadUrl: 'index.php?action=upload_image&page=<?= $page_actuelle ?>', |
| 162 | // noter qu'il est possible (parce que souhaitable je ne pense pas) d'envoyer une requête AJAX | 161 | // noter qu'il est possible (parce que souhaitable je ne pense pas) d'envoyer une requête AJAX |
| 163 | // en indiquant une adresse "statique" du type: fichier.txt ou .xml, jpg, png, etc | 162 | // en indiquant une adresse "statique" du type: fichier.txt ou .xml, jpg, png, etc, |
| 164 | 163 | ||
| 165 | // Headers supplémentaires envoyés avec la requête | 164 | // Headers supplémentaires envoyés avec la requête |
| 166 | // c'est ici qu'on installe les mécanismes de sécurités comme l'authentification et la protection au CSRF | 165 | // c'est ici qu'on installe les mécanismes de sécurités comme l'authentification et la protection au CSRF |
| @@ -171,11 +170,8 @@ if($page_actuelle == 'discographie') | |||
| 171 | }, | 170 | }, |
| 172 | // formats acceptés par défaut: jpeg, png, gif, bmp, webp, tiff | 171 | // formats acceptés par défaut: jpeg, png, gif, bmp, webp, tiff |
| 173 | // le svg n'est pas dans la liste, pour raison de sécurité apparemment, il parait qu'on peut mettre du javascript à l'intérieur | 172 | // le svg n'est pas dans la liste, pour raison de sécurité apparemment, il parait qu'on peut mettre du javascript à l'intérieur |
| 174 | 173 | // ce plugin est simple (JS pur) et n'oblige pas le serveur à disposer de l'extension GD | |
| 175 | // ce plugin a l'intérêt de ne pas imposer l'utilisation de l'extension GD de PHP, | 174 | // niveau perfs, on garde le choix d'utiler GD ou imagemagick ou un système d'onglets |
| 176 | // Reste qu'il sera quand même intéressant de l'ajouter pour le redimensionnement des images trop lourdes, | ||
| 177 | // quoi que le système d'onglets (limiter l'affichge à 5 ou 10 articles par page) règle aussi le problème d'une autre manière | ||
| 178 | |||
| 179 | 175 | ||
| 180 | // plugin autosave | 176 | // plugin autosave |
| 181 | } ) | 177 | } ) |
