How do I send json data using Zend 2 http? - php

I've been struggling with this for a few days now - I need to send a set of data encoded in json to an api. I'm trying to use Zend 2 http to achieve this but I've had no luck so far. Here is what the manual for the api says :
Bulk Create Contacts
This command can be used to insert new numbers into your Textlocal contact groups
and will allow you to insert extra fields such as the contact's name.
Parameter Description
group_id ID of the group you’d like to store the numbers in. This
contacts A JSON object containing all the details for each contact.
Note: It is recommended to send this request via POST.
Sample Request
(POST Variables):
username: testing#Textlocal.co.uk
hash: 4c0d2b951ffabd6f9a10489dc40fc356ec1d26d5
group_id: 5
contacts: [{"number":"447123456789","first_name":"Bob","last_name":"Smith","custom1":"","custom2":"","custom3":""},{"number":"447987654321","first_name":"Sally","last_name":"McKenzie","custom1":"","custom2":"","custom3":""},{"number":"447000000000","first_name":"Ramesh","last_name":"Dewani","custom1":"","custom2":"","custom3":""}]
Ok so that's what it expects and this is my code so far :-
include 'Zend/Loader/StandardAutoloader.php';
$loader = new Zend\Loader\StandardAutoloader(array('autoregister_zf' => true));
$loader->register();
use Zend\Http\Client;
use Zend\Http\Request;
$data = array(
'username' => 'myUsername',
'hash' => 'myHash',
'group_id' => 123456,
'contacts' => json_encode(array('number'=>447123456789,'first_name'=>'Bob','last_name'=>'Smith','custom1'=>"",'custom2'=>"","custom3"=>""))
);
$uri = 'https://api.txtlocal.com/create_contacts_bulk';
$request = new Request();
$request->setUri($uri);
$request->setMethod('POST');
$request->getPost()->set($data);
$config = array(
'adapter' => 'Zend\Http\Client\Adapter\Socket',
'ssltransport' => 'ssl',
'sslcert' => '/etc/pki/tls/cert.pem',
'sslcapath' => '/etc/pki/tls/certs'
);
$client = new Client(null, $config);
$client->setEncType(Client::ENC_FORMDATA);
$response = $client->dispatch($request);
if ($response->isSuccess()) {
echo "the post worked!";
}else{
echo "the post failed";
}
That's not working and I'm sure there's I'm missing - here are the errors I get when I fire that script : -
[Thu Oct 24 09:29:47 2013] [error] [client] PHP Warning: Missing argument 2 for Zend\\Stdlib\\Parameters::set(), called in zend_test.php on line 24 and defined in Zend/Stdlib/Parameters.php on line 110
[Thu Oct 24 09:29:47 2013] [error] [client] PHP Notice: Undefined variable: value in Zend/Stdlib/Parameters.php on line 112
[Thu Oct 24 09:29:47 2013] [error] [client] PHP Fatal error: Uncaught exception 'Zend\\Http\\Client\\Exception\\RuntimeException' with message 'Cannot handle content type '' automatically' in Zend/Http/Client.php:1218\nStack trace:\n#0 Zend/Http/Client.php(858): Zend\\Http\\Client->prepareBody()\n#1 Zend/Http/Client.php(798): Zend\\Http\\Client->send(Object(Zend\\Http\\Request))\n#2 zend_test.php(30): Zend\\Http\\Client->dispatch(Object(Zend\\Http\\Request))\n#3 {main}\n thrown in Zend/Http/Client.php on line 1218
Any light you can shed or help you can give me would be greatly appreciated :)
Thanks in advance
Joe

