Handshake error in PHP call to SurveyMonkey API V3 - php

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... */

Related

How to connect with 2ba it's API using PHP

Im trying to connect to the API services of 2ba. Somehow I just can't connect. I get the error: error: "invalid_client"
I dont know what to try, it feels like I need to hash my cliend_secret or complete url but I dont see that in the documentation.
This is my code (PHP):
<?php
// ---- GET TOKEN ----
// Base url for all api calls.
$baseURL = 'https://authorize.2ba.nl';
// Specified url endpoint. This comes after the baseUrl.
$endPoint = '/OAuth/Token';
// Parameters that are required or/and optianal for the endPoint its request.
$parameters = 'grant_type=password&username=abc#abc.com&password=123abc&client_id=myClientID&client_secret=myClientSecret';
// All parts together.
$url = $baseURL . $endPoint . '?' . $parameters;
//Init session for CURL.
$ch = curl_init();
// Options
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
// Init headers for access to the binance API signed data.
$headers = array();
$headers[] = 'Content-type: application/x-www-form-urlencoded';
$headers[] = 'Content-Length: 0';
// Setting headers
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
// Execute request.
$data = curl_exec($ch);
// If there is an error. Show whats wrong.
if (curl_errno($ch)) {
echo 'Error:' . curl_error($ch);
}
// Ends the CURL session, frees all resources and deletes the curl (ch).
curl_close($ch);
$result = json_encode($data);
echo($data);
exit();
?>
The authentication is oauth2 and I want to use the "Password Grant" flow since I can login automaticly this way. Also I see in the example code in C# that they encode the url, something im not doing yet but did try. It did not work.
// Using $encodedUrl like this: curl_setopt($ch, CURLOPT_URL, $encodedUrl); but does not work.
$encodedUrl = urlencode($url);
Alright so I fixed it. I now got my access token and am able to recieve data from the API. This is what I did:
// ---- GET TOKEN - FLOW: USER PSW ----
// No changes
$baseURL = 'https://authorize.2ba.nl';
// No changes
$endPoint = '/OAuth/Token';
// $parameters is now an array.
$parameters = array(
'grant_type' => 'password',
'username' => 'myUsername',
'password' => 'myPassword',
'client_id' => 'myClientID',
'client_secret' => 'myClientSecret'
);
// Removed the $parameter part
$url = $baseURL . $endPoint;
//Init session for CURL.
$ch = curl_init();
// Init headers for access to the binance API signed data.
$headers = array();
$headers['Content-Type'] = "application/x-www-form-urlencoded";
// NOTE: http_build_query fixed it.
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($parameters)); // Automaticly encodes parameters like client_secret and id.
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
// Execute request.
$data = curl_exec($ch);
// If there is an error. Show whats wrong.
if (curl_errno($ch)) {
echo 'Error:' . curl_error($ch);
}
// Ends the CURL session, frees all resources and deletes the curl (ch).
curl_close($ch);
$result = json_encode($data);
echo($data);
exit();

How do I make a simple PHP API handler?

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

Check whether email is subscribed to list in MailChimp API 3.0 using PHP

I've just read the following on the MailChimp website:
MailChimp API v3.0 is now live!
Prior versions will no longer be supported after 2016, so all API users should begin transitioning to v3.0.
As a result, I would like to move to v3.0 of the API. Please could I have a function, in PHP, that returns a boolean, that will check whether an email address is subscribed to a specific MailChimp list. I do not want to subscribe that user, but merely check whether they are subscribed or not.
If you use the mailchimp-api it looks like that
include 'Mailchimp.php';
use \DrewM\MailChimp\MailChimp;
$MailChimp = new MailChimp('your**api***key');
function emailExistsMc($subscriberMail, $list_id){
global $MailChimp;
$subscriber_hash = $MailChimp->subscriberHash($subscriberMail);
$result = $MailChimp->get("lists/$list_id/members/$subscriber_hash");
if($result['status'] == '404') return false;
return true;
}
If $result['status'] is 404 then the resource was not found. Other possible values for $result['status'] are stated in the docs:
subscribed
unsubscribed
cleaned
pending
transactional
UPDATE: I answered another question with a more elaborate tutorial of how to do this with jQuery .ajax(): Adding subscribers to a list using Mailchimp's API v3
Looking at the Mailchimp documentation and assuming you have a given list in mind, it looks like you would call this endpoint with a GET:
/lists/{list_id}/members/{subscriber_hash}
To do this in PHP, I found a nice script sitting on github. Their last function would probably do the trick for you:
function mc_checklist($email, $debug, $apikey, $listid, $server) {
$userid = md5($email);
$auth = base64_encode( 'user:'. $apikey );
$data = array(
'apikey' => $apikey,
'email_address' => $email
);
$json_data = json_encode($data);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://'.$server.'.api.mailchimp.com/3.0/lists/'.$listid.'/members/' . $userid);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json',
'Authorization: Basic '. $auth));
curl_setopt($ch, CURLOPT_USERAGENT, 'PHP-MCAPI/2.0');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "GET");
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_POSTFIELDS, $json_data);
$result = curl_exec($ch);
if ($debug) {
var_dump($result);
}
$json = json_decode($result);
echo $json->{'status'};
}
If that function doesn't work, the only wrapper I could find for the v3 library works in conjunction with Laravel - Mailchimp v3 API PHP wrapper.
I use the DrewM library
function isSubscribed($emailAddress, $listId) {
$chimp = new \DrewM\MailChimp\MailChimp($apiKeyHere);
$subscriberHash = $chimp->subscriberHash($emailAddress);
$result = $chimp->get('lists/' . $listId . '/members/' . $subscriberHash);
return ($chimp->success() && isset($result['id']));
}

