jQuery using AJAX to display PDF data obtained from a PHP file - php

I am trying to use AJAX to query a PHP file and display a PDF file to the user. The response from the PHP file is the raw data of a PDF file stored on my server. Below is the code I am using to try and accomplish this but it isn't working. I keep getting a bad request error from my browser. Does anyone know the right way of doing this?
My end goal is I do not want the user to be able to see the server path where I store my PDF files. I only want the PDF files to be accessible using the AJAX / PHP script. I understand it's not the most secure method but I just want to keep the layman away from my PDF files.
jQuery:
$.ajax({
type: "POST",
url: 'process.php',
data: {"name" : "value"},
success: function (data) {
var json = $.parseJSON(data);
if(json.hasOwnProperty('success')){
window.location(json.success);
// json.success should contain the pdf binary data
// i just cant figure out how display the pdf in the browser
}
}
});
PHP:
<?php
$fileName = $_POST['name'];
if(isset($fileName)){
$file = './path-to-forms/'.$fileName.'.pdf';
$pdfData = file_get_contents($file);
$data = array("success" => $pdfData, "name" => $fileName);
echo json_encode($data);
}
?>

Does anyone know the right way of doing this?
A couple changes should get the file downloading correctly:
Update the PHP code to send the file contents using base-64 encoding (i.e. with base64_encode()):
$data = array("success" => base64_encode($pdfData));
When the AJAX response completes, create an anchor (link) and simulate clicking on it using .click() to initiate the PDF download. I can't find any jQuery method window.location() on api.jquery.com... if you find it, let me know. Maybe you were thinking of updating the (read-only) property window.location?
var json = $.parseJSON(data);
if(json.hasOwnProperty('success')){
var a = document.createElement("a");
a.href = 'data:application/pdf;base64,'+json.success;
a.download = "filePDF"; //update for filename
document.body.appendChild(a);
a.click();
// remove `a` following `Save As` dialog,
// `window` regains `focus`
window.onfocus = function () {
document.body.removeChild(a)
}
}
Credit to guest271314 for the adapted code from this answer along with some of the code from Alexandre's code in the answer below that.
See it demonstrated in this phpfiddle.

Related

Why is my blob reading as an array?