You need to set the enc type when adding post data to the request object (this isn't very clear in the docs). Also, the example from the API manual implies that it's only the contacts that need to be JSON, you've encoded the whole array.
Try this:
$data = array(
'username' => 'myUsername',
'hash' => 'myHash',
'group_id' => 123456,
'contacts' => json_encode(array('number'=>447123456789,'first_name'=>'Bob','last_name'=>'Smith','custom1'=>"",'custom2'=>"","custom3"=>""))
);
$request = new Request();
$request->setUri('https://api.txtlocal.com/create_contacts_bulk');
$request->setMethod('POST');
$request->getPost()->fromArray($data);
$client = new Client();
$client->setEncType(Client::ENC_FORMDATA);
$response = $client->dispatch($request);
if ($response->isSuccess()) {
echo "the post worked!";
}else{
echo "the post failed";
}
Edit: In order to verify that the SSL certificate is valid, the HTTP client needs the path to the CA certificates on your web server.
You pass this in as a config option to the Http client instance:
$client = new Client(null, array(
'sslcapath' => '/etc/ssl/certs'
));
That's the path on Ubuntu, you'll need to find out what it is for your server.

By the way, instead of long constructions of Request, Response and Client classes please conider static Client usage:
http://framework.zend.com/manual/2.0/en/modules/zend.http.client-static.html
use Zend\Http\ClientStatic;
// Simple GET request
$response = ClientStatic::get('http://example.org');
// More complex GET request, specifying query string 'foo=bar' and adding a
// custom header to request JSON data be returned (Accept: application/json)
$response = ClientStatic::get(
'http://example.org',
array( 'foo' => 'bar' ),
array( 'Accept' => 'application/json')
);
// We can also do a POST request using the same format. Here we POST
// login credentials (username/password) to a login page:
$response = ClientStatic::post('https://example.org/login.php', array(
'username' => 'foo',
'password' => 'bar',
));

Related

Failed to open stream: HTTP request failed! HTTP/1.1 400 Bad Request - PHP Error

SOLUTION: I had malformed my JSON data for the payload body. The "ttl" => 30 was in the incorrect array() method. This probably won't help anyone in the future, moving the ttl key/value pair made this work correctly as seen below.
$data = array(
"statement" => array(
"actor" => array(
"mbox" => "mailto:test#example.com"
),
),
"ttl" => 30
);
I have checked numerous other StackOverflow questions and cannot find a solution that works. I should note that I am testing this using a local XAMPP server running on port 8080. Not sure if that matters. I have been able to get this working using Postman, but translating it to PHP has been problematic. Am I missing something? I am not all that familiar with PHP, but need this for work.
EDIT: Some more information about what the API is expecting. It's a fairly simple API that requires a JSON body, a Basic Authorization header, and a Content-Type: application/json.
Here is the JSON body I am using in Postman. This is a direct copy/paste from Postman, which is successfully communicating with the API:
{
"statement": {
"actor": {
"mbox": "mailto:test#example.com"
}
},
"ttl": 30
}
Is there a syntax error in my below PHP code for this? Again, I am learning PHP on the fly so I'm unsure if I am properly constructing a JSON payload using the array() method in PHP.
My code below has the $https_user,$https_password, and $url domain changed for obvious security reasons. In my actual PHP code, I have the same credentials and domain used in Postman.
The $randomSessionID serves no real purpose other than an identification number for future requests. Has no affect on the API response failing or succeeding.
<?php
$https_user = 'username';
$https_password = 'password';
$randomSessionID = floor((mt_rand() / mt_getrandmax()) * 10000000);
$url = 'https://www.example.com/session/' . $randomSessionID . '/launch';
$json = json_encode(array(
"statement" => array(
"actor" => array(
"mbox" => "mailto:test#example.com"
),"ttl" => 30
)
));
$options = array(
'http' => array(
'method' => 'POST',
'header' => 'Content-Type: application/json\r\n'.
"Authorization: Basic ".base64_encode("$https_user:$https_password")."\r\n",
'content' => $json
)
);
$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);
if ($result === FALSE) { /* Handle error */ }
?>
SOLUTION: I had malformed my JSON data for the payload body. The "ttl" => 30 was in the incorrect array() method. This probably won't help anyone in the future, but moving the ttl key/value pair made this work correctly as seen below.
$data = array(
"statement" => array(
"actor" => array(
"mbox" => "mailto:test#example.com"
),
),
"ttl" => 30
);

Creating a http Client in Cake 3

