I would like to post a base64 image file in a php script through Jquery AJAX..
I already Encoded it with Jquery's encodeURIComponent() function, then decode it with rawurldecode() function on php when the data is posted.
The problem is, the Php can't be able to save the proper image to png.
I have compared the posted base64 data and the original data, and they did not match. which led me to the conclusion that perhaps the base64 data is too large to post.
Is my conclusion true? and if it is, is there any other way I can be able to post the base64 data successfully?
If I was wrong, can you please enlighten me?
This is the Jquery Script
var whereSignatureis = $('.signatureView');
// i got the image from a plugin called jSignature, assign it to a variable data.
var data = signPaper.jSignature("getData","image");
// created an image ddata from what the data returned for displaying purposes.
var ddata = new Image();
// the ddata.src is now the png base64 image
ddata.src = "data:" + data[0] + "," + data[1];
// I encoded the image with uricomponent for safe posting.
var theImg = encodeURIComponent(ddata.src);
// and posted the image
$.ajax({
type: "POST",
url: "processes.php",
data: {img: theImg},
contentType: "application/x-www-form-urlencoded;charset=UTF-8",
success: function(r){
whereSignatureis.append(r);
}
});
This is the Php
define('UPLOAD_DIR', '/images');
$img = rawurldecode($post->img);
$img = str_replace('data:image/png;base64,', '', $img);
$img = str_replace(' ', '+', $img);
$data = base64_decode($img);
$file = UPLOAD_DIR . 'signature' . '.png';
$success = file_put_contents($file, $data);
print $success ? "{$post->img}" : 'File not Saved.';
Thanks in advance!
I found that trying to encode to the base64 text prior to sending just caused problems, since the JavaScript URI encoding functions replace all the spaces in the base64 string with plus signs, breaking the image. I would just remove the encodeURIComponent() function entirely and it should work.
Related
I am trying to upload image taken from webcam. I use canvas for showing that image and send base64_encoded json data by POST method to PHP and therefore in PHP decode the data and try to create an image by file_put_contents. But the uploaded image is corrupted every time. I used header("Access-Control-Allow-Origin: *") in PHP also. I also checked that the file_get_contents is enabled in the server. What may be the error? Please help.
My code is:
JS:
// Trigger photo take
var imagedata;
document.getElementById('snap').addEventListener('click', function() {
$('#canvas').show();
context.drawImage(video, 0, 0, 640, 480);
$('#upload-button').removeAttr("disabled");
var image = new Image();
image.src = canvas.toDataURL();
imagedata = image.src;
$('#webimage').val(imagedata);
});
PHP:
header("Access-Control-Allow-Origin: *");
$input_data = json_decode(trim(file_get_contents('php://input')), true);
$base = $input_data['image'];
$destination_directory = "uploads/";
$file_name = time();
$file_name = $file_name.'.png';
$targetPath = $destination_directory . $file_name;
$input_data = base64_decode($base);
file_put_contents($targetPath, $input_data);
Did you ever inspect the data url of an image? It looks like this:
image/gif;base64,R0lGODlhyAAiALM...DfD0QAADs=
As you can see the actual base64 encoded representation of the binary content of the image starts after the comma. All you have to do is change:
$base = $input_data['image'];
to:
// php >= 5.4
$base = explode(',', $input_data['image'])[1];
// php < 5.4
list (, $base) = explode(',', $input_data['image']);
so the base64_decode function receives proper base64 string.
You are also missing proper validation inside your script:
validate JSON input was decoded properly
validate image key exists in the resulting array
validate base64_decode did decode the string
validate resulting image is a valid image (malicious users can embed PHP code for instance inside the image)
This way you can be 99% sure your server won't get compromised in the future.
I am using quilljs for my editor. All my data are handle by mysql database. I am using Angularjs 1.x and for backend Cakephp is my frame-work.
I am currently trying to build a forum kind of page in which I want to save multiple images along with text which will be formatted using quilljs
<p>sd<img src="data:image/jpeg;base64,iVBORw0KGgoAAAANSUhEUgA....SUVORK5CYII=" alt="i am image"><b>it is image of earth</b></p>
This is what currently storing in my database. Now if there is multiple big images come in then size of field will be too much high there for I want to upload image inside severside folder and want to print image address inside image tag like:
<p>sd<img src="../img/709f2d0be9d13c645037f1b9bb066b00a6d7/image1.jpg" alt="i am image"><b>it is image of earth</b></p>
So I can fetch image directly from given folder.
i have done small trick with quilljs. i have put some code inside quilljs which send image toward my php script on line number 8663 after if (typeof value === 'string') this statement i have added script which sends image value to my php script
var img = {
'img' : value
}
$.ajax({
url: "../Writers/writerCertificateupload",
data: img,
contentType: undefined,
type: 'post'
}).success(function(path){
node.setAttribute('src', path);
})
where node.setAttribute('src', path); sets path which i am returning from php script it sets it on image tag i.e <img src="../img/709f2d0be9d13c645037f1b9bb066b00a6d7/image1.jpg">
and then it sets it inside editor and then we can save that data within editor. this is how i have solve this problem.
my php code is
public function writerCertificateupload()//pending
{
$id = $this->Auth->user('id');
$this->autoRender=false;
define('UPLOAD_DIR', 'files/post/');
$img = $_POST['img'];
$img = str_replace('data:image/jpeg;base64,', '', $img);
$img = str_replace(' ', '+', $img);
$data = base64_decode($img);
$file = UPLOAD_DIR . uniqid() . '.jpg';
$success = file_put_contents($file, $data);
$file = "../".$file;
print $success ? $file : 'Unable to save the file.';
}
You need to create custom image handler (like here) and check base64 string length with fileReader.
I had the same problem in Angular(primeNg) and ended up with the below solution, Btw plz notice that you only need to monitor the editor text change and do some modification like below:
public async handleTextChange(event: any) {
try {
const operations = event.delta.ops;
for (let i = 0; i < operations.length; i++) {
const op = operations[i];
const opType = Object.keys(op)[0] as any;
if (opType == 'insert' && op['insert'].hasOwnProperty('image')) {
this.isLoading = true;
const uploadedImageURL = await this.uploadImage(op['insert'].image);
this._cdr.detectChanges();
const newContent = event.htmlValue.replace(
op['insert'].image,
uploadedImageURL
);
this.editorContent = newContent;
this.contentChanged.emit(newContent);
}
}
} catch (error) {
this.editorContent = this.editorContent + '<br/><br/>';
} finally {
this.isLoading = false;
this._cdr.detectChanges();
}
The upload method will be like this, by the way the upload logic will be depends on your own logic though more or less it's the same:
async uploadImage(dataURL: string): Promise<string> {
const ImageData: FormData = new FormData();
let fileType = dataURL.substring(
dataURL.indexOf(':') + 1,
dataURL.lastIndexOf(';')
);
let fileExtension = fileType.split('/');
const file = new File(
[dataURL],
`file${new Date().getTime()}.${fileExtension[1]}`,
{ type: fileType }
);
ImageData.append('file', file);
const uploadedImageURL = await this._imageUploaderService
.uploadedImage(ImageData)
.toPromise();
return uploadedImageURL ;
}
The component html would be like this
<p-editor
name="editorContent"
[(ngModel)]="editorContent"
[id]="editorId"
[style]="{ height: '320px' }"
(onTextChange)="handleTextChange($event)"
></p-editor>
<app-spinner *ngIf="isLoading == true"></app-spinner>
It's worth mentioning that I used this for p-editor which belongs to primeNg in angular projects
I am working with an app where I am unable to post the File to the server. Therefor I have chose to send it as a string to the server, and remake it to a file using PHP. Below is the javascript code I am using to convert the image to a string.
var file = document.getElementById("fileForUpload").files[0];
if (file) {
var reader = new FileReader();
reader.readAsText(file);
reader.onload = function (evt) {
document.getElementById("fileContents").value = utf8_to_b64(evt.target.result);
}
reader.onerror = function (evt) {
document.getElementById("fileContents").value = "error reading file";
}
}
function utf8_to_b64(str) {
return window.btoa(unescape(encodeURIComponent(str)));
}
On the server side I'm doing this
header("Content-type: image/png");
$data = preg_replace('/\s+/', '', $data);
echo base64_decode($data);
exit;
But it says that the image cannot be displayed because it contains errors.
Can you please tell me what I am doing wrong here? I am correctly receiving the Base64 encoded string to the server.
Edit
Please note that I am trying to post the string through an HTML form.
Easy:
$imagedata = file_get_contents("/path/to/image.jpg");
// alternatively specify an URL, if PHP settings allow
$base64 = base64_encode($imagedata);
bear in mind that this will enlarge the data by 33%, and you'll have problems with files whose size exceed your memory_limit.
My problem is as follows...
I have a screen in which the user can select a PNG image from its computer, using this:
<input id='icon' type='file' accept='image/png' style='width:400px; height:20px' onchange='llenarThumbnail(this)'>
<img id='thumb' src='#'>
When the user selects the image, a thumbnail is shown automatically, using onclick='llenar Thumbnail(this)', like this:
function llenarThumbnail(input){
if (input.files && input.files[0]){
var reader = new FileReader();
reader.onload = function (e){
$('#thumb').attr('src', e.target.result).width(48).height(48);
};
reader.readAsDataURL(input.files[0]);
}
}
Then, when the user clicks on the proper button to upload the image (not a submit button), I do the following to encode the image into Base64:
function getBase64Image(img){
var canvas = document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);
var dataURL = canvas.toDataURL("image/png");
console.log(dataURL);
return dataURL.replace(/^data:image\/(png|jpg);base64,/, "");
}
Then, using AJAX I send this encoded image data to the server, and a PHP script does the following:
$binary=base64_decode($imagen_data);
header('Content-Type: bitmap; charset=utf-8');
$file = fopen($icono, 'wb');
fwrite($file, $binary);
fclose($file);
As I was printing diferent alerts along the process, I could see that the encoding was performing (i'm not so sure if correctly or not), and PHP receives the data and creates the PNG file, but when I open the image, the image is empty, there's no data... Thats why I'm asking if this to methods are compatible... I guess they are because they're both Base64... But if its not this, then what am i doing wrong???
Please, I'm tired of looking for this all over the internet! I need some answers! Thank you!
Without seeing your ajax POST, here's a Wild Guess:
Try leaving the prefix on until the URL gets to php.
Which php server are you using?
Some other usual gotchas:
Make sure you have properly set up your upload directory.
Make sure you have permissions set properly on the upload directory.
Client Side:
// create a dataUrl from the canvas
var dataURL= canvas.toDataURL();
// post the dataUrl to php
$.ajax({
type: "POST",
url: "upload.php",
data: {image: dataURL}
}).done(function( respond ) {
// you will get back the temp file name
// or "Unable to save this image."
console.log(respond);
});
Server File: upload.php
<?php
// make sure the image-data exists and is not empty
// php is particularly sensitive to empty image-data
if ( isset($_POST["image"]) && !empty($_POST["image"]) ) {
// get the dataURL
$dataURL = $_POST["image"];
// the dataURL has a prefix (mimetype+datatype)
// that we don't want, so strip that prefix off
$parts = explode(',', $dataURL);
$data = $parts[1];
// Decode base64 data, resulting in an image
$data = base64_decode($data);
// create a temporary unique file name
$file = UPLOAD_DIR . uniqid() . '.png';
// write the file to the upload directory
$success = file_put_contents($file, $data);
// return the temp file name (success)
// or return an error message just to frustrate the user (kidding!)
print $success ? $file : 'Unable to save this image.';
}
I could not get markE solution to work, had to change the data modification :
From :
$parts = explode(',', $dataURL);
$data = $parts[1];
$data=base64_decode($data)
To :
$img = str_replace('data:image/png;base64,', '', $dataURL);
$img = str_replace(' ', '+', $img);
$data=base64_decode($img);
Method from
I encoded a canvas-image to base64 which gives me this:
data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAICAgICAQICAgICAgIDAwYEAwMDAwcFBQQGCAcICAgHCAgJCg0LCQkMCggICw8LDA0ODg4OCQsQEQ8OEQ0ODg7/2wBDAQICAgMDAwYEBAYOCQgJDg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg7/wAARCAAKAAoDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD5a/Z7/Zw8EfF/9mT4h6Z4u0GTwt8WNP1iSya7vZp0uNKYJBsItyANjt5o2uGkDBsHhMfDsOn2zWcTQ39tJCUBR5HVGYY4JUEgH2BIHrXunw71vWdI/aa+POraTq+p6Xqr+H/Edy15aXTxTNMt4m2QupDbxubDZyMn1r4yRE8pflXoO1fleQYDEzzHGxnXbjeEop6qPNFtpXb00Wm3zP1vNM2pUMLh5RpK75k3fV8rVm7LzP/Z
which seems like a valid base64-image (decoded it with an online-decoder).
I send this with other (form-) variables with jquery ajax like this:
$.ajax({
type: "POST",
url: "index.php?action=saveNewPost",
data: {text: text, img: encodeURIComponent(base64img)},
contentType: "application/x-www-form-urlencoded;charset=UTF-8",
success: function(){
//...
}
});
on the server this goes to this line:
saveImage(utf8_decode($_POST['img']));
which calls:
function saveImage($base64img){
define('UPLOAD_DIR', '../uploads/');
$base64img = str_replace('data:image/jpeg;base64,', '', $base64img);
$data = base64_decode($base64img);
$file = UPLOAD_DIR . uniqid() . '.jpg';
file_put_contents($file, $data);
}
However, the file isn't saved. What could be wrong?
Lets try to create file test.php in same folder with single function and call, check output errors in browser or /var/log/httpd/error_log
<?php
function saveImage($base64img){
define('UPLOAD_DIR', '../uploads/');
$base64img = str_replace('data:image/jpeg;base64,', '', $base64img);
$data = base64_decode($base64img);
$file = UPLOAD_DIR . '123123123.jpg';
file_put_contents($file, $data);
}
saveImage('data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAICAgICAQICAgICAgIDAwYEAwMDAwcFBQQGCAcICAgHCAgJCg0LCQkMCggICw8LDA0ODg4OCQsQEQ8OEQ0ODg7/2wBDAQICAgMDAwYEBAYOCQgJDg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg7/wAARCAAKAAoDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD5a/Z7/Zw8EfF/9mT4h6Z4u0GTwt8WNP1iSya7vZp0uNKYJBsItyANjt5o2uGkDBsHhMfDsOn2zWcTQ39tJCUBR5HVGYY4JUEgH2BIHrXunw71vWdI/aa+POraTq+p6Xqr+H/Edy15aXTxTNMt4m2QupDbxubDZyMn1r4yRE8pflXoO1fleQYDEzzHGxnXbjeEop6qPNFtpXb00Wm3zP1vNM2pUMLh5RpK75k3fV8rVm7LzP/Z');
That mean that troubles in part AJAX => php script. Now, we try to compare what we recieve from ajax and original string, just change your function to this and look at test.txt:
function saveImage($base64img){
define('UPLOAD_DIR', '../uploads/');
$file = UPLOAD_DIR . 'test.txt';
file_put_contents($file, 'ORIG:'.'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAICAgICAQICAgICAgIDAwYEAwMDAwcFBQQGCAcICAgHCAgJCg0LCQkMCggICw8LDA0ODg4OCQsQEQ8OEQ0ODg7/2wBDAQICAgMDAwYEBAYOCQgJDg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg4ODg7/wAARCAAKAAoDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD5a/Z7/Zw8EfF/9mT4h6Z4u0GTwt8WNP1iSya7vZp0uNKYJBsItyANjt5o2uGkDBsHhMfDsOn2zWcTQ39tJCUBR5HVGYY4JUEgH2BIHrXunw71vWdI/aa+POraTq+p6Xqr+H/Edy15aXTxTNMt4m2QupDbxubDZyMn1r4yRE8pflXoO1fleQYDEzzHGxnXbjeEop6qPNFtpXb00Wm3zP1vNM2pUMLh5RpK75k3fV8rVm7LzP/Z'."\n".'AJAX:'.$base64img);
}
It works - seems when a file is included in php using
include('file.php');
the relative path is from the parent and not from the included file :(
That was the whole problem... Thanks to all
You write encodeURIComponent (JS) and then utf8_decode (PHP). Just use urldecode (PHP) and it will work fine! :)