Linkedin Oauth Issue - oauth_verifier - php

Having some problems trying to exchange my JSAPI tokens for REST Oauth Tokens (https://developer.linkedin.com/documents/exchange-jsapi-tokens-rest-api-oauth-tokens)
I'm using this library - http://code.google.com/p/oauth-php/ - As opposed to the PECL extension as I'm unable to install extensions onto the server.
There seem to be plenty of similar questions, but none which actually answer the question - How to use the above library to authenticate with Linkedin.
My code is as follows:
$cookie_name = "linkedin_oauth_" . $this->_c->linkedin_api_key;
$credentials_json = stripslashes($_COOKIE[$cookie_name]);
$credentials = json_decode($credentials_json);
// Get the Access Token + Secret
$access_token_url = 'https://api.linkedin.com/uas/oauth/accessToken';
OAuthStore::instance("2Leg", array(
'consumer_key' => $this->_c->linkedin_api_key,
'consumer_secret' => $this->_c->linkedin_api_secret
));
try {
$request = new OAuthRequester($access_token_url, 'POST', array(
'xoauth_oauth2_access_token' => $credentials->access_token
));
$result = $request->doRequest();
} catch(OAuthException2 $e) {
print_r($e->getMessage());
}
The catch statement outputs:
Request failed with code 400: oauth_problem=parameter_absent&oauth_parameters_absent=oauth_verifier
How do I get this oauth_verifier? It was my understanding that I shouldn't need it if I was passing the xoauth_oauth2_access_token already?
I've checked all of the variables I.E. $credentials and $this->_c and all of the variables are passing through correctly.

This is actually a bug in the oauth-php library. The library is incorrectly handling parameters which are prefixed with xoauth_* and treating them the same way it handles oauth_* parameters. This is in violation of the OAuth spec and most (all?) other OAuth libraries don't have this issue. The fix is to do the following:
Inside the file OAuthRequestSigner.php, find the following:
1) inside the getAuthorizationHeader function, find the line which reads:
if (strncmp($name, 'oauth_', 6) == 0 || strncmp($name, 'xoauth_', 7) == 0)
and change it to be:
if (strncmp($name, 'oauth_', 6) == 0)
2) Inside the function getQueryString, find the line which reads:
|| (strncmp($name, 'oauth_', 6) != 0 && strncmp($name, 'xoauth_', 7) != 0))
and change it to be:
|| (strncmp($name, 'oauth_', 6) != 0)
After that, all you need to do is essentially the same as you were already doing, which is the following:
try {
$request = new OAuthRequester($access_token_url, "POST", array('xoauth_oauth2_access_token' => $access_token));
$result = $request->doRequest();
var_dump($result);
} catch(OAuthException2 $e) {
print_r($e->getMessage());
}
And you should be all set. If you have any further issues, please do not hesitate to reach out on our developer forums and either myself or someone else on the team would be happy to help.
Enjoy!
-Jeremy

Related

Why my PHP script does not "see" the webhook from Dialogflow?