I am having trouble getting a response from an API using a http Client in Cake PHP 3
I want to send the following GET request but I cannot manage to return a result. If visit this url with a browser i get a response.
http://XX.XX.XX.XX:8020/mvapireq/?apientry=newuseru&authkey=XXXXXXXXXX&u_username=NEWUSERNAME&u_password=PASSWORD&u_name=NAME&u_email=EMAIL&u_phone=PHONE&u_currency=USD&u_country=USA&u_address=x&deviceid=DEVICEID&now=555
When I try to send the same request with http Client my reponse object is always null
use Cake\Network\Http\Client;
use Cake\Network\Http\Response;
public function foo(){
$http = new Client();
$data = [
'apientry' => 'newuseru',
'authkey' => 'XXXXXXXX',
'u_username' => 'NEWUSERNAME',
'u_password' => 'PASSWORD',
'u_name' => 'NAME',
'u_email' => 'EMAIL',
'u_phone' => 'PHONE',
'u_currency' => 'USD',
'u_country' => 'USA',
'u_address' => 'x',
'deviceid' => 'DEVICEID',
'now' => '555'
];
$response = $http->get('http://XX.XX.XX.XX:8020/mvapireq', $data);
debug($response->body);
debug($response->code);
debug($response->headers);
}
This is the results from the debug() it seems to me like the request is not being sent.
Notice (8): Trying to get property of non-object [APP/Controller/UsersController.php, line 1159]
/src/Controller/UsersController.php (line 1159)
null
Notice (8): Trying to get property of non-object [APP/Controller/UsersController.php, line 1160]
/src/Controller/UsersController.php (line 1160)
null
Notice (8): Trying to get property of non-object [APP/Controller/UsersController.php, line 1161]
/src/Controller/UsersController.php (line 1161)
null
/src/Controller/UsersController.php (line 1163)
null
I've tried many different ways of structuring $http and all of them have returned the same result. I really can't figure out whats going wrong. Any help would be great.
You can specify hostname and port in the constructor of the Client:
<?php
use Cake\Network\Http\Client;
// ....
public function foo(){
$http = new Client([
'hostname' => 'XX.XX.XX.XX',
'port' => '8020'
]);
$data = [
'apientry' => 'newuseru',
//....
'now' => '555'
];
$response = $http->get('/mvapireq', $data);
// ...
}
And check your system:
firewall (os)
allow_url_fopen (in your php runtime configuration)

Why Share on LinkedIn API return 400 Bad Request?

