I've been trying to get a PHP application to connect to Instapaper's Xauth services, but for the life of me I can't get it to work. I keep getting an "403: Invalid signature." error.
The error says that my signature base string wasn't what it expected, but when I compare the signature base string I construct with what they say they expect, they're exactly the same (sensitive information removed):
My signature base string:
POST&https%3A%2F%2Fwww.instapaper.com%2Fapi%2F1%2Foauth%2Faccess_token&oauth_callback%3DMy_URL%26oauth_consumer_key%3DCONSUMER_KEY%26oauth_nonce%3Dfe379af261aca07d890d2cfaa0f19ce0%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1461898452%26oauth_version%3D1.0%26x_auth_mode%3Dclient_auth%26x_auth_password%3DPASSWORD%26x_auth_username%3DEXAMPLE%2540gmail.com
What the error says it expects:
POST&https%3A%2F%2Fwww.instapaper.com%2Fapi%2F1%2Foauth%2Faccess_token&oauth_callback%3DMy_URL%26oauth_consumer_key%3DCONSUMER_KEY%26oauth_nonce%3Dfe379af261aca07d890d2cfaa0f19ce0%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1461898452%26oauth_version%3D1.0%26x_auth_mode%3Dclient_auth%26x_auth_password%3DPASSWORD%26x_auth_username%3DEXAMPLE%2540gmail.com
I pulled my php library from https://github.com/mheap/Instapaper-XAuth-PHP, but it's old so I've tried to modify it to work with the current Instapaper API. I believe I'm generating the signature string correctly and am following the instructions found here: https://dev.twitter.com/oauth/overview/creating-signatures and here: http://oauthbible.com/
I don't know what's wrong with the code, can someone please help?
class XAuth_Connection
{
private $_headers = array(
"oauth_signature_method" => "HMAC-SHA1",
"oauth_version" => "1.0",
"oauth_callback" => "MY_URL",
"oauth_consumer_key" => "",
"oauth_nonce" => "",
"oauth_timestamp" => ""
);
private $_params = array(
"x_auth_mode" => "client_auth",
"x_auth_username" => "",
"x_auth_password" => ""
);
private $_access_url = '';
public function __construct($key, $private, $access_url)
{
$this->_headers['oauth_consumer_key'] = $key;
$this->_headers['oauth_nonce'] = md5(uniqid(rand(), true));
$this->_headers['oauth_timestamp'] = time();
$this->_oauth_consumer_private = $private;
$this->_access_url = $access_url;
}
public function set_credentials($user, $password)
{
$this->_params['x_auth_username'] = $user;
$this->_params['x_auth_password'] = $password;
}
public function get_params_as_string()
{
ksort($this->_params);
$req = array();
foreach ($this->_params as $k => $v)
{
$req[] = $k ."=". $this->encode($v);
}
return implode("&", $req);
}
public function get_headers_as_string()
{
ksort($this->_headers);
$req = array();
foreach ($this->_headers as $k => $v)
{
$req[] = $k . "=" . $this->encode($v);
}
return implode("&", $req);
}
public function generate_signature()
{
//combine the parameters, encode, and sort them
$temp_params = array_merge($this->_params, $this->_headers);
$encoded_params = Array();
foreach($temp_params as $k => $v){
$encoded_params[$this->encode($k)] = $this->encode($v);
}
ksort($encoded_params);
//Build the param string
$param_base_string = "";
foreach($encoded_params as $k => $v){
$param_base_string .= $k .'='. $v . '&';
}
$param_base_string = rtrim($param_base_string, '&');
//create the signature base
$signature_base = 'POST&' . $this->encode($this->_access_url) .'&'. $this->encode($param_base_string);
$key = $this->encode($this->_oauth_consumer_private) . '&';
return base64_encode(hash_hmac("sha1",$signature_base, $key, true));
}
public function login()
{
$this->_headers['oauth_signature'] = $this->generate_signature();
ksort($this->_headers);
$header_str = 'OAuth ';
foreach ($this->_headers as $k => $v)
{
$header_str .= $k.'="'.$this->encode($v).'", ';
}
$header_str = rtrim($header_str, ', ');
$oauth_str = $this->get_params_as_string();
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $this->_access_url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $oauth_str);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_HTTPHEADER, array("Authorization: " . $header_str));
$exec = curl_exec($ch);
$info = curl_getinfo($ch);
curl_close($ch);
if ($info['http_code'] != 200)
{
return false;
}
parse_str($exec, $r);
return $r;
}
private function encode($s)
{
return ($s === false ? $s : str_replace('%7E','~',rawurlencode($s)));
}
}
Related
SmartpaySPaymentRepository.php
i am new to laravel. i want to passe this value ($url->nodeValue) which is in the SmartpaySPaymentRepository.php sendPaymentToSmartpaySForPaymentToken function to SmartPaySController.php getQuotePayment($quoteId) function can someone help me to do this?
public function sendPaymentToSmartpaySForPaymentToken($xml, $authToken, $transactionId, $doPrepareUrl)
{
$fields = array(
'authToken' => $authToken,
'&requestXML' => $xml,
);
$fields_string = $xml;
foreach ($fields as $key => $value) {
$fields_string .= $key . '=' . $value . '&';
}
rtrim($fields_string, '&');
//open connection
$ch = curl_init($doPrepareUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POST, 2);
curl_setopt($ch, CURLOPT_POSTFIELDS, $fields_string);
$response_from_smartpays = curl_exec($ch);
curl_close($ch);
$testString = $response_from_smartpays;//xml string
$dom = new \DOMDocument();
$dom->formatOutput = TRUE;
$dom->preserveWhiteSpace = FALSE;
$dom->loadXml($testString);
$result = ($dom->getElementsByTagName('redirectURL'));
foreach ($result as $url){
return ($url->nodeValue);//want to passe this value to controller
}
}
SmartPaySController.php
public function getQuotePayment($quoteId)
{
$quote = $this->quoteRepo->getQuoteById($quoteId);
if($quote) {
$totalPrice = $quote->total_price;
if ($quote->amended_policy) {
$totalPrice = $quote->amend_price;
}
dd($url->nodeValue);//want to use $url->nodeValue here
$currency = CURRENCY_TYPE;
return $this->processSmartpaySPayment(PAYMENT_TYPE_QUOTE, $totalPrice, $currency, $quote->customer_id, $quoteId);
}else {
abort(404);
}
}
You can return them as an array in repository
$resultReturn = []
foreach ($result as $url){
$resultReturn[] = ($url->nodeValue);//want to passe this value to controller
}
return $resultReturn; // pass the array contiling all rsults in the loop
In the controller
$currency = CURRENCY_TYPE;
$results = $this->processSmartpaySPayment(PAYMENT_TYPE_QUOTE, $totalPrice, $currency, $quote->customer_id, $quoteId);
dd($results); //array of $url->nodeValue here
return $results;
I am writing my telegram bot codes in PHP. I would like to split my inline keyboard into 2 or 3 columns. Here is my code:
foreach ($categories as $cat) {
$key[] = array(
array('text'=>$cat['name'],'callback_data'=>'sub-'.$cat['id'])
);
if ($k % 2 == 0) {
$keyoptions[] = $key;
$key = array();
}
$k++;
}
$telegram->SendMessage($userid, $keyoptions);
but my code doesn't work. Where is the problem and how can I solve my issue?
EDIT :
i just used this code
$keyoptions = array_chunk($keyoptions,3);
but still can't find the problem;
Telegram API: inline_keyboard: Array of Array of InlineKeyboardButton
Example:
keyboard: [
["uno :+1:"],["uno \ud83d\udc4d", "due"],["uno", "due","tre"]
]
I don't know what library you are using and what are those fields in your code, but this a working with native telegram API:
function inlineKeyboard($text, $chatID, $btnNames, $callBackDatas)
{
$inlineRow = array(); // this is array for each row of buttons
$i = 0;
foreach ($btnNames as $name) {
array_push($inlineRow, array("text" => $name, "callback_data" => $callBackDatas[$i]));
$i++;
}
/* if you need multiple rows then just create other inlineRow arrays
and push to this array below */
$inlineKeyboard = array($inlineRow);
$keyboard = array(
"inline_keyboard" => $inlineKeyboard
);
$postfields = array
(
'chat_id' => "$chatID",
'text' => $text,
'reply_markup' => json_encode($keyboard)
);
send('sendMessage', $postfields);
}
define('BaseURL', 'https://api.telegram.org/bot<TOKEN>');
function send($method, $datas)
{
$url = BaseURL . "/" . $method;
if (!$curld = curl_init()) {
exit;
}
curl_setopt($curld, CURLOPT_POST, true);
curl_setopt($curld, CURLOPT_POSTFIELDS, $datas);
curl_setopt($curld, CURLOPT_URL, $url);
curl_setopt($curld, CURLOPT_RETURNTRANSFER, true);
$output = curl_exec($curld);
curl_close($curld);
return $output;
}
I use the following api to get product info from amazon.
It uses a single value for variable $asin to get the data and print it as xml. It works fine, but this is only for one product at a timeā¦
I would like instead of a single variable $asin, to use an array with multiple values and print to one single xml.
I tried to use foreach, but I get en xml declaration for every loop.
Where do I need to use foreach in my code? Thanks for the help.
<?php
// Region code and Product ASIN
$response = getAmazonPrice("com", "B00KQPGRRE");
function getAmazonPrice($region, $asin) {
$xml = aws_signed_request($region, array(
"Operation" => "ItemLookup",
"ItemId" => $asin,
"IncludeReviewsSummary" => False,
"ResponseGroup" => "Medium,OfferSummary",
));
$item = $xml->Items->Item;
$title = htmlentities((string) $item->ItemAttributes->Title);
$url = htmlentities((string) $item->DetailPageURL);
$image = htmlentities((string) $item->MediumImage->URL);
$price = htmlentities((string) $item->OfferSummary->LowestNewPrice->Amount);
$code = htmlentities((string) $item->OfferSummary->LowestNewPrice->CurrencyCode);
$qty = htmlentities((string) $item->OfferSummary->TotalNew);
if ($qty !== "0") {
$response = array(
"code" => $code,
"price" => number_format((float) ($price / 100), 2, '.', ''),
"image" => $image,
"url" => $url,
"title" => $title
);
}
return $response;
}
function getPage($url) {
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_FAILONERROR, true);
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
$html = curl_exec($curl);
curl_close($curl);
return $html;
}
function aws_signed_request($region, $params) {
$public_key = "PUBLIC_KEY";
$private_key = "PRIVATE_KEY";
$method = "GET";
$host = "ecs.amazonaws." . $region;
$host = "webservices.amazon." . $region;
$uri = "/onca/xml";
$params["Service"] = "AWSECommerceService";
$params["AssociateTag"] = "affiliate-20"; // Put your Affiliate Code here
$params["AWSAccessKeyId"] = $public_key;
$params["Timestamp"] = gmdate("Y-m-d\TH:i:s\Z");
$params["Version"] = "2011-08-01";
ksort($params);
$canonicalized_query = array();
foreach ($params as $param => $value) {
$param = str_replace("%7E", "~", rawurlencode($param));
$value = str_replace("%7E", "~", rawurlencode($value));
$canonicalized_query[] = $param . "=" . $value;
}
$canonicalized_query = implode("&", $canonicalized_query);
$string_to_sign = $method . "\n" . $host . "\n" . $uri . "\n" . $canonicalized_query;
$signature = base64_encode(hash_hmac("sha256", $string_to_sign, $private_key, True));
$signature = str_replace("%7E", "~", rawurlencode($signature));
$request = "http://" . $host . $uri . "?" . $canonicalized_query . "&Signature=" . $signature;
$response = getPage($request);
var_dump($response);
$pxml = #simplexml_load_string($response);
if ($pxml === False) {
return False;// no xml
} else {
return $pxml;
}
}
?>
I used the following code to have multiple values:
<?php
// Region code and Product ASIN
$array = array("B00PXRRB2U","B00F90P9R0","B005OJU3K4");
foreach ($array as $asin) {
$response = getAmazonPrice("com", $asin);
}
function getAmazonPrice($region, $asin) {
$xml = aws_signed_request($region, array(
"Operation" => "ItemLookup",
"ItemId" => $asin,
"IncludeReviewsSummary" => False,
"ResponseGroup" => "Medium,OfferSummary",
));
The result is:
Amazon allows the lookup of up to 10 items with a single request. Its service expects the ASINs to be passed as a string separated by commas.
So you could try the following code (please note I didn't actually try it because I don't have credentials but I used it like that before and it worked):
$array = array("B00PXRRB2U","B00F90P9R0","B005OJU3K4");
$xml = aws_signed_request('com', array(
"Operation" => "ItemLookup",
"ItemId" => join(', ', $array),
"IncludeReviewsSummary" => False,
"ResponseGroup" => "Medium,OfferSummary",
));
And then I think what you're looking for will be in $xml->Items but you'd better double check that.
I watched a tutorial and did exactly what the guy did. I have the following code for my index.php. The guy in the tutorial recieves a result ( from $result variable ) but i get nothing.
var_dump on $result:
string(0) ""
Where is the problem?
<?php
class Paypal_IPN
{
public function __construct($mode)
{
if ($mode == 'live')
$this->_url = 'https://www.paypal.com/cgi-bin/webscr';
else
$this->_url = 'https://www.sandbox.paypal.com/cgi-bin/webscr';
}
public function run()
{
$postFields = "cdm=_notify-validate";
foreach ((array)$_POST as $key => $value)
{
$postFields .= "&$key=".urlencode($value);
}
$ch = curl_init();
curl_setopt_array($ch, array(
CURLOPT_URL => $this->_url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $postFields
));
$result = curl_exec($ch);
curl_close($ch);
$fh = fopen('result.txt', 'w');
fwrite($fh, $result . " -- \n" . $postFields);
fclose($fh);
var_dump( $result );
}
}
$paypal = new Paypal_IPN('sandbox');
$paypal->run();
I should have recieved INVALID or VALID as result...
You have a typo in the string
$postFields = "cdm=_notify-validate";
Should be
$postFields = "cmd=_notify-validate";
I need to put xml into array and then use join function to show xml file
I extract already xml but don't know how to use join function for this code.
Please help me to figure out this.
Here is xml code:
<ValCurs Date="06.07.2012" name="Ratele oficiale de schimb">
<Valute ID="47">
<NumCode>978</NumCode>
<CharCode>EUR</CharCode>
<Nominal>1</Nominal>
<Name>Euro</Name>
<Value>15.3051</Value>
</Valute>
<Valute ID="44">
<NumCode>840</NumCode>
<CharCode>USD</CharCode>
<Nominal>1</Nominal>
<Name>Dolar S.U.A.</Name>
<Value>12.2343</Value>
Function to extraxt xml :
function curs() {
$date = date("d.m.Y");
$link = 'http://bnm.md/md/official_exchange_rates?get_xml=1&date='.$date;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $link);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$xml_array = curl_exec($ch);
curl_close($ch);
$xml_array = file_get_contents($link);
$values = array();
$curs = new SimpleXMLElement($xml_array);
foreach($curs as $key => $value) {
if (($value->CharCode) == 'USD') {
$values .= $value->Name." - ".$value->Value.", ";
}
if (($value->CharCode) == 'EUR') {
$values .= $value->Name." - ".$value->Value.", ";
}
}
$value = str_replace(',', '.', $values);
return $value;
}
It is not overly clear what you are asking for, but if I gather it correctly you want to do something like this. Note you were mixing array and string logic for the variable $values.
$values = array();
$curs = new SimpleXMLElement($xml_array);
foreach($curs as $key => $value) {
if (($value->CharCode) == 'USD') {
$values[] = $value->Name." - ".$value->Value;
}
if (($value->CharCode) == 'EUR') {
$values[] = $value->Name." - ".$value->Value;
}
}
$value = implode('.', $values);
return $value;
Note: I'm not sure on the usefulness of merging these strings with "." i'd expect you'd be after something like \n.