I am using DIalogflow (api.ai) to create chat interfaces. I created a webhook from Dialogflow to a simple app containing a php script deployed on Heroku.
Therefore, I placed in the webhook form of Dialogflow the url of my Heroku app which resembles to this: https://my_heroku_app_name.herokuapp.com.
My ultimate goal is to fetch some data from a database (through the php script) and then feed Dialogflow with them. For now, I am only trying to connect the Heroku app (php script) with Dialogflow through a webhook.
The php script of the Heroku app is the following:
<?php
$method = $_SERVER['REQUEST_METHOD'];
if($method == 'GET'){
$requestBody = file_get_contents('php://input');
$json = json_decode($requestBody);
$text = $json->metadata->intentName->text;
switch ($text) {
case 'Name':
$speech = "This question is too personal";
break;
default:
$speech = "Sorry, I didnt get that.";
break;
}
$response = new \stdClass();
$response->speech = $speech;
$response->displayText = $speech;
$response->source = "webhook";
echo json_encode($response);
}
else
{
echo "Method not allowed";
}
?>
Keep in mind the following:
$method is GET for some reason instead of POST as it is supposed to be from Dialogflow.
if you try to echo any of the variables $requestBody, $json or $text then nothing is printed.
I have tested that the if branch is executed and that the default branch is executed at switch.
Why my PHP script cannot "see" the webhook from DIaloflow and fetch the data from it so as to respond appropriately?
P.S. My question is not a duplicate of Valid JSON output but still getting error. The former is about the input of the php script whereas the latter is about the output of the php script. These two things do not necessarily constitute identical problems.
try to do something like this with some modification in your code.
First, I suggest you to use action instead of using intent name for switch case.
index.php
<?php
require 'get_wardinfo.php';
function processMessage($input) {
$action = $input["result"]["action"];
switch($action){
case 'wardinfo':
$param = $input["result"]["parameters"]["number"];
getWardInfo($param);
break;
default :
sendMessage(array(
"source" => "RMC",
"speech" => "I am not able to understand. what do you want ?",
"displayText" => "I am not able to understand. what do you want ?",
"contextOut" => array()
));
}
}
function sendMessage($parameters) {
header('Content-Type: application/json');
$data = str_replace('\/','/',json_encode($parameters));
echo $data;
}
$input = json_decode(file_get_contents('php://input'), true);
if (isset($input["result"]["action"])) {
processMessage($input);
}
?>
get_wardinfo.php
<?php
require 'config.php';
function getWardInfo($param){
$wardinfo="";
$Query="SELECT * FROM public.wardinfo WHERE wardno=$param";
$Result=pg_query($con,$Query);
if(isset($Result) && !empty($Result) && pg_num_rows($Result) > 0){
$row=pg_fetch_assoc($Result);
$wardinfo= "Here is details that you require: Name: " . $row["name"]. " --- Address: " . $row["address"]. " --- MobileNo: " . $row["contact"];
$arr=array(
"source" => "RMC",
"speech" => $wardinfo,
"displayText" => $wardinfo,
);
sendMessage($arr);
}else{
$arr=array(
"source" => "RMC",
"speech" => "Have some problem .",
"displayText" => "Have some problem .",
);
sendMessage($arr);
}
}
?>
It seems you know each parameter and all about dialogflow and how it works with PHP arrays and all still if you have confusion in above code or method kindly put a comment.
And I will suggest you don't go for Heroku directly first try it with ngrok it will make your local server live and put the URL as webhook in dialogflow and you can easily debug the errors and all.
I managed to connect Dialogflow to my php script on Heroku.
I made the following changes on my php script (on Heroku) and on Dialogflow which led to this result:
I replaced the condition if($method == 'GET') with the condition if($method == 'POST') so as to anticipate the POST request of Dialogflow.
Keep in mind that until I solved the whole problem I was not receiving any POST request but I GET request so I thought that the POST request from Dialogflow leads to GET request because of a webpage redirection which I could not really see at that moment.
I replaced $text = $json->metadata->intentName->text; with $text = $json->results->metadata->intentName; which was the right json parsing for retrieving the value of intentName. (I have published here the json request from Dialogflow but nobody noticed my mistake)
I published my bot on Dialogflow through its built-in web demo and on Slack. This may sound quite irrelevant but also one person on the Dialogflow forum stated that: "Maybe it should rementioned somewhere. that api.ai98 is not parsing any parameters/values/data to you service untill you bot is published!!" (See the second post here: https://discuss.api.ai/t/webhook-in-php-example/229).

Always getting response as Invalid Session Token in soap client php

I have php version 7.1 in my localhost. I have made changes in my php.ini file to run SOAP from my localhost.
I need to generate primary and secondary session token by passing login id and password to SOAP client API.
Once session token is authenticated it will return some rate chart. My code is generating session tokens. But when I am passing that token key to the next method in SOAP Client api its always giving me an error like "Invalid Session Token" or "Invalid Authentication". However the same tokens are working well in SOAP UI exe. I mean I have installed SOAP UI exe and by using wsdl "http://cnx.test.dat.com:9280/wsdl/TfmiFreightMatching.wsdl" and using method "Login" and "LookupRate" its working everything fine. The way i need that.
But whenever i am using that tokens in php localhost its always giving me an authentication error by SOAP Client.
I am sharing my code below.
$wsdl = "http://cnx.test.dat.com:9280/wsdl/TfmiFreightMatching.wsdl";
$client = new SoapClient($wsdl, array('trace' => true));
$params = array('loginOperation'=>array('loginId'=>'ryder_cnx1','password'=>'ryder1','thirdPartyId'=>'dl'));
$client->Login($params);
$data = $client->__getLastResponse();
$p = xml_parser_create();
xml_parse_into_struct($p, $data, $vals, $index);
xml_parser_free($p);
$token = [];
foreach ($vals as $key => $value) {
foreach ($value as $key1 => $value1) {
if($key1 == "value")
$token[] = $value1;
}
}
echo "Primary Token = ".$token[0];
echo "<br> Secondary Token = ".$token[1];
//echo "<br> Expiry Date = ".$token[2];
$params_session = array("sessionToken"=> array("primary"=>$token[0], "secondary"=>$token[1]));
$namespace = 'http://www.tcore.com/TcoreTypes.xsd'; // I am not sure about this namespace. Whether its correct or not.
$header = new SoapHeader($namespace,'sessionHeader',$params_session,true);
$client->__setSoapHeaders($header);
$params_data = array('lookupRateOperations'=> array(
'equipment'=>'Vans',
'origin'=>array('postalCode'=>array('country'=>'US','code'=>'30004')),
'destination'=>array('postalCode'=>array('country'=>'US','code'=>'10001'))
));
try{
$result = $client->LookupRate($params_data);
print_r($result);
}catch (SoapFault $exception){
//or any other handling you like
print_r(get_class($exception));
enter code hereprint_r($exception);
}
if anybody have any idea, please share it with me.
Awaiting any response.
Thanks a lot in advance :)
I know this is very old, and most likely the OP figured it out. But in case anyone else comes along, I was able to get it working with two slight changes.
First,
$namespace = 'http://www.tcore.com/TcoreTypes.xsd';
Should be
$namespace = 'http://www.tcore.com/TcoreHeaders.xsd';
Second,
$params_session = array("sessionToken"=> array("primary"=>$token[0], "secondary"=>$token[1]));
should be
$params_session = array(
"sessionToken"=> array(
"primary"=>base64_decode($token[0]),
"secondary"=>base64_decode($token[1])
)
);
The rest of my code is similar enough that if the above changes are made, it should work. I would also refrain from posting real usernames and passwords, btw.

