web-dev-qa-db-fra.com

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 les dessins sur toile en images PNG. Ce que j'ai maintenant besoin, c’est de convertir les chaînes base64 générées par cet outil en fichiers PNG réels sur le serveur, à l’aide de PHP.

En bref, je suis en train de générer un fichier côté client à l'aide de Canvas2Image, puis de récupérer les données codées en base64 et de les envoyer au serveur à l'aide d'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, "hidden.php" reçoit un bloc de données ressemblant àdata: image/png; base64, iVBORw0KggoAAAANSUhEUgAABE ...

À partir de ce moment, je suis assez perplexe. D'après ce que j'ai lu, je suis supposé utiliser la fonction imagecreatefromstring de PHP, mais je ne sais pas comment créer une image PNG réelle à partir de la chaîne encodée en base64 et la stocker sur mon serveur. . S'il vous plaît aider!

182
Andrei Oniga

Vous devez extraire les données d'image base64 de cette chaîne, les décoder et les sauvegarder sur disque, vous n'avez pas besoin de Gd car il s'agit déjà d'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 une ligne:

$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 la suivante:

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);
360
drew010

Essaye ça:

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

docs_put_contents_fichiers

111
Some Guy

J'ai dû remplacer les espaces par les 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 cela pourra aider.

35
Ben

Cela vaut la peine de dire que le sujet discuté est documenté dans RFC 2397 - Le schéma d'URL "data" ( https://tools.ietf.org/html/rfc2397 )

A cause de cela PHP a un moyen natif de gérer de telles données - "data: stream wrapper" ( http://php.net/manual/en/wrappers.data.php )

Ainsi, vous pouvez facilement manipuler vos données avec PHP streams:

$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);
11

Suivant l’idée de @ dre010, je l’ai étendue à 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épare 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
PolloZen

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
Anextro

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

3
Nick Tsai

Une 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]));
3
Piotr

essaye ça...

$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
Paline

Ce code fonctionne pour moi vérifier le code ci-dessous:

<?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);
?>
2
gauravbhai daxini

sur la base de l'exemple drew010, j'ai créé un exemple pratique pour faciliter la compréhension.

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; 
}
2
sanjeet bisht

Cette fonction devrait fonctionner. cela a le paramètre photo qui contient la chaîne base64 et le chemin d'accès à un répertoire d'image existant si vous avez déjà une image existante que vous souhaitez dissocier pendant la sauvegarde de 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
        }
    }
}
0
Saviour Dela

C'est simple :

Imaginons que vous essayiez de télécharger un fichier dans le framework js, une requête ajax ou une application mobile (côté client)

  1. Tout d'abord, vous envoyez un attribut de données contenant une chaîne Codée en base64.
  2. Du côté du serveur, vous devez le décoder et l'enregistrer dans un dossier de projet Local.

Voici comment faire en utilisant PHP

<?php 

$base64String = "kfezyufgzefhzefjizjfzfzefzefhuze"; // I put a static base64 string, you can implement you special code to retrieve the data received via the request.

$filePath = "/MyProject/public/uploads/img/test.png";

file_put_contents($filePath, base64_decode($base64String));

?>
0
MUSTAPHA GHLISSI