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