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!

166
demandé sur Andrei Oniga 2012-07-16 23:48:49

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);
335
répondu drew010 2017-12-01 03:27:17

Essayez ceci:

file_put_contents('img.png', base64_decode($base64string));

File_put_contents docs

106
répondu Some Guy 2012-07-16 19:52:33

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.

33
répondu Ben 2014-03-03 13:21:41

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);
9
répondu Vladimir Posvistelik 2016-05-18 11:36:25

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);
}
9
répondu PolloZen 2016-08-05 16:39:28

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));
8
répondu Anextro 2015-01-18 22:18:40

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));
2
répondu Paline 2014-09-23 07:18:14

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]));
2
répondu Piotr 2017-01-14 17:11:36

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);
}

Http://php.net/manual/en/wrappers.data.php

Http://php.net/manual/en/function.mime-content-type.php

2
répondu Nick Tsai 2018-08-29 16:08:46

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);
?>
1
répondu gaurav daxini 2018-01-17 10:56:14

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; 
}
0
répondu sanjeet bisht 2018-08-18 21:26:05

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
        }
    }
}
-1
répondu Saviour Dela 2018-06-18 03:51:46