Are canvas.toDataURL compatible with PHP's base64_decode? - php

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

Related

php://input Uplaod image with image type

I'm implementing a drag and drop image uploader with ajax call,
I saw a tutorial on this and implemented like this, with this code I can save the image in .jpg format only! (or any one format that I specify in the code)
uploaded image saved in php://input folder before and we need to grab that image from that temp folder to save that in the server,
but they didn't tell anything to change image format as per the image type,
now I want to upload the image in the original format, how can I collect image information while it is uploading?
here is the code
<?php
$str =file_get_contents('php://input');
$filename = md5(time()).'.jpg';
$path = 'upload/'.$filename;
file_put_contents($path,$str);
echo $path;
here is some JS for taking the image and sending ajax request:
$(function(){
//select the drop container
var obj = $('.drop');
// dragover event listener
obj.on('dragover',function(e){
e.stopPropagation();
e.preventDefault();
$(this).css('border',"2px solid #16a085");
});
//drop event listener
obj.on('drop',function(e){
e.stopPropagation();
e.preventDefault();
$(this).css('border',"2px dotted #bdc3c7");
//get the files
var files = e.originalEvent.dataTransfer.files;
var file =files[0];
//console.log(file);
//upload data using the xhr object
upload(file);
});
function upload(file){
//create xhr object
xhr = new XMLHttpRequest();
//initiate request
xhr.open('post','drop.php',true);
//set headers
xhr.setRequestHeader('Content-Type',"multipart/form-data");
xhr.setRequestHeader('X-File-Name',file.fileName);
xhr.setRequestHeader('X-File-Size',file.fileSize);
xhr.setRequestHeader('X-File-Type',file.fileType);
//send the file
xhr.send(file);
}
});
Finally, I fixed this problem.
there was no problem with PHP to catch headers, as Magnus Eriksson said $_SERVER['HTTP_X_FILE_TYPE'] works fine, but problem was while sending ajax header we set header type and size wrong.
i logged file data and find type and size but i set header as fileType and fileSize
changed the code and here is the code before and after :
BEFORE: AJAX request:
//set headers
xhr.setRequestHeader('Content-Type',"multipart/form-data");
xhr.setRequestHeader('X-File-Name',file.fileName);
xhr.setRequestHeader('X-File-Size',file.fileSize);
xhr.setRequestHeader('X-File-Type',file.fileType);
and PHP:
$str =file_get_contents('php://input');
$filename = md5(time()).'.jpg';
$path = 'upload/'.$filename;
file_put_contents($path,$str);
echo $path;
AFTER: AJAX request:
//set headers
xhr.setRequestHeader('Content-Type',"multipart/form-data");
xhr.setRequestHeader('X-File-Name',file.fileName);
xhr.setRequestHeader('X-File-Size',file.size);
xhr.setRequestHeader('X-File-Type',file.type);
and PHP:
$str =file_get_contents('php://input');
$ext = $_SERVER['HTTP_X_FILE_TYPE'];
$e = explode("/",$ext);
$ext = $e[1];
$filename = md5(time()).'.'.$ext;
$path = 'upload/'.$filename;
file_put_contents($path,$str);
echo $path;
this code is working fine :)

Upload image on server and add file path inside image tag using quilljs

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

Create thumbnail from video without ffmpeg in PHP

I need to create thumbnail without ffmpeg because I have to deploy site on shared hosting and ffmpeg is not available on shared hosting.
Can someone suggest some solution?
If the video can be played back in the browser you could try using the Canvas feature of html5 to playback the video in a canvas and then post a still from that video to your server using javascript... Maybe you could even automate it, or if you only have a few dozen videos do it by hand...
The following is some jquery flavored javascript to upload a base64-encoded jpg in order to get you started. (Mashed up from several different projects, so untested and probably a security nightmare.)
<script>
var vidDOM = $('article').children('video');
var vid = vidDOM.get(2);
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
vidDOM.bind({
'paused':function () {
vid.width = canvas.width = vid.offsetWidth;
vid.height = canvas.height = vid.offsetHeight;
var $this = this;
ctx.drawImage($this, 0, 0, vid.width, vid.height);
uploadbase64();
}
})
function uploadbase64(){
canvasData = canvas.toDataURL("image/jpeg");
var ajax = new XMLHttpRequest();
ajax.open("POST",'ImageUpload.php?filename='+vidDOM.id,false);
ajax.setRequestHeader('Content-Type', 'application/upload');
ajax.send(canvasData);
}
</script>
And here is a bit of php to accept the upload.
<?php
$filename =$_GET['filename'];
if (file_get_contents('php://input')){
// Remove the headers (data:,) part.
$filteredData=substr(file_get_contents('php://input'), strpos(file_get_contents('php://input'), ",")+1);
// Need to decode before saving since the data we received is already base64 encoded
$decodedData=base64_decode($filteredData);
//create the file
if($fp = fopen( $filename, 'wb' )){
fwrite( $fp, $decodedData);
fclose( $fp );
} else {
echo "Could not create file.";
}
}
echo "Created image ".$filename;
?>

Converting file upload to binary, post to server and save file using PHP

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.

Posting base64 image to php

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.

Categories