base64データ文字列からサーバー側でPNG画像を保存する方法


212

Nihilogicの "Canvas2Image" JavaScriptツールを使用して、キャンバスの描画をPNG画像に変換しています。今必要なのは、このツールが生成するbase64文字列を、PHPを使用してサーバー上の実際のPNGファイルに変換することです。

手短に言えば、私が現在行っていることは、Canvas2Imageを使用してクライアント側でファイルを生成し、次にbase64でエンコードされたデータを取得して、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
    }
});

この時点で、「hidden.php」はdata:image / png; base64、iVBORw0KGgoAAAANSUhEUgAABE ...のようなデータブロックを受け取ります。

この時点から、私はかなり困惑しています。私が読んだことから、PHPのimagecreatefromstring関数を使用することになっていると思いますが、実際にbase64でエンコードされた文字列から実際のPNG画像を作成し、サーバーに保存する方法がわかりません。助けてください!


解析する必要があります。そこからイメージタイプを抽出し、base64_decodeを使用して、イメージタイプ別にファイルにその文字列を保存できます
Constantin

@Constantineもっと具体的に教えてください。
Andrei Oniga

7
$ data = $ _REQUEST ['base64data']; $ image = explode( 'base64、'、$ data); file_put_contents( 'img.png'、base64_decode($ image [1]));
コンスタンティン

スナップショットから、データを送信するまで、完全なコードを投稿できますが、私にとっては機能しません。
Ofir Attia 2013

回答:


437

その文字列からbase64画像データを抽出してデコードし、ディスクに保存する必要があります。GDはすでにPNGであるため、GDは必要ありません。

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

そしてワンライナーとして:

$data = base64_decode(preg_replace('#^data:image/\w+;base64,#i', '', $data));

エラーを抽出、デコード、チェックするための効率的な方法は次のとおりです。

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

あなたの例では$ typeがあります。その値はどうあるべきですか?
ジョン

1
@ジョンが$type爆発からに応じて、値を割り当てられますかどうかのデータ:画像/ JPGまたはデータ:画像/ PNG等
drew010

このエラーが発生しました:不正な形式のutf-8文字が誤ってエンコードされている可能性があります
アルド2017

@aldoおそらくコードと詳細を含む新しい質問を投稿してください。そのメッセージだけに基づいて、コードを見たり、画像がどのようにエンコードされているか、スクリプトに送信されたりする方法を知らずに言うことはかなり不可能です。
drew010 2017

120

これを試して:

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

file_put_contents docs


4
私はこれを試しましたが、それdata:image/png;base64,はファイルを壊すものを含んでいます。
マイケルJ.カルキンス2013

2
@MichaelCalkinsも私のためにそれを壊します。drew010の答えは、一貫して機能する唯一のソリューションのようです。
デビッドジョンウェルシュ

24
を含めているdata:image/png;base64,場合、渡した文字列base64_decodeは有効なbase64ではありません。データを送信する必要があるだけです。これは、drew010の答えが示すとおりです。この答えに問題はありません。理解せずにコピーして貼り付けることはできず、「そのまま動作する」ことを期待できます。
Cypher

4
質問で提供されている、base64コンテンツではない例では機能せず、最初に断片に分割する必要があります(受け入れられた回答を参照)。
ベンジャミンピエット2015年

画像が正常に保存されました。しかし、画像のURLを書き込むと、空白の画像が表示されます。私はwindow.open(dataURL)を使用してテストしたので、私のdataURLは正しいと確信しています。なぜ空白の画像ですか?
partho

45

これを機能させるには、スペースをプラス記号に置き換える必要がありstr_replace(' ', '+', $img);ました。

ここに完全なコードがあります

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

お役に立てば幸いです。


1
あなたのライン$img = str_replace(' ', '+', $img);は私に大いに役立ちました、ありがとう!以前にスペースを「+」に変換する必要があるのはなぜですか?
2018

19

