Uploading image using ajax - javascript

I have a variables src and image,
var src = $("#img_tag").attr('src');
var image = new Image();
I want to pass this image variable to a public function in php to upload. What is it that exactly that I need to pass, is it the src, the base64, the image itself as new FormData ?
Right now I have:
var data = new FormData();
var src = $("#img_tag").attr('src');
var image = new Image();
data.append('Image', image);
console.log(data);
$.ajax({
url: "/products/image_upload",
type: "POST",
data: data,
processData: false,
contentType: false,
success: function (msg) {
console.log(msg+"---Image was uploaded");
}
error: function(err) {
console.log(err);
}
});
In my view:
public function image_upload() {
$this->autoRender = false;
echo json_encode($this->data);
if($this->request->is('post'))
{
if(!empty($_FILES['Image']['name'])) {
$file = $_FILES['Image'];
echo json_encode($file);
$ext = substr(strtolower(strrchr($file['name'], '.')), 1);
$arr_ext = array('jpg', 'jpeg', 'gif', 'png');
$temp = explode(".", $file['name']);
$newfilename = $_FILES['Image']['name'];
if(in_array($ext, $arr_ext))
{
if(move_uploaded_file($file['tmp_name'], WWW_ROOT . 'img/product-uploads' . DS . $newfilename))
{
echo json_encode("Image uploaded properly");
return json_encode($_FILES);
}
}
}
}
}
And getting:
{"Image":"[object HTMLImageElement]"}---Image was uploaded
BUT IMAGE IS NOT UPLOADED

If you take a look at the FormData.append doc, you will see that the second argument takes a string or a blob.
So passing an HTMLImageElement isn't going to work, if you cant get the image as a Blob or a File using a FormData object doesn't really help.
Since you're trying to upload the src of #img_tag, this will only really work if it is the base64 encoded image.
In this case use data.append('Image', src); and read the data from $_POST['Image'] then clean it up and decode it.
If the image src is a regular url, use $_POST['Image'] with curl to download the image to your server.

I got a bit of a research, and found this article super helpful. (Thanks to that)
I managed to upload an image file to a directory in my server from an image src by getting the base64 encoded image, passed for the controller to decode and upload. (Also thanks to Musa, DanielO, and Rory McCrossan)
In Controller: Code from this article. (I added a custom filename in a datetime format)
public function additional_image_upload() {
$this->autoRender = false;
$base64 = $this->request->data['base64'];
$product_id = $this->request->data['id'];
$baseFromJavascript = $base64;
$data = base64_decode(preg_replace('#^data:image/\w+;base64,#i', '', $baseFromJavascript));
$t = microtime(true);
$micro = sprintf("%06d",($t - floor($t)) * 1000000);
$date_tmp = new DateTime( date('Y-m-d H:i:s.'.$micro, $t) );
$date = $date_tmp->format("Y-m-d_his.u");
$filepath = WWW_ROOT . 'img/product-uploads' . DS ."$date.jpg"; // or image.jpg
file_put_contents($filepath,$data);
}
In Script: (I passed the base64 encoded image for the controller to handle)
var src = $(this).attr('src');
$.ajax({
url:"/products/additional_image_upload",
data:{
"id": "<?= $id; ?>",
"base64": src
},
type:"POST",
success: function(msg) {
console.log(msg."---Img uploaded");
},
error: function(error) {
console.log(error);
}
});
And all was working great. Added this to help future readers.

Related

JSPDF .output Image + txt

So i have a jspdf script im working with.
.save works as expected and outputs the image + text elements.
How ever
doc.output() = only text
doc.output('datauristring') = corrupted pdf
I think im missing something
here is an example of my code
var imgData = 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQIAdgB2AAD/examplestringonly...';
var doc = new jsPDF('p', 'pt');
doc.text(35, 340, "data notes");
doc.addImage(imgData, 'JPEG', 350, 40, 200, 40);
doc.output('datauristring');
Solved hope this helps anyone.
.output() was correctly sending all the date, how ever the base64 was being corrupted. so i made the php handle the datauri, and used base64_decode() on it.
then made it save to file.
fixes the issues completely.
var pdf = doc.output('datauri');
var data = new FormData();
data.append("data" , pdf);
data.append("id" , id);
$.ajax({
url: 'upload.php',
data: data,
dataType: 'text',
processData: false,
contentType: false,
type: 'POST',
success: function (response) {
console.log('Exit to send request');
},
error: function (jqXHR) {
console.log('Failure to send request');
}
});
<?php
if(!empty($_POST['data'])){
$data = str_replace(' ','+',$_POST['data']);
$data = substr($imgData,strpos($imgData,",")+1);
$data = base64_decode($imgData);
$id = $_POST['id'];
$fname = "test.pdf"; // name the file
$file = fopen("api/warranty/pdf/" .$id, 'w'); // open the file path
fwrite($file, $data); //save data
fclose($file);
} else {
echo "No Data Sent";
}

