Handle CURL headers before downloading body - php

Using PHP and CURL (unless there is a better alternative then CURL in this case), is it possible to have a php function handle the header response before downloading the file?
For example:
I have a script that downloads and processes urls supplied by the user. I would like to add a check so that if the file is not valid for my process (not a text file, too large, etc),the CURL request would be cancelled before the server wastes time downloading the file.
Update: Solution
PEAR class HTTP_Request2: http://pear.php.net/package/HTTP_Request2/
Gives you the ability to set observers to the connection and throw exceptions to cancel anytime. Works perfectly for my needs!

Using cURL, do a HTTP HEAD request to check the headers, then if it is valid (the status is 200) do the full HTTP GET request.
The basic option you must set is CURLOPT_NOBODY, which changes the requested to the type HEAD
curl_setopt($ch, CURLOPT_NOBODY, true);
Then after executing the query, you need to check the return status which can be done using curl_getinfo()
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);

I know this is an old topic but just in case people comes here in the future.
With CURL, you can use CURLOPT_WRITEFUNCTION, who let's you place a callback that will be called as soon as the body response starts coming and needs to be written. In that moment you can read the headers and cancel the process and the body will not be downloaded. All in one request.
For a deeper look and code examples see PHP/Curl: inspecting response headers before downloading body

This is an example how you can solve it:
// Include the Auth string in the headers
// Together with the API version being used
$headers = array(
"Authorization: GoogleLogin auth=" . $auth,
"GData-Version: 3.0",
);
// Make the request
curl_setopt($curl, CURLOPT_URL, "http://docs.google.com/feeds/default/private/full");
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
$response = curl_exec($curl);
curl_close($curl);
// Parse the response
$response = simplexml_load_string($response);
// Output data
foreach($response->entry as $file)
{
//now you can do what ever if file type is a txt
//if($file->title =="txt")
// do something
else
// do soething
echo "File: " . $file->title . "<br />";
echo "Type: " . $file->content["type"] . "<br />";
echo "Author: " . $file->author->name . "<br /><br />";
}

Related

How to send data to another computer via php?

I was wondering whether there is a way to send data from index.php opened on one computer to index.php opened on another one.
I don't have an idea how to do it.
Yes.
Easy/lazy way: just do a remote get request
// example1.com/index.php
file_get_contents("http://example2.com/index.php?your_data=goes_here");
// example2.com/index.php
$your_data = $_GET['your_data'];
Harder/better way: use curl to send a post request
// on example1.com/index.php
$ch = curl_init();
curl_setopt($ch,CURLOPT_URL, "http://example2.com/index.php");
curl_setopt($ch,CURLOPT_POST, 1);
curl_setopt($ch,CURLOPT_POSTFIELDS, 'your_data' => 'goes_here');
$result = curl_exec($ch);
curl_close($ch);
// on example2.com/index.php
$your_data = $_POST['your_data'];
WARNING: Anyone will be able to input anything they want into your scripts with either of these methods. Make sure to encrypt and/or validate any data you're transmitting in this way.
Yes, assuming the computers are able to connect then the obvious way to do it is via HTTP:
<?php
$message="Hello otherhost!";
$response=file_get_contents("http://otherhost.example.com/?data="
. urlencode($message));
print "I said \"$message\"<br />\nand other host replied \""
. htmlentities($response) . "\"";
?>
<?php
if (isset($_GET['data'])) {
print "Hello - you just said \"" . htmlentities($_GET["data"]) . "\"";
} else {
print "Sorry - I can't hear you";
}
?>

How to use GET in PHP with OneNote API?