I'm trying to post a LinkedIn share update via its Share on LinkedIn API using a PHP library LinkedIn-Client API. I've successfully authorized the user and I got the access token returned from it. I use the token along with this share API call. Here is my code:
$linkedInOAuth = new Happyr\LinkedIn\LinkedIn(LINKEDIN_APP_ID, LINKEDIN_APP_SECRET);
if ($accessToken) { // assume that it is retrieved from session
$linkedInOAuth->setAccessToken($accessToken);
$postParams = array(
"content" => array(
'description' => "I'm so exciting to share a post using API."
),
"visibility" => array(
"code" => "connnections-only"
)
);
$result = $linkedInOAuth->api(
"v1/people/~/shares",
array("format" => "json"),
"POST",
$postParams
);
}
However I got 400 bad request error returned from this API call.
Fatal error: Uncaught GuzzleException: 400: Client error response [url] https://api.linkedin.com/v1/people/~/shares?format=json&oauth2_access_token=xxxxxxx [status code] 400 [reason phrase] Bad Request thrown in ...\vendor\happyr\linkedin-api-client\src\Happyr\LinkedIn\Http\GuzzleRequest.php on line 26
What could be the problem?
[UPDATE on 2015-04-30 3:00 PM UTC]
LinkedIn-Client API uses Guzzle internally for HTTP requests. I tried to use GuzzleHttp directly without using Happyr\LinkedIn\LinkedIn->api(), but same error and no success.
if ($accessToken) {
$url = 'https://api.linkedin.com/v1/people/~/shares?format=json&oauth2_access_token=' . $accessToken;
$client = new GuzzleHttp\Client();
$response = $client->post($url, array(
'headers' => array(
'Content-Type' => 'application/json',
'x-li-format' => 'json'
),
'json' => array(
'comment' => 'Check out developer.linkedin.com!',
'content' => array(
'description' => 'I\'m so exciting to share a post using API.'
),
'visibility' => array(
'code' => 'connections-only'
)
)
));
}
Fatal error: Uncaught exception 'GuzzleHttp\Exception\ClientException'
with message 'Client error response [url]
https://api.linkedin.com/v1/people/~/shares?format=json&oauth2_access_token=xxxxx
[status code] 400 [reason phrase] Bad Request' in
\vendor\guzzlehttp\guzzle\src\Exception\RequestException.php:89 Stack
trace: #0 \vendor\guzzlehttp\guzzle\src\Subscriber\HttpError.php(33):
GuzzleHttp\Exception\RequestException::create(Object(GuzzleHttp\Message\Request),
Object(GuzzleHttp\Message\Response)) #1
\vendor\guzzlehttp\guzzle\src\Event\Emitter.php(109):
GuzzleHttp\Subscriber\HttpError->onComplete(Object(GuzzleHttp\Event\CompleteEvent),
'complete') #2 \vendor\guzzlehttp\guzzle\src\RequestFsm.php(91):
GuzzleHttp\Event\Emitter->emit('complete', Object(Guz in
\vendor\guzzlehttp\guzzle\src\Exception\RequestException.php on line
89
[UPDATE on 2015-05-05 9:40 AM UTC]
I copied and used both xml and json examples of Share on LinkedIn API page. This time, the error changed to Internal Server Error.
if ($accessToken) {
$format = 'xml';
$url = 'https://api.linkedin.com/v1/people/~/shares?format='.$format.'&oauth2_access_token=' . $connect->accessToken;
$postParams = array(
"xml" => "
<share>
<comment>Check out developer.linkedin.com!</comment>
<content>
<title>LinkedIn Developer Resources</title>
<description>Leverage LinkedIn's APIs to maximize engagement</description>
<submitted-url>https://developer.linkedin.com</submitted-url>
<submitted-image-url>https://example.com/logo.png</submitted-image-url>
</content>
<visibility>
<code>anyone</code>
</visibility>
</share>",
"json" => array(
"comment" => "Check out developer.linkedin.com!",
"content" => array(
"title" => "LinkedIn Developers Resources",
"description" => "Leverage LinkedIn's APIs to maximize engagement",
"submitted-url" => "https://developer.linkedin.com",
"submitted-image-url" => "https://example.com/logo.png"
),
"visibility" => array(
"code" => "anyone"
)
)
);
$client = new GuzzleHttp\Client();
if ($format === 'xml') {
$response = $client->post($url, array(
'body' => $postParams['xml']
));
} else {
$response = $client->post($url, array(
'headers' => array(
'Content-Type' => 'application/json',
'x-li-format' => 'json'
),
'json' => $postParams['json']
));
}
}
Fatal error: Uncaught exception 'GuzzleHttp\Exception\ServerException'
with message 'Server error response [url]
https://api.linkedin.com/v1/people/~/shares?format=json&oauth2_access_token=xxxx
[status code] 500 [reason phrase] Internal Server Error'
According to the Github issue of Happyr\LinkedIn-API-client, some updates have been made in 0.5.0 and it solved my problem. However, LinkedIn has unclear documentation about its Share API. The following information have to be noted:
The comment field is the sharing update content. The name comment leads confusing.
Using the field comment, URL is optional in the sharing update content.
The content field means snapshot about the content of the URL you are sharing. To describe more clearly, it reflects open graph meta tags;
content.title overrides <meta property="og:title" content="..." />
content.description overrides <meta property="description" content="..." />
content.title overrides <meta property="og:title" content="..." />
content.submitted-url overrides <meta property="og:url" content="..." />
content.submitted-image-url overrides <meta property="og:image" content="..." />
When the content field is used, the field submitted-url is required. The rest are optional. If it is missing, 400 Bad Request would return.
The URLs included in the example codes of LinkedIn Share API would cause 500 Internal Server Error. They should not be used for testing purpose.
The following is the correct usage of API using Happyr\LinkedIn-API-client.
(1) Happyr\LinkedIn - Using the field comment
$linkedInOAuth = new Happyr\LinkedIn\LinkedIn(LINKEDIN_APP_ID, LINKEDIN_APP_SECRET);
// retrieve $accessToken from db or session
$linkedInOAuth->setAccessToken($accessToken);
$postParams = array(
'json' => array(
"comment" => "PHPLucidFrame - The simple, lightweight and flexible web application development framework http://phplucidframe.sithukyaw.com",
"visibility" => array(
"code" => "anyone"
)
)
);
$result = $linkedInOAuth->post('v1/people/~/shares', $postParams);
(2) Happyr\LinkedIn - Using the field content
$linkedInOAuth = new Happyr\LinkedIn\LinkedIn(LINKEDIN_APP_ID, LINKEDIN_APP_SECRET);
// retrieve $accessToken from db or session
$linkedInOAuth->setAccessToken($accessToken);
$postParams = array(
'json' => array(
"content" => array(
"title" => "PHPLucidFrame",
"description" => "The simple, lightweight and flexible web application development framework",
"submitted-url" => "http://phplucidframe.sithukyaw.com"
),
"visibility" => array(
"code" => "anyone"
)
)
);
$result = $linkedInOAuth->post('v1/people/~/shares', $postParams);
The following is the correct usage of API using GuzzleHttp.
(3) GuzzleHttp - Using the field comment
// retrieve $accessToken from db or session
$url = 'https://api.linkedin.com/v1/people/~/shares?format=json&oauth2_access_token=' . $accessToken;
$client = new GuzzleHttp\Client();
$response = $client->post($url, array(
"json" => array(
"comment" => "PHPLucidFrame - The simple, lightweight and flexible web application development framework http://phplucidframe.sithukyaw.com",
"visibility" => array(
"code" => "anyone"
)
)
));
(4) GuzzleHttp - Using the field content
// retrieve $accessToken from db or session
$url = 'https://api.linkedin.com/v1/people/~/shares?format=json&oauth2_access_token=' . $accessToken;
$client = new GuzzleHttp\Client();
$response = $client->post($url, array(
"json" => array(
"content" => array(
"title" => "PHPLucidFrame",
"description" => "The simple, lightweight and flexible web application development framework",
"submitted-url" => "http://phplucidframe.sithukyaw.com"
),
"visibility" => array(
"code" => "anyone"
)
)
));
The fields comment and content can also be used together.
Just a quick guess here but you might need to add json_encode to your $postParams before you send it to the API.
$result = $linkedInOAuth->api(
"v1/people/~/shares",
array("format" => "json"),
"POST",
json_encode($postParams),
);
ALTERNATIVELY
If that does not work I also notice the Linkedin Docs say the following. You could try adding these two headers (if you havent already).
By default, all API calls expect input in XML format, however if it is more covienent for your application to submit data in JSON format, you can inform the APIs that they will be receiving a JSON-formatted payload by including the following two HTTP header values in the call:
Content-Type: application/json
x-li-format: json
Your JSON post body needs to be corrected. Check:
https://developer.linkedin.com/docs/share-on-linkedin
You need to follow either one of these formats.
Share via a comment containing a URL
{
"comment": "Check out developer.linkedin.com! http://linkd.in/1FC2PyG",
"visibility": {
"code": "anyone"
}
}
Share with specific values
{
"comment": "Check out developer.linkedin.com!",
"content": {
"title": "LinkedIn Developers Resources",
"description": "Leverage LinkedIn's APIs to maximize engagement",
"submitted-url": "https://developer.linkedin.com",
"submitted-image-url": "https://example.com/logo.png"
},
"visibility": {
"code": "anyone"
}
}

Confusion with Thu Johns Twitter Laravel 4 PHP package

I am trying to use thu john's twitter-laravel package. I am trying to dynamically set the access tokens and then get the user's home timeline. It says that the method doesn't exist. But I know for sure the method exists in the Twitter class. It is giving me this error.
Error:
Call to undefined method
Thujohn\Twitter\TwitterFacade::getHomeTimeline()
My code:
$config = array(
'ACCESS_TOKEN' => 'xxx',
'ACCESS_TOKEN_SECRET' => 'xxxx'
);
$tw = new Twitter($config);
return $tw->getHomeTimeline(array('count' => 20, 'format' => 'json'));

SOAP error; missing parameter despite given arguments

The following soap request
$response = $this->client->__soapCall('Match', array('word' => 'test', 'strategy' => 'exact'));
yields the error
Uncaught SoapFault exception: [soap:Client] Parameter not specified (null)
Parameter name: word
How can this be? I specified the word parameter in the request, didnt I? Why doesn's the server recognize it?
The service I want to use is an online dictionary webservive
Generally you need to wrap the arguments in a double array:
$response = $this->client->__soapCall('Match', array(array('word' => 'test', 'strategy' => 'exact')));
It reads a bit nicer if you
$aParams = array('word' => 'test', 'strategy' => 'exact');
$response = $this->client->__soapCall('Match', array($aParams));
Or you can simply call the Match function directly
$aParams = array('word' => 'test', 'strategy' => 'exact');
$response = $this->client->Match($aParams);
Or, as a final resort, use the HTTP GET option: http://services.aonaware.com/DictService/DictService.asmx?op=Match
Should get you on the road again.

Categories