diff options
| -rw-r--r-- | public/index.php | 131 |
1 files changed, 121 insertions, 10 deletions
diff --git a/public/index.php b/public/index.php index d32dfff..d8d26e2 100644 --- a/public/index.php +++ b/public/index.php | |||
| @@ -57,6 +57,36 @@ function sanitizeFileName(string $filename): string { | |||
| 57 | return trim($filename, '_'); | 57 | return trim($filename, '_'); |
| 58 | } | 58 | } |
| 59 | 59 | ||
| 60 | function checkFileDownload(array $file): bool | ||
| 61 | { | ||
| 62 | $extensions_white_list = ['pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'odt', 'ods', 'odp']; | ||
| 63 | $mime_type_white_list = ['application/pdf', 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/vnd.ms-powerpoint', 'application/vnd.openxmlformats-officedocument.presentationml.presentation', 'application/vnd.oasis.opendocument.text', 'application/vnd.oasis.opendocument.spreadsheet', 'application/vnd.oasis.opendocument.presentation']; | ||
| 64 | |||
| 65 | // 1/ extension | ||
| 66 | $extension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION)); | ||
| 67 | if(!in_array($extension, $extensions_white_list, true)){ | ||
| 68 | return false; | ||
| 69 | } | ||
| 70 | |||
| 71 | // 2/ fichier obtenu par HTTP POST (théoriquement inutile si le routeur est solide, mais ça ne mange pas de pain) | ||
| 72 | if(!is_uploaded_file($file['tmp_name'])){ | ||
| 73 | return false; | ||
| 74 | } | ||
| 75 | |||
| 76 | $finfo = finfo_open(FILEINFO_MIME_TYPE); | ||
| 77 | |||
| 78 | // 3/ objet $finfo valide (dépend du paramètre FILEINFO_MIME_TYPE) | ||
| 79 | if($finfo === false){ | ||
| 80 | return false; | ||
| 81 | } | ||
| 82 | |||
| 83 | $real_type = finfo_file($finfo, $file['tmp_name']); | ||
| 84 | finfo_close($finfo); | ||
| 85 | |||
| 86 | // 4/ contrôle du "vrai" type mime (finfo_file lit les 1ers octets des fichiers pour y trouver des "signatures", très fiable sauf avec les conteneurs: doc, zip...) | ||
| 87 | return in_array($real_type, $mime_type_white_list, true); | ||
| 88 | } | ||
| 89 | |||
| 60 | if(isset($_GET['action']) && $_GET['action'] == 'editor_submit'){ | 90 | if(isset($_GET['action']) && $_GET['action'] == 'editor_submit'){ |
| 61 | // récupération des données | 91 | // récupération des données |
| 62 | $data = file_get_contents('php://input'); | 92 | $data = file_get_contents('php://input'); |
| @@ -95,12 +125,12 @@ elseif(isset($_GET['action']) && $_GET['action'] == 'delete_article'){ | |||
| 95 | die; | 125 | die; |
| 96 | } | 126 | } |
| 97 | elseif(isset($_GET['action']) && $_GET['action'] == 'upload_image'){ | 127 | elseif(isset($_GET['action']) && $_GET['action'] == 'upload_image'){ |
| 98 | if (isset($_FILES['file'])) { | 128 | if(isset($_FILES['file'])){ |
| 99 | $file = $_FILES['file']; | 129 | $file = $_FILES['file']; |
| 100 | $dest = 'images/'; | 130 | $dest = 'images/'; |
| 101 | 131 | ||
| 102 | if(!is_dir($dest)) { // Vérifier si le répertoire existe, sinon le créer | 132 | if(!is_dir($dest)){ |
| 103 | mkdir($dest, 0777, true); | 133 | mkdir($dest, 0755, true); |
| 104 | } | 134 | } |
| 105 | 135 | ||
| 106 | $allowed_extensions = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'tiff', 'tif']; | 136 | $allowed_extensions = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'tiff', 'tif']; |
| @@ -111,8 +141,13 @@ elseif(isset($_GET['action']) && $_GET['action'] == 'upload_image'){ | |||
| 111 | } | 141 | } |
| 112 | $file_path = $dest . $name . '_' . uniqid() . '.' . $extension; | 142 | $file_path = $dest . $name . '_' . uniqid() . '.' . $extension; |
| 113 | 143 | ||
| 144 | if(!is_uploaded_file($file['tmp_name'])) { | ||
| 145 | http_response_code(500); | ||
| 146 | echo json_encode(['message' => "Le fichier n'a pas été téléchargé correctement."]); | ||
| 147 | } | ||
| 148 | |||
| 114 | if(imagickCleanImage(file_get_contents($file['tmp_name']), $file_path, $extension)){ // recréer l’image pour la nettoyer | 149 | if(imagickCleanImage(file_get_contents($file['tmp_name']), $file_path, $extension)){ // recréer l’image pour la nettoyer |
| 115 | echo json_encode(['location' => $file_path]); // renvoyer l'URL de l'image téléchargée | 150 | echo json_encode(['location' => $file_path]); |
| 116 | } | 151 | } |
| 117 | else{ | 152 | else{ |
| 118 | http_response_code(500); | 153 | http_response_code(500); |
| @@ -132,8 +167,8 @@ elseif(isset($_GET['action']) && $_GET['action'] == 'upload_image_url'){ | |||
| 132 | $image_data = curlDownloadImage($json['image_url']); // téléchargement de l’image par le serveur avec cURL au lieu de file_get_contents | 167 | $image_data = curlDownloadImage($json['image_url']); // téléchargement de l’image par le serveur avec cURL au lieu de file_get_contents |
| 133 | $dest = 'images/'; | 168 | $dest = 'images/'; |
| 134 | 169 | ||
| 135 | if(!is_dir($dest)) { // Vérifier si le répertoire existe, sinon le créer | 170 | if(!is_dir($dest)){ |
| 136 | mkdir($dest, 0777, true); | 171 | mkdir($dest, 0755, true); |
| 137 | } | 172 | } |
| 138 | 173 | ||
| 139 | if($image_data === false){ | 174 | if($image_data === false){ |
| @@ -152,7 +187,7 @@ elseif(isset($_GET['action']) && $_GET['action'] == 'upload_image_url'){ | |||
| 152 | $local_path = $dest . $name . '_' . uniqid() . '.' . $extension; | 187 | $local_path = $dest . $name . '_' . uniqid() . '.' . $extension; |
| 153 | 188 | ||
| 154 | if(imagickCleanImage($image_data, $local_path, $extension)){ // recréer l’image pour la nettoyer | 189 | if(imagickCleanImage($image_data, $local_path, $extension)){ // recréer l’image pour la nettoyer |
| 155 | echo json_encode(['location' => $local_path]); // nouvelle adresse | 190 | echo json_encode(['location' => $local_path]); |
| 156 | } | 191 | } |
| 157 | else{ | 192 | else{ |
| 158 | http_response_code(500); | 193 | http_response_code(500); |
| @@ -168,8 +203,8 @@ elseif(isset($_GET['action']) && $_GET['action'] == 'upload_image_base64'){ | |||
| 168 | $json = json_decode(file_get_contents('php://input'), true); | 203 | $json = json_decode(file_get_contents('php://input'), true); |
| 169 | $dest = 'images/'; | 204 | $dest = 'images/'; |
| 170 | 205 | ||
| 171 | if(!is_dir('images')){ | 206 | if(!is_dir($dest)){ |
| 172 | mkdir('images', 0777, true); | 207 | mkdir($dest, 0755, true); |
| 173 | } | 208 | } |
| 174 | 209 | ||
| 175 | // détection de data:image/ et de ;base64, et capture du format dans $type | 210 | // détection de data:image/ et de ;base64, et capture du format dans $type |
| @@ -203,6 +238,39 @@ elseif(isset($_GET['action']) && $_GET['action'] == 'upload_image_base64'){ | |||
| 203 | } | 238 | } |
| 204 | die; | 239 | die; |
| 205 | } | 240 | } |
| 241 | elseif(isset($_GET['action']) && $_GET['action'] == 'upload_file'){ | ||
| 242 | if(isset($_FILES['file'])){ | ||
| 243 | $file = $_FILES['file']; | ||
| 244 | $dest = 'media/'; | ||
| 245 | |||
| 246 | if(!is_dir($dest)){ // Vérifier si le répertoire existe, sinon le créer | ||
| 247 | mkdir($dest, 0755, true); | ||
| 248 | } | ||
| 249 | |||
| 250 | $name = sanitizeFileName(pathinfo($file['name'], PATHINFO_FILENAME)); // retirer caractères spéciaux et changer espaces en underscores | ||
| 251 | $extension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION)); | ||
| 252 | $file_path = $dest . $name . '_' . uniqid() . '.' . $extension; // nom unique | ||
| 253 | |||
| 254 | if(checkFileDownload($file)){ | ||
| 255 | if(move_uploaded_file($file['tmp_name'], $file_path)){ | ||
| 256 | echo json_encode(['location' => $file_path]); | ||
| 257 | } | ||
| 258 | else{ | ||
| 259 | http_response_code(500); | ||
| 260 | echo json_encode(['message' => 'Erreur enregistrement du fichier.']); | ||
| 261 | } | ||
| 262 | } | ||
| 263 | else{ | ||
| 264 | http_response_code(400); | ||
| 265 | echo json_encode(['message' => 'Erreur 400: fichier non valide.']); | ||
| 266 | } | ||
| 267 | } | ||
| 268 | else{ | ||
| 269 | http_response_code(400); | ||
| 270 | echo json_encode(['message' => 'Erreur 400: Bad Request']); | ||
| 271 | } | ||
| 272 | die; | ||
| 273 | } | ||
| 206 | ?> | 274 | ?> |
| 207 | <!DOCTYPE html> | 275 | <!DOCTYPE html> |
| 208 | <html lang="fr"> | 276 | <html lang="fr"> |
| @@ -356,6 +424,20 @@ elseif(isset($_GET['action']) && $_GET['action'] == 'upload_image_base64'){ | |||
| 356 | }, | 424 | }, |
| 357 | // upload d'image natif de tinymce avec le bouton "Insérer une image" | 425 | // upload d'image natif de tinymce avec le bouton "Insérer une image" |
| 358 | images_upload_handler: images_upload_handler, // = fonction fléchée | 426 | images_upload_handler: images_upload_handler, // = fonction fléchée |
| 427 | // upload de documents (bouton "insérer un lien") | ||
| 428 | files_upload_handler: files_upload_handler, // = fonction fléchée | ||
| 429 | documents_file_types: [ // files_upload_handler a besoin qu'on lui donne tous les types mime | ||
| 430 | { mimeType: 'application/pdf', extensions: [ 'pdf' ] }, | ||
| 431 | { mimeType: 'application/msword', extensions: [ 'doc' ] }, | ||
| 432 | { mimeType: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', extensions: [ 'docx' ] }, | ||
| 433 | { mimeType: 'application/vnd.ms-excel', extensions: [ 'xls' ] }, | ||
| 434 | { mimeType: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', extensions: [ 'xlsx' ] }, | ||
| 435 | { mimeType: 'application/vnd.ms-powerpoint', extensions: [ 'ppt' ] }, | ||
| 436 | { mimeType: 'application/vnd.openxmlformats-officedocument.presentationml.presentation', extensions: [ 'pptx' ] }, | ||
| 437 | { mimeType: 'application/vnd.oasis.opendocument.text', extensions: [ 'odt' ] }, | ||
| 438 | { mimeType: 'application/vnd.oasis.opendocument.spreadsheet', extensions: [ 'ods' ] }, | ||
| 439 | { mimeType: 'application/vnd.oasis.opendocument.presentation', extensions: [ 'odp' ] } | ||
| 440 | ], | ||
| 359 | image_caption: true | 441 | image_caption: true |
| 360 | }); | 442 | }); |
| 361 | 443 | ||
| @@ -374,7 +456,7 @@ elseif(isset($_GET['action']) && $_GET['action'] == 'upload_image_base64'){ | |||
| 374 | .then(response => response.json()) | 456 | .then(response => response.json()) |
| 375 | .then(data => { | 457 | .then(data => { |
| 376 | if(data.location) { | 458 | if(data.location) { |
| 377 | resolve(data.location); | 459 | resolve({url: data.location}); |
| 378 | } | 460 | } |
| 379 | else { | 461 | else { |
| 380 | reject("Erreur: Chemin d'image invalide"); | 462 | reject("Erreur: Chemin d'image invalide"); |
| @@ -385,6 +467,35 @@ elseif(isset($_GET['action']) && $_GET['action'] == 'upload_image_base64'){ | |||
| 385 | }); | 467 | }); |
| 386 | }); | 468 | }); |
| 387 | 469 | ||
| 470 | const files_upload_handler = (blobInfo, progress) => new Promise((resolve, reject) => { | ||
| 471 | const formData = new FormData(); | ||
| 472 | formData.append("file", blobInfo.blob()); | ||
| 473 | |||
| 474 | fetch('index.php?action=upload_file', { | ||
| 475 | method: 'POST', | ||
| 476 | body: formData | ||
| 477 | }) | ||
| 478 | .then(response => response.json()) | ||
| 479 | .then(data => { | ||
| 480 | if(data.location) { | ||
| 481 | console.log(blobInfo.filename()); | ||
| 482 | console.log(data.location); | ||
| 483 | |||
| 484 | // resolve et reject fonctionne avec Promise => type de retour standardisé et évite l'utilistion de callbacks | ||
| 485 | resolve({ | ||
| 486 | url: data.location, | ||
| 487 | fileName: blobInfo.filename(), | ||
| 488 | }); | ||
| 489 | } | ||
| 490 | else { | ||
| 491 | reject("Erreur: Chemin du fichier invalide"); | ||
| 492 | } | ||
| 493 | }) | ||
| 494 | .catch(error => { | ||
| 495 | reject("Erreur lors de l'upload"); | ||
| 496 | }); | ||
| 497 | }); | ||
| 498 | |||
| 388 | function deleteArticle(articleId) { | 499 | function deleteArticle(articleId) { |
| 389 | if (confirm('Voulez-vous vraiment supprimer cet article ?')) { | 500 | if (confirm('Voulez-vous vraiment supprimer cet article ?')) { |
| 390 | // Envoyer une requête au serveur pour supprimer l'article | 501 | // Envoyer une requête au serveur pour supprimer l'article |
