Comment enregistrer une image PNG côté serveur, à partir d'une chaîne de données base64
J'utilise L'outil JavaScript "Canvas2Image" de Nihilogic pour convertir des dessins de toile en images PNG. Ce dont j'ai besoin maintenant est de transformer ces chaînes base64 que cet outil génère, en fichiers PNG réels sur le serveur, en utilisant PHP.
En bref, ce que je fais actuellement est de générer un fichier côté client en utilisant Canvas2Image, puis de récupérer les données codées en base64 et de les envoyer au serveur en utilisant AJAX:
// Generate the image file
var image = Canvas2Image.saveAsPNG(canvas, true);
image.id = "canvasimage";
canvas.parentNode.replaceChild(image, canvas);
var url = 'hidden.php',
data = $('#canvasimage').attr('src');
$.ajax({
type: "POST",
url: url,
dataType: 'text',
data: {
base64data : data
}
});
À ce stade, "caché.php" reçoit un bloc de données qui ressemble à Données: image / png; base64, iVBORw0KGgoAAAANSUhEUgAABE...
À partir de Maintenant, je suis assez perplexe. D'après ce que j'ai lu, je crois que je suis censé utiliser la fonction imagecreatefromstring de PHP, mais je ne sais pas comment créer une image PNG réelle à partir de la chaîne codée en base64 et la stocker sur mon serveur. Merci de l'aide!
12 réponses
Vous devez extraire les données d'image base64 de cette chaîne, les décoder et ensuite les enregistrer sur le disque, vous n'avez pas besoin de GD car c'est déjà un png.
$data = 'data:image/png;base64,AAAFBfj42Pj4';
list($type, $data) = explode(';', $data);
list(, $data) = explode(',', $data);
$data = base64_decode($data);
file_put_contents('/tmp/image.png', $data);
Et comme un one-liner:
$data = base64_decode(preg_replace('#^data:image/\w+;base64,#i', '', $data));
Une méthode efficace pour extraire, Décoder et vérifier les erreurs est:
if (preg_match('/^data:image\/(\w+);base64,/', $data, $type)) {
$data = substr($data, strpos($data, ',') + 1);
$type = strtolower($type[1]); // jpg, png, gif
if (!in_array($type, [ 'jpg', 'jpeg', 'gif', 'png' ])) {
throw new \Exception('invalid image type');
}
$data = base64_decode($data);
if ($data === false) {
throw new \Exception('base64_decode failed');
}
} else {
throw new \Exception('did not match data URI with image data');
}
file_put_contents("img.{$type}", $data);
J'ai dû remplacer les espaces par des symboles plus str_replace(' ', '+', $img);
pour que cela fonctionne.
Voici le code complet
$img = $_POST['img']; // Your data 'data:image/png;base64,AAAFBfj42Pj4';
$img = str_replace('data:image/png;base64,', '', $img);
$img = str_replace(' ', '+', $img);
$data = base64_decode($img);
file_put_contents('/tmp/image.png', $data);
J'espère que ça aide.
Il vaut la peine de dire que le sujet discuté est documenté dans la RFC 2397 - le schéma D'URL" data " ( https://tools.ietf.org/html/rfc2397 )
Pour cette raison, PHP a un moyen natif de gérer de telles données - "data: stream wrapper" ( http://php.net/manual/en/wrappers.data.php )
Vous pouvez donc facilement manipuler vos données avec des flux PHP:
$data = 'data:image/gif;base64,R0lGODlhEAAOALMAAOazToeHh0tLS/7LZv/0jvb29t/f3//Ub//ge8WSLf/rhf/3kdbW1mxsbP//mf///yH5BAAAAAAALAAAAAAQAA4AAARe8L1Ekyky67QZ1hLnjM5UUde0ECwLJoExKcppV0aCcGCmTIHEIUEqjgaORCMxIC6e0CcguWw6aFjsVMkkIr7g77ZKPJjPZqIyd7sJAgVGoEGv2xsBxqNgYPj/gAwXEQA7';
$source = fopen($data, 'r');
$destination = fopen('image.gif', 'w');
stream_copy_to_stream($source, $destination);
fclose($source);
fclose($destination);
Pris l'idée @dre010, Je l'ai étendu à une autre fonction qui fonctionne avec n'importe quel type d'image: PNG, JPG, JPEG ou GIF et donne un nom unique au nom de fichier
La fonction séparer les données d'image et le type d'image
function base64ToImage($imageData){
$data = 'data:image/png;base64,AAAFBfj42Pj4';
list($type, $imageData) = explode(';', $imageData);
list(,$extension) = explode('/',$type);
list(,$imageData) = explode(',', $imageData);
$fileName = uniqid().'.'.$extension;
$imageData = base64_decode($imageData);
file_put_contents($fileName, $imageData);
}
Eh bien, votre solution ci-dessus dépend de l'image étant un fichier jpeg. Pour une solution générale, j'ai utilisé
$img = $_POST['image'];
$img = substr(explode(";",$img)[1], 7);
file_put_contents('img.png', base64_decode($img));
Essayez ceci...
$file = $_POST['file']; //your data in base64 'data:image/png....';
$img = str_replace('data:image/png;base64,', '', $file);
file_put_contents('img/imag.png', base64_decode($img));
Solution linéaire.
$base64string = 'data:image/png;base64,R0lGODlhEAAOALMAAOazToeHh0tLS/7LZv/0jvb29t/f3//Ub//ge8WSLf/rhf/3kdbW1mxsbP//mf///yH5BAAAAAAALAAAAAAQAA4AAARe8L1Ekyky67QZ1hLnjM5UUde0ECwLJoExKcppV0aCcGCmTIHEIUEqjgaORCMxIC6e0CcguWw6aFjsVMkkIr7g77ZKPJjPZqIyd7sJAgVGoEGv2xsBxqNgYPj/gAwXEQA7';
file_put_contents('img.png', base64_decode(explode(',',$base64string)[1]));
Total des préoccupations:
$data = 'data:image/png;base64,AAAFBfj42Pj4';
// Extract base64 file for standard data
$fileBin = file_get_contents($data);
$mimeType = mime_content_type($data);
// Check allowed mime type
if ('image/png'==$mimeType) {
file_put_contents('name.png', $fileBin);
}
Ce code fonctionne pour moi vérifier ci-dessous code:
<?php
define('UPLOAD_DIR', 'images/');
$image_parts = explode(";base64,", $_POST['image']);
$image_type_aux = explode("image/", $image_parts[0]);
$image_type = $image_type_aux[1];
$image_base64 = base64_decode($image_parts[1]);
$file = UPLOAD_DIR . uniqid() . '.png';
file_put_contents($file, $image_base64);
?>
Basé sur l'exemple drew010, j'ai fait un exemple de travail pour une compréhension facile.
imagesaver("data:image/jpeg;base64,/9j/4AAQSkZJ"); //use full base64 data
function imagesaver($image_data){
list($type, $data) = explode(';', $image_data); // exploding data for later checking and validating
if (preg_match('/^data:image\/(\w+);base64,/', $image_data, $type)) {
$data = substr($data, strpos($data, ',') + 1);
$type = strtolower($type[1]); // jpg, png, gif
if (!in_array($type, [ 'jpg', 'jpeg', 'gif', 'png' ])) {
throw new \Exception('invalid image type');
}
$data = base64_decode($data);
if ($data === false) {
throw new \Exception('base64_decode failed');
}
} else {
throw new \Exception('did not match data URI with image data');
}
$fullname = time().$type;
if(file_put_contents($fullname, $data)){
$result = $fullname;
}else{
$result = "error";
}
/* it will return image name if image is saved successfully
or it will return error on failing to save image. */
return $result;
}
Cette fonction devrait fonctionner. cela a le paramètre photo qui contient la chaîne base64 et aussi le chemin d'accès à un répertoire d'image existant si vous avez déjà une image existante que vous souhaitez dissocier pendant que vous enregistrez la nouvelle.
public function convertBase64ToImage($photo = null, $path = null) {
if (!empty($photo)) {
$photo = str_replace('data:image/png;base64,', '', $photo);
$photo = str_replace(' ', '+', $photo);
$photo = str_replace('data:image/jpeg;base64,', '', $photo);
$photo = str_replace('data:image/gif;base64,', '', $photo);
$entry = base64_decode($photo);
$image = imagecreatefromstring($entry);
$fileName = time() . ".jpeg";
$directory = "uploads/customer/" . $fileName;
header('Content-type:image/jpeg');
if (!empty($path)) {
if (file_exists($path)) {
unlink($path);
}
}
$saveImage = imagejpeg($image, $directory);
imagedestroy($image);
if ($saveImage) {
return $fileName;
} else {
return false; // image not saved
}
}
}