How to decode and save a file sent to php from js - php

I have a drag and drop uploader. I am using File Reader to send data As url.
var files = evt.dataTransfer.files;
for (var i = 0, f; f = files[i]; i++) {
var start = 0;
var stop = files[0].size - 1;
var reader2 = new FileReader();
var ext = f.name.substring(f.name.indexOf(".")+1);
reader2.onloadend = function(evt) {
if (evt.target.readyState == FileReader.DONE) { // DONE == 2
$.post("/process/upload.php",{"blob":evt.target.result,"extension":ext},function(data){
console.log(data);
});
}
};
var blob = f.slice(start, stop + 1);
reader2.readAsDataURL(blob);
}
PHP recieves it but once I decode it I get "null" returned
$extension = $_POST['extension'];
$file = base64_decode($_POST['blob']);
$filePath = "../tmp/monkey.".$extension;
echo json_encode(base64_decode($_POST['blob']));
I also tried:
if(file_put_contents($filePath,$file)){
echo json_encode("it worked");
}else{
echo json_encode("it failed");
}
EDIT: I maintain the POST info all the way until I decode it. So once I decode it how do I determine the file is intact and can be saved?
Is there a better way to decode and save file?
What exactly am i doing wrong?
Thanks in advance!

$_POST['extension'] and $_POST['blob'] don't magically get populated into $_POST array when posting in JSON format. In fact based on your JSON format, the JSON will decode into an object, not an array.
You will need to get the contents directly from input like this:
$post = file_get_contents('php://input');
$post_obj = json_decode($post);
$extension = $post_obj->extension;
$file = base64_decode($post_obj->blob);
Or using $HTTP_RAW_POST_DATA variable like:
$post_obj = json_decode($HTTP_RAW_POST_DATA);
$extension = $post_obj->extension;
$file = base64_decode($post_obj->blob);

Related

Parse CSV file to JSON after uploading using temporary copy