I've got the OneNote API PHP Sample (thanks jamescro!) working with all the POST examples, but there's no GET example and I haven't managed to put together code of my own that works. Here's what I've tried without success:
// Use page ID returned by POST
$pageID = '/0-1bf269c43a694dd3aaa7229631469712!93-240BD74C83900C17!600';
$initUrl = URL . $pageID;
$cookieValues = parseQueryString(#$_COOKIE['wl_auth']);
$encodedAccessToken = rawurlencode(#$cookieValues['access_token']);
$ch = curl_init($initUrl);
curl_setopt($ch, CURLOPT_URL, $initUrl); // Set URL to download
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
if (! $response === false) {
curl_close($ch);
echo '<i>Response</i>: '. htmlspecialchars($response);
}
else {
$info = curl_getinfo($ch);
curl_close($ch);
echo '<i>Error</i>: ';
echo var_export($info);
}
It just returns 'Error' with an info dump. What am I doing wrong?
without information on the specific error I'm not sure what issue you are hitting. Try looking at the PHP Wordpress plugin here: https://github.com/wp-plugins/onenote-publisher/blob/master/api-proxy.php
look at what is sent to wp_remote_get - there are necessary headers that are needed.
Also make sure you have the scope "office.onenote" when you request the access token.
If you need more help, please add information about the specific URL you are attempting to call, as well as the contents of your headers. If you have any errors, please include the output.
Solved:
As Jay Ongg pointed out, "there are necessary headers that are needed".
After adding more detailed error checking and getting a 401 response code, I added:
curl_setopt($ch, CURLOPT_HTTPHEADER, array("Content-Type:text/html\r\n".
"Authorization: Bearer ".$encodedAccessToken));
... and could access the requested page.

Redirecting an HTTP POST

Ok, so in my web app's API I have an incoming HTTP post request.
I would like to pass that POST request on to a different server, without losing the data in the POST header. Is this possible? which type of redirect would I use? php examples?
Edit: The HTTP request is coming from a mobile app, not a web browser.
Thanks!
You could use cURL or sockets to re-post the data, but you can't really redirect it.
POST'ing to a URL with cURL:
$ch = curl_init('http://www.somewhere.com/that/receives/postdata.php');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($_POST));
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$response = curl_exec($ch);
RewriteRule current-page.php http://www.newserver.com/newpage.php [NC,P]
The P on there (proxy) will preserve the POST data. You'll need to turn on the apache proxy module if it isn't already.
I know this is an old question but this may help people who stumble upon this question. You should be able to send an HTTP 307 response code to make the user agent redirect to the new url and continue to use the same method and data. This answer has more details
If the client (ie the mobile app) HTTP library supports this, then you can return HTTP 307 from server which states that "the request should be repeated with another URI ... with the same method". This is essentially a temporary redirect but tells the client to use the the same method, a POST.
The client making the request must be able to respond accordingly to the HTTP 307 response and follow the redirection with the same method - for many libraries this may be an additional flag or setting.
You cannot tell a browser to make a post request through an HTTP header. The location header will redirect, but only for GET or HEAD requests.
You can work around this limitation by displaying a page with a hidden form with the method attribute set to POST and the action set to the URL you want the browser to post to, then automatically submit it on page load. Example:
<body onload="document.getElementById('form').submit();">
<form id="form" action="http://example.com/form_handler.php" method="POST">
<input type="hidden" name="param_1" value="data">
</form>
</body>
Alternately, you can make the POST request on your server and then display the results.
I used the following code to redirect a post. In my case I am using only application/octet-stream content type so make sure you take that into consideration.
$request = file_get_contents ( "php://input" );
$arrContextOptions=array(
"http" => array(
"method" => "POST",
"header" =>
'Content-Type: application/octet-stream'. "\r\n".
'Content-Length: ' . strlen($request) . "\r\n",
"content" => $request,
),
"ssl"=>array(
"allow_self_signed"=>true,
"verify_peer"=>false,
),
);
$arrContextOptions = stream_context_create($arrContextOptions);
header ( "HTTP/1.1" );
header ( "Content-Type: application/octet-stream" );
$result = file_get_contents('http://thenewaddress.yes.it.works', false, $arrContextOptions);
file_put_contents("php://output", $result);
I think the solution I'm about to go with is something like:
<?
$url = 'http://myserver.com/file.php';
foreach ($_POST as $key => $value) {
$text .= (strlen($text) > 0 ? '&' : '');
$text .= $key . '=' . $value;
}
header('Location: ' . $url . '?' . $text);
exit;
?>
Can anyone think of a reason why this is a bad idea?
If you want to take data from a POST request and simply POST it to another server, then use cURL.
--or--
If you want to take data from a POST request and redirect the client to that other server while POSTing the data, then use this method...
Dynamically generate a form with all of the POST data. Something likes this...
echo "<form name=\"someform\" action=\"http://www.somewhereelse.com/someform.whatever\">";
foreach ($_POST as $key=>$value) {
echo "<input type=\"hidden=\" name=\"" . htmlspecialchars($key) . "\" value=\"" . htmlspecialchars($value) . "\" />";
}
echo "</form>";
Then, submit that form with some JavaScript when the page is done loading...
document.forms['someform'].submit();

php, curl, headers and content-type

I am having some trouble working with curl and headers returned by servers.
1) My php file on my_website.com/index.php looks like this (trimmed version):
<?php
$url = 'http://my_content_server.com/index.php';
//Open connection
$ch = curl_init();
curl_setopt($ch,CURLOPT_URL,$url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
//execute post
$result = curl_exec($ch);
//close connection
curl_close($ch);
echo $result;
?>
The php file on my_content_server.com/index.php looks like this:
<?php
header("HTTP/1.0 404 Not Found - Archive Empty");
echo "Some content > 600 words to make chrome/IE happy......";
?>
I expect that when I visit my_website.com/index.php, I should get a 404, but that is not happening.
What am I doing wrong?
2) Basically what I want to achieve is:
my_content_server.com/index.php will decide the content type and send appropriate headers, and my_website.com/index.php should just send the same content-type and other headers (along with actual data) to the browser. But it seems that my_website.com/index.php is writing its own headers? (Or maybe I am not understanding the working correctly).
regards,
JP
Insert before curl_exec():
curl_setopt($ch,CURLOPT_HEADER,true);
Instead of just echo'ing the result, forward the headers to the client as well:
list($headers,$content) = explode("\r\n\r\n",$result,2);
foreach (explode("\r\n",$headers) as $hdr)
header($hdr);
echo $content;