議論されたトピックはRFC 2397-「データ」URLスキーム(https://tools.ietf.org/html/rfc2397)に文書化されていると言う価値があります

このため、PHPにはそのようなデータを処理するネイティブの方法があります-"data:stream wrapper"(http://php.net/manual/en/wrappers.data.php

そのため、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);

2
私はこの答えが好きです、それはより多くの投票を持つべきです、それはネイティブ関数を使用しています、汚い自家製のデータ操作はありません!しかし、パフォーマンスについて何か考えはありますか?予想よりもpreg_replace+ より速いfile_put_contentsですか?
Bonswouar 2018年

1
@Bonswouarありがとう。あなたの質問について:私の意見では、アプリケーションにパフォーマンスの問題がないことを確認する最良の方法は、特定のケースでのパフォーマンスを測定することです(環境、予想されるファイルサイズ、許可されるファイルサイズなどに基づく)。ここでコードを試してみて、答えに数字を表示することもできますが、実際には、実際のケースでは、肯定的な結果よりも害をもたらす可能性があります。自分で確認することをお勧めします(特に、アプリのパフォーマンスが重要な部分について話している場合)。
Vladimir Posvistelik

11

上記の解決策は、画像がjpegファイルであることに依存しています。私が使用した一般的な解決策

$img = $_POST['image'];
$img = substr(explode(";",$img)[1], 7);
file_put_contents('img.png', base64_decode($img));

11

@ dre010のアイデアを取り入れて、PNG、JPG、JPEG、GIFのいずれかの画像タイプで機能し、ファイル名に一意の名前を付ける別の関数に拡張しました

関数は画像データと画像タイプを分離します

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


5

ワンリニアソリューション。

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

5

drew010の例に基づいて、わかりやすいように実際の例を作成しました。

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

4

これを試して...

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

4

このコードは私のために働き、以下のコードをチェックします:

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

0

この機能は動作するはずです。これには、base64文字列を保持するphotoパラメーターと、新しいイメージを保存するときにリンクを解除したい既存のイメージが既にある場合に、既存のイメージディレクトリへのパスがあります。

 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

それは簡単です :

jsフレームワーク、ajaxリクエスト、またはモバイルアプリケーション(クライアント側)内でファイルをアップロードしようとしているとしましょう。

  1. まず、base64でエンコードされた文字列を含むデータ属性を送信します。
  2. サーバー側では、それをデコードしてローカルプロジェクトフォルダーに保存する必要があります。

ここでは、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

画像の名前をランダムに変更し、データベースの画像パスをblobとして保存し、画像自体をフォルダーに保存する場合は、このソリューションが役立ちます。Webサイトのユーザーは、必要に応じて画像をいくつでも保存できますが、セキュリティの目的で画像の名前はランダムに変更されます。

PHPコード

イメージ名として使用するランダムなvarcharを生成します。

function genhash($strlen) {
        $h_len = $len;
        $cstrong = TRUE;
        $sslkey = openssl_random_pseudo_bytes($h_len, $cstrong);
        return bin2hex($sslkey);
}
$randName = genhash(3); 
#You can increase or decrease length of the image name (1, 2, 3 or more).

画像から画像データ拡張とbase_64部分(data:image / png; base64の後の部分)を取得します。

$pos  = strpos($base64_img, ';');
$imgExten = explode('/', substr($base64_img, 0, $pos))[1];
$extens = ['jpg', 'jpe', 'jpeg', 'jfif', 'png', 'bmp', 'dib', 'gif' ];

if(in_array($imgExten, $extens)) {

   $imgNewName = $randName. '.' . $imgExten;
   $filepath = "resources/images/govdoc/".$imgNewName;
   $fileP = fopen($filepath, 'wb');
   $imgCont = explode(',', $base64_img);
   fwrite($fileP, base64_decode($imgCont[1]));
   fclose($fileP);

}

# => $filepath <= This path will be stored as blob type in database.
# base64_decoded images will be written in folder too.

# Please don't forget to up vote if you like my solution. :)

0

PHPにはすでにbase64->ファイル変換の公平な扱いがあります

私はこの方法でそれを成し遂げるために使用します:

$blob=$_POST['blob']; // base64 coming from an url, for example
$blob=file_get_contents($blob);
$fh=fopen("myfile.png",'w'); // be aware, it'll overwrite!
fwrite($fh,$blob);
fclose($fh);
echo '<img src=myfile.png>'; // just for the check
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.