Image crop Code in Symfony 3.3 works in localhost well but does not work in live website

So I recently saw a tutorial and created an Image crop and upload feature in website. In my case I have :-
a. Title
b. Description
c. Image
d. Date
Initially I did exactly like in tutorial when file browse is clicked the image would have mounted in Bootstrap 4 modal where there had a feature to crop. The main problem over there was when I clicked on that crop button the ajax used to run and persist all the data into database. Later I changed in JavaScript so that when crop button is clicked the cropped image is displayed and finally the Submit button would saved all data in database. This feature is working well in Localhost, but when I updated in my live website the features seems not to work.
JavaScript Code:
$('.crop_image').click(function(event){
$image_crop.croppie('result', {
type: 'canvas',
size: 'viewport'
}).then(function(response){
$('#uploadimageModal').modal('hide');
$("#previewImg").attr('src', response);
getResponse = response;
});
$('#upload_btn').on('click',function(){
var block = getResponse.split(";");
// Get the content type
var contentType = block[0].split(":")[1];// In this case "image/gif"
// get the real base64 content of the file
var realData = block[1].split(",")[1];// In this case "iVBORw0KGg...."
// Convert to blob
var blob = b64toBlob(realData, contentType);
let formData = new FormData(form);
formData.append('image_path', blob);
$.ajax({
url: "{{ path('app_bundle_route') }}",
type: 'POST',
data: formData,
processData: false,
contentType: false,
headers: {'X-Requested-With':'XMLHttpRequest'},
success: function(data){
$("#previewImg").attr('src', getResponse);
}
});
Controller:
/**
* #Security("is_granted('ROLE_ADMIN')")
* #Route("/form", name="form")
*/
public function indexAction(Request $request) {
$members = new members();
$form = $this->createForm(event::class, $members);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
return $this->redirectToRoute('dev');
}
return $this->render('admin/create.html.twig', [
'form' => $form->createView()
]);
}
/**
* #Security("is_granted('ROLE_ADMIN')")
* #Route("/getImage", name="getImage")
* #Method({"POST"})
*/
public function getImageAction(Request $request){
$members = new members();
$form = $this->createForm(event::class, $members);
$form->handleRequest($request);
if($form->isSubmitted() && $form->isValid()){
if($request->isXmlHttpRequest()){
/** #var Symfony\Component\HttpFoundation\File\UploadedFile $file */
$file = $request->files->get('image_path');
//$file = $form->get('image_path');
$filename = md5(uniqid()).'.'.$file->guessExtension();
$file->move($this->getParameter('event_directory'), $filename);
$title = $form['title']->getData();
$description = $form['description']->getData();
$date = $form['date']->getData();
$members->setImagePath($filename);
$members->setTitle($title);
$members->setDescription($description);
$members->setDate($date);
$em = $this->getDoctrine()->getManager();
$em->persist($members);
$em->flush();
$this->addFlash(
'notice', 'Event Added!!'
);
}
}
return new JsonResponse("This is Ajax");
}
I have deleted cache several times but didn't work. The exact code works in Localhost.

Save image on server error

I have an ajax fuction to take a div and make it picture and then post it on php for saving it .
<script>
$("#capture").click(function() {
html2canvas([document.getElementById('printableArea')], {
onrendered: function (canvas) {
var imagedata = canvas.toDataURL('image/png');
var imgdata = imagedata.replace(/^data:image\/(png|jpg);base64,/, "");
//ajax call to save image inside folder
$.ajax({
url: 'save_image.php',
data: {
imgdata:imgdata
},
type: 'post',
success: function (response) {
console.log(response);
$('#image_id img').attr('src', response);
}
});
}
})
});
</script>
Then i have the save image php to save it on server
<?php
$imagedata = base64_decode($_POST['imgdata']);
$filename = md5(uniqid(rand(), true));
//path where you want to upload image
$file = '/home/a7784524/public_html/barcodeimage/'.$filename.'.png';
$imageurl = 'http://panosmoustis.netai.net/barcodeimage/'.$filename.'.png';
file_put_contents($file,$imagedata);
echo $imageurl;
?>
My problem is although the image is saved on path when i try to open it i get the error the image cannot be displayed because it contains errors
Thank you
#aristeidhsP Please check file_put_contents return; is the image really created ?
If so you, have to check the content of $imagedata: have you correctly stripped the extra stuff from the image data (your regex may not fire on jpeg or gif extension).
Hope this helps

How to save my generated javascript pdf file to my server's filesystem?

I'm using pdfmake to create my pdf and while it allows the user to open the pdf directly or download it to their computer, I'm not sure how I would go about generating the pdf and saving it to my server's file system.
From what I understand, there are plenty of security measures not allowing javascript to save data to file(s), so would sending it to my php backend be the only choice ? and how would i go about doing that ?
Thanks !
(untested)
PHP:
<?
// pull the raw binary data from the POST array
$data = substr($_POST['data'], strpos($_POST['data'], ",") + 1);
// decode it
$decodedData = base64_decode($data);
// print out the raw data,
echo ($decodedData);
$filename = "test.pdf";
// write the data out to the file
$fp = fopen($filename, 'wb');
fwrite($fp, $decodedData);
fclose($fp);
?>
JS:
var docDefinition = {
content: 'This is an sample PDF printed with pdfMake'
};
pdfMake.createPdf(docDefinition).getBuffer(function(buffer) {
var blob = new Blob([buffer]);
var reader = new FileReader();
// this function is triggered once a call to readAsDataURL returns
reader.onload = function(event) {
var fd = new FormData();
fd.append('fname', 'test.pdf');
fd.append('data', event.target.result);
$.ajax({
type: 'POST',
url: 'upload.php', // Change to PHP filename
data: fd,
processData: false,
contentType: false
}).done(function(data) {
// print the output from the upload.php script
console.log(data);
});
};
// trigger the read from the reader...
reader.readAsDataURL(blob);
});
Upload and receive code from How can javascript upload a blob?.

how to get a zip with $.ajax from php server

I'm trying to send a zip generated by a php server when requested by jquery's $.ajax.
This is my code:
php:
$file = tempnam($a_folder_path, "zip");
$zip = new ZipArchive();
$zip->open($file, ZipArchive::OVERWRITE);
$zip->addFile($path_to_json, 'data.json');
$zip->close();
rename($file, $file . '.zip');
$filename = basename($file . '.zip');
$filepath = $file . '.zip';
while (ob_get_level()) {
ob_end_clean();
}
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: public, must-revalidate, post-check=0, pre-check=0");
header("Content-Description: File Transfer");
header("Content-type: application/octet-stream");
header("Content-Disposition: attachment; filename=\"".$filename."\"");
header("Content-Transfer-Encoding: binary");
header("Content-Length: ".filesize($filepath));
ob_end_flush();
echo file_get_contents($filepath);
//#readfile($filepath);
javascript:
$.ajax(
{
url: myUrl,
type: 'POST',
data: {
"leData" : "some_data"
},
context: document.body,
cache: false,
success: function(data) {
console.log(data);
console.log(data.length);
var bytes = new Uint8Array(data.length);
for (var i=0; i<data.length; i++) {
bytes[i] = data.charCodeAt(i);
}
blob = new Blob([bytes], {type: "application/zip"})
saveAs(blob, "test.zip");//trying to access data with FileSave.js
zip.load(data);//trying to access data with JSZip.js
jsonData = JSON.parse(zip.file('shouldBeThere.json').asText());
},
error: function() {
alert('error');
}
}
);
What happens:
The server creates the zip file I ask it to, and this file isn't corrupted. It contains, among others, shouldBeThere.json.
The server sends data to the frontend.
The console.log(data); line in javascript prints a string almost identical from what I get by opening the zip file created on the server with a text editor.
The console.log(data.length); line in javascript prints a number smaller than the content length of the response header according to chrome's devtools. Maybe a hint to a data corruption.
saveAs creates a zip containing the file it's meant to, with the right name, but when I try to unzip it 7zip shows an error: "an attempt was made to move the file pointer before the beginning of the file".
6.JSZip seems to load the data but then zip.file('shouldBeThere.json') is null.
The problem is I have no idea if the problem comes from php or from javascript. I don't know if php is sending a corrupted zip or if javascript isn't reading it right.
I have tried all the php headers combinations and methods i've found on the internet. I have also tried to do things differently in javascript: using an ArrayBuffer instead of Uint8Array, passing bytes instead of data to zip.load(), using {type: "application/octet-stream"} in Blob().
I finally found a solution: It has to be specified to ajax the received data type, and then convert this unicode data into characters. Here is my new javascript code:
$.ajax(
{
url: myUrl,
type: 'POST',
data: {
"leData" : "some_data"
},
context: document.body,
cache: false,
dataType: 'text', //solution code
mimeType: 'text/plain; charset=x-user-defined', //solution code
success: function(data) {
console.log(data);
console.log(data.length);
newContent = ""; //solution code
for (var i = 0; i < data.length; i++) { //solution code
newContent += String.fromCharCode(data.charCodeAt(i) & 0xFF); //solution code
}
var bytes = new Uint8Array(newContent.length); //modified
for (var i=0; i<newContent.length; i++) { //modified
bytes[i] = newContent.charCodeAt(i); //modified
}
blob = new Blob([bytes], {type: "application/zip"})
saveAs(blob, "test.zip");
zip.load(newContent); //modified
jsonData = JSON.parse(zip.file('shouldBeThere.json').asText());
},
error: function() {
alert('error');
}
}
);
My php code was fine, it even worked without headers. Here is the minimal php code I need:
$file = tempnam($a_folder_path, "zip");
$zip = new ZipArchive();
$zip->open($file, ZipArchive::OVERWRITE);
$zip->addFile($path_to_json, 'data.json');
$zip->close();
rename($file, $file . '.zip');
echo file_get_contents($file . '.zip');
Solution inspired by this
I was searching for a solution for following problem:
"Sending a request on php url for creating a zip of a directory and downloading it by using ajax response."
Following code works:
PHP part for zip:
// Function for creating a zip of a directory
function zipFilesAndDownload($directory, $file_names) {
$zip = new ZipArchive();
if ($zip->open("../temp/$directory.zip", ZIPARCHIVE::CREATE) !== TRUE) {
exit("Error on creating '../temp/$directory.zip'");
}
foreach ($file_names as $file) {
$zip->addFile($file, substr($file, strrpos($file, "/") + 1));
}
$zip->close();
readfile("../temp/$directory.zip");
unlink("../temp/$directory.zip");
}
// Code for creating array of filenames
$directory = $_POST['directory']; // e.g. a directory with ID "123"
$dirToZip = "../uploaddir/$directory";
if ($handle = opendir($dirToZip)) {
$file_names = array();
while (($file = readdir($handle)) !== false) {
if ($file != "." && $file != "..") {
array_push($file_names, "$dirToZip/$file");
}
}
closedir($handle);
zipFilesAndDownload($directory, $file_names);
}
JS part:
$(document).on('click', '#downloadDirectory', function () {
var directory = '123';
$.ajax({
type: 'POST',
url: '../createZip.php',
data: {"directory": directory},
dataType: 'text',
mimeType: 'text/plain; charset=x-user-defined',
success: function (data) {
var bytes = new Uint8Array(data.length);
for (var i = 0; i < data.length; i++) {
bytes[i] = data.charCodeAt(i);
}
blob = new Blob([bytes], {type: "application/zip"})
saveAs(blob, "pictures.zip"); // "saveAs" function is provided in FileSaver.js
}
});
});
I update your JS code for JSZip 3+ version.
It's more easy. I hope i'll be useful to someone.
$.ajax(
{
url : url,
type: "POST",
data: $('#form').serialize(),
cache: false,
dataType: 'text',
responseType :'blob',
mimeType: 'text/plain; charset=x-user-defined',
success: function(data) {
JSZip.loadAsync(data)
.then(function (zip){
return zip.generateAsync({type: "blob"})})
.then(function (blob){
var date = new Date();
saveAs(blob, date.getFullYear() + "" + (date.getMonth() + 1) + "" + date.getDate() + "" + date.getHours() + "" + date.getMinutes() + "" + date.getSeconds()+".zip");
});
},
error: function() {
alert('error');
}
);

Categories