How to get LINE user mid using PHP SDK?

I use the LINE BOT API Trial SDK PHP (https://github.com/line/line-bot-sdk-php).
But, for this method:
$res = $bot->sendText(['TARGET_MID'], 'Message');
How to get the user's MID to send them a message?
Thanks for help.
1) A very quick way to get the mid of an interactive user (more of a fun hack, really) is to register a callback URL as per the API instructions, then capture the POST data to that URL like so:
// /callback/index.php
<?php
$postdata = file_get_contents("php://input");
#file_get_contents('https://'.$_SERVER['SERVER_NAME'].'/LINE/' . json_encode($postdata));
Next, scan the QR code in the channel console and add your trial bot to your LINE account. After that is done, send it a quick "Hello!" text.
You could then save the POST data to a text file if you wish, or you could check the server logs. For example, you might see something like this:
163.128.118.223 - - [03/Sep/2016:07:25:25 -0700] "POST /line/callback/ HTTP/1.1" 200 - "-" "ChannelEventDispatcher/1.0"
106.152.218.107 - - [03/Sep/2016:07:25:25 -0700] "GET /LINE/{\"result\":[{\"content\":{\"toType\":1,\"createdTime\":1472114754839,\"from\":\"ub7dbd4a12c322f6c0117773d739c55a4\",\"location\":null,\"id\":\"4357194057879\",\"to\":[\"u2b6a4ba287028dee7291122094dac827\"],\"text\":\"Hello!\",\"contentMetadata\":{\"AT_RECV_MODE\":\"2\",\"SKIP_BADGE_COUNT\":\"true\"},\"deliveredTime\":0,\"contentType\":1,\"seq\":null},\"createdTime\":1472912724868,\"eventType\":\"138311609000106301\",\"from\":\"u236d23c2e36bd87217655609a1c31cb8\",\"fromChannel\":1241102815,\"id\":\"WB1519-3102846635\",\"to\":[\"u2b6a4ba287028dee7291122094dac827\"],\"toChannel\":1462261375}]} HTTP/1.1" 404 15 "-" "-"
The \"from\":\"ub7dbd4a12c322f6c0117773d739c55a4\" is the pertinent part.
2) If you'd like to get started with receiving messages, you can start like this as your callback script. Simply send your BOT the message 'mid' and it should respond with your mid.
Here is a starting callback script I made with signature verification included for you.
// /callback/index.php
<?php
// Show all errors for testing
error_reporting(E_ALL);
// SDK is installed via composer
require_once __DIR__ . "/includes/vendor/autoload.php";
use LINE\LINEBot;
use LINE\LINEBot\HTTPClient\GuzzleHTTPClient;
// Set these
$config = [
'channelId' => LINE_CHANNEL_ID,
'channelSecret' => LINE_CHANNEL_SECRET,
'channelMid' => LINE_CHANNEL_MID,
];
$sdk = new LINEBot($config, new GuzzleHTTPClient($config));
$postdata = #file_get_contents("php://input");
$messages = $sdk->createReceivesFromJSON($postdata);
// Verify the signature
// REF: http://line.github.io/line-bot-api-doc/en/api/callback/post.html#signature-verification
$sigheader = 'X-LINE-ChannelSignature';
// REF: http://stackoverflow.com/a/541450
$signature = #$_SERVER[ 'HTTP_'.strtoupper(str_replace('-','_',$sigheader)) ];
if($signature && $sdk->validateSignature($postdata, $signature)) {
// Next, extract the messages
if(is_array($messages)) {
foreach ($messages as $message) {
if ($message instanceof LINEBot\Receive\Message\Text) {
$text = $message->getText();
if ($text == "mid") {
$fromMid = $message->getFromMid();
// Send the mid back to the sender and check if the message was delivered
$result = $sdk->sendText([$fromMid], 'mid: ' . $fromMid);
if(!$result instanceof LINE\LINEBot\Response\SucceededResponse) {
error_log('LINE error: ' . json_encode($result));
}
} else {
// Process normally, or do nothing
}
} else {
// Process other types of LINE messages like image, video, sticker, etc.
}
}
} // Else, error
} else {
error_log('LINE signatures didn\'t match');
}