I have an HTML5 audio recorder which produces an audio blob (recorder.js by Matt Diamond) and executes a jquery ajax call to my PHP file.
function audioUpload() {
recorder && recorder.exportWAV(function(blob) {
//first look at the blob
console.log(blob);
var fd = new FormData();
fd.append('audioBlob', blob);
var audioBlob = fd.get('audioBlob');
//second look at the blob
console.log(audioBlob);
$.ajax({
method: "POST",
data: fd,
contentType: false,
processData: false,
url: "audioSend.php",
}).done(function(data) {
console.log(data);
})
});
There are two console.log functions here that report the blob:
In the first, the console reads as a blob. 1 In another part of the code I create an object URL with this and can play the audio using an HTML5 audio tag, so it's working.
In the second, the console reads it as a file. 2 I can understand this, as blobs are file-like objects by definition. Still, I'm not sure why it isn't reported as a blob like the first instance.
The formData object is posted to audioSend.php where I get the value and insert it into my DB.
$audioBlob = $_FILES['audioBlob'];
$results = mysqli_query($connection, "INSERT INTO audioLog (audio) VALUES ('$audioBlob')");
echo ($audioBlob);
Attempting to insert the blob value into my DB throws an "Array to String Conversion" error, and echoing $audioBlob confirms that it is read as an array. The value shown in my MYSQL DB Blob column is only a few bytes as a result, and not the much larger audio blob object that I want.
Why is the blob read as an array, and how can I get the REAL blob value be inserted into my DB?
You are POSTing the data, so access it via $_POST:
$audioBlob = $_POST['audioBlob'];
Also, use prepared statements as you are vulnerable to SQL injection.
Taking a second look at your code and, while I'm no JS programmer, it looks like you've disabled any sort of graceful POST and have just crammed the raw data into a POST request.
If you want to get this data you'll have to open the php://input stream which contains the un-processed POST body. Eg:
$f_in = fopen('php://input', 'rb');
$f_out = fopen($APPROOT.'/files/foo.bin', 'wb');
while( ! feof($f_in) ) {
$buf = fread($f_in, 4096);
fwrite($f_out, $buf);
}
fclose($f_in);
fclose($f_out);
Which will write the POST data to the file $APPROOT.'/files/foo.bin' 4KB at a time without cramming the entire thing into memory first.
If you want to upload it as a file and have it available in $_FILES you'll have to look into how to properly upload a file via whatever JS library that is.

Convert base 64 to audio Mp3 Format on PHP

I have an "audio" tag with the script (actually a plugin) that receives and saves it as base64. And this works okay.
I am trying to alter the script to send the base64 into the server and convert it to mp3 and display the recorded audio in the page.
This is what I have done so far.
Script to save file through ajax:
$(document).on("click", "#download:not(.disabled)", function(){
Fr.voice.export(function(url){
//$("<a href='"+url+"' download='MyRecording.wav'></a>")[0].click();
var src = url;
$.ajax({
url: $("#base_url").val() + "ajax/saveRecordedVoice",
type: "POST",
data: {"record_src": src},
success: function(result){
alert(result);
}
});
}, "base64");
restore();
});
PHP Script to Convert and Save File:
public function saveRecordedVoice()
{
$audio = $_POST['record_src'];
$decoded = base64_decode($audio);
$file_location = "assets/records/recorded_audio.mp3";
$success = file_put_contents($file_location, $decoded);
if($success){
echo "File Saved";
}else{
echo "Uh-uh!";
}
}
The file was successfully saved as .mp3 in my server but when I try to play it manually, Media player says:
Without knowing which plugin you're using to capture the audio, it's hard to really be sure. However i assume that the:
//$("<a href='"+url+"' download='MyRecording.wav'></a>")[0].click();
actually worked before, meaning that whatever audio you're receiving is direct sound.
Mp3 however is an encoded format, and as such, your media player is probably failing, trying to decode unencoded audio.
Try changing the output ending:
$file_location = "assets/records/recorded_audio.wav";
and see if those files will play for you.
If that does not solve it, you should output the "url" you send as data, to see if it sends unwanted markers/headers along.

Saving blob video with php

I am trying to send a buffered video to save it as a file on my server.
Always the file is empty.
My js get the url "blob:https://..." and sends to the php that receive it.
$file = file_get_contents(url);
file_put_contents($video_url_mp4."helloWorld.webm",$file);
I tried send the video as canvas and i only get one frame.
suggest please
A blob url is only usable in the browser that created it. So you cant use it on your server or copy and paste it into another browser or send the link to your friend etc.
What you need to do is get the blob that url was created from and use a FormData object and upload that to your server.
I get a file with the content as string on my php but this is not in a video format.
my js:
var myFile = new File(video.src);
var fd = new FormData();
fd.append('data', myFile);
and my php:
$f = $_POST['data'];
$decode = base64_decode(preg_replace('/^data\:image\/webp\;base64\,/', '', $f));
what is wrong?

Upload XML file, put in temporary folder or localStorage and access contents

I have an HTML form as such which consists of a input type=file.
<form method="post" id="xml-upload" enctype="multipart/form-data">
<input type="file" accept=".xml" required name="xml-selection-hidden" id="upload-btn">
</form>
(There is no submit button, submit is triggered via jQuery:)
$("input[type=file]#upload-btn").change(function(){
$("form#xml-upload").submit();
});
That's the easy part. Now, I am not quite knowledgeable in PHP file handling so the next part is harder for me. My idea of how these things work is that I make a PHP file and link to it in the action attribute of the form. For instance action="upload.php".
First of I need to check the file type, XML only (might allow TXT in the feature, but not of yet). A maximum size of the file of around 200kB ought to suffice. Simply using an embedded if-clause seems fine? (not tested)
if(($_FILES["file"]["type"]=="text/xml")) {
if ($_FILES["file"]["size"] < 200000) {
// run function
} else {
// error: max file size is 200kB
}
} else {
// error: only xml files are allowed
}
But now I'm stuck.
The goal is to manipulate the XML client-side. This is useful because I allow users to either choose the file upload option, or to give a direct XML input in a textarea. The server-side function (jQuery) for parsing the XML in the textarea is already finished, so it would be useful if I could use the same function to parse the XML that I get from the uploaded file.
I thought of two options:
1. The uploaded file is put in a temporary directory with a random name, I then run an ajax call with jQuery to the file. But how? How do I get jQuery to know where the file is stored?
2. Store the content of the uploaded file in localStorage and manipulate it accordingly. When a new file is uploaded, the older localStorage ought to be cleared of course.
The script that is run on the XML is something along these lines. Just so you know what happens with the XML input:
var xml = $("textarea#xml-input").val(),
xmlParsed = $.parseXML(xml),
xmlObject = $(xmlParsed);
$("#tree").html(output(xmlObject.find('node').first()));
function output(nodes) {
var newList = $("<ol>");
nodes.each(function (x, e) {
var newLI = $('<li> </li>');
for (var i = 0, l = e.attributes.length, a = null; i < l; i++) {
a = e.attributes[i];
newLI.attr("data-" + a.nodeName, a.value);
if (a.nodeName == "cat") {
newLI.html('' + a.value + '');
}
else if (a.nodeName == "word") {
newLI.html('' + a.value + '');
}
}
if ($(this).children('node').length) {
newLI.append(output($(this).children('node')));
}
newList.append(newLI);
});
return newList;
}
As I have said, I have tried my best in this post and gave it all I got, but I lack the knowledge. Looking for some help here. All help welcome!
For doing same as you wants you can create your own "xml_tmp" folder in your server root and then by using PHP move_uploaded_file() function to store your file in directory you selected for this and after storing current uploaded xml file you can ask via AJAX to get file name and path then send the requested info back to the client by using jQuery.parseXML() method you can read and manipulate your xml there.
I hope it help you!
Storing uploaded file by PHP:
move_uploaded_file($_FILES["file"]["tmp_name"], "xml_tmp/tmp.xml")
Imagine that 'xmlSrc' variable is the result of response from you AJAX call for requesting xml path and name
$.ajax({
type: "GET",
url: xmlSrc,
dataType: "xml",
success: function(xml) {
var xmlDoc = xml,
$xml = $( xmlDoc ),
$author = $xml.find( "author" );
// append the text from your parsed xml element to some HTML element
$( "#element" ).append( $author.text() );
}
});
1. The uploaded file is put in a temporary directory with a random name, I then run an ajax call with jQuery to the file. But how? How do I get jQuery to know where the file is stored?
jQuery has no interest in the temporary filename. The moment your PHP script has processed the upload request, the temporary file is deleted. That's on the server-side. jQuery is on client side.
So jQuery would get a filename of an inexistent file then.
You're perhaps looking for the browser file API which is able to access contents of a file without uploading it. Which seems fair as you're anyway dealing with a textbox if I understood your question right.

Download a file with an ajax call

I am using PHPExcel to read an excel template, populate the data, and ask the user to download the file.
generate_excel.php
$objPHPExcel = PHPExcel_IOFactory::load("./template.xlsx");
//populate data ...
header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
header('Content-Disposition: attachment;filename="01simple.xlsx"');
header('Cache-Control: max-age=0');
$objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel2007');
$objWriter->save('php://output');
When I open generate_excel.php directly from the browser, the result file is downloaded.
But if I make an ajax call to the generate_excel.php, I don't get the download prompt. Using chrome developer tools, I can see from the Network tab that the ajax call was successfully completed and a bunch of random characters is seen in the response data. I'm assuming that is the excel object.
Does anyone know how I can achieve the download excel feature using ajax? I don't want to refresh the page. When the user clicks on the "export" button, there should be an ajax call to the php file and prompt the user to download.
Thanks!
I looked for ways to pass JSON data with ajax to PHP and return an excel file (MySQL and PHPExcel) for the user to save.
I looked around and put some pieces together, hope it can help someone:
jQuery:
$("#exportBotton").on("click",function(event) {
event.preventDefault();
// create json object;
str_json = JSON.stringify({"key01":val01, "key02":val02, "key03":val03});
$.ajax({
type: "post",
data: str_json,
url: "../../includes/dbSelect_agentFormExport.php",
dataType: "json",
success: function(output){
// output returned value from PHP t
document.location.href =(output.url);
}
});
});
PHP:
$str_json = file_get_contents('php://input');
$objPHPExcel = new PHPExcel();
// here i populated objPHPExcel with mysql query result.....
function saveExcelToLocalFile($objWriter){
// make sure you have permission to write to directory
$filePath = '../tmp/saved_File.xlsx';
$objWriter->save($filePath);
return $filePath;
}
$objWriter = new PHPExcel_Writer_Excel2007($objPHPExcel);
$response = array(
'success' => true,
'url' => saveExcelToLocalFile($objWriter)
);
echo json_encode($response);
exit();
Not everything should be done with AJAX. Sometimes plain old HTML is more suitable for a job. I guess your button has a tag? Why won't you do something like this
Export to Excel
in your HTML? Note the target="_blank" part. It's there to make sure your page is not reloaded.
For input you can use construct
<form action="generate_excel.php" target="_blank"><input type="button">...whatever</form>
Here is an example of how to download a file using an AJAX call:
var xhr = new XMLHttpRequest();
xhr.open("GET", "path/to/file.ext", true);
xhr.responseType = "blob";
xhr.onload = function(e) {
if (xhr.status === 200) {
var a = document.createElement("a");
a.href = URL.createObjectURL(xhr.response);
a.download = "file.ext";
a.style.display = "none";
document.body.appendChild(a);
a.click();
}
};
xhr.send();
Found a way to do this, although I'm not sure if this is an ideal approach.
I added a hidden iframe in the page. When the ajax call returns, it returns the url of the created data. I used javascript to redirect the iframe to that url which automatically triggers the download action.
You can try this way:
Send a Jquery AJAX POST request with the data that is to be used to generate excel report, and store that data in a session variable. Return an arbitrary string like 'success' as the response.
If the output of the above AJAX call is 'success', then do a GET request to another URL in your application, that reads the data from session (stored in the first step, else throw an error), prepares an excel file out of that data, and forces the download of that excel file to the browser.

Categories