aboutsummaryrefslogtreecommitdiff
path: root/src/controller/ImageUploadController.php
diff options
context:
space:
mode:
Diffstat (limited to 'src/controller/ImageUploadController.php')
-rw-r--r--src/controller/ImageUploadController.php191
1 files changed, 0 insertions, 191 deletions
diff --git a/src/controller/ImageUploadController.php b/src/controller/ImageUploadController.php
deleted file mode 100644
index af9a553..0000000
--- a/src/controller/ImageUploadController.php
+++ /dev/null
@@ -1,191 +0,0 @@
1<?php
2// src/controller/ImageUploadController.php
3
4declare(strict_types=1);
5
6use Symfony\Component\HttpFoundation\JsonResponse;
7
8class ImageUploadController
9{
10 const ALLOWED_EXTENSIONS = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'tiff', 'tif'];
11
12 static public function imagickCleanAndWriteImage(string $image_data, string $local_path): bool // "string" parce que file_get_contents...
13 {
14 $format = strtolower(pathinfo($local_path)['extension']);
15 try{
16 $imagick = new Imagick();
17 $imagick->readImageBlob($image_data);
18 $imagick->stripImage(); // nettoyage métadonnées
19 //$imagick->setImageFormat($format); // inutile, writeImage force la conversion
20
21 // compression
22 switch($format){
23 case 'jpeg': // particularité du switch, si 'jpeg' le test de 'jpg' est ignoré et on va jusqu'au break
24 case 'jpg':
25 $imagick->setImageCompression(Imagick::COMPRESSION_JPEG);
26 $imagick->setImageCompressionQuality(85);
27 break;
28 case 'webp':
29 $imagick->setImageCompression(Imagick::COMPRESSION_WEBP);
30 $imagick->setImageCompressionQuality(85);
31 break;
32 case 'png':
33 $imagick->setImageCompression(Imagick::COMPRESSION_ZIP);
34 $imagick->setImageCompressionQuality(7); // 9 est sans perte
35 break;
36 case 'tiff':
37 $imagick->setImageCompression(Imagick::COMPRESSION_LZW); // LZW est sans perte
38 break;
39 }
40
41 // enregistrement
42 // writeImage utilise l'extension du fichier et ignore le format détecté
43 // imagemagick est à l'origine une appli console, elle considère que l'extension montre l'intention de l'utilisateur
44 $imagick->writeImage($local_path); // enregistrement
45 $imagick->clear();
46 $imagick->destroy();
47 return true;
48 }
49 catch(Exception $e){
50 return false;
51 }
52 }
53 static public function curlDownloadImage(string $url, int $maxRetries = 3, int $timeout = 10): string|false
54 {
55 $attempt = 0;
56 $imageData = false;
57
58 while($attempt < $maxRetries){
59 $ch = curl_init($url); // instance de CurlHandle
60 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
61 curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
62 curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
63 curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
64 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
65 curl_setopt($ch, CURLOPT_USERAGENT, 'TinyMCE-Image-Downloader');
66
67 $imageData = curl_exec($ch);
68 $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
69 //$curlError = curl_error($ch);
70
71 if($imageData !== false && $httpCode >= 200 && $httpCode < 300){
72 return $imageData;
73 }
74
75 $attempt++;
76 sleep(1);
77 }
78
79 return false; // échec après trois tentatives
80 }
81
82 // téléchargement par le plugin (bouton "insérer une image")
83 static public function imageUploadTinyMce(): JsonResponse
84 {
85 if(!isset($_FILES['file'])){
86 return new JsonResponse(['message' => 'Erreur 400: Bad Request'], JsonResponse::HTTP_BAD_REQUEST); // code 400
87 }
88 if(!is_uploaded_file($_FILES['file']['tmp_name'])) {
89 return new JsonResponse(['message' => "Le fichier n'a pas été téléchargé correctement."], JsonResponse::HTTP_BAD_REQUEST); // code 400
90 }
91
92 $dest = 'user_data/images/';
93 $dest_mini = 'user_data/images-mini/';
94
95 // Vérifier si les répertoires existent, sinon les créer
96 if(!is_dir($dest)){
97 mkdir($dest, 0755, true);
98 }
99 if(!is_dir($dest_mini)){
100 mkdir($dest_mini, 0755, true);
101 }
102
103 $name = Security::secureFileName(pathinfo($_FILES['file']['name'], PATHINFO_FILENAME));
104 $extension = strtolower(pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION));
105 $image_data = file_get_contents($_FILES['file']['tmp_name']);
106 if(!in_array($extension, self::ALLOWED_EXTENSIONS)){
107 $extension = 'jpeg';
108 }
109 $local_path = uniqid($dest . $name . '_') . '.' . $extension;
110
111 // créer une miniature de l'image
112 //
113
114 if(self::imagickCleanAndWriteImage($image_data, $local_path)){ // recréer l’image pour la nettoyer
115 return new JsonResponse(['location' => $local_path]); // renvoyer l'URL de l'image téléchargée
116 }
117 else{
118 return new JsonResponse(['message' => 'Erreur image non valide'], JsonResponse::HTTP_INTERNAL_SERVER_ERROR); // code 500
119 }
120 }
121
122 // collage de HTML => recherche de balises <img>, téléchargement côté serveur et renvoi de l'adresse sur le serveur
123 static public function uploadImageHtml(): JsonResponse
124 {
125 $json = json_decode(file_get_contents('php://input'), true);
126
127 if(!isset($json['image_url'])){
128 return new JsonResponse(['message' => "Erreur 400: Bad Request"], JsonResponse::HTTP_BAD_REQUEST); // code 400
129 }
130
131 $image_data = self::curlDownloadImage($json['image_url']); // téléchargement de l’image par le serveur avec cURL au lieu de file_get_contents
132 if(!$image_data){
133 return new JsonResponse(['message' => "Erreur, le serveur n'a pas réussi à télécharger l'image."], JsonResponse::HTTP_BAD_REQUEST); // code 400
134 }
135
136 $dest = 'user_data/images/';
137 if(!is_dir($dest)){ // Vérifier si le répertoire existe, sinon le créer
138 mkdir($dest, 0755, true);
139 }
140
141 $url_path = parse_url($json['image_url'], PHP_URL_PATH);
142 $name = Security::secureFileName(pathinfo($url_path, PATHINFO_FILENAME));
143 $extension = strtolower(pathinfo($url_path, PATHINFO_EXTENSION));
144 if(!in_array($extension, self::ALLOWED_EXTENSIONS) || $extension === 'jpg'){
145 $extension = 'jpeg';
146 }
147 $local_path = uniqid($dest . $name . '_') . '.' . $extension;
148
149 if(self::imagickCleanAndWriteImage($image_data, $local_path)){ // recréer l’image pour la nettoyer
150 return new JsonResponse(['location' => $local_path]); // nouvelle adresse
151 }
152 else{
153 return new JsonResponse(['message' => 'Erreur image non valide', 'format' => $extension], JsonResponse::HTTP_INTERNAL_SERVER_ERROR); // code 500
154 }
155 }
156
157 // collage simple d'une image (base64 dans le presse-papier) non encapsulée dans du HTML
158 static public function uploadImageBase64(): JsonResponse
159 {
160 $json = json_decode(file_get_contents('php://input'), true);
161 $dest = 'user_data/images/';
162
163 if(!is_dir($dest)){
164 mkdir($dest, 0755, true);
165 }
166
167 // détection de data:image/ et de ;base64, et capture du format dans $type
168 if(!isset($json['image_base64']) || !preg_match('/^data:image\/(\w+);base64,/', $json['image_base64'], $type)){
169 return new JsonResponse(['message' => 'Données image base64 manquantes ou invalides'], JsonResponse::HTTP_BAD_REQUEST); // code 400
170 }
171
172 $extension = strtolower($type[1]); // dans (\w+)
173 if(!in_array($extension, self::ALLOWED_EXTENSIONS)){
174 $extension = 'jpeg';
175 }
176
177 $name = 'pasted_image';
178 $image_data = base64_decode(substr($json['image_base64'], strpos($json['image_base64'], ',') + 1)); // découpe la chaine à la virgule puis convertit en binaire
179 if($image_data === false){
180 return new JsonResponse(['message' => 'Décodage base64 invalide'], JsonResponse::HTTP_BAD_REQUEST); // code 400
181 }
182 $local_path = uniqid($dest . $name . '_') . '.' . $extension;
183
184 if(self::imagickCleanAndWriteImage($image_data, $local_path)){
185 return new JsonResponse(['location' => $local_path]);
186 }
187 else{
188 return new JsonResponse(['message' => 'Erreur image non valide', 'format' => $extension], JsonResponse::HTTP_INTERNAL_SERVER_ERROR); // code 500
189 }
190 }
191} \ No newline at end of file