Failed to validate oauth signature and token - php

For reasons beyond my control I am using PHP4 to write a twitter client. Requests don't work properly - I am having a tough time seeing what's wrong. Any ideas?
I have grabbed the code and banged it in a very simple script here to illustrate essentially what's going on. I've hidden OAuth keys for security purposes.
<?php
$requestTokenURL = 'https://api.twitter.com/oauth/request_token';
$consumerKey = 'fLxA6J1111111111PnvVOg';
$consumerSecret = 'H5QxDHAOHn1111111111111Ozet1HRTtVAV1FM3oYk';
$callbackURL = 'http://www.example.com';
$signature = 'POST&' . urlencode($requestTokenURL) . '&';
$auth_params = array(
'oauth_callback' => $callbackURL,
'oauth_consumer_key' => $consumerKey,
'oauth_nonce' => md5(time()),
'oauth_signature_method' => 'HMAC-SHA1',
'oauth_timestamp' => time(),
'oauth_version' => '1.0'
);
ksort($auth_params);
foreach($auth_params as $k=>$v) {
if ($k == 'oauth_callback') {
$v = urlencode($v);
}
$signature .= urlencode($k) . '%3D' . urlencode($v) . '%26';
}
$signature = substr($signature, 0, strlen($signature) - 3);
$signing_key = $consumerSecret . '&';
$oauth_signature = hmac_sha1($signing_key, $signature);
$auth_params['oauth_signature'] = $oauth_signature;
$auth_string = 'OAuth ';
foreach($auth_params as $k=>$v) {
$auth_string .= $k . '="' . urlencode($v);
$auth_string .= ($k == 'oauth_signature') ? '&' : '';
$auth_string .= '", ';
}
$auth_string = substr($auth_string, 0, strlen($auth_string) - 2);
echo 'Authorization header: <pre>';
echo $auth_string;
echo '</pre>';
echo '<br /><br />';
echo 'OAuth Signature: <pre>';
var_dump($oauth_signature);
echo '</pre>';
echo '<br /><br />';
//exit;
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $requestTokenURL);
curl_setopt($curl, CURLOPT_POST, GET);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_HTTPHEADER, array('Authorization: ' . $auth_string)
);
$response = curl_exec($curl);
curl_close($curl);
var_dump($response);
/* function from PHP.net - no PHP4 built-in function */
function hmac_sha1( $key, $data ) {
$blocksize = 64;
$hashfunc = 'sha1';
if ( strlen( $key ) >$blocksize ) {
$key = pack( 'H*', $hashfunc( $key ) );
}
$key = str_pad( $key, $blocksize, chr(0x00) );
$ipad = str_repeat( chr( 0x36 ), $blocksize );
$opad = str_repeat( chr( 0x5c ), $blocksize );
$hash = pack( 'H*', $hashfunc( ( $key^$opad ).pack( 'H*',$hashfunc( ($key^$ipad).$data ) ) ) );
return base64_encode($hash);
}
?>
the thing is, I tried running this script with the values from http://dev.twitter.com/pages/auth#signing-requests and the signature and the Authorization string were exactly the same - but when I try execute with CURL with my own values (using the exacty same code) it just gives me the rather non-descript "Failed to validate oauth signature and token"

Can't believe it - just found it a second or two after posting this question. There was in fact two things wrong with it:
1) The time on my dev server wasn't properly set. After setting this correctly however, it still didn't work.
2) after setting curl_setopt($curl, CURLOPT_POST, true) everything magically worked. Hoorah!

Related

Twitter stream api print out statuses