Executing Curl in PHP to do a Stripe subscription

The Stripe API allows for Curl calls to be made. For example, the command:
curl https://api.stripe.com//v1/customers/cus_5ucsCmNxF3jsSY/subscriptions -u sk_test_REDACTED:
returns the subscription of customer cus_5ucsCmNxF3jsSY.
How can I use PHP to call this curl command (I am trying to avoid using the PHP Stripe libraries).
I am trying the following:
<?php
// create curl resource
$ch = curl_init();
// set url
curl_setopt($ch, CURLOPT_URL, "https://api.stripe.com//v1/customers/cus_5ucsCmNxF3jsSY/subscriptions -u sk_test_REDACTED:");
//return the transfer as a string
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
// $output contains the output string
$output = curl_exec($ch);
print($output);
// close curl resource to free up system resources
curl_close($ch);
?>
However, it seems that curl does not take the -u parameter of the URL. I get the following error:
{ "error": { "type": "invalid_request_error", "message": "You did not provide an API key. You need to provide your API key in the Authorization header, using Bearer auth (e.g. 'Authorization: Bearer YOUR_SECRET_KEY'). See https://stripe.com/docs/api#authentication for details, or we can help at https://support.stripe.com/." }
How can I pass the -u sk_test_REDACTED: parameter to my curl call?
I ran into the same issue. I wanted to use PHP's CURL functions instead of using the official stripe API because singletons make me nauseous.
I wrote my own very simple Stripe class which utilizes their API via PHP and CURL.
class Stripe {
public $headers;
public $url = 'https://api.stripe.com/v1/';
public $method = null;
public $fields = array();
function __construct () {
$this->headers = array('Authorization: Bearer '.STRIPE_API_KEY); // STRIPE_API_KEY = your stripe api key
}
function call () {
$ch = curl_init();
curl_setopt($ch, CURLOPT_HTTPHEADER, $this->headers);
switch ($this->method){
case "POST":
curl_setopt($ch, CURLOPT_POST, 1);
if ($this->fields)
curl_setopt($ch, CURLOPT_POSTFIELDS, $this->fields);
break;
case "PUT":
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PUT");
if ($this->fields)
curl_setopt($ch, CURLOPT_POSTFIELDS, $this->fields);
break;
default:
if ($this->fields)
$this->url = sprintf("%s?%s", $this->url, http_build_query($this->fields));
}
curl_setopt($ch, CURLOPT_URL, $this->url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$output = curl_exec($ch);
curl_close($ch);
return json_decode($output, true); // return php array with api response
}
}
// create customer and use email to identify them in stripe
$s = new Stripe();
$s->url .= 'customers';
$s->method = "POST";
$s->fields['email'] = $_POST['email'];
$customer = $s->call();
// create customer subscription with credit card and plan
$s = new Stripe();
$s->url .= 'customers/'.$customer['id'].'/subscriptions';
$s->method = "POST";
$s->fields['plan'] = $_POST['plan']; // name of the stripe plan i.e. my_stripe_plan
// credit card details
$s->fields['source'] = array(
'object' => 'card',
'exp_month' => $_POST['card_exp_month'],
'exp_year' => $_POST['card_exp_year'],
'number' => $_POST['card_number'],
'cvc' => $_POST['card_cvc']
);
$subscription = $s->call();
You can dump $customer and $subscription via print_r to see the response arrays if you want to manipulate the data further.

mobile.de search api Authorization fehler mit PHP curl

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.

Categories