diff options
author | polo <ordipolo@gmx.fr> | 2021-08-10 02:11:20 +0200 |
---|---|---|
committer | polo <ordipolo@gmx.fr> | 2021-08-10 02:11:20 +0200 |
commit | 0d2fd7a0a53c527d3f6f112a149960a52c1082e1 (patch) | |
tree | b1d459b68da7d1a0a38574c8014a6a25c86bd56e | |
parent | 86c2a611e55c9e35384febecf34964e214c0296e (diff) | |
download | melaine-0d2fd7a0a53c527d3f6f112a149960a52c1082e1.zip |
disco
-rw-r--r-- | controller/admin.php | 88 | ||||
-rw-r--r-- | controller/ckeditor.php | 105 | ||||
-rw-r--r-- | controller/installation.php | 8 | ||||
-rw-r--r-- | controller/visitor.php | 24 | ||||
-rw-r--r-- | data/melaine/images/ânon.jpg | bin | 0 -> 22992 bytes | |||
-rw-r--r-- | imageAJAX.php | 40 | ||||
-rw-r--r-- | index.php | 120 | ||||
-rw-r--r-- | model/Article.php | 92 | ||||
-rw-r--r-- | model/Classes.php | 176 | ||||
-rw-r--r-- | model/melaine-read.php | 59 | ||||
-rw-r--r-- | model/melaine-write.php | 32 | ||||
-rw-r--r-- | public/discographie.css | 202 | ||||
-rw-r--r-- | public/main.js | 15 | ||||
-rw-r--r-- | public/melaine.css | 55 | ||||
-rw-r--r-- | view/accueil.php | 2 | ||||
-rw-r--r-- | view/discographie.php | 87 | ||||
-rw-r--r-- | view/melaine.php | 13 | ||||
-rw-r--r-- | view/template-ckeditor.php | 16 | ||||
-rw-r--r-- | view/template.php | 6 |
19 files changed, 768 insertions, 372 deletions
diff --git a/controller/admin.php b/controller/admin.php index a35f28a..2f7a7cb 100644 --- a/controller/admin.php +++ b/controller/admin.php | |||
@@ -2,16 +2,19 @@ | |||
2 | // controller/admin.php | 2 | // controller/admin.php |
3 | // | 3 | // |
4 | // utilisation du site en écriture | 4 | // utilisation du site en écriture |
5 | // version des pages en mode admin lorsque celui-ci crée ou modifie quelque chose | ||
5 | 6 | ||
6 | // pages du site en version admin | 7 | function melaineEdit($numArticle, $suppression) |
7 | function melaineEdit($numArticle) | ||
8 | { | 8 | { |
9 | $page_actuelle = "melaine"; | 9 | $page_actuelle = "melaine"; |
10 | 10 | ||
11 | // tableau $articles[] | 11 | $Articles = new ArticlesManager; |
12 | $croissant = False; | ||
13 | $articles = lireArticles($page_actuelle, $croissant); | ||
14 | 12 | ||
13 | // contenu de la page | ||
14 | $Articles->setPage($page_actuelle); | ||
15 | $Articles->getFiles(); | ||
16 | |||
17 | // nouvel article | ||
15 | if($numArticle == 0) | 18 | if($numArticle == 0) |
16 | { | 19 | { |
17 | $title = "Ajouter un article"; | 20 | $title = "Ajouter un article"; |
@@ -19,10 +22,31 @@ function melaineEdit($numArticle) | |||
19 | } | 22 | } |
20 | else | 23 | else |
21 | { | 24 | { |
22 | $title = "Modifier un article"; | 25 | // nom de l'article ciblé (objet et session) |
23 | $texte = lireUnArticle($_SESSION['nomFichier']); | 26 | $Articles->findFileName($numArticle); |
27 | $_SESSION['nomFichier'] = $Articles->getFileName(); | ||
28 | |||
29 | // suppression | ||
30 | if($suppression) | ||
31 | { | ||
32 | $Articles->delete(); | ||
33 | header('Location: index.php?page=' . $page_actuelle); | ||
34 | } | ||
35 | // modification | ||
36 | else | ||
37 | { | ||
38 | $title = "Modifier un article"; | ||
39 | |||
40 | // contenu envoyé à l'éditeur | ||
41 | $texte = $Articles->getOne(); | ||
42 | } | ||
24 | } | 43 | } |
25 | 44 | ||
45 | // pour l'affichage des articles | ||
46 | //$Articles->setAscending(False); | ||
47 | $Articles->reverseFilesArray(); | ||
48 | $articles = $Articles->getAll(); | ||
49 | |||
26 | // traitements PHP pour l'éditeur | 50 | // traitements PHP pour l'éditeur |
27 | require('controller/ckeditor.php'); | 51 | require('controller/ckeditor.php'); |
28 | // sécurisation du contenu pré-existant inséré dans l'éditeur | 52 | // sécurisation du contenu pré-existant inséré dans l'éditeur |
@@ -31,16 +55,52 @@ function melaineEdit($numArticle) | |||
31 | // NB: penser à ajouter au template la fonctionnalité "autosave" | 55 | // NB: penser à ajouter au template la fonctionnalité "autosave" |
32 | // https://ckeditor.com/docs/ckeditor5/latest/builds/guides/integration/saving-data.html | 56 | // https://ckeditor.com/docs/ckeditor5/latest/builds/guides/integration/saving-data.html |
33 | 57 | ||
34 | // variable $editeurHTML, $initial est inséré dedans | 58 | // création des morceaux en HTML avant assemblage |
35 | require('view/template-ckeditor.php'); | ||
36 | 59 | ||
37 | // création des morceaux en HTML avant assemblage, c'est-à -dire; | 60 | // variable $editeurHTML, on insère $texte dedans |
38 | // les variables $css, $js, $header et $content | 61 | require('view/template-ckeditor.php'); |
62 | |||
63 | // variables $css, $js, $header et $content | ||
39 | require('view/melaine.php'); | 64 | require('view/melaine.php'); |
40 | // le tableau de données ($articles) et l'éditeur ($editeurHTML) | 65 | // le tableau de données ($articles) et l'éditeur ($editeurHTML) font partie de $content |
41 | // font partie de $content | 66 | |
67 | // fin de l'assemblage | ||
68 | require('view/template.php'); | ||
69 | } | ||
42 | 70 | ||
43 | // assemblage de la page! | 71 | function discoEdit($numArticle, $suppression) |
72 | { | ||
73 | $page_actuelle = "discographie"; | ||
74 | $title = "Discographie"; | ||
75 | |||
76 | // modèle | ||
77 | $Albums = new AlbumsManager; | ||
78 | $texte = ''; | ||
79 | |||
80 | // traitements PHP pour l'éditeur | ||
81 | require('controller/ckeditor.php'); | ||
82 | // sécurisation du contenu pré-existant inséré dans l'éditeur | ||
83 | $texte = preparationCKeditor($numArticle, $texte); | ||
84 | |||
85 | // variable $additionalInputs | ||
86 | ob_start(); | ||
87 | ?> | ||
88 | <p><i>Infos qui seront affichées sur cette page:</i></p> | ||
89 | <label for="titre" >Titre</label> | ||
90 | <input type="text" name="titre" required ><br /> | ||
91 | <label for="annee" >Année</label> | ||
92 | <input type="text" name="annee" ><br /> | ||
93 | <label for="pochette" >Pochette du disque (jpg ou png)</label> | ||
94 | <input type="file" name="pochette" > | ||
95 | <br /><br /> | ||
96 | <?php | ||
97 | $additionalInputs = ob_get_clean(); | ||
98 | |||
99 | // variable $editeurHTML, on insère $texte dedans | ||
100 | require('view/template-ckeditor.php'); | ||
101 | // variables $css, $js et $content | ||
102 | require('view/discographie.php'); | ||
103 | // fin de l'assemblage | ||
44 | require('view/template.php'); | 104 | require('view/template.php'); |
45 | } | 105 | } |
46 | 106 | ||
diff --git a/controller/ckeditor.php b/controller/ckeditor.php index ea90726..9262da0 100644 --- a/controller/ckeditor.php +++ b/controller/ckeditor.php | |||
@@ -9,11 +9,18 @@ | |||
9 | // avant de placer l'éditeur | 9 | // avant de placer l'éditeur |
10 | function preparationCKeditor($numArticle, $texte) | 10 | function preparationCKeditor($numArticle, $texte) |
11 | { | 11 | { |
12 | // $numArticle sert à placer l'éditeur sur la page et à lire et écrire dans le bon dossier | 12 | // ici $numArticle sert uniquement à savoir si on crée ou modifie un article |
13 | 13 | ||
14 | // texte initial pour setData() à modifier avec l'éditeur | 14 | // texte initial inséré avec setData() dans l'éditeur, |
15 | // on recherche ici les causes expliquant qu'il n'apparaisse pas à l'ouverture de l'éditeur, | ||
16 | // les données précédentes sont écrasées à la validation du nouveau texte | ||
15 | if ($numArticle > 0) | 17 | if ($numArticle > 0) |
16 | { | 18 | { |
19 | if(empty($texte)) | ||
20 | { | ||
21 | header('Location: index.php?erreur=empty_input'); | ||
22 | } | ||
23 | |||
17 | // supprimer espaces, tabulations et sauts de ligne en début et fin de chaine | 24 | // supprimer espaces, tabulations et sauts de ligne en début et fin de chaine |
18 | $texte = trim($texte); | 25 | $texte = trim($texte); |
19 | 26 | ||
@@ -34,8 +41,11 @@ function preparationCKeditor($numArticle, $texte) | |||
34 | 41 | ||
35 | // réception du HTML créé par l'éditeur | 42 | // réception du HTML créé par l'éditeur |
36 | // le nom du fichier est celui dans $_SESSION['nomFichier'] | 43 | // le nom du fichier est celui dans $_SESSION['nomFichier'] |
37 | function submitCKeditor($page, $nomFichier, $contenu) | 44 | function submitCKeditor($nomFichier) |
38 | { | 45 | { |
46 | $page = $_GET['page']; | ||
47 | $contenu = $_POST['contenu']; | ||
48 | |||
39 | // déjà fait mais on ne sait jamais | 49 | // déjà fait mais on ne sait jamais |
40 | if(!isset($_SESSION['admin']) || $_SESSION['admin'] != 1) | 50 | if(!isset($_SESSION['admin']) || $_SESSION['admin'] != 1) |
41 | { | 51 | { |
@@ -43,30 +53,45 @@ function submitCKeditor($page, $nomFichier, $contenu) | |||
43 | } | 53 | } |
44 | else | 54 | else |
45 | { | 55 | { |
46 | // ne pas continuer si la variable est vide (javascript mal supporté ou utilisation de IE, bug?, erreur de l'utilisateur) | 56 | // récupérer les liens multimedia |
47 | // on évitera de perdre un article existant par erreur !! | 57 | //require("media.php"); |
58 | //$contenu = mediaSubmit($contenu); | ||
59 | |||
60 | // sécurité faille XSS | ||
61 | $configHtmLawed = array( | ||
62 | 'safe'=>1, // protection contre les élements et attributs dangereux | ||
63 | '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 | ||
64 | 'deny_attribute'=>'id', // gêner le JS hostile | ||
65 | // on garde 'class' et 'style' utilisés par le ckediteur | ||
66 | ); | ||
67 | $specHtmLawed = ''; // optionnel: faire qu'un certain élément puisse n'avoir que certains attributs | ||
68 | } | ||
69 | |||
70 | if($page == 'discographie') | ||
71 | { | ||
72 | $titre = $_POST['titre']; | ||
73 | $annee = $_POST['annee']; | ||
74 | $pochette = $_POST['pochette']; | ||
75 | |||
76 | $titre = htmLawed($titre, $configHtmLawed, $specHtmLawed); | ||
77 | $titre = trim($titre); | ||
78 | $contenu = htmLawed($contenu, $configHtmLawed, $specHtmLawed); | ||
79 | $annee = htmLawed($annee, $configHtmLawed, $specHtmLawed); | ||
80 | $annee = trim($annee); | ||
81 | $contenu = trim($contenu); | ||
82 | } | ||
83 | else // pages comme "melaine" | ||
84 | { | ||
85 | // ne pas continuer si la variable est vide (javascript mal supporté ou utilisation de IE, bug?, erreur de l'utilisateur), risque perte de contenu !! | ||
48 | if($contenu == '') | 86 | if($contenu == '') |
49 | { | 87 | { |
50 | header('Location: index.php?page=' . $page . '&erreur=contenu_vide'); | 88 | header('Location: index.php?page=' . $page . '&erreur=contenu_vide'); |
51 | } | 89 | } |
52 | else | 90 | else |
53 | { | 91 | { |
54 | // récupérer les liens multimedia | 92 | // failles XSS |
55 | //require("media.php"); | ||
56 | //$contenu = mediaSubmit($contenu); | ||
57 | |||
58 | // sécurité faille XSS | ||
59 | $configHtmLawed = array( | ||
60 | 'safe'=>1, // protection contre les élements et attributs dangereux | ||
61 | '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 | ||
62 | // paramètre optionnel: les balises non indiquées sont supprimées | ||
63 | 'deny_attribute'=>'id', // gêner le JS hostile | ||
64 | // on garde 'class' et 'style' utilisés par l'ckediteur | ||
65 | ); | ||
66 | $specHtmLawed = ''; // optionnel: faire qu'un certain élément puisse n'avoir que certains attributs | ||
67 | $contenu = htmLawed($contenu, $configHtmLawed, $specHtmLawed); | 93 | $contenu = htmLawed($contenu, $configHtmLawed, $specHtmLawed); |
68 | 94 | // supprimer espaces, tabulations et sauts de ligne en début et fin de chaine (pour l'entrée de l'éditeur) | |
69 | // supprimer espaces, tabulations et sauts de ligne en début et fin de chaine | ||
70 | $contenu = trim($contenu); | 95 | $contenu = trim($contenu); |
71 | } | 96 | } |
72 | } | 97 | } |
@@ -81,22 +106,42 @@ function submitCKeditor($page, $nomFichier, $contenu) | |||
81 | // solution 2 (façon pop-up): fermer ce nouvel onglet avec echo '<SCRIPT>javascript:window.close()</SCRIPT>'; | 106 | // solution 2 (façon pop-up): fermer ce nouvel onglet avec echo '<SCRIPT>javascript:window.close()</SCRIPT>'; |
82 | // pour faire passer par le .htaccess l'info comme quoi la page précédente comportait un éditeur ouvert... | 107 | // pour faire passer par le .htaccess l'info comme quoi la page précédente comportait un éditeur ouvert... |
83 | 108 | ||
84 | // echo($page); | 109 | //var_dump($titre, $annee, $pochette, $contenu); |
85 | // echo($article); | 110 | //die(); |
86 | // echo($contenu); | 111 | |
87 | // die(); | 112 | // modèle |
113 | $Article = new ArticlesManager; | ||
114 | $Article->setPage($page); | ||
88 | 115 | ||
89 | // enregistrement | 116 | // enregistrement |
90 | require('model/melaine-write.php'); | ||
91 | if($_GET['article'] == 0) | 117 | if($_GET['article'] == 0) |
92 | { | 118 | { |
93 | nouvelArticle($page, $contenu); | 119 | $Article->create($contenu); |
94 | } | 120 | } |
95 | else | 121 | else |
96 | { | 122 | { |
97 | modifArticle($page, $nomFichier, $contenu); | 123 | $Article->setFileName($nomFichier); |
124 | $Article->update($contenu); | ||
125 | } | ||
126 | |||
127 | if($page == 'discographie') | ||
128 | { | ||
129 | $Album = new AlbumsManager; | ||
130 | |||
131 | var_dump($_POST); | ||
132 | echo('<br />'); | ||
133 | //var_dump($_GET['article']); | ||
134 | |||
135 | // enregistrement | ||
136 | if($_GET['article'] == 0) | ||
137 | { | ||
138 | // ERREUR, il faut le même nombre de paramètre pour une méthode du même nom | ||
139 | $Album->create($titre, $annee, $pochette); | ||
140 | } | ||
141 | else | ||
142 | { | ||
143 | $Album->update($titre, $annee, $pochette); | ||
144 | } | ||
145 | die(); | ||
98 | } | 146 | } |
99 | |||
100 | // debuggage | ||
101 | //exit(); | ||
102 | } \ No newline at end of file | 147 | } \ No newline at end of file |
diff --git a/controller/installation.php b/controller/installation.php index 4d5791a..b15dce1 100644 --- a/controller/installation.php +++ b/controller/installation.php | |||
@@ -48,7 +48,7 @@ function installation() | |||
48 | // - modifier soit-même les droits du dossier data (777), quoique 111 serait pas mal non plus | 48 | // - modifier soit-même les droits du dossier data (777), quoique 111 serait pas mal non plus |
49 | // - 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 | 49 | // - 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 |
50 | 50 | ||
51 | $listePages = array('melaine', 'disco', 'concerts', 'presse', 'ateliers', 'liens', 'peinture', 'archives'); | 51 | $listePages = array('melaine', 'discographie', 'concerts', 'presse', 'ateliers', 'liens', 'peinture', 'archives'); |
52 | foreach ($listePages as $page) | 52 | foreach ($listePages as $page) |
53 | { | 53 | { |
54 | if(!file_exists('data/' . $page)) | 54 | if(!file_exists('data/' . $page)) |
@@ -56,6 +56,12 @@ function installation() | |||
56 | mkdir('data/' . $page); | 56 | mkdir('data/' . $page); |
57 | chmod('data/' . $page, 0777); | 57 | chmod('data/' . $page, 0777); |
58 | } | 58 | } |
59 | // un dossier en plus dans discographie | ||
60 | if(!file_exists('data/discographie/json')) | ||
61 | { | ||
62 | mkdir('data/discographie/json'); | ||
63 | chmod('data/discographie/json', 0777); | ||
64 | } | ||
59 | if(!file_exists('data/' . $page . '/html')) | 65 | if(!file_exists('data/' . $page . '/html')) |
60 | { | 66 | { |
61 | mkdir('data/' . $page . '/html'); | 67 | mkdir('data/' . $page . '/html'); |
diff --git a/controller/visitor.php b/controller/visitor.php index a08ea95..6fa0822 100644 --- a/controller/visitor.php +++ b/controller/visitor.php | |||
@@ -32,9 +32,12 @@ function melaineVisitor() | |||
32 | $page_actuelle = "melaine"; | 32 | $page_actuelle = "melaine"; |
33 | $title = "Mais qui est Melaine Favennec?"; | 33 | $title = "Mais qui est Melaine Favennec?"; |
34 | 34 | ||
35 | // tableau $articles | 35 | // modèle |
36 | $croissant = False; | 36 | $Articles = new ArticlesManager; |
37 | $articles = lireArticles($page_actuelle, $croissant); | 37 | $Articles->setPage($page_actuelle); |
38 | $Articles->getFiles(); | ||
39 | $Articles->reverseFilesArray(); | ||
40 | $articles = $Articles->getAll(); | ||
38 | 41 | ||
39 | // vérification pour protéger les visiteurs | 42 | // vérification pour protéger les visiteurs |
40 | // normalement déjà faite dans submit.php, au cas où la base a été trafiquée | 43 | // normalement déjà faite dans submit.php, au cas où la base a été trafiquée |
@@ -46,8 +49,19 @@ function melaineVisitor() | |||
46 | require('view/template.php'); | 49 | require('view/template.php'); |
47 | } | 50 | } |
48 | 51 | ||
49 | function discographie() | 52 | function discoVisitor() |
50 | {} | 53 | { |
54 | $page_actuelle = "discographie"; | ||
55 | $title = "Discographie"; | ||
56 | |||
57 | // modèle | ||
58 | $Albums = new AlbumsManager; | ||
59 | |||
60 | // variables $css, $js et $content | ||
61 | require('view/discographie.php'); | ||
62 | // HTML | ||
63 | require('view/template.php'); | ||
64 | } | ||
51 | 65 | ||
52 | function presse() | 66 | function presse() |
53 | {} | 67 | {} |
diff --git a/data/melaine/images/ânon.jpg b/data/melaine/images/ânon.jpg new file mode 100644 index 0000000..5bac4ee --- /dev/null +++ b/data/melaine/images/ânon.jpg | |||
Binary files differ | |||
diff --git a/imageAJAX.php b/imageAJAX.php index 49c856d..0831986 100644 --- a/imageAJAX.php +++ b/imageAJAX.php | |||
@@ -1,4 +1,6 @@ | |||
1 | <?php | 1 | <?php |
2 | // imageAJAX.php | ||
3 | // | ||
2 | // le problème pour écrire ce fichier est qu'il est impossible d'afficher le contenu des variables avec "echo" ou "var_dump" | 4 | // le problème pour écrire ce fichier est qu'il est impossible d'afficher le contenu des variables avec "echo" ou "var_dump" |
3 | // puisqu'on reste toujours sur la même page, il y a heureusement au moins deux manières de faire autrement: | 5 | // puisqu'on reste toujours sur la même page, il y a heureusement au moins deux manières de faire autrement: |
4 | // - avec les outils de développement du navigateur (utiliser firefox ou chromium/chrome mais pas les autres) | 6 | // - avec les outils de développement du navigateur (utiliser firefox ou chromium/chrome mais pas les autres) |
@@ -31,28 +33,26 @@ | |||
31 | // "url": "chemin/images/foo.jpg" | 33 | // "url": "chemin/images/foo.jpg" |
32 | //} | 34 | //} |
33 | 35 | ||
34 | // get envoyé avec le javascript | ||
35 | $page = $_GET['page']; | ||
36 | |||
37 | // debuggage | 36 | // debuggage |
38 | // $_FILES contient: | 37 | /*print_r($_FILES); |
39 | //~ $upload = array( | 38 | $upload = array( |
40 | //~ 'name' => $_FILES['upload']['name'], | 39 | 'name' => $_FILES['upload']['name'], |
41 | //~ 'type' => $_FILES['upload']['type'], | 40 | 'type' => $_FILES['upload']['type'], |
42 | //~ 'tmp_name' => $_FILES['upload']['tmp_name'], | 41 | 'tmp_name' => $_FILES['upload']['tmp_name'], |
43 | //~ 'error' => $_FILES['upload']['error'], | 42 | 'error' => $_FILES['upload']['error'], |
44 | //~ 'size' => $_FILES['upload']['size'] | 43 | 'size' => $_FILES['upload']['size'] |
45 | //~ ); | 44 | ); |
46 | // print_r sert à "afficher" un tableau, | 45 | print_r($upload);*/ |
47 | // le 2ème paramètre 'true' permet de produire une simple chaine au lieu d'un affichage HTML | 46 | |
48 | // $tableau = print_r($_FILES, true); | 47 | session_start(); |
49 | // $nom_fichier = "POST_AJAX.log"; | 48 | // et une backdoor de fermée! |
50 | // $fichier = fopen('data/' . $page . '/images/' . $nom_fichier, 'w'); | 49 | if(!isset($_SESSION['admin']) || $_SESSION['admin'] != 1 || !isset($_FILES['upload']) || empty($_FILES['upload'])) |
51 | // // w peut créer un fichier, si il existe déjà , il est effacé par le nouveau contenu | 50 | { |
52 | // fputs($fichier, $tableau); | 51 | header('Location: index.php?erreur=imageajax'); |
53 | // fclose($fichier); | 52 | } |
54 | // chmod('data/' . $page . '/images/' . $nom_fichier, 0666); | ||
55 | 53 | ||
54 | // get envoyé avec le javascript | ||
55 | $page = $_GET['page']; | ||
56 | 56 | ||
57 | // déjà fait dans installation.php | 57 | // déjà fait dans installation.php |
58 | if(!file_exists('data/' . $page . '/images')) | 58 | if(!file_exists('data/' . $page . '/images')) |
@@ -2,48 +2,41 @@ | |||
2 | // index.php | 2 | // index.php |
3 | // | 3 | // |
4 | // routeur MVC ou controlleur principal | 4 | // routeur MVC ou controlleur principal |
5 | // il récupère les GET, inclut les contrôleurs et appelle des fonctions | 5 | // il traite les GET et passe la main aux contrôleurs |
6 | // | ||
6 | // ce site utilise une architecture Modèle-Vue-Contrôleur (MVC) | 7 | // ce site utilise une architecture Modèle-Vue-Contrôleur (MVC) |
7 | // le schéma ci-dessous représente le sens dans lequel le code est interprété | 8 | // le schéma ci-dessous représente le sens dans lequel le code est interprété |
8 | // | 9 | // |
9 | // modèle | 10 | // modèle |
10 | // ^ | | 11 | // ^ | |
11 | // | v | 12 | // | v |
12 | // routeur --> contrôleur | 13 | // routeur --> contrôleur |
13 | // | | 14 | // | |
14 | // v | 15 | // v |
15 | // vue ---> envoi de la page au client | 16 | // vue ---> envoi de la page au client |
16 | // | 17 | // |
17 | // pour retrouver quelque chose dans le code, il suffit de suivre un chemin linéaire dont le départ est ici | 18 | // pour retrouver quelque chose dans le code, il suffit de suivre un chemin linéaire dont le départ est ici |
18 | // pas de croisement, pas de marche arrière, impossible de se perdre! | 19 | // pas de croisement, pas de marche arrière, impossible de se perdre! |
20 | // autre avantage: les chemins sont tous relatifs et sont toujours bons, parce que tous les fichiers sont "inclus" dans index.php | ||
19 | // | 21 | // |
20 | // Ã la racine de l'arbre des fichiers nous avons: | ||
21 | // - 1 fichier index.php sur lequel se greffe tout le reste | ||
22 | // - 4 dossiers pricipaux: controller - model - view - public | ||
23 | // un avantage est que les chemins sont tous relatifs, partent tous de la racine du site et sont toujours bons | ||
24 | |||
25 | // Les dossiers: | 22 | // Les dossiers: |
26 | // -> contrôleurs: traitements en PHP pur | 23 | // -> controller: traitements en PHP pur |
27 | // -> modèles: interface entre PHP et données, on y trouve le SQL ou la manipulation de fichiers textes, le PHP y est générlement orienté objet | 24 | // -> model: interface entre PHP et données, on y trouve le SQL ou la manipulation de fichiers textes, le PHP y est orienté objet |
28 | // -> vues: le PHP y produit le HTML, il construit les pages, | 25 | // -> view: le PHP y produit le HTML, il construit les pages, |
29 | // le mélange PHP/HTML étant très vite assez dégueulasse, le HTML figé à placé à part dans le fichier view/template.php | 26 | // le mélange PHP/HTML étant très vite assez dégueulasse, le HTML figé est placé à part dans le fichier view/template.php |
30 | // -> le dossier public contient CSS, JS, images, polices, medias, etc, il est utilisé par le template | 27 | // -> public: contient CSS, JS, images, polices, medias, etc, il est utilisé par template.php |
31 | // -> le dossier lib contient les bibliothèques, il contient notamment le ckeditor qui occupe une place centrale dans le projet, on y trouve aussi la bibli htmLawed qui protège des données dangereuses (failles XSS) | 28 | // -> lib: les bibliothèques, on y trouve en particulier le ckeditor qui occupe une place centrale dans le projet, et aussi htmLawed qui nettoie le HTML produit par l'éditeur (failles XSS) |
32 | // -> le dossier data qui est techniquement séparé du site | 29 | // -> data: comme son nom l'indique |
33 | // | 30 | // |
34 | // pour le reste nous avons: | 31 | // Quelques fichiers spéciaux (indépendants de index.php): |
35 | // - le fichier imageAJAX.php traitant les requêtes AJAX | 32 | // - imageAJAX.php traite les requêtes AJAX envoyées par l'éditeur |
36 | // ce fichier est appelé sans index.php et est pour cette raison un peu spécial | 33 | // - .htaccess pour la sécurité (configurer le httpd.conf d'apache peut être nécessaire) |
37 | // - 1 fichier .htaccess pour la sécurité (configurer le httpd.conf peut être nécessaire) | 34 | // - erreur404.php (fonctionne avec .htaccess) |
38 | // - 1 fichier erreur404.php (fonctionne avec .htaccess) | ||
39 | // - des bibliothèques externes dans lib: | ||
40 | // ckeditor5, ckfinder, htmlawed et HtmlFormatter | ||
41 | // | 35 | // |
42 | // le dossier data et son contenu sont "normalement" autorisés en écriture pour deux raisons: | 36 | // le dossier data et son contenu sont "normalement" autorisés en écriture pour deux raisons: |
43 | // - placer le contenu pré-existant avec son client FTP | 37 | // - placer le contenu pré-existant avec son client FTP |
44 | // - autoriser PHP (sinon, c'est comme si on avait un site statique) | 38 | // - autoriser PHP (sinon, c'est comme si on avait un site statique) |
45 | // | 39 | // -> pour pouvoir installer le site en n'ayant qu'à modifier les droits du dossier data uniquement et éviter les situations pénibles ou l'utilisateur est bloqué sans rien comprendre, on pourra créer ou utiliser des sauvegardes au format ZIP depuis une page spéciale accessible avec le compte admin |
46 | // pour pouvoir installer le site en n'ayant qu'à modifier les droits du dossier data uniquement et éviter les situations pénibles ou l'utilisateur est bloqué sans rien comprendre, on pourra créer ou utiliser des sauvegardes au format ZIP depuis une page spéciale accessible avec le compte admin | ||
47 | 40 | ||
48 | // au premier démarrage du site | 41 | // au premier démarrage du site |
49 | require('controller/installation.php'); | 42 | require('controller/installation.php'); |
@@ -58,25 +51,25 @@ installation(); | |||
58 | // infos: https://fr.wikipedia.org/wiki/Cross-site_request_forgery | 51 | // infos: https://fr.wikipedia.org/wiki/Cross-site_request_forgery |
59 | session_start(); | 52 | session_start(); |
60 | 53 | ||
61 | // sécurité failles XSS | ||
62 | require('lib/htmlawed/htmLawed.php'); | ||
63 | |||
64 | // traitement des POST du ckeditor | 54 | // traitement des POST du ckeditor |
65 | // la fonction submitCKeditor n'affiche rien (controller/admin.php n'est pas utilisé) puis redirige sans GET | 55 | // la fonction submitCKeditor n'affiche rien (controller/admin.php n'est pas utilisé) puis redirige sans GET |
66 | if(isset($_SESSION['admin']) && $_SESSION['admin'] == 1 | 56 | if(isset($_SESSION['admin']) && $_SESSION['admin'] == 1 |
67 | && isset($_GET['action']) && $_GET['action'] == 'submit' | 57 | && isset($_GET['action']) && $_GET['action'] == 'submit' |
68 | && isset($_POST['contenu']) && $_POST['contenu'] != '') | 58 | && isset($_POST['contenu']) && $_POST['contenu'] != '') |
69 | { | 59 | { |
70 | require('controller/ckeditor.php'); | 60 | require('controller/ckeditor.php'); // traitement du POST |
61 | require('lib/htmlawed/htmLawed.php'); // failles XSS | ||
62 | require('model/Classes.php'); // modèle | ||
63 | |||
71 | // modification | 64 | // modification |
72 | if(isset($_SESSION['nomFichier'])) | 65 | if(isset($_SESSION['nomFichier'])) |
73 | { | 66 | { |
74 | submitCKeditor($_GET['page'], $_SESSION['nomFichier'], $_POST['contenu']); | 67 | submitCKeditor($_SESSION['nomFichier']); |
75 | } | 68 | } |
76 | // nouvel article | 69 | // nouvel article |
77 | else | 70 | else |
78 | { | 71 | { |
79 | submitCKeditor($_GET['page'], '', $_POST['contenu']); | 72 | submitCKeditor(''); |
80 | } | 73 | } |
81 | 74 | ||
82 | // nettoyage | 75 | // nettoyage |
@@ -87,12 +80,12 @@ if(isset($_SESSION['admin']) && $_SESSION['admin'] == 1 | |||
87 | } | 80 | } |
88 | 81 | ||
89 | // déconnexion: nettoyer et recharger la page | 82 | // déconnexion: nettoyer et recharger la page |
90 | if(isset($_GET['action'])) | 83 | if(isset($_GET['action']) && isset($_GET['page'])) |
91 | { | 84 | { |
92 | if($_GET['action'] == "deconnexion") | 85 | if($_GET['action'] == "deconnexion") |
93 | { | 86 | { |
94 | $_SESSION['admin'] = 0; | 87 | $_SESSION['admin'] = 0; |
95 | header('Location: index.php'); | 88 | header('Location: index.php?page=' . $_GET['page']); |
96 | } | 89 | } |
97 | } | 90 | } |
98 | 91 | ||
@@ -107,7 +100,7 @@ require('controller/visitor.php'); | |||
107 | // utile pour presque toutes les pages | 100 | // utile pour presque toutes les pages |
108 | if(isset($_GET['page']) && $_GET['page'] != 'menu') | 101 | if(isset($_GET['page']) && $_GET['page'] != 'menu') |
109 | { | 102 | { |
110 | require('model/melaine-read.php'); | 103 | require('model/Classes.php'); |
111 | } | 104 | } |
112 | 105 | ||
113 | // contrôleur des pages en mode admin | 106 | // contrôleur des pages en mode admin |
@@ -136,43 +129,72 @@ if(isset($_GET['page'])) | |||
136 | // page melaine | 129 | // page melaine |
137 | elseif($_GET['page'] == 'melaine') | 130 | elseif($_GET['page'] == 'melaine') |
138 | { | 131 | { |
139 | // ouverture de l'éditeur pour modification | 132 | // Si ouverture de l'éditeur pour modification: |
140 | // le lien utilisé pour ouvrir l'éditeur contient un GET avec le numéro de l'article, mais pas le nom du fichier que le visiteur ne doit pas voir | 133 | // le lien utilisé pour ouvrir l'éditeur contient un GET avec le numéro de l'article, mais pas le nom du fichier que le visiteur ne doit pas voir |
141 | // GET, POST, cookies => navigation (utiles au visiteur) | 134 | // GET, POST, cookies => navigation (utiles au visiteur) |
142 | // sessions => action | 135 | // sessions => action |
143 | // c'est ici qu'on passe des GET aux sessions | 136 | // c'est ici qu'on passe des GET aux sessions |
144 | // on associe maintenant le numéro de l'article et le nom du fichier, l'article déjà existant inséré dans l'éditeur DOIT être celui qui sera modifié | 137 | // on associe maintenant le numéro de l'article et le nom du fichier, l'article déjà existant inséré dans l'éditeur DOIT être celui qui sera modifié |
145 | // | 138 | |
146 | if($_SESSION['admin'] == 1 && isset($_GET['action']) && $_GET['action'] == 'editor') | 139 | if($_SESSION['admin'] == 1 && isset($_GET['action']) && $_GET['action'] == 'editor') |
147 | { | 140 | { |
148 | // modification | 141 | // modification |
149 | // A MODIFIER! on a aussi besoin du nom du fichier, | ||
150 | // infos à mettre dans la session! | ||
151 | |||
152 | if(isset($_GET['article']) && is_numeric($_GET['article']) && $_GET['article'] > 0) | 142 | if(isset($_GET['article']) && is_numeric($_GET['article']) && $_GET['article'] > 0) |
153 | { | 143 | { |
154 | // obtenir le nom du fichier à l'aide du modèle | 144 | melaineEdit($_GET['article'], 0); |
155 | $_SESSION['nomFichier'] = getFileName($_GET['page'], $_GET['article']); | ||
156 | |||
157 | melaineEdit($_GET['article']); | ||
158 | } | 145 | } |
159 | // nouvel article | 146 | // nouvel article |
160 | else | 147 | else |
161 | { | 148 | { |
162 | // prévenir une hypothétique perte de donnée | 149 | // par sécurité |
163 | if(isset($_SESSION['nomFichier'])) | 150 | if(isset($_SESSION['nomFichier'])) |
164 | { | 151 | { |
165 | unset($_SESSION['nomFichier']); | 152 | unset($_SESSION['nomFichier']); |
166 | } | 153 | } |
167 | 154 | melaineEdit(0, 0); | |
168 | melaineEdit(0); | ||
169 | } | 155 | } |
170 | } | 156 | } |
157 | // suppression | ||
158 | else if($_SESSION['admin'] == 1 && isset($_GET['action']) && $_GET['action'] == 'suppression') | ||
159 | { | ||
160 | melaineEdit($_GET['article'], 1); | ||
161 | } | ||
171 | else | 162 | else |
172 | { | 163 | { |
173 | melaineVisitor(); | 164 | melaineVisitor(); |
174 | } | 165 | } |
175 | } | 166 | } |
167 | // page discographie | ||
168 | elseif($_GET['page'] == 'discographie') | ||
169 | { | ||
170 | if($_SESSION['admin'] == 1 && isset($_GET['action']) && $_GET['action'] == 'edition') | ||
171 | { | ||
172 | // modification | ||
173 | if(isset($_GET['album']) && is_numeric($_GET['album']) && $_GET['album'] > 0) | ||
174 | { | ||
175 | discoEdit($_GET['album'], 0); | ||
176 | } | ||
177 | // nouvel article | ||
178 | else | ||
179 | { | ||
180 | // par sécurité | ||
181 | if(isset($_SESSION['nomFichier'])) | ||
182 | { | ||
183 | unset($_SESSION['nomFichier']); | ||
184 | } | ||
185 | discoEdit(0, 0); | ||
186 | } | ||
187 | } | ||
188 | // suppression | ||
189 | else if($_SESSION['admin'] == 1 && isset($_GET['action']) && $_GET['action'] == 'suppression') | ||
190 | { | ||
191 | discoEdit($_GET['album'], 1); | ||
192 | } | ||
193 | else | ||
194 | { | ||
195 | discoVisitor(); | ||
196 | } | ||
197 | } | ||
176 | // page connexion au mode admin | 198 | // page connexion au mode admin |
177 | elseif($_GET['page'] == 'connexion') | 199 | elseif($_GET['page'] == 'connexion') |
178 | { | 200 | { |
diff --git a/model/Article.php b/model/Article.php deleted file mode 100644 index aee4f5d..0000000 --- a/model/Article.php +++ /dev/null | |||
@@ -1,92 +0,0 @@ | |||
1 | <?php | ||
2 | // model/Article.php | ||
3 | |||
4 | class Article | ||
5 | { | ||
6 | private $page = ''; // page et donc dossier concerné | ||
7 | private $croissant = True; // ordre des éléments du tableau $files | ||
8 | private $files; // noms des fichiers d'un dossier | ||
9 | private $oneFile; // correspond à $_SESSION['nomFichier'] | ||
10 | private $nbArticles; // un fichier = un article | ||
11 | private $articles; // contenu des fichiers | ||
12 | |||
13 | private function getFiles() | ||
14 | { | ||
15 | if($this->page == '') | ||
16 | { | ||
17 | die("debug: la méthode setPage() doit être appelée avant toute autre."); | ||
18 | } | ||
19 | |||
20 | $this->files = glob('data/' . $this->page . '/html/*.html'); | ||
21 | |||
22 | if($croissant == False) | ||
23 | { | ||
24 | $files = array_reverse($files); | ||
25 | } | ||
26 | |||
27 | $this->nbArticles = count($this->files); | ||
28 | } | ||
29 | |||
30 | // fonctions CRUD (create - read - update - delete) | ||
31 | // ce sont les 4 opérations de base qu'un programme doit permettre pour être complet | ||
32 | |||
33 | // create | ||
34 | public function create($content) | ||
35 | { | ||
36 | if($this->page == '') | ||
37 | { | ||
38 | die("debug: la méthode setPage() doit être appelée avant toute autre."); | ||
39 | } | ||
40 | |||
41 | $nom_fichier = time() . '.html'; | ||
42 | $fichier = fopen('data/' . $this->page . '/html/' . $nom_fichier, 'w'); // w peut créer un fichier, si il existe déjà , il est effacé par le nouveau contenu | ||
43 | fputs($fichier, $content); | ||
44 | fclose($fichier); | ||
45 | chmod('data/' . $this->page . '/html/' . $nom_fichier, 0666); | ||
46 | } | ||
47 | |||
48 | // read | ||
49 | public function getNumber() | ||
50 | { | ||
51 | return $this->nbArticles; | ||
52 | } | ||
53 | |||
54 | public function getOne() | ||
55 | {} | ||
56 | |||
57 | public function getAll($croissant) | ||
58 | { | ||
59 | $this->croissant = $croissant; // inversion de $files? | ||
60 | getFiles(); | ||
61 | |||
62 | $i = 0; | ||
63 | $articles = array(); | ||
64 | foreach ($this->files as $file) | ||
65 | { | ||
66 | $articles[$i] = file_get_contents($file); | ||
67 | $i++; | ||
68 | } | ||
69 | |||
70 | return $articles; | ||
71 | } | ||
72 | |||
73 | public function getDate($fileNumber) | ||
74 | { | ||
75 | // le 2è paramètre exclut le suffixe .html | ||
76 | $timestamp = basename($this->files[$fileNumber], '.html'); | ||
77 | return getdate($timestamp); | ||
78 | } | ||
79 | |||
80 | // update | ||
81 | public function update() | ||
82 | {} | ||
83 | |||
84 | public function setPage($page) | ||
85 | { | ||
86 | $this->page = $page; | ||
87 | } | ||
88 | |||
89 | // delete | ||
90 | public function delete() | ||
91 | {} | ||
92 | } | ||
diff --git a/model/Classes.php b/model/Classes.php new file mode 100644 index 0000000..d940e53 --- /dev/null +++ b/model/Classes.php | |||
@@ -0,0 +1,176 @@ | |||
1 | <?php | ||
2 | // model/ArticlesManager.php | ||
3 | |||
4 | class ArticlesManager | ||
5 | { | ||
6 | private $page = ''; // page et donc dossier concerné | ||
7 | //private $Ascending = True; // ordre des éléments du tableau $files | ||
8 | private $files; // noms des fichiers d'un dossier | ||
9 | private $fileName; // correspond à $_SESSION['nomFichier'] | ||
10 | private $nbArticles; // un fichier = un article | ||
11 | private $articles; // contenu des fichiers | ||
12 | |||
13 | // SET | ||
14 | public function setPage($page) | ||
15 | { | ||
16 | $this->page = $page; | ||
17 | } | ||
18 | |||
19 | //public function setAscending($croissant) | ||
20 | //{ | ||
21 | // $this->Ascending = $croissant; | ||
22 | //} | ||
23 | |||
24 | public function findFileName($numArticle) | ||
25 | { | ||
26 | $this->fileName = $this->files[$numArticle - 1]; | ||
27 | } | ||
28 | |||
29 | public function setFileName($nomFichier) | ||
30 | { | ||
31 | $this->fileName = $nomFichier; | ||
32 | } | ||
33 | |||
34 | // GET | ||
35 | public function getPage() | ||
36 | { | ||
37 | return($this->page); | ||
38 | } | ||
39 | |||
40 | public function getFileName() | ||
41 | { | ||
42 | return($this->fileName); | ||
43 | } | ||
44 | |||
45 | public function nbArticles() | ||
46 | { | ||
47 | return($this->nbArticles); | ||
48 | } | ||
49 | |||
50 | |||
51 | // tableau des noms des articles | ||
52 | public function getFiles() | ||
53 | { | ||
54 | if($this->page == '') | ||
55 | { | ||
56 | die("debug: la méthode setPage() doit être appelée avant toute autre."); | ||
57 | } | ||
58 | |||
59 | $this->files = glob('data/' . $this->page . '/html/*.html'); | ||
60 | |||
61 | //$this->nbArticles = count($this->files); | ||
62 | } | ||
63 | |||
64 | // ordre du tableau des noms de fichiers | ||
65 | public function reverseFilesArray() | ||
66 | { | ||
67 | $this->files = array_reverse($this->files); | ||
68 | } | ||
69 | |||
70 | |||
71 | // fonctions CRUD (create - read - update - delete) | ||
72 | // ce sont les 4 opérations de base qu'un programme doit permettre pour être complet | ||
73 | |||
74 | // create | ||
75 | public function create($content) | ||
76 | { | ||
77 | if($this->page == '') | ||
78 | { | ||
79 | die("debug: la méthode setPage() doit être appelée avant toute autre."); | ||
80 | } | ||
81 | |||
82 | // nommer les fichiers avec le timestamp | ||
83 | // - trie par ordre chronologique | ||
84 | // - rendre quasi impossible d'avoir deux fois le même nom (à la condition de gérer la "concurrence") | ||
85 | $nom_fichier = 'data/' . $this->page . '/html/' . time() . '.html'; | ||
86 | |||
87 | $fichier = fopen($nom_fichier, 'w'); // w peut créer un fichier, si il existe déjà , il est effacé par le nouveau contenu | ||
88 | fputs($fichier, $content); | ||
89 | fclose($fichier); | ||
90 | chmod($nom_fichier, 0666); | ||
91 | } | ||
92 | |||
93 | // read | ||
94 | public function getNumber() | ||
95 | { | ||
96 | return $this->nbArticles; | ||
97 | } | ||
98 | |||
99 | public function getOne() | ||
100 | { | ||
101 | return(file_get_contents($this->fileName)); | ||
102 | } | ||
103 | |||
104 | public function getAll() | ||
105 | { | ||
106 | //$this->getFiles(); | ||
107 | |||
108 | $i = 0; | ||
109 | $articles = array(); | ||
110 | foreach ($this->files as $file) | ||
111 | { | ||
112 | $articles[$i] = file_get_contents($file); | ||
113 | $i++; | ||
114 | } | ||
115 | |||
116 | //print_r($articles); | ||
117 | return $articles; | ||
118 | } | ||
119 | |||
120 | public function getDate($fileNumber) | ||
121 | { | ||
122 | // le 2è paramètre exclut le suffixe .html | ||
123 | $timestamp = basename($this->files[$fileNumber], '.html'); | ||
124 | return getdate($timestamp); | ||
125 | } | ||
126 | |||
127 | // update | ||
128 | public function update($content) | ||
129 | { | ||
130 | $file = fopen($this->fileName, 'w'); | ||
131 | // w peut créer un fichier, si il existe déjà , il est effacé par le nouveau contenu | ||
132 | fputs($file, $content); | ||
133 | fclose($file); | ||
134 | //chown($this->fileName, 'http'); | ||
135 | chmod($this->fileName, 0666); | ||
136 | } | ||
137 | |||
138 | // delete | ||
139 | public function delete() | ||
140 | { | ||
141 | unlink($this->fileName); | ||
142 | } | ||
143 | } | ||
144 | |||
145 | // note: les pros font de l'hydration | ||
146 | // le code du modèle est orienté objet et "refactorisé" d'une manière précise: | ||
147 | // on utilise un objet pour une chose (des articles, commentaires, etc), | ||
148 | // un objet article contiendrait ainsi tout le nécessaire pour lire, écrire ou modifier un article | ||
149 | // 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 | ||
150 | |||
151 | class AlbumsManager extends ArticlesManager | ||
152 | { | ||
153 | // variables | ||
154 | |||
155 | // SET | ||
156 | |||
157 | // GET | ||
158 | |||
159 | // fonctions CRUD | ||
160 | |||
161 | // create | ||
162 | public function create() | ||
163 | {} | ||
164 | |||
165 | // read | ||
166 | public function read() | ||
167 | {} | ||
168 | |||
169 | // update | ||
170 | public function update() | ||
171 | {} | ||
172 | |||
173 | // delete | ||
174 | public function delete() | ||
175 | {} | ||
176 | } \ No newline at end of file | ||
diff --git a/model/melaine-read.php b/model/melaine-read.php deleted file mode 100644 index 7105acd..0000000 --- a/model/melaine-read.php +++ /dev/null | |||
@@ -1,59 +0,0 @@ | |||
1 | <?php | ||
2 | // model/melaine-read.php | ||
3 | // | ||
4 | // accès en lecture seule | ||
5 | |||
6 | // obtenir le nom du fichier de l'article qu'on modifie | ||
7 | function getFileName($page, $numArticle) | ||
8 | { | ||
9 | $files = lireNomsFichiers($page); | ||
10 | $fileName = $files[$numArticle - 1]; | ||
11 | |||
12 | return($fileName); | ||
13 | } | ||
14 | |||
15 | function lireNomsFichiers($page) | ||
16 | { | ||
17 | // créer un tableau avec le nom des fichiers html | ||
18 | $files = glob('data/' . $page . '/html/*.html'); | ||
19 | |||
20 | return $files; | ||
21 | } | ||
22 | |||
23 | function lireUnArticle($nomFichier) | ||
24 | // ce nom est le chemin complet, donc la page y figure | ||
25 | { | ||
26 | return(file_get_contents($nomFichier)); | ||
27 | } | ||
28 | |||
29 | function lireArticles($page, $croissant) | ||
30 | { | ||
31 | // créer un tableau avec le nom des fichiers html | ||
32 | $files = lireNomsFichiers($page); | ||
33 | |||
34 | // inverse l'ordre du tableau retourné | ||
35 | if($croissant == False) | ||
36 | { | ||
37 | $files = array_reverse($files); | ||
38 | } | ||
39 | |||
40 | $i = 0; | ||
41 | $articles = array(); | ||
42 | foreach ($files as $oneFile) | ||
43 | { | ||
44 | $articles[$i] = file_get_contents($oneFile); | ||
45 | $i++; | ||
46 | } | ||
47 | // nombre de fichiers (= taille du tableau $files) | ||
48 | //$nombreDarticles = count($files); | ||
49 | |||
50 | //print_r($articles); | ||
51 | |||
52 | return($articles); | ||
53 | } | ||
54 | |||
55 | // note: les pros font de l'hydration | ||
56 | // le code du modèle est orienté objet et "refactorisé" d'une manière précise: | ||
57 | // on utilise un objet pour une chose (des articles, commentaires, etc), | ||
58 | // un objet article contiendrait ainsi tout le nécessaire pour lire, écrire ou modifier un article | ||
59 | // 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/melaine-write.php b/model/melaine-write.php deleted file mode 100644 index 462d59e..0000000 --- a/model/melaine-write.php +++ /dev/null | |||
@@ -1,32 +0,0 @@ | |||
1 | <?php | ||
2 | // model/melaine-write.php | ||
3 | // | ||
4 | // accès en écriture pour créer ou modifier des articles | ||
5 | |||
6 | |||
7 | |||
8 | function nouvelArticle($page, $contenuHTML) | ||
9 | { | ||
10 | // nommer les fichiers avec le timestamp | ||
11 | // pour les trier par ordre chronologique | ||
12 | // rendre impossible d'avoir deux fois le même nom (à la condition de gérer la "concurrence") | ||
13 | $nom_fichier = 'data/' . $_GET['page'] . '/html/' . time() . '.html'; | ||
14 | |||
15 | $fichier = fopen($nom_fichier, 'w'); // w peut créer un fichier, si il existe déjà , il est effacé par le nouveau contenu | ||
16 | fputs($fichier, $contenuHTML); | ||
17 | fclose($fichier); | ||
18 | chmod($nom_fichier, 0666); | ||
19 | } | ||
20 | |||
21 | function modifArticle($page, $nomFichier, $contenuHTML) | ||
22 | { | ||
23 | // manipulation du fichier | ||
24 | //$fichier = fopen('data/' . $page . '/html/' . $nom_fichier, 'w'); | ||
25 | $fichier = fopen($nomFichier, 'w'); | ||
26 | // w peut créer un fichier, si il existe déjà , il est effacé par le nouveau contenu | ||
27 | fputs($fichier, $contenuHTML); | ||
28 | fclose($fichier); | ||
29 | //chmod('data/' . $page . '/html/' . $nom_fichier, 0666); | ||
30 | chown($nomFichier, 'http'); | ||
31 | chmod($nomFichier, 0666); | ||
32 | } \ No newline at end of file | ||
diff --git a/public/discographie.css b/public/discographie.css new file mode 100644 index 0000000..326cfbb --- /dev/null +++ b/public/discographie.css | |||
@@ -0,0 +1,202 @@ | |||
1 | /* public/discographie.css */ | ||
2 | |||
3 | .police_titre | ||
4 | { | ||
5 | color: #c9a068; | ||
6 | } | ||
7 | |||
8 | #multicolonnes | ||
9 | { | ||
10 | /*display: flex;*/ | ||
11 | } | ||
12 | |||
13 | aside | ||
14 | { | ||
15 | display: flex; | ||
16 | flex-direction: column; | ||
17 | align-items: flex-end; | ||
18 | font-size: 80%; | ||
19 | font-family: 'Monospace'; | ||
20 | /*margin-right: 10px;*/ | ||
21 | /*position: absolute;*/ | ||
22 | } | ||
23 | |||
24 | aside div | ||
25 | { | ||
26 | position: absolute; | ||
27 | } | ||
28 | |||
29 | #bouton_chronologie | ||
30 | { | ||
31 | width: 200px; | ||
32 | text-align: center; | ||
33 | font-size: large; | ||
34 | font-weight: bold; | ||
35 | /*text-decoration: underline;*/ | ||
36 | /*border: 1px red solid;*/ | ||
37 | margin: 13px 0 0 0; | ||
38 | } | ||
39 | |||
40 | #chronologie | ||
41 | { | ||
42 | width: 200px; | ||
43 | font-weight: bold; | ||
44 | /*padding: 5px;*/ | ||
45 | display: none; | ||
46 | z-index: 1; /* placer le menu déroulant au dessus */ | ||
47 | background-color: #9fa8d0; | ||
48 | } | ||
49 | |||
50 | #chronologie p | ||
51 | { | ||
52 | margin: 8px; | ||
53 | } | ||
54 | |||
55 | /* PC uniquement, pour les smartphones prévoir un clic | ||
56 | => :checked et une checkbox | ||
57 | => ou la balise select qui crée un menu déroulant */ | ||
58 | aside:hover #chronologie | ||
59 | { | ||
60 | display: block; | ||
61 | } | ||
62 | |||
63 | section | ||
64 | { | ||
65 | /*border: 1px red solid;*/ | ||
66 | } | ||
67 | |||
68 | h3 | ||
69 | { | ||
70 | margin-top: 45px; | ||
71 | } | ||
72 | |||
73 | form p | ||
74 | { | ||
75 | margin: 0px; | ||
76 | } | ||
77 | |||
78 | input | ||
79 | { | ||
80 | margin: 2px 0; | ||
81 | } | ||
82 | |||
83 | .boutonAlbum | ||
84 | { | ||
85 | margin-top: 45px; | ||
86 | padding-bottom: 20px; | ||
87 | border-bottom: 1px black solid; | ||
88 | } | ||
89 | .boutonAlbum a | ||
90 | { | ||
91 | padding: 2px; | ||
92 | border: 4px black groove; | ||
93 | } | ||
94 | |||
95 | article | ||
96 | { | ||
97 | margin: 5px 0px; | ||
98 | } | ||
99 | |||
100 | figure | ||
101 | { | ||
102 | margin: 0px; | ||
103 | display: inline-block; | ||
104 | } | ||
105 | |||
106 | figcaption | ||
107 | { | ||
108 | margin: 2px; | ||
109 | color: #666; | ||
110 | font-size: small; | ||
111 | font-weight: bold; | ||
112 | text-align: center; | ||
113 | } | ||
114 | |||
115 | a | ||
116 | { | ||
117 | |||
118 | display: inline-block; | ||
119 | } | ||
120 | |||
121 | article a:hover | ||
122 | { | ||
123 | border: 2px blue solid; | ||
124 | } | ||
125 | |||
126 | |||
127 | a:hover figure figcaption | ||
128 | { | ||
129 | text-decoration: underline; | ||
130 | } | ||
131 | |||
132 | @media screen and (min-width: 700px) | ||
133 | { | ||
134 | #titre | ||
135 | { | ||
136 | width: 630px; | ||
137 | height: 171px; | ||
138 | background-image: url("mouette.png"); | ||
139 | } | ||
140 | |||
141 | #contenu | ||
142 | { | ||
143 | position: relative; | ||
144 | bottom: 35px; | ||
145 | } | ||
146 | } | ||
147 | |||
148 | @media screen and (max-width: 699px) | ||
149 | { | ||
150 | #titre | ||
151 | { | ||
152 | width: 480px; | ||
153 | height: 131px; | ||
154 | background-image: url("mouette_petit.png"); | ||
155 | margin: auto; | ||
156 | } | ||
157 | |||
158 | #contenu | ||
159 | { | ||
160 | position: relative; | ||
161 | bottom: 24px; | ||
162 | } | ||
163 | } | ||
164 | |||
165 | @media screen and (max-width: 479px) | ||
166 | { | ||
167 | #titre | ||
168 | { | ||
169 | width: 320px; | ||
170 | height: 88px; | ||
171 | background-image: url("mouette_mini.png"); | ||
172 | margin: auto; | ||
173 | } | ||
174 | |||
175 | #multicolonnes | ||
176 | { | ||
177 | flex-direction: column; | ||
178 | } | ||
179 | |||
180 | aside | ||
181 | { | ||
182 | width: 320px; | ||
183 | } | ||
184 | |||
185 | #chronologie | ||
186 | { | ||
187 | display: flex; | ||
188 | |||
189 | } | ||
190 | |||
191 | #chronologie p | ||
192 | { | ||
193 | max-width: 80px; | ||
194 | margin: 2px; | ||
195 | } | ||
196 | |||
197 | #contenu | ||
198 | { | ||
199 | position: relative; | ||
200 | bottom: 15px; | ||
201 | } | ||
202 | } | ||
diff --git a/public/main.js b/public/main.js index d4fb43a..1c04dec 100644 --- a/public/main.js +++ b/public/main.js | |||
@@ -1,6 +1,6 @@ | |||
1 | // public/main.js | 1 | // public/main.js |
2 | 2 | ||
3 | function accueil_vers_menu() | 3 | function versMenu() |
4 | { | 4 | { |
5 | // ergonomique | 5 | // ergonomique |
6 | window.setTimeout("location=('index.php?page=menu');", 10000); | 6 | window.setTimeout("location=('index.php?page=menu');", 10000); |
@@ -15,6 +15,19 @@ function deconnexionAutomatique() | |||
15 | //window.setTimeout("location=('index.php?action=deconnexion');", 600000); | 15 | //window.setTimeout("location=('index.php?action=deconnexion');", 600000); |
16 | } | 16 | } |
17 | 17 | ||
18 | // fonction appelée avec onClick dans un lien, | ||
19 | // si on sélectionne pas "oui", on ne doit pas suivre le lien | ||
20 | // si javascript est désactivé, le lien fonctionne | ||
21 | function confirmerSuppression(page) | ||
22 | { | ||
23 | // ne suivre le lien "href" que si on clique sur oui | ||
24 | var oui = confirm('Confirmer la suppression de cet article.'); | ||
25 | if(!oui) | ||
26 | { | ||
27 | event.preventDefault(); | ||
28 | } | ||
29 | } | ||
30 | |||
18 | // bouton "mailto", le visiteur ne quitte pas la page | 31 | // bouton "mailto", le visiteur ne quitte pas la page |
19 | function clientCourriel() | 32 | function clientCourriel() |
20 | { | 33 | { |
diff --git a/public/melaine.css b/public/melaine.css index 97872da..9736147 100644 --- a/public/melaine.css +++ b/public/melaine.css | |||
@@ -18,7 +18,7 @@ pre | |||
18 | 18 | ||
19 | figure | 19 | figure |
20 | { | 20 | { |
21 | margin: 5px; | 21 | /*margin: 5px;*/ |
22 | } | 22 | } |
23 | .boutonArticle | 23 | .boutonArticle |
24 | { | 24 | { |
@@ -106,56 +106,3 @@ figure | |||
106 | max-width: 320px; | 106 | max-width: 320px; |
107 | } | 107 | } |
108 | } | 108 | } |
109 | |||
110 | |||
111 | /* CONTENU */ | ||
112 | |||
113 | /*.article1_elem1 | ||
114 | { | ||
115 | color: #2e5487; | ||
116 | font-size: 150%; | ||
117 | } | ||
118 | |||
119 | .article1_elem2 | ||
120 | { | ||
121 | color: #006ffd; | ||
122 | font-size: 90%; | ||
123 | font-weight: bold; | ||
124 | } | ||
125 | |||
126 | .article7_elem1 | ||
127 | { | ||
128 | color: #141aff; | ||
129 | } | ||
130 | |||
131 | .article8_elem1 | ||
132 | { | ||
133 | color: #141aff; | ||
134 | } | ||
135 | |||
136 | .article9_elem1 | ||
137 | { | ||
138 | color: #2a5971; | ||
139 | } | ||
140 | |||
141 | .article10_elem1 | ||
142 | { | ||
143 | color: #ad8b15; | ||
144 | } | ||
145 | |||
146 | .article10_elem2 | ||
147 | { | ||
148 | color: #ad240a; | ||
149 | } | ||
150 | |||
151 | .article11_elem1 | ||
152 | { | ||
153 | color: #ad8b15; | ||
154 | } | ||
155 | |||
156 | .article12_elem1 | ||
157 | { | ||
158 | color: #2878aa; | ||
159 | font-size: 125%; | ||
160 | font-weight: normal; | ||
161 | }*/ \ No newline at end of file | ||
diff --git a/view/accueil.php b/view/accueil.php index 3d852d7..a7b6b71 100644 --- a/view/accueil.php +++ b/view/accueil.php | |||
@@ -5,7 +5,7 @@ | |||
5 | ob_start(); | 5 | ob_start(); |
6 | ?> | 6 | ?> |
7 | <script type="text/javascript" src="public/main.js" ></script> | 7 | <script type="text/javascript" src="public/main.js" ></script> |
8 | <script type="text/javascript" >accueil_vers_menu();</script> | 8 | <script type="text/javascript" >versMenu();</script> |
9 | <?php | 9 | <?php |
10 | $js = ob_get_clean(); | 10 | $js = ob_get_clean(); |
11 | 11 | ||
diff --git a/view/discographie.php b/view/discographie.php new file mode 100644 index 0000000..45960d2 --- /dev/null +++ b/view/discographie.php | |||
@@ -0,0 +1,87 @@ | |||
1 | <?php | ||
2 | // view/discographie.php | ||
3 | |||
4 | // variable $css | ||
5 | ob_start(); | ||
6 | ?> | ||
7 | <link rel="stylesheet" type="text/css" href="public/<?= $page_actuelle ?>.css" /> | ||
8 | <link rel="stylesheet" type="text/css" href="public/donnees_hors_editeur.css" /> | ||
9 | <?php | ||
10 | $css = ob_get_clean(); | ||
11 | |||
12 | |||
13 | //variable $js | ||
14 | ob_start(); | ||
15 | ?> | ||
16 | <script type="text/javascript" src="public/main.js" ></script> | ||
17 | <?php | ||
18 | if(isset($_GET['action']) && $_GET['action'] == 'edition') | ||
19 | { | ||
20 | |||
21 | // bibliothèques JS ckeditor | ||
22 | ?> | ||
23 | <script src="lib/ckeditor5/build/ckeditor.js"></script> | ||
24 | <?php | ||
25 | } | ||
26 | $js = ob_get_clean(); | ||
27 | |||
28 | |||
29 | // variable $header | ||
30 | ob_start(); | ||
31 | echo "\n"; | ||
32 | ?> | ||
33 | <header> | ||
34 | <div id="titre" > | ||
35 | <span class="police_titre" >Discographie</span> | ||
36 | </div> | ||
37 | <div id="photo" ></div> | ||
38 | </header> | ||
39 | <?php | ||
40 | $header = ob_get_clean(); | ||
41 | |||
42 | |||
43 | // variable $content | ||
44 | ob_start(); | ||
45 | ?> | ||
46 | <!-- <div id="multicolonnes" > --> | ||
47 | <aside> | ||
48 | <div> | ||
49 | <p id="bouton_chronologie" >Chronologie</p> | ||
50 | <div id="chronologie" > | ||
51 | <!-- ajouter à chaque entrée une ancre et un lien soit vers l'ancre soit vers la page dédiée --> | ||
52 | <p><a href="emoi_des_mots.php" >Emoi des mots, MF chante Max Jacob (2012)</a></p> | ||
53 | <p>Kan Tri (2011)</p> | ||
54 | <p>Tri Men (2007)</p> | ||
55 | <p><a href="kan_tri_2003.php" >Kan Tri (2003)</a></p> | ||
56 | <p><a href="hey_ho.php" >Hey ! Ho ! (2005)</a></p> | ||
57 | </div> | ||
58 | </div> | ||
59 | </aside> | ||
60 | <section> | ||
61 | <?php | ||
62 | if($_SESSION['admin'] == 1) | ||
63 | { | ||
64 | if(isset($_GET['action']) && $_GET['action'] == 'edition' && !isset($_GET['album'])) | ||
65 | { | ||
66 | ?> | ||
67 | <h3>Ajouter un album</h3> | ||
68 | <?= $editeurHTML ?> | ||
69 | <?php | ||
70 | } | ||
71 | else | ||
72 | { | ||
73 | ?> | ||
74 | <p class="boutonAlbum" > | ||
75 | <a href="index.php?page=discographie&action=edition" > | ||
76 | Nouvel album | ||
77 | </a> | ||
78 | </p> | ||
79 | <!-- <article></article> --> | ||
80 | <?php | ||
81 | } | ||
82 | } | ||
83 | ?> | ||
84 | </section> | ||
85 | <!-- </div> --> | ||
86 | <?php | ||
87 | $content = ob_get_clean(); | ||
diff --git a/view/melaine.php b/view/melaine.php index debd4e3..4b3b818 100644 --- a/view/melaine.php +++ b/view/melaine.php | |||
@@ -1,6 +1,6 @@ | |||
1 | <?php | 1 | <?php |
2 | // view/melaine.php | 2 | // view/melaine.php |
3 | // | 3 | |
4 | // variable $css | 4 | // variable $css |
5 | ob_start(); | 5 | ob_start(); |
6 | ?> | 6 | ?> |
@@ -18,7 +18,7 @@ ob_start(); | |||
18 | if(isset($_GET['action']) && $_GET['action'] == 'editor') | 18 | if(isset($_GET['action']) && $_GET['action'] == 'editor') |
19 | { | 19 | { |
20 | 20 | ||
21 | // bibliothèques JS ckeditor et ckfinder | 21 | // bibliothèques JS ckeditor |
22 | ?> | 22 | ?> |
23 | <script src="lib/ckeditor5/build/ckeditor.js"></script> | 23 | <script src="lib/ckeditor5/build/ckeditor.js"></script> |
24 | <?php | 24 | <?php |
@@ -44,7 +44,7 @@ $header = ob_get_clean(); | |||
44 | ob_start(); | 44 | ob_start(); |
45 | if($_SESSION['admin'] == 1) | 45 | if($_SESSION['admin'] == 1) |
46 | { | 46 | { |
47 | // éditeur | 47 | // à la place du bouton après rechargement |
48 | if(isset($_GET['action']) && $_GET['action'] == 'editor' && !isset($_GET['article'])) | 48 | if(isset($_GET['action']) && $_GET['action'] == 'editor' && !isset($_GET['article'])) |
49 | { | 49 | { |
50 | echo("<p>Rédiger un nouvel article</p>"); | 50 | echo("<p>Rédiger un nouvel article</p>"); |
@@ -101,6 +101,13 @@ foreach ($articles as $article) | |||
101 | <a href="index.php?page=melaine&action=editor&article=<?= $j ?>#article<?= $j ?>" > | 101 | <a href="index.php?page=melaine&action=editor&article=<?= $j ?>#article<?= $j ?>" > |
102 | Modifier cet article | 102 | Modifier cet article |
103 | </a> | 103 | </a> |
104 | <!-- un espace --> | ||
105 | <!-- <button> | ||
106 | Supprimer cet article | ||
107 | </button> --> | ||
108 | <a href="index.php?page=melaine&action=suppression&article=<?= $j ?>" onclick="confirmerSuppression('<?= $page_actuelle ?>')" > | ||
109 | Supprimer cet article | ||
110 | </a> | ||
104 | </p> | 111 | </p> |
105 | <?php | 112 | <?php |
106 | } | 113 | } |
diff --git a/view/template-ckeditor.php b/view/template-ckeditor.php index 12e1430..8e87f1d 100644 --- a/view/template-ckeditor.php +++ b/view/template-ckeditor.php | |||
@@ -16,22 +16,20 @@ | |||
16 | // le javascript place les données dans le formulaire caché | 16 | // le javascript place les données dans le formulaire caché |
17 | // avec la fonction envoiDonnees(), les données se retrouvent dans une <input> et sont donc envoyées avec par la POST (haha) | 17 | // avec la fonction envoiDonnees(), les données se retrouvent dans une <input> et sont donc envoyées avec par la POST (haha) |
18 | 18 | ||
19 | // l'envoi d'image en revanche utilise nécessairement de l'AJAX et | ||
20 | // la bibliothèque "ckfinder" (en JS + PHP) me permet de ne pas coder moi-même un "upload adapter", ce sera l'objet d'une autre amélioration, et en plus certaines fonctionnalités sont payantes | ||
21 | // https://ckeditor.com/docs/ckeditor5/latest/framework/guides/deep-dive/upload-adapter.html | ||
22 | // le ckfinder communique avec le serveur au moyen de requêtes AJAX, | ||
23 | // le fichier est ainsi téléchargé sur le serveur avant même d'apparaître dans l'éditeur | ||
24 | // attention, le ckfinder nécessite php7.3, les extensions GD et FileInfo et le support du type MIME JSON sur le serveur (retenir php7.3 et GD) | ||
25 | // https://ckeditor.com/ckfinder/download/ | ||
26 | |||
27 | // variable $editeurHTML | 19 | // variable $editeurHTML |
28 | ob_start(); | 20 | ob_start(); |
29 | ?> | 21 | ?> |
30 | 22 | ||
31 | <div class="conteneur_article" > | 23 | <div class="conteneur_article" > |
32 | <form action="index.php?page=<?= $page_actuelle ?>&article=<?= $numArticle ?>&action=submit" method="post" > | 24 | <form action="index.php?page=<?= $page_actuelle ?>&article=<?= $numArticle ?>&action=submit" method="post" > |
25 | <?php | ||
26 | if($page_actuelle == 'discographie') | ||
27 | { | ||
28 | echo($additionalInputs . "<p><i>Infos qui seront affichées dans la page dédiée:</i></p>"); | ||
29 | } | ||
30 | ?> | ||
31 | |||
33 | <textarea id="editor" name="contenu" ></textarea> | 32 | <textarea id="editor" name="contenu" ></textarea> |
34 | |||
35 | <?php | 33 | <?php |
36 | // falsification de requête inter-site | 34 | // falsification de requête inter-site |
37 | // on ajoute un formulaire caché avec une valeur aléatoire cryptée utilisable une seule fois (=jeton) | 35 | // on ajoute un formulaire caché avec une valeur aléatoire cryptée utilisable une seule fois (=jeton) |
diff --git a/view/template.php b/view/template.php index 772b0b1..b7ea0fb 100644 --- a/view/template.php +++ b/view/template.php | |||
@@ -66,12 +66,14 @@ if($_SESSION['admin'] == 0) | |||
66 | if($_SESSION['admin'] == 1) | 66 | if($_SESSION['admin'] == 1) |
67 | { | 67 | { |
68 | ?> | 68 | ?> |
69 | <!-- zone superposée par les commande du mode admin --> | 69 | <!-- zone superposée par les commandes du mode admin --> |
70 | <div class="zoneVideAdmin" ></div> | 70 | <div class="zoneVideAdmin" ></div> |
71 | 71 | ||
72 | <div id="modeAdmin" > | 72 | <div id="modeAdmin" > |
73 | <p>Vous êtes en mode administrateur. | 73 | <p>Vous êtes en mode administrateur. |
74 | <a href="index.php?action=deconnexion" >Déconnexion</a></p> | 74 | <a href="" >Options</a> |
75 | <a href="index.php?page=<?= $page_actuelle ?>&action=deconnexion" >Déconnexion</a> | ||
76 | </p> | ||
75 | <div> | 77 | <div> |
76 | <p><a href="index.php?from=<?= $page_actuelle ?>&action=nouveau_mdp" > | 78 | <p><a href="index.php?from=<?= $page_actuelle ?>&action=nouveau_mdp" > |
77 | Changer le mot de passe de connexion.</a></p> | 79 | Changer le mot de passe de connexion.</a></p> |