Problems doing ajax-requests with a Phonegap application - php

I'm trying to create a simple RSS reader with Phonegap and jQuery.
I am following this tutorial: http://visualrinse.com/2008/09/24/how-to-build-a-simple-rss-reader-with-jquery/.
I've managed to get this working just fine when I try out the code in my browser. The php-file fetches the feed and outputs it just like I expect it to. But when I run the same file from within my compiled Phonegap application the ajax-request just returns the contents of the php-file (the php-code, not the executed result).
I've spent hours Googling this and tried numerous tutorials and tweaks. I found no solutions in the offical Phonegap forums either. What am I doing wrong? The problem seems to be PHP not responding to the request. I've tried to move the php-file to a different domain but the result is the same, it works in my browser but not in the compiled app.
Here's the jQuery code that initiates the ajax-code:
function get_rss_feed() {
//clear the content in the div for the next feed.
$("#feed_content").empty().html('<img class="loader" src="js/images/ajax-loader.gif" alt=""/>');
$.ajax({
url: 'http://192.168.1.7/rssApp/www/rss-proxy.php?url=http://www.nytimes.com/services/xml/rss/nyt/GlobalHome.xml',
success: function parseRSS(d) {
//find each 'item' in the file and parse it
$(d).find('item').each(function() {
//name the current found item this for this particular loop run
var $item = $(this);
// grab the post title
var title = $item.find('title').text();
// grab the post's URL
var link = $item.find('link').text();
// next, the description
var description = $item.find('description').text();
//don't forget the pubdate
var pubDate = $item.find('pubDate').text();
// now create a var 'html' to store the markup we're using to output the feed to the browser window
var html = "<div class=\"entry\"><h2 class=\"postTitle\">" + title + "<\/h2>";
html += "<em class=\"date\">" + pubDate + "</em>";
html += "<p class=\"description\">" + description + "</p>";
html += "<a href=\"" + link + "\" target=\"_blank\">Read More >><\/a><\/div>";
//put that feed content on the screen!
$('#feed_content').append($(html));
});
$('#feed_content img.loader').fadeOut();
}
});
};
Here's the rss-proxy.php that loads the XML from the url and outputs it:
<?php
// PHP Proxy
// Loads a XML from any location. Used with Flash/Flex apps to bypass security restrictions
// Author: Paulo Fierro
// January 29, 2006
// usage: proxy.php?url=http://mysite.com/myxml.xml
$session = curl_init($_GET['url']); // Open the Curl session
curl_setopt($session, CURLOPT_HEADER, false); // Don't return HTTP headers
curl_setopt($session, CURLOPT_RETURNTRANSFER, true); // Do return the contents of the call
$xml = curl_exec($session); // Make the call
header("Content-Type: text/xml"); // Set the content type appropriately
echo $xml; // Spit out the xml
curl_close($session); // And close the session
?>

I've finally managed to solve this!
It turns out that you need to whitelist the server you wish to request from your PhoneGap application in Xcode if you want to do requests to a certain domain (be it your localhost or whatever).
The reason that I didn't found this out earlier was that I didn't check for errors in the ajax response. Once I did that I got the http status code 401 (Unauthorized) and error message "Whitelist rejected".
To fix this I opened the file PhoneGap.plist in my project and under the key ExternalHosts i added a new item with the value: *.localhost.
I also changed the ajax url to:
url: 'http://localhost/rssApp/www/rss-proxy.php?url=http://www.nytimes.com/services/xml/rss/nyt/GlobalHome.xml'
I compiled and run the application on the iOS Simulator and my localhost server responded with a perfectly successful ajax response!
For every external host that you wish your application to connect to you must add it to the list of ExternalHosts. For example if you wish to access an API on http://google.com/maps/api.php you must add *.google.com to your list.
Kind of annoying when you try to figure out why the server isn't responding, but I guess it's good for security reasons. Hope this helps someone else out there who's struggling with simple ajax requests from their PhoneGap application!

It looks like you are running your server locally (based on the 192.168.x.x IP address) which means that only devices connnected to your network can access it. You could connect the phone to the same wifi network as your computer as a temporary fix. But you're going to need to host this on a real server for it to be accessible over the internet.
You could also forward port 80 on your router to this IP address and then use your actual IP address (see whatsmyip.org) in your request url. But that's not a really stable solution.

Related

Save file from post response on button click in wordpress

