Several questions here very helpfully discuss downloading binary files using jQuery and Ajax. My files download but are corrupted. The ones I'm testing are MS docx type but they arrive with different contents and sizes to the original with BOM header bytes EF BB BF prefixed, which I guess means something somewhere in transit is trying to convert them to UTF8.
Test PHP code:
$id = json_decode(filter_input(INPUT_POST, 'downloadfile', FILTER_SANITIZE_STRING);
getFileData($pdo, $fileData, $id); // from database
$file = file_get_contents($fileData['file_location']);
header('Content-type: application/octet-stream');
header("Content-Transfer-Encoding: binary");
echo $file;
jQuery (I'm using v3.6.0):
$('#dodownload').on('click', function() {
$.ajax({
type: 'POST',
data: {'downloadfile': id},
xhrFields: {responseType: 'blob'},
url: '/php/ajax/fbdownload-ajax.php',
})
.done(function(blob, status, xhr){
var link=document.createElement('a');
link.href=window.URL.createObjectURL(blob);
link.download="testfile.docx";
link.click();
});
})
jQuery says blob is 'Blob {size: 14403, type: "application/octet-stream"', status is "success" and xhr.readyState is 4.
How do prevent the corruption to the file?
I am attempting to learn Vue.js. I'm working through building a very minimal component. The component is literally just an option list using select. Nowhere in the documentation, or any tutorials I can find online, does it show how to load data from database into a Vue component. I have found some examples using Axios, but I have no interest at all in using Axios. I am simply trying to learn how Vue works, so that I can see if I can use it to improve my workflow. This is literally a basic test case. Also, the PHP portion that this code is referencing works fine. I have tested it directly, and it loads the data exactly as expected.
Here is the javascript portion.
const cityChoice = {
data() {
return {
citys: [
{ Abbrev: 'Lima' },
{ Abbrev: 'FtWayne' },
],
err: false
}
},
methods: {
},
mounted() {
fetch('Controller/get_cities.php', {
method: 'POST', // *GET, POST, PUT, DELETE, etc.
cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
headers: {
// 'Content-Type': 'application/json'
'Content-Type': 'application/x-www-form-urlencoded',
},
redirect: 'follow', // manual, *follow, error
referrerPolicy: 'no-referrer', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
body: '' // body data type must match "Content-Type" header
}).then(function (response) {
return response.text();
}).then(function (data) {
testData = data
return testData;
});
},
methods: {
getCities() {
fetch('Controller/get_cities.php', {
method: 'POST', // *GET, POST, PUT, DELETE, etc.
cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
headers: {
// 'Content-Type': 'application/json'
'Content-Type': 'application/x-www-form-urlencoded',
},
redirect: 'follow', // manual, *follow, error
referrerPolicy: 'no-referrer', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
body: '' // body data type must match "Content-Type" header
}).then(function (response) {
return response.text();
}).then(function (data) {
this.citys = data;
alert(this.citys)
});
this.citys = [
{ Abbrev: 'Dayton' },
{ Abbrev: 'Cincy' },
]
}
}
}
Vue.createApp(cityChoice).mount('#cityChoice')
And here is the HTML portion.
<?php
$lifetime = 60 * 60 * 24 * 14;
session_set_cookie_params($lifetime, '/');
session_start();
include 'Controller/login_check.php';
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://unpkg.com/vue#next"></script>
<title>BAI Inventory Entry</title>
</head>
<body>
<div id="cityChoice">
<select id="city">
<option v-for="city in citys">
{{ city.Abbrev }}
</option>
</select>
<button v-on:click="getCities">Get Cities</button>
</div>
</body>
<script src="js/global.js?ver3"></script>
</html>
I am positive that I'm just not understanding how this software language works. But, I need to understand how it calls real data, or else I'm never going to be able to wrap my mind around the other basics of it, because I am constantly finding myself asking "why is this better than just coding it in javascript". I'm trying to see how to make this simple example work, so that I can get past that question in my head and move forward with learning the language.
I have tried this with using "mounted" and using "created" to load the getCities method, while having the data portion of cities set to ''. Still no dice. When hard coding the cities with an array and/or JSON data, it loads exactly as expected.
UPDATE: I have adjusted the code as what is now shown in the javascript section. Using chrome tools, I can see that my cities variable is filled with an array of JSON objects, but I'm still not getting any data into the Select list. I'm completely at a loss as to why this isn't working, as well as why this seems to be so ridiculously difficult to do. And...this is literally just code to load a few cities into a drop down list.
Update 2: Apparently Vue will not let the item be updated from inside of a Fetch. I have updated the code to show my testing. My API returns the data fine, and I have verified it multiple times. I have tried hard coding the this.citys inside of the final fetch .then portion, and it doesn't work. But, when I hard code it outside of the fetch (as shown in the code above), it works fine. I'm to the point where I have to assume this is a limitation of Vue, which seems pretty crazy to me. I found one other question on Stackoverflow that had this same problem, but the answer literally just tells him to do exactly what I've been trying to do above. And, I'm unable to comment to ask if he found a solution, because I don't have enough reputation.
//Html
<div id="cityChoice">
/* <select > to load options on mounted use mounted hook*/
/* <select v-on:click="getCities"> to load options on click(whatever event)*/
<option v-for="city in cities">
{{ city.City }}
</option>
</select>
</div>
var app3 = new Vue({
el: '#cityChoice',
data(){
return {
cities:[],
err:false
}
},
methods:{
async getCities() {
//fetch -> assumption: the php call works -> u can use postman to test this
let data = await fetch('Controller/get_cities.php', {
method: 'GET', // *GET, POST, PUT, DELETE, etc.
})
//Data will likely have a data.data field
if( data in data && !data.error){
//Set data
this.cities = data.data //this assumes that data.data is correctly formatted from ur php call
}else{
this.err = true
}
}
},
//Add if you want data loaded on paint
created(){
// or mounted(){
this.getCities()
}
})
See hello world example
https://codesandbox.io/s/github/vuejs/vuejs.org/tree/master/src/v2/examples/vue-20-hello-world
Found information at this question that led me to the answer to mine.
Updating a vuejs alert component from a fetch return value
I will include my updated code in case someone happens past this question instead of the one linked here.
I had to update the response.text() to response.json(), but the biggest issue was the problem of the this not being recognized inside of the fetch function. I knew that, but in the middle of learning vue, I thought this would behave differently.
const cityChoice = {
data() {
return {
citys: [
{ Abbrev: 'Lima' },
{ Abbrev: 'FtWayne' },
],
err: false
}
},
methods: {
},
mounted() {
var self = this;
fetch('Controller/get_cities.php', {
method: 'POST', // *GET, POST, PUT, DELETE, etc.
cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
headers: {
// 'Content-Type': 'application/json'
'Content-Type': 'application/x-www-form-urlencoded',
},
redirect: 'follow', // manual, *follow, error
referrerPolicy: 'no-referrer', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
body: '' // body data type must match "Content-Type" header
}).then(function (response) {
return response.json();
}).then(function (data) {
self.citys = data;
});
},
methods: {
getCities() {
var self = this;
fetch('Controller/get_cities.php', {
method: 'POST', // *GET, POST, PUT, DELETE, etc.
cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached
headers: {
// 'Content-Type': 'application/json'
'Content-Type': 'application/x-www-form-urlencoded',
},
redirect: 'follow', // manual, *follow, error
referrerPolicy: 'no-referrer', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
body: '' // body data type must match "Content-Type" header
}).then(function (response) {
return response.json();
}).then(function (data) {
self.citys = data
});
}
}
}
Vue.createApp(cityChoice).mount('#cityChoice')
Hopefully this helps someone else who's trying to pick up the new language.
I'm using JQuery and AJAX to call a slow function in a PHP file, but I don't get a response until the PHP function is complete. I can't figure out why, despite 2 days of searching. I've shrunk it down to two test files, that exhibit exactly the same behaviour. My php function is thus, in a file called "ajaxfuncs.php":
<?php
Class AjaxFuncs{
public function __construct() {
$this->testbuffer ();
}
function testbuffer(){
echo 'Starting Test Buffer Output. There should be a 2 second delay after this text displays.' . PHP_EOL;
echo " <br><br>";
echo '<div id="testdata" class="testdata">0</div>';
// The above should be returned immediately
flush();
// Delay before returning anything else
sleep(2);
for ($a = 0; $a < 3; $a++) {
echo '<script type="text/javascript">document.getElementById("testdata").innerHTML="' . (int)($a + 1) . '"</script>';
flush();
// Delay for 1 second before updating the value
sleep(1);
}
}
}
$AjaxFuncs = new AjaxFuncs();
?>
The above works if I open the "ajaxfuncs.php" file in the browser. It does exactly as I'd expect, and the output updates every second until complete. So I know I've buffering sorted on the server.
But when I call it using the following $.ajax it's not right. I've put everything except the php for the ajax function into another php file called "testindex.php" for convenience. This is it:
<?php
header( 'Content-type: text/html; charset=utf-8' );
header("Cache-Control: no-store, must-revalidate");
header ("Pragma: no-cache");
header("Expires: Mon, 24 Sep 2012 04:00:00 GMT");
?>
<body>
<a>Test Page. Wait for it...</a>
<div id="maincontent">
</div>
</body>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.js"></script>
<script>
$(document).ready(function(){
console.log ('Document Ready');
function callajax(){
var ajaxfilepath = "ajaxfuncs.php";
return $.ajax({
url: ajaxfilepath,
data: {action: 'testbuffer'},
type: 'get',
cache: false,
dataType: "text",
beforeSend: console.log('Starting Ajax Operation')
})
.done(function(result){
processajaxcalloutput(result);
})
.always(function(){
console.log(' Ajax Internal Complete Detected');
})
.fail(function( jqXHR, textStatus ) {
console.log( "Ajax Request failed: " + textStatus );
});
}
function processajaxcalloutput(result){
var message = 'Processing Ajax Response' ;
console.log(message);
$("#maincontent").append(result);
}
callajax();
});
Everything works without error. Console is clear - no errors (I'm testing with Chrome & Firefox). But I can't seem to get a response until the entire PHP function is done. I've tried everything I can find, in particular hundreds of different things to force caching off, but to no avail. Any help is much appreciated. Thanks.
Update:
So based on the feedback so far, it's clear the call is asynchronous and the code is fine, but asynchronous does not mean I'll get a continuous stream of output data from the php function as it executes. Instead the entire response will be returned at the end of the execution. Rather than divert this question into one about streaming, I'll leave it at this until I resolve the streaming issue.
Here is what I'm trying to do:
I use an Ajax call to select messages from my database, I echo the content in my PHP and i try to get the echoed html in the Ajax success. But it does not work. Here is the code.
JQUERY:
function SelectMessages()
{
console.log("Selecting messages");
console.log("Talk = " + talk);
$.ajax({
url: "select_messages.php",
type: "GET",
data: "talk=" + talk,
success: function (html) {
alert(html);
console.log("In success");
$("#message_box").prepend(html)
},
error: function (html) {
alert(html);
console.log("In error");
}
});//ajax()
}//SelectMessages()
PHP:
<?php
//SELECTING MESSAGES
require 'dbconnect.php';
header('Cache-Control: no-cache, must-revalidate');
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Content-type: application/json');
if ($_GET['talk'] != "") {
$request = $bdd->prepare('SELECT AUTHOR,CONTENT FROM MESSAGE WHERE TALK = :talk');
$request->execute(array("talk"=>$_GET['talk']));
while ($data = $request->fetch(PDO::FETCH_ASSOC)) {
echo' <p> '.$data['CONTENT'].'</p>';
}
}
?>
Using this code, I get "In error" displayed on the console and the code in the alert is "[object Object]". However, the status of my query is "OK" in my browser and the echoed result in the network window is the one expected with all the right values of messages.
I just don't understand why I get through the error instead of success.
Please do not mark this as a duplicate as I have already checked and tested the Ajax/PHP solutions and did not get any result.
In your php file you have set content type header as follows
header('Content-type: application/json');
but normally echoed the response as plain text/html. Either you have to send the response in json.
echo json_encode($data['CONTENT']);
Or remove content-type header as json.
I've a function that parse Twitter search result and put into my HTML document. The code works!
Here is the code.
<script>
$(function update_twit(){
$("#notice_div").html('Updating..');
$.ajax({
url: "http://search.twitter.com/search.json?q=stackoverflow&rpp=2",
dataType: 'jsonp',
success: function(json_results){
$("#notice_div").html('');
$("#twitList").html('');
console.log(json_results);
$('#twitList').append('<ul data-role="listview" data-inset="true" data-theme="c"></ul>');
listItems = $('#twitList').find('ul');
$.each(json_results.results, function(key) {
html = '<p class="ui-li-bside">'+json_results.results[key].text+'</p>';
html += '<p class="ui-li-aside">Gönderen: <strong>'+json_results.results[key].from_user+'<strong></p>';
listItems.append('<li>'+html+'</li>');
});
// Need to refresh list after AJAX call
$('#twitList ul').listview();
window.setTimeout(update_twit, 10000);
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
$("#notice_div").html(errorThrown+'Error..'+textStatus);
window.setTimeout(update_twit, 60000);
}
});
})
</script>
The problem is I copy the Twitter url and paste into my browser. After getting response. I make a PHP document (getmyjson.php) like that
<?
header('Cache-Control: no-cache, must-revalidate');
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT');
header('Content-type: application/json');
$json='{"completed_in":0.021,"max_id":158455057786998785,"max_id_str":"158455057786998785","next_page":"?page=2&max_id=158455057786998785&q=erhan&rpp=2","page":1,"query":"erhan","refresh_url":"?since_id=158455057786998785&q=erhan","results":[{"created_at":"Sun, 15 Jan 2012 07:46:44 +0000","from_user":"_VCG_","from_user_id":169112180,"from_user_id_str":"169112180","from_user_name":"vedat can g\u00FCm\u00FC\u015F","geo":null,"id":158455057786998785,"id_str":"158455057786998785","iso_language_code":"tr","metadata":{"result_type":"recent"},"profile_image_url":"http://a3.twimg.com/profile_images/1710193374/bb_normal.png","profile_image_url_https":"https://si0.twimg.com/profile_images/1710193374/bb_normal.png","source":"<a href="http://twitter.com/">web</a>","text":"#erhan_ordu ben gidemiyom ya ama ke\u015Fke bi ihtimal olsa da gitsem :D bi de VGC DE\u011E\u0130L VCG VCG :d","to_user":"erhan_ordu","to_user_id":458677081,"to_user_id_str":"458677081","to_user_name":"ERHAN ORDU"},{"created_at":"Sun, 15 Jan 2012 07:39:34 +0000","from_user":"hannyfaarah","from_user_id":199700684,"from_user_id_str":"199700684","from_user_name":"H\u2639","geo":null,"id":158453256241168384,"id_str":"158453256241168384","iso_language_code":"in","metadata":{"result_type":"recent"},"profile_image_url":"http://a2.twimg.com/profile_images/1736543252/cats_normal.jpg","profile_image_url_https":"https://si0.twimg.com/profile_images/1736543252/cats_normal.jpg","source":"<a href="http://twitter.com/">web</a>","text":"\"mantan bebep erhan tersayang selalu dihati\" HAHAHAHA emir emir ngakak weeey","to_user":null,"to_user_id":null,"to_user_id_str":null,"to_user_name":null}],"results_per_page":2,"since_id":0,"since_id_str":"0"}';
echo $json;
?>
Now i am trying to change Twitter URL in the first code to www.mywebiste.com/getmyjson.php
But it does not work!
Error message is : jQuery164018531796569004655_1326623562322 was not calledError.parsererror
For you local server testing switch to usual json instead of jsonp. So it becomes:
$.ajax({
//url: "http://search.twitter.com/search.json?q=stackoverflow&rpp=2",
//dataType: 'jsonp',
url: 'getmyjson.php',
dataType: 'json',
...
});
Or if you still want to use jsonp change your php script as follows:
$json = '{...}';
echo $_GET['callback'] . '(' .$json . ')';