PHP - How to check if Curl actually post/send request?

I basically created a script using Curl and PHP that sends data to the website e.g. host, port and time. Then it submits the data. How would I know if the Curl/PHP actually sent those data to the web pages?
$fullcurl = "?host=".$host."&time=".$time.";
Any ways to see if they actually sent the data to those URLs on My MYSQL?
You can use curl_getinfo() to get the status code of the response like so:
// set up curl to point to your requested URL
$ch = curl_init($fullcurl);
// tell curl to return the result content instead of outputting it
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
// execute the request, I'm assuming you don't care about the result content
curl_exec($ch);
if (curl_errno($ch)) {
// this would be your first hint that something went wrong
die('Couldn\'t send request: ' . curl_error($ch));
} else {
// check the HTTP status code of the request
$resultStatus = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($resultStatus == 200) {
// everything went better than expected
} else {
// the request did not complete as expected. common errors are 4xx
// (not found, bad request, etc.) and 5xx (usually concerning
// errors/exceptions in the remote script execution)
die('Request failed: HTTP status code: ' . $resultStatus);
}
}
curl_close($ch);
For reference: http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
Or, if you are making requests to some sort of API that returns information on the result of the request, you would need to actually get that result and parse it. This is very specific to the API, but here's an example:
// set up curl to point to your requested URL
$ch = curl_init($fullcurl);
// tell curl to return the result content instead of outputting it
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
// execute the request, but this time we care about the result
$result = curl_exec($ch);
if (curl_errno($ch)) {
// this would be your first hint that something went wrong
die('Couldn\'t send request: ' . curl_error($ch));
} else {
// check the HTTP status code of the request
$resultStatus = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($resultStatus != 200) {
die('Request failed: HTTP status code: ' . $resultStatus);
}
}
curl_close($ch);
// let's pretend this is the behaviour of the target server
if ($result == 'ok') {
// everything went better than expected
} else {
die('Request failed: Error: ' . $result);
}
in order to be sure that curl sends something, you will need a packet sniffer.
You can try wireshark for example.
I hope this will help you,
Jerome Wagner

Categories