diff options
author | polo <ordipolo@gmx.fr> | 2021-09-08 02:09:34 +0200 |
---|---|---|
committer | polo <ordipolo@gmx.fr> | 2021-09-08 02:09:34 +0200 |
commit | cdf1bda847edd3e22e9fe817a802219ad8e0f626 (patch) | |
tree | adbe2b35e9741a5db74491c85914f4c03d3d4c99 | |
parent | 9a552c6b751f25bac9e816cf605fb972da8b9e27 (diff) | |
download | melaine-cdf1bda847edd3e22e9fe817a802219ad8e0f626.zip |
vignette
-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 | } ) |