A task:
The user, by clicking on the button, should be able to download and save the file.
The file is creating on another service. It can be obtained by post-request with body and headers.
I am using wordpress and my plugin. I can call a php function using form or jquery.
//Accept: application/pdf
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
$res = curl_exec($ch);
This returns the headers and response body as a string.
(My asp .Net 6 external service returns FileStreamResult from method)
I don't know how to implement saving a file on the user's PC.
As far as I understand, I have two ways:
Download the file using curl on the server side. Then somehow transfer the ready file to the user for saving.
But then there will be an extra load on the backend.
I can create request body and headers on backend. Then execute this post request on the client side.
I am weak in web development...
I think the right way is to make a function on the backend that will return a json with the request body and headers.
I can create a separate php page (I think it's redundant) that will call this function. Or I can call this function from javascript or jquery, but I don't know how to initialize post request to save the file.
Maybe someone has already implemented this behavior and can tell me?
Thanks.
upd. #1
I found this solution:
var request = new XMLHttpRequest();
request.responseType = "blob";
request.open("POST", url, true);
request.setRequestHeader("Content-Type", "application/json");
request.onload = function() {
var url = window.URL.createObjectURL(this.response);
var a = document.createElement("a");
document.body.appendChild(a);
a.href = url;
a.download = this.response.name || "filename"
a.click();
}
request.send(json);
But it looks like a dirty hack.
And it does not work as it should (the file is first downloaded before saving).
upd. #2
I'm willing to change the method from POST to GET, but I still need to pass the ApiKey in the header.
I think my issue is discussed here: https://github.com/whatwg/html/issues/7810
So far, I have not found a way that implements both points:
Adding custom headers to the request.
Showing the file save dialog before it is downloaded.

Google drive api file_get_contents and refferer

I am trying to list files from google drive folder.
If I use jquery I can successfully get my results:
var url = "https://www.googleapis.com/drive/v3/files?q='" + FOLDER_ID + "'+in+parents&key=" + API_KEY;
$.ajax({
url: url,
dataType: "jsonp"
}).done(function(response) {
//I get my results successfully
});
However I would like to get this results with php, but when I run this:
$url = 'https://www.googleapis.com/drive/v3/files?q='.$FOLDER_ID.'+in+parents&key='.$API_KEY;
$content = file_get_contents($url);
$response = json_decode($content, true);
echo json_encode($response);
exit;
I get an error:
file_get_contents(...): failed to open stream: HTTP request failed! HTTP/1.0 403 Forbidden
If I run this in browser:
https://www.googleapis.com/drive/v3/files?q={FOLDER_ID}+in+parents&key={API_KEY}
I get:
The request did not specify any referer. Please ensure that the client is sending referer or use the API Console to remove the referer restrictions.
I have set up referrers for my website and localhost in google developers console.
Can someone explain me what is the difference between jquery and php call and why does php call fails?
It's either the headers or the cookies.
When you conduct the request using jQuery, the user agent, IP and extra headers of the user are sent to Google, as well as the user's cookies (which allow the user to stay logged in). When you do it using PHP this data is missing because you, the server, becomes the one who sends the data, not the user, nor the user's browser.
It might be that Google blocks requests with invalid user-agents as a first line of defense, or that you need to be logged in.
Try conducting the same jQuery AJAX request while you're logged out. If it didn't work, you know your problem.
Otherwise, you need to alter the headers. Take a look at this: PHP file_get_contents() and setting request headers. Of course, you'll need to do some trial-and-error to figure out which missing header allows the request to go through.
Regarding the referrer, jQuery works because the referrer header is set as the page you're currently on. When you go to the page directly there's no referrer header. PHP requests made using file_get_contents have no referrer because it doesn't make much sense for them to have any.

PHP: How to send cookies with REST API call by clicking on a link?

I'm new to the REST APIs style of web development. I have to send 2 cookies along with 1 REST API. How do I send them together by clicking on a link?
For example, if an user clicks on the link, it is supposed to make the REST API call and send the cookie along with it. I know how to do it in the cURL but I am confused as to how I can trigger that via a link. Ideally, the user should be able to download a zip file by clicking the link. The link should call the REST API and send 2 cookies over to get the zip file. I am able to get the raw code of the zip file using the following code but is not able to achieve that by clicking on the link.
$getResultsDetails = curl_init();
$getResults_service_url = '<URL of the REST API call>';
curl_setopt($getResultsDetails,CURLOPT_URL,$getResults_service_url);
curl_setopt($getResultsDetails,CURLOPT_COOKIE,"LWSSO_COOKIE_KEY=".$LWSSO_COOKIE_KEY.";QCSession=".$QCSession);
curl_setopt($getResultsDetails, CURLOPT_RETURNTRANSFER, true); //get response
$getResults_service_url_response = curl_exec($getResultsDetails);
curl_setopt($getResultsDetails, CURLOPT_RETURNTRANSFER, true);
if ($getResults_service_url_response === false) {
$info = curl_getinfo($getResultsDetails);
curl_close($getResultsDetails);
die('error occured during curl exec. Additional info: ' . var_export($info));
}
curl_close($getResultsDetails);
Any ideas how I can achieve that?
This is mostly a duplicate of this but with the added 'how do I?' part. So, heres the bit to add to the answer of that question.
just use a link to direct your user to the php script making the call.
you can do this in 2 ways:
1.
click me
read this answer for details on how to do the cookie part.
or
2. use an ajax call using jquery:
from jquery docs
$.ajax({
type: "POST",
url: "path/to/yourCurlScript.php",
data: data,
success: success,
dataType: dataType
});
same script is called, so process cookies in the same way.
for the best user experience I would probably opt for number 2. I dont know what it is that youre planning on retrieving from the API, but you can pipe it into a file using either.

Offer file download

I am currently working on an AngularJS project with a server backend written in PHP. The frontend and backend communicate entirely in JSON, however, there is an export scenario where the server's output is not JSON encoded but instead a (text or binary) file.
The web application cannot just redirect the client's browser to a download URL as the server requires custom headers in the HTTP request (i.e. an API key) to serve the file. Therefore, I am using $http in AngularJS to initiate an AJAX request. Here is what happens:
File generation on the server side (using PHP with Slim framework):
$export = $this->model->export_cards($project_key);
$this->app->response()->status(200);
$this->app->response()->header("Content-Type", "text/plain");
$this->app->response()->header("Content-Disposition", "attachment; filename=\"export.txt\"");
$this->app->response()->header("Last-Modified", date("r");
$this->app->response()->header("Cache-Control", "cache, must-revalidate");
$this->app->response()->body($export);
$this->app->stop();
This is what happens on the client side (so far):
$http({
method: "get",
url: "/server/projects/cards/export_cards/" + $scope.key,
headers: {
"X-API-Key": session_service.get("api_key")
}
}).then(
function(response)
{
// Success, data received
var data = response.data; // This variable contains the file contents (might be plain text, or even binary)
// How do I get the browser to offer a file download dialog here?
},
function(response)
{
// Error handling
}
);
I successfully receive the file contents in the AngularJS frontend and store them in a variable data. How do I get the browser to display a file download dialog?
The solution must work in Internet Explorer 10+ and reasonably recent versions of Firefox, Chrome and Safari (only desktop versions).
What is the best way to achieve this?
Thank you for your help and let me know if I need to provide any additional information.
Peter
I'm not sure this is possible.
Could you either:
Supply the API key directly, eg:
location.href = "/server/projects/cards/export_cards/" + $scope.key + '?api_key=' + session_service.get("api_key");
Or, have your API return a temporary, time-expiring URL for the file download, and then use location.href to access this URL.

Outputting file contents as binary as AJAX response

OK the title doesn't give much a way so let me explain my very strange set-up.
Two servers are involved:
website: remote
localhost: local machine
The workflow is as follows:
The site calls localhost via cross-domain AJAX
In response localhost dynamically creates a ZIP file via PHP's ZipArchive lib
localhost conveys the raw data that comprises the archive as the AJAX response
The request is made and the archive is made - all good. The archive is openable, all good. What I'm stuck on now is how to convey that archive as the AJAX response, such that it can be "put together again" (à la Humpty Dumpty). When I do this currently (via file_put_contents()) it errors on opening, saying it's invalid. Currently I'm just outputting the archive's raw data:
echo file_get_contents('path/to/archive.zip');
This is fine, but sends garbled characters in the response. I don't know much about encoding and headers, so apologise if this seems obvious.
For the response, should I be looking to convert it to binary, or sending certain headers etc? I tried sending the multipart/form-data header, but no dice. Headers aren't my strong point.
Please note cURL is not an option in this scenario, else I'd be laughing.
You have to read the zip file as a binary data with Blob javascript class.
This is a code snippet from Mozilla documentation
var oReq = new XMLHttpRequest();
oReq.open("GET", "/myfile.png", true);
oReq.responseType = "arraybuffer";
oReq.onload = function(oEvent) {
var blob = new Blob([oReq.response], {type: "application/octet-stream"}); //
// you have nothing to do with the blob...
// ...
};
oReq.send();
Then send this file (blob) with POST method to your destination
var oReq = new XMLHttpRequest();
oReq.open("POST", url, true);
oReq.onload = function (oEvent) {
// Uploaded.
};
oReq.send(blob); //the blob that you loaded
you can read more in the documentation by Mozilla :https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Sending_and_Receiving_Binary_Data

Categories