Context.io PHP API Giving Error

I have run into a problem with the Context.io API. I keep getting the following error message:
Warning: Invalid argument supplied for foreach() in /usr/share/nginx/html/custom-assets/includes/ContextIO/demo.php on line 11
Here is my php code:
// Require the Context.io PHP Library
require('class.contextio.php');
// See https://console.context.io/#settings to get your consumer key and consumer secret.
$contextIO = new ContextIO('consumer key','consumer secret');
$accountId = 'xxxxxxxxxx'; // Account ID of email account
$args = array('folder' => 'Inbox', 'include_flags' => 1, 'include_thread_size' => 1, 'include_body' => 1, 'limit' => 50);
echo "Getting last 50 messages...<br><br>";
$r = $contextIO->listMessages($accountId, $args);
if ($r !== false) {
foreach ($r->getData() as $message) {
echo "Subject: ".$message['subject']."<br>";
}
} else {
var_dump($r);
}
I have no clue why this is not working. Anybody have any clue why?
All of the functions in the ContextIO library return a ContextIOResponse object, or false if the API returns an http error code. If you add a check for if($r !== false) before you call getData() it should catch any errors.

How to perform multiple Guzzle requests at the same time?

I can perform single requests using Guzzle and I'm very pleased with Guzzle's performance so far however, I read in the Guzzle API something about MultiCurl and Batching.
Could someone explain to me how to make multiple requests at the same time? Async if possible. I don't know if that is what they mean with MultiCurl. Sync would also be not a problem. I just want to do multiple requests at the same time or very close (short space of time).
From the docs:
http://guzzle3.readthedocs.org/http-client/client.html#sending-requests-in-parallel
For an easy to use solution that returns a hash of request objects mapping to a response or error, see http://guzzle3.readthedocs.org/batching/batching.html#batching
Short example:
<?php
$client->send(array(
$client->get('http://www.example.com/foo'),
$client->get('http://www.example.com/baz'),
$client->get('http://www.example.com/bar')
));
An update related to the new GuzzleHttp guzzlehttp/guzzle
Concurrent/parallel calls are now run through a few different methods including Promises.. Concurrent Requests
The old way of passing a array of RequestInterfaces will not work anymore.
See example here
$newClient = new \GuzzleHttp\Client(['base_uri' => $base]);
foreach($documents->documents as $doc){
$params = [
'language' =>'eng',
'text' => $doc->summary,
'apikey' => $key
];
$requestArr[$doc->reference] = $newClient->getAsync( '/1/api/sync/analyze/v1?' . http_build_query( $params) );
}
$time_start = microtime(true);
$responses = \GuzzleHttp\Promise\unwrap($requestArr); //$newClient->send( $requestArr );
$time_end = microtime(true);
$this->get('logger')->error(' NewsPerf Dev: took ' . ($time_end - $time_start) );
Update:
As suggested in comments and asked by #sankalp-tambe, you can also use a different approach to avoid that a set of concurrent request with a failure will not return all the responses.
While the options suggested with Pool is feasible i still prefer promises.
An example with promises is to use settle and and wait methods instead of unwrap.
The difference from the example above would be
$responses = \GuzzleHttp\Promise\settle($requestArr)->wait();
I have created a full example below for reference on how to handle the $responses too.
require __DIR__ . '/vendor/autoload.php';
use GuzzleHttp\Client as GuzzleClient;
use GuzzleHttp\Promise as GuzzlePromise;
$client = new GuzzleClient(['timeout' => 12.0]); // see how i set a timeout
$requestPromises = [];
$sitesArray = SiteEntity->getAll(); // returns an array with objects that contain a domain
foreach ($sitesArray as $site) {
$requestPromises[$site->getDomain()] = $client->getAsync('http://' . $site->getDomain());
}
$results = GuzzlePromise\settle($requestPromises)->wait();
foreach ($results as $domain => $result) {
$site = $sitesArray[$domain];
$this->logger->info('Crawler FetchHomePages: domain check ' . $domain);
if ($result['state'] === 'fulfilled') {
$response = $result['value'];
if ($response->getStatusCode() == 200) {
$site->setHtml($response->getBody());
} else {
$site->setHtml($response->getStatusCode());
}
} else if ($result['state'] === 'rejected') {
// notice that if call fails guzzle returns is as state rejected with a reason.
$site->setHtml('ERR: ' . $result['reason']);
} else {
$site->setHtml('ERR: unknown exception ');
$this->logger->err('Crawler FetchHomePages: unknown fetch fail domain: ' . $domain);
}
$this->entityManager->persist($site); // this is a call to Doctrines entity manager
}
This example code was originally posted here.
Guzzle 6.0 has made sending multiple async requests very easy.
There are multiple ways to do it.
You can create the async requests and add the resultant promises to a single array, and get the result using the settle() method like this:
$promise1 = $client->getAsync('http://www.example.com/foo1');
$promise2 = $client->getAsync('http://www.example.com/foo2');
$promises = [$promise1, $promise2];
$results = GuzzleHttp\Promise\settle($promises)->wait();
You can now loop through these results and fetch the response using GuzzleHttpPromiseall or GuzzleHttpPromiseeach. Refer to this article for further details.
In case if you have an indeterminate number of requests to be sent(say 5 here), you can use GuzzleHttp/Pool::batch().
Here is an example:
$client = new Client();
// Create the requests
$requests = function ($total) use($client) {
for ($i = 1; $i <= $total; $i++) {
yield new Request('GET', 'http://www.example.com/foo' . $i);
}
};
// Use the Pool::batch()
$pool_batch = Pool::batch($client, $requests(5));
foreach ($pool_batch as $pool => $res) {
if ($res instanceof RequestException) {
// Do sth
continue;
}
// Do sth
}

Categories