I have the following code
<?php
/*
This is an app to search tiwtter statuses.
*/
function queryTwitter($search)
{
$url = "https://api.twitter.com/1.1/search/tweets.json";
if($search != "")
$search = "#".$search;
$query = array( 'count' => 100, 'q' => urlencode($search), "result_type" => "recent");
$oauth_access_token = "XXXX";
$oauth_access_token_secret = "xxxx";
$consumer_key = "xxxx";
$consumer_secret = "xxxx";
$oauth = array(
'oauth_consumer_key' => $consumer_key,
'oauth_nonce' => time(),
'oauth_signature_method' => 'HMAC-SHA1',
'oauth_token' => $oauth_access_token,
'oauth_timestamp' => time(),
'oauth_version' => '1.0');
$base_params = empty($query) ? $oauth : array_merge($query,$oauth);
$base_info = buildBaseString($url, 'GET', $base_params);
$url = empty($query) ? $url : $url . "?" . http_build_query($query);
$composite_key = rawurlencode($consumer_secret) . '&' . rawurlencode($oauth_access_token_secret);
$oauth_signature = base64_encode(hash_hmac('sha1', $base_info, $composite_key, true));
$oauth['oauth_signature'] = $oauth_signature;
$header = array(buildAuthorizationHeader($oauth), 'Expect:');
$options = array( CURLOPT_HTTPHEADER => $header,
CURLOPT_HEADER => false,
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_SSL_VERIFYPEER => false);
$feed = curl_init();
curl_setopt_array($feed, $options);
$json = curl_exec($feed);
curl_close($feed);
return json_decode($json);
}
function buildBaseString($baseURI, $method, $params)
{
$r = array();
ksort($params);
foreach($params as $key=>$value){
$r[] = "$key=" . rawurlencode($value);
}
return $method."&" . rawurlencode($baseURI) . '&' . rawurlencode(implode('&', $r));
}
function buildAuthorizationHeader($oauth)
{
$r = 'Authorization: OAuth ';
$values = array();
foreach($oauth as $key=>$value)
$values[] = "$key=\"" . rawurlencode($value) . "\"";
$r .= implode(', ', $values);
return $r;
}
// This is where I want to break down the object to an array and have it print out each individual tweet
function displayTweets($object){
$myArray = json_decode(json_encode($object), true);
//print_r($myArray);
foreach ($myArray as $tweet){
print "Status: ";
$array = print_r($tweet,true);
print $array['text'];
print "<br>";
}
}
?>
<html>
<head>
</head>
<body>
Search here for twitter statuses.
<input type='text'>
<br>
<?php
$search = queryTwitter("dbz");
//print_r($search);
displayTweets($search);
?>
</body>
</html>
I am trying to put out a status found like this...
print $tweet['text'];
I am not sure on how to convert the $search object to an array where I can print $tweet['text'] or print $tweet['location'];
How do I convert the object created by the function queryTwitter($search) to a printable array. I also tried to foreach the object and print out $tweet->text and it didn't work. When I use print_r($object) it prints out the information. How can I complete the displayTweets function?
I figured it out.
here is the solution in code.
function displayTweets($object){
$myArray = json_decode(json_encode($object), true);
//$myArray = json_encode($object);
//echo print_r($myArray["statuses"][0]);
foreach ($myArray["statuses"] as $tweet){
echo "User :";
echo $tweet['user']['screen_name'];
echo "<br>";
echo $tweet['text'];
echo "<br>";
}
}

Custom google sheets function returning "Illegally formed XML syntax. (Last line) - PHP script

I have been trying to implement this function in google sheets, however it keeps returning "Illegally formed xml syntax" in line 93,the very last line "?>". I have attached the code without my personal information.
I am pasting this code in the code editor of google sheets by coding to tools --> Script editor, does anyone know what I need to change?
If anyone could help me figure out where I am going wrong implementing this custom function code into google sheets it would be much appreciated!
Code Starts: (Sorry I couldn't figure out how to input it correctly)
<?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;
}
}
?>
Please try serving canonical URLs with https instead of using http.
As stated in HTTPS required for active content
"Active" content like scripts, external stylesheets, and XmlHttpRequests must be loaded over HTTPS, not HTTP.
Hope that works for you!

How to populate a "select" form with flickr photoset titles? (with PHP)

