I tryed to get data from the "mobile.de Search API", but it doesn't work =/
.. this error cames every time :
HTTP Status 401 - This request requires HTTP authentication ().
.. what am I doing wrong?
$authCode = base64_encode("{Benutzername}:{Passwort}");
$uri = 'http://services.mobile.de/1.0.0/ad/search?modificationTime.min=2012-05-04T18:13:51.0Z';
$ch = curl_init($uri);
curl_setopt_array($ch, array(
CURLOPT_HTTPHEADER => array('Authorization: '.$authCode,'Accept-Language: de','Accept: application/xml'),
CURLOPT_RETURNTRANSFER =>true,
CURLOPT_VERBOSE => 1
));
$out = curl_exec($ch);
curl_close($ch);
echo $out;
As far as I can tell, I have complied with the interface description fully.
You need to set the following curl options for a correct authorization:
curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC ); // HTTP Basic Auth
curl_setopt($curl, CURLOPT_USERPWD, $username.":".$password); // Auth String
A simplified version of my implementation:
<?
class APIProxy {
/* The access proxy for mobile.de search API */
private $username;
private $password;
private $api_base;
function __construct(){
/* Auth Data */
$this->username = '{username}';
$this->password = '{password}';
$this->api_base = 'http://services.mobile.de/1.0.0/';
}
function execute($query){
/* executes the query on remote API */
$curl = curl_init($this->api_base . $query);
$this->curl_set_options($curl);
$response = curl_exec($curl);
$curl_error = curl_error($curl);
curl_close($curl);
if($curl_error){ /* Error handling goes here */ }
return $response;
}
function get_auth_string(){
/* e.g. "myusername:mypassword" */
return $this->username.":".$this->password;
}
function curl_set_options($curl){
curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC ); // HTTP Basic Auth
curl_setopt($curl, CURLOPT_USERPWD, $this->get_auth_string()); // Auth String
curl_setopt($curl, CURLOPT_FAILONERROR, true); // Throw exception on error
curl_setopt($curl, CURLOPT_HEADER, false); // Do not retrieve header
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); // Retrieve HTTP Body
}
}
$api = new APIProxy();
$result = $api->execute('ad/search?interiorColor=BLACK');
echo $result;
?>
A very basic non object oriented approach is using file get contents with manipulated header for accessing the search API. I share it to give a very simple example how the mobile.de API can be used. However, remember file_get_contents might be 30% - 50% slower than curl.
### Set language property in header (e.g. German) ###
$opts = array(
'http'=>array(
'method'=>"GET",
'header'=>"Accept-language: de\r\n"
)
);
$baseURL = 'http://<<username>>:<<password>>#services.mobile.de/1.0.0/ad/search?';
$searchURL .= $searchString; ## provide get parameters e.g. color=red&make=bmw
##fetch your results
$file = file_get_contents($searchURL, false, $context);
Regarding the auth data. Mobile.de provides it for free for every dealer. Just generate the auth properties in your dealer dashboard.
Related
I am new to REST and have been tasked with retrieving SurveyMonkey survey data using the V3 API. I am using PHP. My code is as follows:
$fields = array(
'title'=>'New Admission Survey',
'object_ids' => array($surveyID));
$fieldsString = json_encode($fields);
$curl = curl_init();
$requestHeaders = array(
"Authorization" => 'bearer abc123',
"Content-Type" => 'application/json',
'Content-Length: ' . strlen($fieldsString));
$baseUrl = 'https://api.surveymonkey.net/v3';
$endpoint = '/surveys/';
curl_setopt($curl, CURLOPT_URL, $baseUrl . $endpoint);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_HTTPHEADER, $requestHeaders);
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($curl, CURLOPT_POSTFIELDS, $fieldsString);
$curl_response = curl_exec($curl);
if($curl_response == false){
echo('Well, crap');
$info = curl_getinfo($curl);
echo('<pre>');print_r($info);echo('</pre>');
echo('<pre>');print_r(curl_error($curl));echo('</pre>');}
else {
echo('Test: ' . $curl_response);}
curl_close($curl);
I am getting the following error:
error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure
I have verified the Auth Token I am using is the one issued to me when I registered my app (done today).
Am I missing something? Most of the questions and answers deal with V2 of the SurveyMonkey API. I am using V3.
Thanks for your help!
I'm not sure if this will help the specific error you're encountering, but have you tried using this API wrapper? https://github.com/ghassani/surveymonkey-v3-api-php
This API wrapper simplified my tasks considerably:
<?php
// Init the client.
$client = Spliced\SurveyMonkey\Client(MY_CLIENT_ID, MY_ACCESS_TOKEN);
// Get a specific survey.
$survey = $client->getSurvey(MY_SURVEY_ID);
// Get all responses for this survey.
/** #var Spliced\SurveyMonkey\Response $responses */
$responses = $client->getSurveyResponses(MY_SURVEY_ID);
// Get a specific response.
/** #var Spliced\SurveyMonkey\Response $response */
$response = $client->getSurveyResponse(MY_SURVEY_ID, RESPONSE_ID, TRUE);
/* etc... */
I've written a basic API script in PHP using cURL - and successfully used a version of it on another API, this one is specifically to handle domain DNS management on DigitalOcean - and I can't send data?
Prelude...
I understand there is a PHP library available, I'm not after something that full featured or bloated with dependencies - just something small to use locally and primarily to help me understand how RESTful API's work a little better in practice - an educational exercise
The offending Code...
function basic_api_handle($key, $method, $URI, $data) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Authorization: Bearer '.$key,
'Content-Type: application/json')
);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
curl_setopt($ch, CURLOPT_URL, $URI);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
$result = curl_exec($ch);
if($result === false) error_log("API ERROR: Connection failure: $URI", 0);
curl_close($ch);
return json_decode($result, true);
}
var_dump(basic_api_handle($api_key, 'POST', 'https://api.digitalocean.com/v2/domains', array('name' => 'my-domain.tld', 'ip_address' => '1.2.3.4')));
This works with a GET request, such as listing the domains on the account but seems to fail at posting/sending data... this results in "unprocessable_entity" and "Name can't be blank" - as the name is not blank and is correctly formatted (as far as I can tell) it suggests to me the data is not being sent correctly?
Solution Attempts so far...
I've tried json encoding the data (seen in code), not json encoding, url encoding with and without json encoding and various other options with no luck.
I've seen a few posts online about this exact same issue specifically with DigitalOcean's API (and a another) but no one had an explanation (other than give up and use the library or something to that affect).
Using cURL directly from a terminal does work etc so there is nothing wrong with the API for creating a domain.
As far as I understand, the authentication is working, and the general setup works as I can list domains within the account, I just cant POST or PUT new data. I've been though the API's documentation and can't see what I'm doing wrong, maybe some sort of wrong encoding?
Any help would be much appreciated! :)
Edit:
After much work and research even other simple API handlers do not work with Digital Ocean (such as https://github.com/ledfusion/php-rest-curl) - is there something this API in particular needs or am I missing something fundamental about API's in general?
Technically this is not an fix but a work around. Thank you everyone for your comments and ideas, unfortunately nothing worked/fixed the code and the bounty expired :(
Although I have no idea why the PHP cURL option didn't work (the HTTP works, just Digital Ocean spitting errors for unknown reason linked to validation of the post data)...
I do have a new method that DOES WORK finally... (thanks to jtittle post on the Digital Ocean Community forum)
Just incase that link dies in the future... he's the working function using streams and file_get_contents and not curl...
<?php
function doapi( $key, $method, $uri, array $data = [] )
{
/**
* DigitalOcean API URI
*/
$api = 'https://api.digitalocean.com/v2';
/**
* Merge DigitalOcean API URI and Endpoint URI
*
* i.e if $uri is set to 'domains', then $api ends up as
* $api = 'https://api.digitalocean.com/v2/domains'
*/
$uri = $api . DIRECTORY_SEPARATOR . $uri;
/**
* Define Authorization and Content-Type Header.
*/
$headers = "Authorization: Bearer $key \r\n" .
"Content-Type: application/json";
/**
* If $data array is not empty, assume we're passing data, so we'll encode
* it and pass it to 'content'. If $data is empty, assume we're not passing
* data, so we won't sent 'content'.
*/
if ( ! empty( $data ) )
{
$data = [
'http' => [
'method' => strtoupper( $method ),
'header' => $headers,
'content' => json_encode( $data )
]
];
}
else
{
$data = [
'http' => [
'method' => strtoupper( $method ),
'header' => $headers
]
];
}
/**
* Create Stream Context
* http://php.net/manual/en/function.stream-context-create.php
*/
$context = stream_context_create( $data );
/**
* Send Request and Store to $response.
*/
$response = file_get_contents( $uri, false, $context );
/**
* Return as decoded JSON (i.e. an array)
*/
return json_decode( $response, true );
}
/**
* Example Usage
*/
var_dump(doapi(
'do-api-key',
'get',
'domains'
));
I used this to actually post the data successfully...
var_dump(doapi(
$api_key,
'post',
'domains',
array("name" => (string) $newDomain, "ip_address" => "1.2.3.4")
));
Add the Content-Length header and use CURLOPT_POST option for POST requests
function basic_api_handle($key, $method, $URI, $data) {
$json = json_encode($data)
$headers = array(
'Authorization: Bearer '.$key,
'Content-Type: application/json'
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_URL, $URI);
if ( $method === 'POST' ) {
curl_setopt($curl, CURLOPT_POST, 1);
} else {
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
array_push($headers, 'Content-Length: ' . strlen($json) );
}
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers)
curl_setopt($ch, CURLOPT_POSTFIELDS, $json );
$result = curl_exec($ch);
if($result === false) error_log("API ERROR: Connection failure: $URI", 0);
curl_close($ch);
return json_decode($result, true);
}
Maybe this will work for you:
function basic_api_handle($key, $method, $URI, $data) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method); // <-- Should be set to "GET" or "POST"
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // <-- Maybe the SSL is the problem
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36"); // <-- I am not familiar with this API, but maybe it needs a user agent?
curl_setopt($ch, CURLOPT_VERBOSE, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Authorization: Bearer '.$key,
'Content-Type: application/json')
);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
curl_setopt($ch, CURLOPT_URL, $URI);
curl_setopt($ch, CURLOPT_POST, count($data)); // <-- Add this line which counts the inputs you send
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
$result = curl_exec($ch);
if($result === false) error_log("API ERROR: Connection failure: $URI", 0);
curl_close($ch);
return json_decode($result, true);
}
It can also be a problem of a header you should sent and your missing it.
It could be a 307 or 308 http redirect.
Maybe "https://api.digitalocean.com/v2/domains" redirects to another url.
If this is the case, try adding:
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
to make curl follow the redirection and keep the parameters.
It is suggested that you also use:
curl_setopt($curl, CURLOPT_POSTREDIR, 3);
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "POST");
to keep the request body.
Hope it helps.
You can also try use CURLOPT_POST
I want to get an Authentication Token for the Microsoft Translator API. This is my code:
<?php
//1. initialize cURL
$ch = curl_init();
//2. set options
//Set to POST request
curl_setopt($ch, CURLOPT_POST,1);
// URL to send the request to
curl_setopt($ch, CURLOPT_URL, 'https://api.cognitive.microsoft.com/sts/v1.0/issueToken');
//return instead of outputting directly
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
//whether to include header in the output. here set to false
curl_setopt($ch, CURLOPT_HEADER, 0);
//pass my subscription key
curl_setopt($ch, CURLOPT_POSTFIELDS,array(Subscription-Key => '<my-key>'));
//CURLOPT_SSL_VERIFYPEER- Set to false to stop verifying certificate
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
//3. Execute the request and fetch the response. check for errors
$output = curl_exec($ch);
if ($output === FALSE) {
echo "cURL Error" . curl_error($ch);
}
//4. close and free up the curl handle
curl_close($ch);
//5. display raw output
print_r($output);
?>
it gives me the following error:
{ "statusCode": 401, "message": "Access denied due to missing subscription key. Make sure to include subscription key when making requests to an API." }
which could mean that the key is invalid according to the website below, but I ensured the key is valid on the same website.
http://docs.microsofttranslator.com/oauth-token.html
I did find some examples online on how to get the Authenticationtoken, but they are outdated.
How can I get the AuthenticationToken/achieve that microsoft recognises my key?
You're passing the subscription-key wrong -
The subscription key should passed in the header (Ocp-Apim-Subscription-Key) or as a querystring parameter in the URL ?Subscription-Key=
And you should use Key1 or Key2 generated by the Azure cognitive service dashboard.
FYI - M$ has made a token generator available for testing purposes, this should give you a clue which keys are used for which purpose:
http://docs.microsofttranslator.com/oauth-token.html
Here's a working PHP script which translates a string from EN to FR (it's based on an outdated WP plugin called Wp-Slug-Translate by BoLiQuan which I've modified for this purpose):
<?php
define("CLIENTID",'<client-name>'); // client name/id
define("CLIENTSECRET",'<client-key>'); // Put key1 or key 2 here
define("SOURCE","en");
define("TARGET","fr");
class WstHttpRequest
{
function curlRequest($url, $header = array(), $postData = ''){
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
if(!empty($header)){
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
}
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
if(!empty($postData)){
curl_setopt($ch, CURLOPT_POST, TRUE);
curl_setopt($ch, CURLOPT_POSTFIELDS, is_array($postData) ? http_build_query($postData) : $postData);
}
$curlResponse = curl_exec($ch);
curl_close($ch);
return $curlResponse;
}
}
class WstMicrosoftTranslator extends WstHttpRequest
{
private $_clientID = CLIENTID;
private $_clientSecret = CLIENTSECRET;
private $_fromLanguage = SOURCE;
private $_toLanguage = TARGET;
private $_grantType = "client_credentials";
private $_scopeUrl = "http://api.microsofttranslator.com";
private $_authUrl = "https://api.cognitive.microsoft.com/sts/v1.0/issueToken";
// added subscription-key
private function _getTokens(){
try{
$header = array('Ocp-Apim-Subscription-Key: '.$this->_clientSecret);
$postData = array(
'grant_type' => $this->_grantType,
'scope' => $this->_scopeUrl,
'client_id' => $this->_clientID,
'client_secret' => $this->_clientSecret
);
$response = $this->curlRequest($this->_authUrl, $header, $postData);
if (!empty($response))
return $response;
}
catch(Exception $e){
echo "Exception-" . $e->getMessage();
}
}
function translate($inputStr){
$params = "text=" . rawurlencode($inputStr) . "&from=" . $this->_fromLanguage . "&to=" . $this->_toLanguage;
$translateUrl = "http://api.microsofttranslator.com/v2/Http.svc/Translate?$params";
$accessToken = $this->_getTokens();
$authHeader = "Authorization: Bearer " . $accessToken;
$header = array($authHeader, "Content-Type: text/xml");
$curlResponse = $this->curlRequest($translateUrl, $header);
$xmlObj = simplexml_load_string($curlResponse);
$translatedStr = '';
foreach((array)$xmlObj[0] as $val){
$translatedStr = $val;
}
return $translatedStr;
}
}
function bing_translator($string) {
$wst_microsoft= new WstMicrosoftTranslator();
return $wst_microsoft->translate($string);
}
echo bing_translator("How about translating this?");
?>
Add your key also in the URL.
curl_setopt($ch, CURLOPT_URL, 'https://api.cognitive.microsoft.com/sts/v1.0/issueToken?Subscription-Key={your key}');
But leave it also in the CURLOPT_POSTFIELDS.
I would like to integrate with ChannelAdvisor REST API using the SOAP Credentials Flow.
Based on their documentation, I have setup the following in PostMan (rest client in Chrome browser) like this:
When I make the rest; the rest api server returns the expected response:
So, I tried to replicate this in PHP with the following class:
<?php
class ChannelAdvisorREST {
/**
* ChannelAdvisor constants & properties
*/
const BASE_URL = 'https://api.channeladvisor.com/v1';
private $config;
/**
* Class constructor
*/
public function __construct()
{
$this->config = \Config::get('channeladvisor');
}
// TEST
public function test($accountId)
{
// var_dump($this->config);
var_dump(self::getAccessToken($accountId));
}
// TEST
/**
* Method to get access token from rest server.
*
* #param $accountId
* #return string
*/
private function getAccessToken($accountId)
{
return self::curlPOST('/oauth2/token', [
'client_id' => $this->config['api_app_id'],
'grant_type' => 'soap',
'scope' => 'inventory',
'developer_key' => $this->config['api_developer_key'],
'password' => $this->config['api_password'],
'account_id' => $accountId
]);
}
/**
* Method to generate a HTTP POST request
*
* #param $endpoint
* #param $fields
* #return string
*/
private function curlPOST($endpoint, $fields = array())
{
// Open connection
$ch = curl_init();
// Set the url, number of POST vars, POST data
curl_setopt($ch, CURLOPT_USERPWD, $this->config['api_app_id'] .':'. $this->config['api_shared_secret']);
curl_setopt($ch, CURLOPT_URL, self::BASE_URL . $endpoint);
curl_setopt($ch, CURLOPT_POST, count($fields));
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($fields, '', '&'));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/x-www-form-urlencoded'
));
// Execute post request
$result = curl_exec($ch);
// Close connection
curl_close($ch);
// Finished
return $result;
}
}
When I execute the test($accId) method on this class, I get the following response:
boolean false
Any idea why it isn't quite working as same as the PostMan test?
P.S. I have already verified all the config/parms etc... are correct and same as my PostMan test. This class is a snipped version from my original code (created in Laravel 4.2, but this issue is not related to Laravel).
Two things:
Make sure that you send the same headers as your browser sends. For example, I don't see the Authorization-header in your code, and that one is probably quite crucial for authorizing the request on the server-side. Also for the scope you use 'inventory' instead of 'orders inventory'. Be very strict in this exercise.
Test the post-data not in an array, but write down the query-string as it should be according to yourself, this way you know there is not some issue by CURL trying to convert your array into a query-string (note, both is possible for CURL, array and query-string).
So most easy to test with:
client_id=1234&grant_type=soap&scope=order%20inventory...etc add other variables...
I have found the problem. The issue was caused by my php not being configured with curl.cainfo.
I found this by adding the following debug code to my curlPOST method like this:
private function curlPOST($endpoint, $fields = array())
{
// Open connection
$ch = curl_init();
// Set the url, number of POST vars, POST data
curl_setopt($ch, CURLOPT_USERPWD, $this->config['api_app_id'] .':'. $this->config['api_shared_secret']);
curl_setopt($ch, CURLOPT_URL, self::BASE_URL . $endpoint);
curl_setopt($ch, CURLOPT_POST, count($fields));
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($fields, '', '&'));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/x-www-form-urlencoded'
));
curl_setopt($ch, CURLOPT_VERBOSE, true);
$verbose = fopen('php://temp', 'w+');
curl_setopt($ch, CURLOPT_STDERR, $verbose);
// Execute post request
$result = curl_exec($ch);
// Debug error
if ($result === FALSE) {
printf("cUrl error (#%d): %s<br>\n", curl_errno($ch), htmlspecialchars(curl_error($ch)));
rewind($verbose);
$verboseLog = stream_get_contents($verbose);
echo "Verbose information:\n<pre>", htmlspecialchars($verboseLog), "</pre>\n";
}
#fclose($verbose);
// Close connection
curl_close($ch);
// Finished
return $result;
}
This outputted the following error message:
cUrl error (#60): SSL certificate problem: unable to get local issuer certificate
Verbose information:
* Hostname was found in DNS cache
* Hostname in DNS cache was stale, zapped
* Trying 216.27.89.14...
* Connected to api.channeladvisor.com (216.27.89.14) port 443 (#7)
* SSL certificate problem: unable to get local issuer certificate
* Closing connection 7
boolean false
Which helped me track down the issue with my php.
I'm new to REST and I'm trying to develop a web app that will connect with JIRA from one sid (already covered) and with HP's ALM from the other side.
what I'm attempting to accomplish right now is basic authentication to ALM with PHP but can't seem to progress.
here is my code:
$handle=curl_init('http://192.168.1.7:8081');
$headers = array(
'Accept: application/xml',
'Content-Type: application/xml',
'Authorization: Basic YWRtaW46MTIzNA==',
);
$username='admin';
$password='1234';
$url = 'http://192.168.1.7:8081/qcbin/authentication-point/login.jsp';
curl_setopt_array(
$handle,
array(
CURLOPT_URL=>'http://192.168.1.7:8081/qcbin/rest/domains/default/projects/Ticomsoft/defects?login-form-required=y',
//CURLOPT_COOKIEFILE=>$ckfile,
CURLOPT_POST=>true,
//CURLOPT_HTTPGET =>true,
CURLOPT_COOKIEJAR=>$ckfile,
CURLOPT_VERBOSE=>1,
//CURLOPT_POSTFIELDS=>,
//CURLOPT_GETFIELDS=>'j_username=admin&j_password=1234&redirect-url=http://192.168.1.7:8081/myUiResource.jsps',
CURLOPT_SSL_VERIFYHOST=> 0,
CURLOPT_SSL_VERIFYPEER=> 0,
CURLOPT_RETURNTRANSFER=>true,
CURLOPT_FOLLOWLOCATION=>true,
CURLOPT_HEADER=>false,
CURLOPT_HTTPHEADER=> $headers,
CURLOPT_AUTOREFERER=>true
//CURLOPT_COOKIE=>
//CURLOPT_USERPWD=>"admin:yahala"
//CURLOPT_CUSTOMREQUEST=>"POST"
)
);
$result=curl_exec($handle);
$ch_error = curl_error($handle);
$response = curl_getinfo($handle);
print_r($response);
if ($ch_error) {
echo "cURL Error: $ch_error";
} else {
//var_dump(json_decode($result, true));
echo $result;
}
curl_close($handle);
?>
as you can see there is a lot of garbage as my trial and error progressed.
Here we go. I followed the QC Rest API documentation to study the order that QC expects requests to be made. I've tested it against ALM11. I'm new to cURL as well, but this should get you in and working......
<?php
//create a new cURL resource
$qc = curl_init();
//create a cookie file
$ckfile = tempnam ("/tmp", "CURLCOOKIE");
//set URL and other appropriate options
curl_setopt($qc, CURLOPT_URL, "http://qualityCenter:8080/qcbin/rest/is-authenticated");
curl_setopt($qc, CURLOPT_HEADER, 0);
curl_setopt($qc, CURLOPT_HTTPGET, 1);
curl_setopt($qc, CURLOPT_RETURNTRANSFER, 1);
//grab the URL and pass it to the browser
$result = curl_exec($qc);
$response = curl_getinfo($qc);
//401 Not authenticated (as expected)
//We need to pass the Authorization: Basic headers to authenticate url with the
//Correct credentials.
//Store the returned cookfile into $ckfile
//Then use the cookie when we need it......
if($response[http_code] == '401')
{
$url = "http://qualityCenter:8080/qcbin/authentication-point/authenticate";
$credentials = "qc_username:qc_password";
$headers = array("GET /HTTP/1.1","Authorization: Basic ". base64_encode($credentials));
curl_setopt($qc, CURLOPT_URL, $url);
curl_setopt($qc, CURLOPT_HTTPGET,1); //Not sure we need these again as set above?
curl_setopt($qc, CURLOPT_HTTPHEADER, $headers);
//Set the cookie
curl_setopt($qc, CURLOPT_COOKIEJAR, $ckfile);
curl_setopt($qc, CURLOPT_RETURNTRANSFER, true);
$result = curl_exec($qc);
$response = curl_getinfo($qc);
//The response will be 200
if($response[http_code] == '200')
{
//Use the cookie for subsequent calls...
curl_setopt($qc, CURLOPT_COOKIEFILE, $ckfile);
curl_setopt($qc, CURLOPT_RETURNTRANSFER, true);
curl_setopt($qc, CURLOPT_URL, "http://qualityCenter:8080/qcbin/rest/domains/Your_Domain/projects/Your_Project/defects");
//In this example we are retrieving the xml so...
$xml = simplexml_load_string(curl_exec($qc));
print_r($xml);
//Call Logout
logout($qc,"http://qualityCenter:8080/qcbin/authentication-point/logout");
}
else
{
echo "Authentication failed";
}
}
else
{
echo "Not sure what happened?!";
}
//Close cURL resource, and free up system resources
curl_close($qc);
function logout($qc, $url)
{
curl_setopt($qc, CURLOPT_URL, $url);
curl_setopt($qc, CURLOPT_HEADER, 0);
curl_setopt($qc, CURLOPT_HTTPGET,1);
curl_setopt($qc, CURLOPT_RETURNTRANSFER, 1);
//grab the URL and pass it to the browser
$result = curl_exec($qc);
}
?>
Let me know if it worked!
Thanks,
Rich
one of the important things to keep in mind is after authenticating you must do the following
POST /qcbin/rest/site-session
with cookies LWSSO
this will return QCSession and XSRF-TOKEN which are needed to perform any operations
Here is my solution in Perl for this problem: The authentication step is performed first, setting the cookie for the next libcurl request which then can be performed with no problems. This is a version for background jobs. For a dialog application, the credentials could be passed through from the user's input instead. Also, I had to do this with https instead of http. The Perl program also shows how to instruct curl for https (there is a very good how-to on http://unitstep.net/blog/2009/05/05/using-curl-in-php-to-access-https-ssltls-protected-sites/ ).
#!/usr/bin/perl
# This script accesses, as a proxy, the REST API of the HP quality center
# Running it without query parameter, the complete list of defects is returned
# A query parameter, e.g. 'query={id[2283]}' will be passed as is to the HP QC API
# We are using the libcurl wrapper WWW::Curl::Easy
# The access is https, so a certificate has to be passed to libcurl
# The main point for using curl, however, is the authentication procedure:
# HP requires a preparative call to a special authentication service
# The authentication ticket will then be passed back as a cookie
# Only with this ticket, the real GET request on the defects can be performed
use WWW::Curl::Easy;
use strict;
use warnings;
use constant {
URL_QC_DEFECTS => "https://[QC DOMAIN]/qcbin/rest/domains/[DOMAIN]/projects/[PROJECT]/defects/",
URL_QC_AUTH => "https://[QC DOMAIN]/qcbin/authentication-point/authenticate",
PATH_CERT => "[PATH TO CREDENTIALS]" # contains certificate and credentials, see below
};
doRequest( URL_QC_DEFECTS . "?" . $ENV{QUERY_STRING} );
return 0;
sub doRequest {
my ($url,$cookies,$response) = (shift,"","");
eval {
my $curl = get_curl_instance(\$cookies,\$response);
authenticate( $curl );
get( $curl, $url );
if ($response =~ /.*?(<\?xml\b.*)/s) {
print "Content-Type:text/xml\n\n";
print $1;
}
else {
die "The response from HP QC is not in XML format";
}
};
if ($#) {
print "Content-Type:text/plain\n\n$#";
}
}
sub get_curl_instance {
my ($cookie,$response) = #_;
my $curl = WWW::Curl::Easy->new( );
open( my $cookiefile, ">", $cookie) or die "$!";
$curl->setopt( CURLOPT_COOKIEFILE, $cookiefile );
open( my $responsefile, ">", $response) or die "$!";
$curl->setopt( CURLOPT_WRITEDATA, $responsefile );
$curl->setopt( CURLOPT_SSL_VERIFYPEER, 1);
$curl->setopt( CURLOPT_SSL_VERIFYHOST, 2);
$curl->setopt( CURLOPT_CAINFO, cert() );
$curl->setopt( CURLOPT_FOLLOWLOCATION, 1 );
return $curl;
}
sub authenticate {
my $curl = shift;
my ($rc,$status);
$curl->setopt( CURLOPT_URL, URL_QC_AUTH );
$curl->setopt( CURLOPT_USERPWD, cred( ) );
if (($rc = $curl->perform( )) != 0) {
die "Error Code $rc in curl->perform( ) on URL " . URL_QC_AUTH;
}
if (($status=$curl->getinfo(CURLINFO_HTTP_CODE))!="200") {
die "HTTP-Statuscode $status from authentication call";
}
}
sub get {
my ($curl,$url) = #_;
my ($rc,$status);
$curl->setopt( CURLOPT_URL, $url );
$curl->setopt( CURLOPT_HEADER, { Accept => "text/xml" } );
if (($rc = $curl->perform( )) != 0) {
die "Error Code $rc from defects request";
}
if (($status=$curl->getinfo(CURLINFO_HTTP_CODE))!="200") {
die "HTTP Statuscode $status from defects request";
}
}
sub cred {
open CRED, PATH_CERT . '/.cred_qc' or die "Can't open credentials file: $!";
chomp( my $cred = <CRED>);
close CRED;
return $cred;
}
sub cert {
return PATH_CERT . '/qc.migros.net.crt';
}
As an alternative to Sohaib's answer concerning the need to POST to /qcbin/rest/site-session after authenticating, you can do both in one step by POSTing to /qcbin/api/authentication/sign-in , as per the below:
"There are four cookies that come back, and in ALM 12.53 the authentication point has changed ( but the documentation has not so it sends you to the wrong place ! )
So, send a POST request with BASIC authentication, base64 encoded username / password to /qcbin/api/authentication/sign-in and you will get back
LWSSO_COOKIE_KEY
QCSESSION
ALM_USER
XSRF_TOKEN
include these with all your subsequent GETS and PUTS and you should be OK."
(This answer is taken from https://community.microfocus.com/t5/ALM-QC-User-Discussions/Authentication-fails-when-trying-to-pull-data-from-ALM-server/td-p/940921, and worked for me in a similar context).