I am currently working on a web2print project based on Adobes Scene7. The full url to a print product (pdf) is very long and exceeds all browser limitation of url length. So to get the final print product I assume I have to submit the url in a different way via POST method.
There seem to be two ways: First, use a html form (method=post) and create all url parameters as (hidden) input fields. Second, make an ajax call (e.g. jQuery.ajax) with post.
Actually if I would open the print url in the browser, the ready pdf would be opened within the browser. So I need a way to send the very long url via POST to the server and open the PDF I get back from it. Testing the ajax version I ran into the same-origin-policy and get an error, as I call a url not on my local server. This must be a standard situation in web2print projects, how is this handled?
Thx in advance
Michbeck
I got the problem solved. I did it in two steps. First I use ajax to send the base url and the url parameters to a php script on my local server. It is easily done with jQuery:
jQuery.ajax({
type : "POST",
url : './includes/php/userdata.php',
data: { method: 'get_print_version',
url: base_url,
parameter: query_parameter,
num: num_parameter },
error: function(error) {
console.log("Print version failed");
},
success: function(reault) {
console.log("What is the result?");
}
});
The server script uses cURL to send the data to the final server. Therefore the base url and the parameters are not posted as one url but seperated by the use of CURLOPT_POST and CURLOPT_POSTFIELDS. The server response (a pdf) can be written to file with file_put_contents. If the PDF gets to big, you will get a memory limitation error here. Than it is better to write the answer from cURL directly to the pdf file.
if ($_method == 'get_print_version')
{
$url = $_REQUEST['url'];
$parameter = $_REQUEST['parameter'];
$num = $_REQUEST['num'];
$post = curl_init();
curl_setopt($post, CURLOPT_URL, $url);
curl_setopt($post, CURLOPT_POST, $num);
curl_setopt($post, CURLOPT_POSTFIELDS, $parameter);
/* write calendar directly to file */
$pdf = fopen('./Calendar.pdf', 'w');
curl_setopt($post, CURLOPT_FILE, $pdf);
curl_exec($post);
curl_close($post);
echo $result;
}
Related
I would like to return a file in my controller that is downloaded from an API (who needs a basic auth).
This API returns the file and the problem is I can't use ajax because of Access-Control-Allow-Origin, even when I add the basic auth in the header, it returns this error. And I don't have access to this API so I can't change it the config.
So I found another way! I call this API from my controller with the header and the basic auth. It's working! I can access this API and I don't have the error message: Access-Control-Allow-Origin.
But the problem is the API returns heavy files, and I have this exception OutOfMemoryException. It's normal.
So I would like to returns in my controller just a redirect link to this API with the header and basic auth to download the file. Do you think it's possible?
An example of what I want (But it's not working):
public function indexAction()
{
// API
$url = "http://api-who-callback-a-file.com/api/file";
//Create header
$curl = curl_init();
$url = sprintf("%s?%s", $url, http_build_query(false));
// Optional Authentication:
curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_setopt($curl, CURLOPT_USERPWD, "admin:admin");
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
// Get file (Problem here because the file is to heavy to be downloaded by the server)
$result = curl_exec($curl);
curl_close($curl);
// Return the file
return $this->file($result);
}
In this example, it's not working because the server download the file and it's too heavy. Me I just want to return the URL with the Header to the client, and he will download the file.
Thank you
I am trying to pass parameter from my controller to my view.
My code is like this:
$this->redirect(array('marketingEmail/mailToSend','lot'=>$lotNum));
public function actionMailToSend()
{
$lotValue = Yii::app()->request->getQuery('lot');
$model=new Marketing();
$this->render('_mailList',array(
'lotVal'=>$lotValue,'model'=>$model,
));
}
My current url is like: http://localhost/test/marketingEmail/mailToSend/lot/1.
I want my url like: http://localhost/test/marketingEmail/mailToSend.
how can I achieve this?
No, it is not possible.
You can use session variable for your purpose. Save your id in session and get this id in your redirected page.
For more solution you can refer this URL.
No, it's impossible to make HTTP POST redirect using PHP. The only way to do it using user's browser side. For example generate page with form and submit it from window.onload.
You could perhaps use curl_exec on a REST API function that accepts a POST.
David Walsh wrote an article in 2008 entitled: Execute a HTTP POST Using PHP CURL
Quoting from the blog post:
//open connection
$ch = curl_init();
//set the url, number of POST vars, POST data
curl_setopt($ch,CURLOPT_URL, $url);
curl_setopt($ch,CURLOPT_POST, count($fields));
curl_setopt($ch,CURLOPT_POSTFIELDS, $fields_string);
//execute post
$result = curl_exec($ch);
//close connection
curl_close($ch);
Otherwise, use javascript.
The following function transfers a curl delete request to an api, and returns the response to php.
The api returns a json array for all requests (get, post, put and delete), and everything works fine for everything except delete requests.
The following curl function doesn't seem to be working properly:
function curl_delete($url)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "DELETE");
curl_setopt($ch, CURLOPT_URL,$url);
$result = curl_exec($ch);
curl_close($ch);
return $result; // <-- Function ALWAYS returns whether this is here or not??!..
}
This is how I call the function from PHP:
// [DELETE API URL]:
$url = 'http://localhost/website/api/users/user/id/123';
$html = json_decode(curl_delete($url), true);
If you look at the function (above), whether or not I include the return statement (at the end of the function), the result of the curl call (the jsonified array) always gets dumped to the browser after the function has completed - which is not what I want.
If I then say echo count($html), the correct length of the returned result will print, and the $html array is working fine, however I can't seem to prevent it from automatically dumping to the screen.
This does not happen for any of the other curl functions, which just work as expected.
QUESTION:
Is this normal behaviour? How do I prevent the json from dumping to the screen?
PS Using Codeigniter & Phil Sturgeon's REST Server
You should try Phil Sturgeon's cURL library for Codeigniter and its method simple_delete() :
$this->load->library('curl');
$url = 'http://localhost/website/api/users/user/id/123';
$response = $this->curl->simple_delete($url);
$html = json_decode($response, TRUE);
If it does not solve your problem, maybe you will have to take a closer look at your REST server.
This a screen shot of what I get when I call my ajax request:
How do I run only the task, without printing the whole page? This is my ajax call:
$.ajax
({
type: "POST",
url: "index.php?option=com_similar&task=abc",
data: {
id: id,
name: name,
similar_id: similar_id,
},
cache: false,
success: function(html)
{
$("#flash").fadeOut("slow");
$("#content"+similar_id).html(html);
}
});
});
$(".close").click(function()
{
$("#votebox").slideUp("slow");
});
});
Don't go with exit or die, Joomla! has it's nice way of dealing with this stuff.
The answers below are tested in Joomla! 2.5 & 3 (for 1.5. may work as well).
General
Your URL for the task needs to look like this:
index.php?option=com_similar&task=abc&format=raw
You than create the controller which will use the view, let's say Abc, which will contain the file view.raw.html (identical to a normal view file).
Below you have the code for generate a raw HTML response:
/controller.php
public function abc()
{
// Set view
JRequest::setVar('view', 'Abc');
parent::display();
}
/views/abc/view.raw.php
<?php
defined('_JEXEC') or die;
jimport('joomla.application.component.view');
class SimilarViewAbc extends JView
{
function display($tpl = null)
{
parent::display($tpl);
}
}
/views/abc/tmpl/default.php
<?php
echo "Hello World from /views/abc/tmpl/default.php";
Note: This is the solution I would use if I had to return HTML (it's cleaner and follows Joomla logic). For returning simple JSON data, see below how to put everything in the controller.
If you make your Ajax request to a subcontroller, like:
index.php?option=com_similar&controller=abc&format=raw
Than your subcontroller name (for the raw view) needs to be abc.raw.php.
This means also that you will / may have 2 subcontrollers named Abc.
If you return JSON, it may make sense to use format=json and abc.json.php. In Joomla 2.5. I had some issues getting this option to work (somehow the output was corrupted), so I used raw.
If you need to generate a valid JSON response, check out the docs page Generating JSON output
// We assume that the whatver you do was a success.
$response = array("success" => true);
// You can also return something like:
$response = array("success" => false, "error"=> "Could not find ...");
// Get the document object.
$document = JFactory::getDocument();
// Set the MIME type for JSON output.
$document->setMimeEncoding('application/json');
// Change the suggested filename.
JResponse::setHeader('Content-Disposition','attachment;filename="result.json"');
echo json_encode($response);
You would generally put this code in the controller (you will call a model which will return the data you encode - a very common scenario). If you need to take it further, you can also create a JSON view (view.json.php), similar with the raw example.
Security
Now that the Ajax request is working, don't close the page yet. Read below.
Don't forget to check for request forgeries. JSession::checkToken() come in handy here. Read the documentation on How to add CSRF anti-spoofing to forms
Multilingual sites
It may happen that if you don't send the language name in the request, Joomla won't translate the language strings you want.
Consider appending somehow the lang param to your request (like &lang=de).
New in Joomla 3.2! - Joomla! Ajax Interface
Joomla now provides a lightweight way to handle Ajax request in a plugin or module. You may want to use the Joomla! Ajax Interface if you don't have already a component or if you need to make requests from a module your already have.
If you just want to include the response output in some HTML element, append format=raw to your URL as mentioned above. Then you could have a controller function like this:
function abc(){
//... handle the request, read variables, whatever
print "this is what I want to place in my html";
}
The AJAX response will output everything you printed / echoed in the controller.
I know that lots of social network APIs provide a way to construct a url to the profile picture of a user, using their user_id or username. For Facebook it looks like this:
http://graph.facebook.com/user_id/picture?type=square
Now is there something like this for Google Plus? Or any other way to get user's pic without an API call??
Google had changed their policy so the old way for getting the Google profile image will not work now, which was
https://plus.google.com/s2/photos/profile/(user_id)?sz=150
New Way for doing this is
Request URL
https://www.googleapis.com/plus/v1/people/115950284...320?fields=image&key={YOUR_API_KEY}
That will give the Google profile image url in json format as given below
Response :
{
"image":
{
"url": "https://lh3.googleusercontent.com/-OkM...AANA/ltpH4BFZ2as/photo.jpg?sz=50"
}
}
More parameters can be found to send with URL which you may need from here
For more detail you can also check the given question where I have answered for same type of problem
How to get user image through user id in Google plus?
UPDATE: The method below DOES NOT WORK since 2015
It is possible to get the profile picture, and you can even set the size of it:
https://plus.google.com/s2/photos/profile/<user_id>?sz=<your_desired_size>
Example: My profile picture, with size set to 100 pixels:
https://plus.google.com/s2/photos/profile/116018066779980863044?sz=100
Usage with an image tag:
<img src="https://plus.google.com/s2/photos/profile/116018066779980863044?sz=100" width="100" height="100">
Hope you get it working!
UPDATE: Google stopped support for this method, that now returns a 404 (not found) error.
All this urls fetch the profile picture of a user:
https://www.google.com/s2/photos/profile/{user_id}
https://plus.google.com/s2/photos/profile/{user_id}
https://profiles.google.com/s2/photos/profile/{user_id}
They redirect to the same image url you get from Google API, an ugly link as
lh6.googleusercontent.com/-x1W2-XNKA-A/AAAAAAAAAAI/AAAAAAAAAAA/ooSNulbLz8U/photo.jpg
The simplest is to directly use like image source:
<img src="https://www.google.com/s2/photos/profile/{user_id}">
Otherwise to obtain exactly the same url of a Google API call you can read image headers,
for example in PHP:
$headers = get_headers("https://www.google.com/s2/photos/profile/{user_id}", 1);
echo "<img src=$headers[Location]>";
as described in article Fetch Google Plus Profile Picture using PHP.
Approach 1: (no longer works)
https://plus.google.com/s2/photos/profile/<user_id>?sz=<your_desired_size>
Approach 2: (each request counts in your api rate limits which is 10k requests per day for free)
https://www.googleapis.com/plus/v1/people/<user_id>?fields=image&key={YOUR_API_KEY}
with the following response format:
{ "image": { "url": "lh5.googleusercontent.com/-keLR5zGxWOg/.../photo.jpg?sz=50"; } }
Approach 3: (donot require api key)
http://picasaweb.google.com/data/entry/api/user/<user_id>?alt=json
in the json response you get a property named "gphoto$thumbnail", which contains the profile picture url like the following:
http://lh6.ggpht.com/-btLsReiDeF0/AAAAAAAAAAI/AAAAAAAAAAA/GXBpycNk984/s64-c/filename.jpg
You may notice in the url the portion "s64-c" which means the image size to be 64, I've tried using other values like "s100-c" and they worked. Also if you remove the "s64-c" part and append the "?sz=100" parameter, that will also work as of now. Though this is not very good way of getting the profile picture of a gplus user, but the advantage is it do not require any api key.
Google, no API needed:
$data = file_get_contents('http://picasaweb.google.com/data/entry/api/user/<USER_ID>?alt=json');
$d = json_decode($data);
$avatar = $d->{'entry'}->{'gphoto$thumbnail'}->{'$t'};
// Outputs example: https://lh3.googleusercontent.com/-2N6fRg5OFbM/AAAAAAAAAAI/AAAAAAAAADE/2-RmpExH6iU/s64-c/photo.jpg
CHANGE: the 64 in "s64" for the size
If you want to show the profile picture for the currently logged in user, you do not even need to know the {user_id}. Simply using https://plus.google.com/s2/photos/profile/me will be enough.
2020 Solution
Please comment if no longer available.
In order to get profile URL from authenticated user.
GET https://people.googleapis.com/v1/people/[THE_USER_ID_OF_THE_AUTHENTICATED_USER]?personFields=photos&key=[YOUR_API_KEY] HTTP/1.1
Authorization: Bearer [YOUR_ACCESS_TOKEN]
Accept: application/json
Response:
{
"resourceName": "people/[THE_USER_ID_OF_THE_AUTHENTICATED_USER]",
"etag": "12345",
"photos": [
{
"metadata": {
"primary": true,
"source": {
"type": "PROFILE",
"id": "[THE_USER_ID_OF_THE_AUTHENTICATED_USER]"
}
},
"url": "https://lh3.googleusercontent.com/a-/blablabla=s100"
}
]
}
and the link can be used as:
<img src="https://lh3.googleusercontent.com/a-/blablabla=s100">
You can get the URL for the profile image using the people.get method of the Google+ API. That does require an extra round trip, but is the most reliable way to get the image.
You technically can also use the URL https://s2.googleusercontent.com/s2/photos/profile/{id}?sz={size} which will then redirect to the final URL. {id} is the Google user ID or one of the old Google Profiles usernames (they still exist for users who had them, but I don't think you can create new ones anymore). {size} is the desired size of the photo in pixels. I'm almost certain this is not a documented, supported feature, so I wouldn't rely on it for anything important as it may go away at anytime without notice. But for quick prototypes or small one-off applications, it may be sufficient.
trying to access the /s2/profile/photo url works for most users but not all.
The only full proof method is to use the Google+ API. You don't need user authentication to request public profile data so it's a rather simple method:
Get a Google+ API key on https://cloud.google.com/console
Make a simple GET request to: https://www.googleapis.com/plus/v1/people/+< username >?key=
Note the + before the username.
If you use user ids instead (the long string of digits), you don't need the +
you will get a very comprehensive JSON representation of the profile data which includes:
"image":{"url": "https://lh4.googleusercontent.com/..... the rest of the picture url...."}
If you use Flutter, then you can access it via people.googleapis.com endpoint, code uses google_sign_in library
import 'package:google_sign_in/google_sign_in.dart';
Future<String> getPhotoUrl(GoogleSignInAccount account, String userId) async {
// final authentication = await account.authentication;
final url = 'https://people.googleapis.com/v1/people/${userId}?personFields=photos';
final response = await http.get(
url,
headers: await account.authHeaders
);
final data = json.decode(response.body);
return data['photos'].first['url'];
}
You will get something like
{
resourceName: people/998812322529259873423,
etag: %EgQBAzcabcQBAgUH,
photos: [{metadata: {primary: true, source: {type: PROFILE, id: 107721622529987673423}},
url: https://lh3.googleusercontent.com/a-/abcdefmB2p1VWxLsNT9WSV0yqwuwo6o2Ba21sh_ra7CnrZ=s100}]
}
where url is an accessible image url.
Tried everything possible.. here is final piece of working code. Hope it helps someone who is looking for it.
<?
$url='https://www.googleapis.com/plus/v1/people/116599978027440206136?fields=image%2Furl&key=MY_API_KEY&fields=image';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_PROXYPORT, 3128);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
$response = curl_exec($ch);
curl_close($ch);
$d = json_decode($response);
$avatar_url = $d->{'image'}->{'url'};
echo $avatar_url;
?>
Simple answer: No
You will have to query the person API and the take the profile image.url data to get the photo. AFAIK there is no default format for that url that contains the userID.