I'm in the process of creating a photo uploader that uploads photos directly to a personal flickr account... right now I'm trying to call all my photosets (by title) and populate my select dropdown with them. Unfortunately everything I've been trying hasn't worked... so I'm here for some help from you experienced people! ;)
Here's the code I'm working with:
From my file called class.flickr.php
// Code being used for the purpose of calling photoset titles
public function getPhotosets() {
// Function specific variables
$flickr_api_call = "http://api.flickr.com/services/rest/";
$method = "flickr.photosets.getList";
$nsid = 'my user id';
$url_parameters = array(
'method' =>$method,
'oauth_consumer_key' =>$this->flickr_key,
'user_id' =>$nsid,
'format' =>$this->format,
'nojsoncallback' =>'1',
'oauth_nonce' =>$this->nonce,
'oauth_timestamp' =>$this->timestamp,
'oauth_version' =>'1.0',
);
$parameters_string = "";
foreach ( $url_parameters as $key=>$value ) $parameters_string .= "$key=" . urlencode( $value ) . "&";
$url = $flickr_api_call . "?" . $parameters_string;
$photosets = array();
$data = json_decode(file_get_contents($url), true);
if ( $data['stat'] != 'fail' ) {
$photosets = $data['photosets']['photoset'];
return $photosets;
} else {
return false;
}
var_dump( $photosets );
} // end getPhotosets
The code being used to call the getPhotosets method within my main document:
<select class="categorize-options">
<?php
require_once( 'class.flickr.php' );
$flickr = new Flickr( 'api key', 'api shared secret' );
$results = $flickr->getPhotosets();
if ( !empty( $results )):
foreach( $results as $photoset ):?>
<option><?php echo $photoset['title']; ?></option>
<?php endforeach;
else:
echo "This isn't working!!! :)";
endif;
?>
</select>
The thing that is really confusing me is that both the var_dump() and the else statement are not displaying... but, neither is anything else. Would be a great help to get some experienced input... thanks!
First, though flickr documentation says you don't need authorization for the method flickr.photosets.getList... it is wrong. You will need to run an authorization function something like this:
// Get list of photosets (for their titles)
public function getPhotosets() {
// Function specific variables
$flickr_api_call = $this->flickr_rest_call;
$method = "flickr.photosets.getList";
$nsid = 'user_id';
$access_token = "access_token";
$access_token_secret = "access_token_secret";
$url = "format=" . $this->format;
$url .= "&method=" . $method;
$url .= "&nojsoncallback=1";
$url .= "&oauth_consumer_key=" . $this->flickr_key;
$url .= "&oauth_nonce=" . $this->nonce;
$url .= "&oauth_signature_method=" . $this->sig_method;
$url .= "&oauth_timestamp=" . $this->timestamp;
$url .= "&oauth_token=" . $access_token;
$url .= "&oauth_version=1.0";
$url .= "&user_id=" . urlencode( $nsid );
$baseurl = "GET&" . urlencode( $flickr_api_call ) . "&" . urlencode( $url );
$hashkey = $this->flickr_secret . "&" . $access_token_secret;
$oauth_signature = base64_encode( hash_hmac( 'sha1', $baseurl, $hashkey, true ));
$url_parameters = array(
'method' =>$method,
'oauth_consumer_key' =>$this->flickr_key,
'user_id' =>$nsid,
'format' =>$this->format,
'nojsoncallback' =>'1',
'oauth_nonce' =>$this->nonce,
'oauth_timestamp' =>$this->timestamp,
'oauth_signature_method'=>$this->sig_method,
'oauth_version' =>'1.0',
'oauth_token' =>$access_token,
'oauth_signature' =>$oauth_signature
);
/* Now that we have encoded the parameters for our ouath_signature
* and have reformated them for the url we need to send... we must
* re-urlencode them too. */
$parameters_string = "";
foreach ( $url_parameters as $key=>$value )
$parameters_string .= "$key=" . urlencode( $value ) . "&";
$url = $flickr_api_call . "?" . $parameters_string;
NOTE: any time you use nsid you need to urlencode the value twice! Reason: the #, if only encoded once will return like this %40, but in order to keep the % you MUST encode twice resulting in this: %2540
Secondly, change your call from the json response from this: <option><?php echo $photoset['title']; ?></option> to this: <option><?php echo $photoset['title']['_content']; ?></option>
This is how I was able to accomplish this... if there is a better, more efficient way of doing this I'd love to hear about it.

Delete a tweet using the twitter-async library by searching for the tweet?

I'm looking for some help deleting a tweet using twitter-async from https://github.com/jmathai/twitter-async by I guess searching for the tweet?
If we try the following code we can post to twitter
try {
$twitter->post_statusesUpdate(array('status' => $tweet));
} catch (EpiTwitterForbiddenException $e) {
$msg = json_decode($e->getMessage());
if ($msg->error != 'Status is a duplicate.') {
//throw $e;
}
}
https://dev.twitter.com/docs/api/1.1/post/statuses/destroy/%3Aid
However, if it's ran twice the second time it will return that it's a duplicate tweet... or if it was tweeted a few tweets prior it will again return that it's a duplicate tweet.
How can I either search for and then delete or directly delete the duplicate tweet and then tweet the exact message again (putting it to top/latest tweet)
Any ideas?
To do what you want, you have to:
1st: search the tweets of the user, and interpret its json to get the id of a repeated tweet if there is one. (notice that when comparing the text you shall use the php function htmlspecialchars() because there are special characters that are stored in twitter as HTML entities [ref.]);
2nd: remove the repeated tweet if it exists;
3rd: (re-)post the tweet.
(optionally you can add a 0th step, which would be to try a normal submission of the tweet, and advance to the other steps only if you have an error, it's up to you.)
Here you have a code that makes these requests and interpret the json of the search, etc.:
$settings = array(
'oauth_access_token' => "...",
'oauth_access_token_secret' => "...",
'consumer_key' => "...",
'consumer_secret' => "..."
);
$API = new twitter_API($settings);
$tweet_text = '>>testing the twitter API-1.1...';
## search the list of tweets for a duplicate...
$url = "https://api.twitter.com/1.1/statuses/user_timeline.json";
$json = $API->make_request($url, "GET");
$twitter_data = json_decode($json);
$id_str = null;
foreach ($twitter_data as $item){
$cur_text = $item->text;
if (strcmp($cur_text, htmlspecialchars($tweet_text))==0){
$id_str = $item->id_str;
echo "found a duplicate tweet with the id: " . $id_str . "<br /><br />";
}
}
## remove the duplicate, if there is one...
if ($id_str){
$url = "https://api.twitter.com/1.1/statuses/destroy/" . $id_str . ".json";
$json = $API->make_request($url, "POST");
echo $json . '<br /><br />';
}
## post the tweet
$url = "https://api.twitter.com/1.1/statuses/update.json";
$postfields = array(
'status' => $tweet_text
);
$json = $API->make_request($url, "POST", $postfields);
echo $json . '<br /><br />';
This code uses the class twitter_API, which is an adaptation from the answers in [ref.]. You can use this class, or replace the callings to their functions by the functions of twitter-async.
class twitter_API
{
private $oauth_access_token;
private $oauth_access_token_secret;
private $consumer_key;
private $consumer_secret;
protected $oauth;
public function __construct(array $settings){
if (!in_array('curl', get_loaded_extensions())){
echo 'you need to install cURL!';
exit();
}
$this->oauth_access_token = $settings['oauth_access_token'];
$this->oauth_access_token_secret = $settings['oauth_access_token_secret'];
$this->consumer_key = $settings['consumer_key'];
$this->consumer_secret = $settings['consumer_secret'];
}
function build_base_string($base_URI, $method, $params){
$r = array();
ksort($params);
foreach($params as $key=>$value){
$r[] = "$key=" . rawurlencode($value);
}
return $method . "&" . rawurlencode($base_URI) . '&' . rawurlencode(implode('&', $r));
}
function build_authorization_header($oauth){
$r = 'authorization: oauth ';
$values = array();
foreach ($oauth as $key=>$value)
$values[] = "$key=\"" . rawurlencode($value) . "\"";
$r .= implode(', ', $values);
return $r;
}
function make_request($url, $type, $args=null){
$this->oauth = array( 'oauth_consumer_key' => $this->consumer_key,
'oauth_nonce' => time(),
'oauth_signature_method' => 'HMAC-SHA1',
'oauth_token' => $this->oauth_access_token,
'oauth_timestamp' => time(),
'oauth_version' => '1.0');
if (($type=="GET") && (!is_null($args))){
$getfields = str_replace('?', '', explode('&', $args));
foreach ($getfields as $field){
$field_strs = explode('=', $field);
$this->oauth[$field_strs[0]] = $field_strs[1];
}
}
$base_info = $this->build_base_string($url, $type, $this->oauth);
$composite_key = rawurlencode($this->consumer_secret) . '&' . rawurlencode($this->oauth_access_token_secret);
$oauth_signature = base64_encode(hash_hmac('sha1', $base_info, $composite_key, true));
$this->oauth['oauth_signature'] = $oauth_signature;
// make request
$header = array($this->build_authorization_header($this->oauth), 'expect:');
$options = array( CURLOPT_HTTPHEADER => $header,
CURLOPT_HEADER => false,
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_SSL_VERIFYPEER => false);
if ($type=="POST"){
if (is_null($args)){
$args = array();
}
$options[CURLOPT_POSTFIELDS] = $args;
}
else if (($type=="GET") && (!is_null($args))){
$options[CURLOPT_URL] .= $args;
}
$feed = curl_init();
curl_setopt_array($feed, $options);
$json = curl_exec($feed);
curl_close($feed);
return $json;
}
}

why $items is Null

I have this line in my code:
$item=$page->items;
$page is an array, and its content is as it should be but $item is Null. do you have any idea what could be the reason?
UPDATE:
<?php
search( "Steve Jobs" );
// Submit query to Google Web Search
function search( $query )
{
$url = "https://www.googleapis.com/customsearch/v1?key=YOUR_KEY&cx=YOUR_SEARCHE_NGINE_ID&q=" . urlencode( $query ) . "&callback=handleResponse&prettyprint=true&num=10";
$result = get_web_page( $url );
// Exception handling
if ( $result['http_code'] == 403 )
echo "... error: daily limit exceeded ...";
if ( $result['errno'] != 0 )
echo "... error: bad url, timeout, redirect loop ...";
if ( $result['http_code'] != 200 )
echo "... error: no page, no permissions, no service ...";
// Get and parse JSON output
$page = $result['content'];
$page = str_replace("// API callback\nhandleResponse(", "", $page);
$page = str_replace(");", "", $page);
$page=json_decode($page, true);
// Print results
$items=$page->items;
var_dump($items);
for ($i = 0; $i < sizeof($items); $i++)
{
$item = $items[$i];
print("<font size=\"3\">" . "" . $item->htmlTitle . "</font><br>");
print("<font size=\"2\" color=\"black\">" . $item->htmlSnippet . "</font><br>");
print("<font size=\"2\" color=\"green\">" . $item->displayLink . "</font><br>"); print("<br>");
}
}
function get_web_page( $url )
{
$options = array(
CURLOPT_RETURNTRANSFER => true, // return web page
CURLOPT_HEADER => false, // don't return headers
CURLOPT_FOLLOWLOCATION => true, // follow redirects
CURLOPT_ENCODING => "", // handle all encodings
CURLOPT_USERAGENT => "spider", // who am i
CURLOPT_AUTOREFERER => true, // set referer on redirect
CURLOPT_CONNECTTIMEOUT => 120, // timeout on connect
CURLOPT_TIMEOUT => 120, // timeout on response
CURLOPT_MAXREDIRS => 10, // stop after 10 redirects
);
$ch = curl_init( $url );
curl_setopt_array( $ch, $options );
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
// curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
$content = curl_exec( $ch );
$err = curl_errno( $ch );
$errmsg = curl_error( $ch );
$header = curl_getinfo( $ch );
curl_close( $ch );
$header['errno'] = $err;
$header['errmsg'] = $errmsg;
$header['content'] = $content;
return $header;
}
?>
ANSWER:
this part should be changed since $page is an array.
$items = $page['items'];
foreach ($items as $item)
{
$item = (object) $item;
print("<font size=\"3\">" . "" . $item->htmlTitle . "</font><br>");
print("<font size=\"2\" color=\"black\">" . $item->htmlSnippet . "</font><br>");
print("<font size=\"2\" color=\"green\">" . $item->displayLink . "</font><br>"); print("<br>");
}
Simple question, simple answer:
$item is NULL because $page->items is NULL.
More details:
You're treating $page as an object, but you write it's an array.
Suggestion:
Treat $page as an array instead.
Further information:
The PHP manual has information how to treat a value like an array or like an object. Additionally if you enable warnings on your development box, you will be notified about undefined properties which are always NULL.
Update:
For your concrete code, with a slight modification this should work, just change your for loop a bit:
foreach ($items as $item)
{
$item = (object) $item;
print("<font size=\"3\">" . "" . $item->htmlTitle . "</font><br>");
print("<font size=\"2\" color=\"black\">" . $item->htmlSnippet . "</font><br>");
print("<font size=\"2\" color=\"green\">" . $item->displayLink . "</font><br>"); print("<br>");
}
$page is an array, and its content is as it should be
If $page is an array, you should access it like
$item=$page['items'];
If you provide more info you would get more helpful answer.
EDIT
First, Please make sure you have $page not empty at all.
What you have is $page=json_decode($page, true); that return an associative array and you should use the way I posted above.
If you don't want the array to be returned you should change your json_decode to return object by not passing second argument as true.
$page=json_decode($page); then you are okay with the code you have right now.
If $page is array you do this $page['items']. If it is JSON or XML you can also access ait the way you are doing. like $page->items;

Categories