I'm almost finishing building a functionality for parsing CSV files to JSON and just need help in piecing it together. The way it works is that files will be uploaded using AJAX/Jquery. Once the files has been uploaded and sent the PHP to parse the CSV file to JSON will then execute.
After parsing, the converted file will be push or sent to the API as a JSON object. Here is the code that I have been working. For the uploading i'm using this plugin AJAX/JQuery File Uploader
This functionality is also built on using RactiveJS
AJAX/Jquery File Uploader
This is the section where I'm currently uploading or placing the file. URL is pointed at the upload.php.
<div id="fileuploader">Upload</div>
<script>
$(document).ready(function() {
$("#fileuploader").uploadFile({
url: 'upload.php',
});
})
</script>
Uploads.php
Is there a way to GET the temporary copy of the uploaded file and parse using the PHP code I have built below to convert the CSV to JSON
<?php
if ( 0 < $_FILES['file']['error'] ) {
echo 'Error' . $_FILES['file']['error'] . '<br/>';
}
else {
move_uploaded_file($_FILES['file']['tmp_name'], 'uploads/' . $_FILES['file']['name']);
}
?>
PHP (CSV to JSON)
Right now be the file is being declared manually.
<?php
$json_data = csvToJson('lms.csv');
?>
<?php
function csvToJson($fname) {
if (!($fp = fopen($fname, 'r') )) {
die("Can't open file");
}
else {
('Upload File');
}
$key = fgetcsv($fp, "1024", ",");
$json = array();
while ($row = fgetcsv($fp, "1024", ",")) {
$json[] = array_combine($key, $row);
}
fclose($fp);
foreach ( $json as $k=>$v ) {
$json[$k]['accountName'] = $json[$k]['ACCOUNT NAME'];
$json[$k]['dateRequested'] = $json[$k]['DATE'];
unset($json[$k]['ACCOUNT NAME']);
unset($json[$k]['DATE']);
}
return json_encode($json, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_NUMERIC_CHECK);
}
?>
<?php // $target_file = fopen($_FILES["fileToUpload"]["tmp_name"], 'r'); ?>
Send Converted to API (Ractive/AJAX/JS)
As you can see the sending part is triggered by an on-click event (app.on)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ractive/0.9.0-build-48/ractive.js"></script>
<script type="text/javascript">
var app = new Ractive({
el : '#container',
template : '#template',
});
var proxy = 'http://192.168.1.126/lms-dev-noel/proxy.php';
var endpoint = 'account/leads/';
var rt = 'POST';
var url = proxy+'?endpoint='+endpoint+'&rt='+rt;
var lms_json = <?php echo json_encode($json_data); ?>;
var jobjects = JSON.parse(lms_json);
for ( i = 0; i < jobjects.length; i++ ) {
var data = jobjects[i];
console.log(data);
$.ajax({
type : 'POST',
url : url,
data : data,
dataType : 'json',
success : function() {
},
error : function(error) {
console.log('Error')
}
});
}
</script>
Warning and Notices
Well, it depends a bit on where that csvToJson function is located in your code. If it's within uploads.php, or in a separate file that you can include in uploads.php, then you can just do:
move_uploaded_file($_FILES['file']['tmp_name'], 'uploads/' . $_FILES['file']['name']);
$json_data = csvToJson('uploads/' . $_FILES['file']['name']);
echo $json_data;
Then in the script, change
var lms_json = <?php echo json_encode($json_data); ?>;
to
var lms_json;
and move it to the top of your javascript.
It seems like you are trying to assign the variable before the API call has been made. Instead you need to capture the data from the the response of the uploadFile call (as per these docs: http://hayageek.com/docs/jquery-upload-file.php):
$("#fileuploader").uploadFile({
url: 'upload.php',
onSuccess:function(files,data,xhr,pd)
{
//data: response from server
lms_json = data;
}
});

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

Are canvas.toDataURL compatible with PHP's base64_decode?

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

Saving binary string to file in php sent from POST

I have a drag and drop uploader for (.jpg,.ai,.pdf,.flv,.psd ....etc.)
I'm reading the file as binary and sending the string in a jquery post:
function importZoneDrop(evt) {
evt.stopPropagation();
evt.preventDefault();
var files = evt.dataTransfer.files; // FileList object.
// files is a FileList of File objects. List some properties.
for (var i = 0, f; f = files[i]; i++) {
var start = 0;
var stop = files[0].size - 1;
var reader1 = new FileReader();
var reader2 = new FileReader();
var ext = f.name.substring(f.name.indexOf(".")+1);
if(ext == "JPEG" || ext == "jpeg" || ext == "JPG"){
ext ="jpg";
}
reader1.onload = (function(theFile) {
return function(e) {
// Render thumbnail.
$("#import-drop-zone").append('<img src="'+e.target.result+'" />');
};
})(f);
reader2.onloadend = function(evt) {
if (evt.target.readyState == FileReader.DONE) { // DONE == 2
$.post("/process/upload.php",{"blob":evt.target.result,"extension":ext},function(data){
console.log(data);
});
}
};
reader1.readAsDataURL(f);
var blob = f.slice(start, stop + 1);
reader2.readAsBinaryString(f);
}
}
This works and send the file. Next Get the string and write it using file_put_contents:
$extension = $_POST['extension'];
$file = $_POST['blob'];//sent from jquery post
$filePath = "../_temp/monkey.".$extension;
file_put_contents($filePath,$file);
if(file_put_contents($filePath,$file)){
echo json_encode("it worked");
}else{
echo json_encode("it failed");
}
This will successfully write the file. But the file does not work, it's broke.
What am I doing wrong?
You need to use base64_decode.
file_put_contents($filePath, base64_decode($file));
Note, you're currently writing the data twice. Don't.
if (file_put_contents($filePath, base64_decode($file))) {
is fine
Edit
Also worth nothing that it's more efficient to upload the binary file directly, then you can skip base64_decode. Something like this:
var xhr = new XMLHttpRequest(),
data = new FormData();
data.append("file", f); // You don't need to use a FileReader
// append your post fields
// attach your events
xhr.addEventListener('load', function(e) {});
xhr.upload.addEventListener('progress', function(e) {});
xhr.open('POST', '/process/upload.php', true);
xhr.send(data);
You can view the rest of the events here with some samples here.

Send bitmap data from Flex to Php

I want to save a screenshot from my Flex app on the Webserver (LAMP).
Here is the Flex code:
private function getBitmapData( target : UIComponent ) : BitmapData
{
var bd : BitmapData = new BitmapData( target.width, target.height );
var m : Matrix = new Matrix();
bd.draw( target, m );
return bd;
}
Now, how do I send / receive this data to the server?
You are going to have to use a HttpService to post the data to a page on your website. When I implemented this I posted the Image data as a Base64 encoded string to a PHP page that used the GD library to save it to a png file on the server. Here is a simplified example of what my code looked like
Flex Code
public function saveImg():void{
var bd:BitmapData = new BitmapData(mycanvas.width,mycanvas.height);
bd.draw(mycanvas);
var ba:ByteArray = PNGEncoder.encode(bd);
var encoded:String = Base64.encodeByteArray(ba);
var objSend:Object = new Object;
objSend.data = encoded;
objSend.filename = _imgResult;
writeImage.send(objSend);
}
<mx:HTTPService id="writeImage" url="/saveImage.php" method="POST" resultFormat="text" result="resultHandler(event)"/>
PHP File (saveImage.php)
<?php
//check for the posted data and decode it
if (isset($_POST["data"]) && ($_POST["data"] !="")){
$data = $_POST["data"];
$data = base64_decode($data);
$im = imagecreatefromstring($data);
}
//make a file name
$filename = "test"
//save the image to the disk
if (isset($im) && $im != false) {
$imgFile = "/etc/www/html/".$filename.".png";
//delete the file if it already exists
if(file_exists($imgFile)){
unlink($imgFile);
}
$result = imagepng($im, $imgFile);
imagedestroy($im);
echo "/".$filename.".png";
}
else {
echo 'Error';
}
?>
On the flex side I am using the Base64Encode utilty from dynamicflash, but now that there is one built into flex you could use that instead. In your php config you will need to make sure you have the GD library enabled so that you can save the image.
Of course this is a very simple example and does not take into account all the error handling and security concerns needed, but should provide you a good base to get going with.

Categories