I'm trying to POST to a Web Service (not RESTful) and get response through PHP. However, that web service requires Digest Authentication.
I've been searching online and found most of the discussions and articles are about the other way around (Requesting Digest Authentications to users), instead of responding it, using PHP.
I'm able to generate the Digest response using the code this thread provide:HTTP Digest authenticating in PHP, but the problem is to sending it along with(or not?) the POST data.
Here's the code I'm using:
$domain = "https://api.example.com";
$uri = "/ws.asmx/do";
// get headers
$response1_array = get_headers($web_service_url);
// get request part of digest auth
$response1 = $response1_array[5];
// get things behind "WWW-Authenticate:"
$response1 = substr($response1, 18);
// response() is a invented function to calculate the response according to the RFC2617
$response2 = response($response1, "username", "password", "GET", $uri);
// manually add some headers for POST, and fill out the parts that the calculation function missed
// for auth
$header =
"Host: api.example.com\r\n" .
"Content-Type: application/x-www-form-urlencoded\r\n" .
"Authorization: " . $response2 . ", nc=\"00000001\", opaque=\"0000000000000000\"" . "\r\nContent-Length: 0\r\n\r\n";
// echo the response from server
echo do_post_request($web_service_url, "", $header);
function do_post_request($url, $data, $optional_headers = null)
{
$params = array('http' => array(
'method' => 'POST',
'content' => $data
));
if ($optional_headers !== null) {
$params['http']['header'] = $optional_headers;
}
$ctx = stream_context_create($params);
$fp = fopen($url, 'rb', false, $ctx);
if (!$fp) {
throw new Exception("Problem with $url");
}
$response = stream_get_contents($fp);
if ($response === false) {
throw new Exception("Problem reading data from $url");
}
return $response;
}
In the response:
$response1(from web service):
Digest realm="example.com", nonce="OS82LzIwMTMgMTI6MDI6NDYgUE0", opaque="0000000000000000", stale=false, algorithm=MD5, qop="auth"
$response2(I calculated given the server response):
Digest username="username", realm="example.com", nonce="OS82LzIwMTMgMTI6MDI6NDYgUE0", uri="/ws.asmx/do", cnonce="1378494106", nc="1", response="0f96788854cf2098ba22c6121529d7de", qop="auth"
the final (2nd) response from server:
Warning: fopen(https://api.example.com/ws.asmx/do): failed to open stream: HTTP request failed! HTTP/1.1 500 Internal Server Error in ...
I don't understand why server responded 500 error in this case. Is there anything wrong in the code? Or has anyone met this problem before and solved it and can help me with a solution?
Regards,
Mylo
Eventually solved it with cURL after 2 days' fumbling. I guess this is the first time a piece of ready-made PHP code for digest auth is posted, hopefully it can help someone who are in the same ditch as I was in.
Code:
<?php
error_reporting(E_ALL);
ini_set( 'display_errors','1');
$url = "https://api.example.com/ws.asmx/do";
$username = "username";
$password = "pwd";
$post_data = array(
'fieldname1' => 'value1',
'fieldname2' => 'value2'
);
$options = array(
CURLOPT_URL => $url,
CURLOPT_HEADER => true,
CURLOPT_VERBOSE => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_SSL_VERIFYPEER => false, // for https
CURLOPT_USERPWD => $username . ":" . $password,
CURLOPT_HTTPAUTH => CURLAUTH_DIGEST,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => http_build_query($post_data)
);
$ch = curl_init();
curl_setopt_array( $ch, $options );
try {
$raw_response = curl_exec( $ch );
// validate CURL status
if(curl_errno($ch))
throw new Exception(curl_error($ch), 500);
// validate HTTP status code (user/password credential issues)
$status_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($status_code != 200)
throw new Exception("Response with Status Code [" . $status_code . "].", 500);
} catch(Exception $ex) {
if ($ch != null) curl_close($ch);
throw new Exception($ex);
}
if ($ch != null) curl_close($ch);
echo "raw response: " . $raw_response;
?>
If you want to send JSON data with PUT method:
<?php
error_reporting(E_ALL);
ini_set( 'display_errors','1');
$url = "https://api.example.com/ws.asmx/do";
$username = "username";
$password = "pwd";
$post_data = array(
'fieldname1' => 'value1',
'fieldname2' => 'value2'
);
$options = array(
CURLOPT_URL => $url,
CURLOPT_HEADER => true,
CURLOPT_VERBOSE => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_SSL_VERIFYPEER => false, // for https
CURLOPT_USERPWD => $username . ":" . $password,
CURLOPT_HTTPAUTH => CURLAUTH_DIGEST,
CURLOPT_CUSTOMREQUEST => "PUT",
CURLOPT_POSTFIELDS => json_encode($post_data) ,
);
$ch = curl_init();
curl_setopt_array( $ch, $options );
try {
$raw_response = curl_exec( $ch );
// validate CURL status
if(curl_errno($ch))
throw new Exception(curl_error($ch), 500);
// validate HTTP status code (user/password credential issues)
$status_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($status_code != 200)
throw new Exception("Response with Status Code [" . $status_code . "].", 500);
} catch(Exception $ex) {
if ($ch != null) curl_close($ch);
throw new Exception($ex);
}
if ($ch != null) curl_close($ch);
echo "raw response: " . $raw_response;
?>
Related
public function auth_callback()
{
if ($this->input->get("code") != null)
{
$this->Strava_model->UpdateProfileStravaToken($this->input->get("code"),$this->session->userdata("athlete_id"));
$url = "http://www.strava.com/oauth/token?client_id=[xxxxx]&client_secret=[xxxxxxxxxxx]&code=".$this->input->get("code")."&grant_type=authorization_code";
$post = array();
$options = array(
'http' => array(
'header' => "Content-type: application/x-www-form-urlencoded\r\n",
'method' => 'POST',
'content' => http_build_query($post)
)
);
$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);
if ($result === FALSE) { /* Handle error */ }
var_dump($result);
echo $result;exit;
$cURLConnection = curl_init($url);
curl_setopt($cURLConnection, CURLOPT_POSTFIELDS, $post);
curl_setopt($cURLConnection, CURLOPT_RETURNTRANSFER, true);
$apiResponse = curl_exec($cURLConnection);
curl_close($cURLConnection);
$jsonArrayResponse = json_decode($apiResponse);
redirect($this->config->item("base_url") . "/activity");
}
}
I manage to get the code, and now proceed to get access token.
I'm using php curl to send post as below:
http://www.strava.com/oauth/token?client_id=[xxxx]&client_secret=[xxxxx]&code=[code retrieve from redirection]&grant_type=authorization_code
Once I executed the code above, I got this "You're being redirect..."
Can anyone advice and help?
Generally requests to the OAuth2 token endpoint require parameters to be passed as form-data, in the request body. Based on your current source, you are sending an empty request body.
I need to send data to an API using PHP. The API has a redirect page before showing the final result. The following code shows the content of the redirecting page rather than the final result. How can I wait until the final result?
$url = 'https://example.com/api';
$data = array('text' => "try");
$options = array(
'http' => array(
'header' => "Content-type: application/x-www-form-urlencoded\r\n",
'method' => 'GET',
'content' => http_build_query($data)
)
);
$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);
if ($result === FALSE) { /* Handle error */ }
echo $result;
P.S. I got this code from one of stackoverflow's questions.
You could use cURL to get the final response, using CURLOPT_FOLLOWLOCATION:
From documentation :
CURLOPT_FOLLOWLOCATION: TRUE to follow any "Location: " header that the server sends as part of the HTTP header (note this is recursive, PHP will follow as many "Location: " headers that it is sent, unless CURLOPT_MAXREDIRS is set).
$url = 'https://example.com/api';
$data = array('text' => "try");
$full_url = $url . (strpos($url, '?') === FALSE ? '?' : '')
. http_build_query($data) ;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $full_url) ;
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-type: application/x-www-form-urlencoded',
]);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$response = curl_exec($ch);
curl_close ($ch);
var_dump($response) ;
I am working with twitter digit. my mobile verification works corrccetly. but with auth header information when I call curl then it not working.my curl code
$request=$_REQUEST['someData'];
function oauth_value($headersIndex = [])
{
if(empty($headersIndex)) return 'Invalid Index Number';
$value = explode('=', $headersIndex);
return str_replace('"', '', $value[1] );
}
$headersData = explode(',',$request['headers']);
$ch = curl_init();
$ch = curl_init($request['apiUrl']);
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Authorization' => 'OAuth oauth_consumer_key="'.oauth_value($headersData[0]).'",
oauth_nonce="'.oauth_value($headersData[1]).'",
oauth_signature="'.oauth_value($headersData[2]).'",
oauth_signature_method="HMAC-SHA1",
oauth_timestamp="'.oauth_value($headersData[4]).'",
oauth_token="'.oauth_value($headersData[5]).'",
oauth_version="'.oauth_value($headersData[6]).'"'
)
);
$resp = curl_exec($ch);
$info = curl_getinfo($ch);
curl_close($ch);
example information that come form $_REQUEST['someData'];
Array
(
[apiUrl] => https://api.digits.com/1.1/sdk/account.json
[headers] =>
OAuth oauth_consumer_key="OybCXYoYTuS0Cw0usZYry6Nlj",
oauth_nonce="3942830480-TILitVHHZGmcczuuFj3nbJtnMm00DHvvgduawMHOybCXYoYTuS0Cw0usZYry6Nlj1445246231940",
oauth_signature="dXHcH%2FsLBIlYOVWBIhEBWSCMLJo%3D",
oauth_signature_method="HMAC-SHA1",
oauth_timestamp="1445246231",
oauth_token="3942830480-TILitVHHZGmcczuuFj3nbJtnMm00DHvvgduawMH",
oauth_version="1.0"
)
What can I do Now?
If you have a URL and header from digits then you can use below code:
$apiUrl = 'https://api.digits.com/1.1/sdk/account.json';
$authHeader = 'OAuth oauth_consumer_key="**********", oauth_nonce="****", oauth_signature="****", oauth_signature_method="HMAC-SHA1", oauth_timestamp="1481554529", oauth_token="*****", oauth_version="1.0"';
// Create a stream
$opts = array(
'http'=>array(
'method'=>"GET",
'header'=>"Authorization: {$authHeader}"
)
);
$context = stream_context_create($opts);
// Open the file using the HTTP headers set above
$file = file_get_contents($apiUrl, false, $context);
$final_output = array();
if($file)
{
$final_output = json_decode($file,true);
}
print_r($final_output);
It will return id_str, phone number etc. You can store those data in your database.
I'm just testing the Paypal IPN here. I've got it set up with Sandbox. I'm sending it fake IPN requests, and it's receiving the IPN. Then, I'm getting it to return the information for verification, and I'm writing the response to a text file so I can check it out on my own. The IPN is firing fine, and the response is getting written to the text file.
There's just one problem... The response is blank.
The response is supposed to be received as "VERIFIED" or "INVALID", and these are the only 2 possible responses... so what's going on =S. Any help is greatly appreciated.
The entire code is posted below:
$ipn_post_data = $_POST;
$response = "";
// Choose url
$url = 'https://www.sandbox.paypal.com/cgi-bin/webscr';
// Set up request to PayPal
$request = curl_init();
curl_setopt_array($request, array
(
CURLOPT_URL => $url,
CURLOPT_POST => TRUE,
CURLOPT_POSTFIELDS => http_build_query(array('cmd' => '_notify-validate') + $ipn_post_data),
CURLOPT_RETURNTRANSFER => TRUE,
CURLOPT_HEADER => FALSE,
CURLOPT_SSL_VERIFYPEER => TRUE,
CURLOPT_CAINFO => 'cacert.pem',
));
// Execute request and get response and status code
$response = curl_exec($request);
$status = curl_getinfo($request, CURLINFO_HTTP_CODE);
// Close connection
curl_close($request);
$fh = fopen( "ipntest.txt", 'a+' );
$date = date( "Y-M-j H:i" );
fwrite( $fh, $date . " Response: " . $response . "\n" );
fclose( $fh );
if($status == 200 && $response == 'VERIFIED')
{
// All good! Proceed...
}
else
{
// Not good. Ignore, or log for investigation...
}
Text file output:
2012-Nov-26 23:24 Response:
2012-Nov-26 23:25 Response:
I had been using this code previously, I've been trying to get it to work for a week, so it's not just a temporary failure or something...
Cheers guys.
So just for future reference, for people with this same problem:
The issue here was not having a CA file.
I'm unsure what exactly a CA file does but I know it has something to do with Paypal's SSL certificate and establishing an SSL connection. When I started looking at cURL's errors, I saw the following:
[27-Nov-2012 21:46:11 UTC] cURL error: [77] error setting certificate verify locations:
CAfile: /etc/ssl/certs/api_cert_chain.crt
CApath: /etc/ssl/certs
The quick solution that I found was to download the IpnListener.php class. (This was recommended by eldblz. It made dealing with IPN way easier AND it provided a solution to my not having a CAFile. If you download the entire IpnListener.php package, it includes a folder called cert which includes the api_cert_chain.crt that you need, and already has it configured for use.
I've always used the following and it works nicely...
// Validate with curl
$curl_result=$curl_err='';
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,'https://'.$ppHost.'/cgi-bin/webscr');
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $req);
curl_setopt($ch, CURLOPT_HTTPHEADER, array("Content-Type: application/x-www-form-urlencoded", "Content-Length: " . strlen($req)));
curl_setopt($ch, CURLOPT_HEADER , 1);
curl_setopt($ch, CURLOPT_VERBOSE, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $ssl);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
$curl_result = curl_exec($ch);
$curl_err = curl_error($ch);
curl_close($ch);
//are we verified? If so, let's process the IPN
if (strpos($curl_result, "VERIFIED")!==false)
$valid = true;
else
$valid = false;
You would just need to make sure $ppHost in this sample was correct depending on whether the transaction came from the sandbox or the live servers, and then of course fill in $req and $ssl accordingly.
class Paypal_IPN
{
/** #var string $_url The paypal url to go to through cURL
private $_url;
/**
* #param string $mode 'live' or 'sandbox'
*/
public function __construct($mode = 'live')
{
if ($mode == 'live')
$this->_url = 'https://www.paypal.com/cgi-bin/webscr';
else
$this->_url = 'https://www.sandbox.paypal.com/cgi-bin/webscr';
}
public function run()
{
$postFields = 'cmd=_notify-validate';
foreach($_POST as $key => $value)
{
$postFields .= "&$key=".urlencode($value);
}
$ch = curl_init();
curl_setopt_array($ch, array(
CURLOPT_URL => $this->_url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $postFields
));
$result = curl_exec($ch);
curl_close($ch);
$fh = fopen('result.txt', 'w');
fwrite($fh, $result . ' -- ' . $postFields);
fclose($fh);
echo $result;
}
}
call this in another php file:
<?php
require 'Paypal_IPN.php';
$paypal= new Paypal_IPN('sandbox');
$paypal->run();
?>
I created the following PHP function to the HTTP code of a webpage.
function get_link_status($url, $timeout = 10)
{
$ch = curl_init();
// set cURL options
$opts = array(CURLOPT_RETURNTRANSFER => true, // do not output to browser
CURLOPT_URL => $url, // set URL
CURLOPT_NOBODY => true, // do a HEAD request only
CURLOPT_TIMEOUT => $timeout); // set timeout
curl_setopt_array($ch, $opts);
curl_exec($ch); // do it!
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE); // find HTTP status
curl_close($ch); // close handle
return $status;
}
How can I modify this function to follow 301 & 302 redirects (possibility multiple redirects) and get the final HTTP status code?
set CURLOPT_FOLLOWLOCATION to TRUE.
$opts = array(CURLOPT_RETURNTRANSFER => true, // do not output to browser
CURLOPT_URL => $url, // set URL
CURLOPT_NOBODY => true, // do a HEAD request only
CURLOPT_FOLLOWLOCATION => true // follow location headers
CURLOPT_TIMEOUT => $timeout); // set timeout
If you're not bound to curl, you can do this with standard PHP http wrappers as well (which might be even curl then internally). Example code:
$url = 'http://example.com/';
$code = FALSE;
$options['http'] = array(
'method' => "HEAD"
);
$context = stream_context_create($options);
$body = file_get_contents($url, NULL, $context);
foreach($http_response_header as $header)
{
sscanf($header, 'HTTP/%*d.%*d %d', $code);
}
echo "Status code (after all redirects): $code<br>\n";
See as well HEAD first with PHP Streams.
A related question is How can one check to see if a remote file exists using PHP?.