How to use paging in the Facebook Graph API? - php

When using the Facebook Graph API to return more than 500 elements (like a friend list) paging is required. What's a good way to do this?

Here is the way that I use paging on my own apps.
http://developsocialapps.com/facebook-friends-list-and-paging/
The library has most of the code needed. The main method is getGraphObjectWithPaging. It gets the object with the graph API and then keeps looping as long as there is a next page in the response or the $maxpages has been reached. One peculiarity is that sometimes Facebook returns the next page as the same page you just got, so it checks for this and stops at that point too.
class FacebookApp {
public $appId;
private $appSecret;
private $nameSpace;
public $userId;
public $token;
public $tokenExpires;
// get your own from http://www.w3.org/P3P/
public $p3p = 'P3P:CP="IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT"';
/* construct object
appid, secret, and namespace from app settings */
public function __construct($id, $secret, $namespace) {
$this->appId = $id;
$this->appSecret = $secret;
$this->nameSpace = $namespace;
}
/* return json data from a graph api object using paging
$object = object to get
limit = limit parameter for API object
maxpages = maximum number of pages to get */
function getGraphObjectWithPaging($object,$limit=500,$maxpages=10) {
$data = array();
$url = $this->getGraphUrl($object,$limit);
// loop through API calls until maxpages or no paging->next
while ($maxpages > 0) {
$response = $this->makeCurlRequest($url);
if ($repsonse === false) {
// something went wrong
break;
} else {
$jsonarray = json_decode($response,true);
if (isset($jsonarray['error'])) {
// something went wrong
break;
} else {
// add current data to data array
$data = array_merge ($data,$jsonarray['data']);
if (isset($jsonarray['paging']['next'])) {
if ($url == $jsonarray['paging']['next']) {
// for some reason facebook sometimes returns a next url which is the same as we just got, so exit here
break;
} else {
// keep looping
$url = $jsonarray['paging']['next'];
$maxpages--;
}
} else {
// no more pages
break;
}
}
}
}
return array("data"=>$data); // using data so it is the same format as other API repsonses
}
/* constructs graphs url */
public function getGraphUrl($object,$limit=false) {
$url = "https://graph.facebook.com/".$object;
if (strpos($url,"?") === false) $url .= "?";
else $url .= "&";
$url .= "access_token=".$this->token;
if ($limit !== false) $url .= "&limit=".$limit;
return $url;
}
/* uses curl to get a url, use $postarray to make a post, otherwise it will get */
public function makeCurlRequest($url,$postarray=false) {
$return = false;
try {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
if($postarray !== false){
curl_setopt ($ch, CURLOPT_POST, true);
curl_setopt ($ch, CURLOPT_POSTFIELDS, $postarray);
}
$response = curl_exec($ch);
$responseInfo = curl_getinfo($ch);
curl_close($ch);
if ($responseInfo['http_code']==200) {
$return = $response;
}
} catch (Exception $e) {
$return = false;
}
return $return;
}
/* sets userid and token from signed request, return true or false if authorized */
public function initOauthUserFromSignedRequest() {
$authorized = false;
if (isset($_REQUEST['signed_request'])) {
$data = $this->parseSignedRequest($_REQUEST['signed_request']);
if ($data !== false) {
if (isset($data['user_id']) && isset($data['oauth_token'])) {
$this->userId = $data['user_id'];
$this->token = $data['oauth_token'];
$this->tokenExpires = $data['expires'];
$authorized = true;
}
}
}
return $authorized;
}
/* require user to authorize and have permissions for page
redirect_uri = url to return after user has authorized like redirect.php
success_uri = url to redirect to on successful authorization like mypage.php
scope = comma separted list of permissions */
function requireAuthorization($redirect_uri,$success_uri=false,$scope=false) {
if ($success_uri === false) {
// if no success_uri use current page, all files for app must be in same directory
$success_uri = substr($_SERVER['REQUEST_URI'],strrpos($_SERVER['REQUEST_URI'],"/")+1);
}
$this->setCookie ("success_uri",$success_uri,0); // we will use this on the redirect_uri page
$requireauth = true;
if ($this->initOauthUserFromSignedRequest()) { // user has authorized
if (($scope === false) || ($this->hasAllPermissions($scope))) { // now check for perms
$requireauth = false;
}
}
if ($requireauth) { // user is either not authorized or doesn't have permissions
$url = $this->getAuthUrl($this->getCanvasUrl($redirect_uri),$scope);
echo "<html>\n<body>\n<script>\ntop.location.href='".$url."';\n</script></body></html>";
exit();
}
}
/* checks to see if has permissions, scope is comma separated list */
public function hasAllPermissions($scope) {
$return = false;
$cookiename = "permissions_".$this->appId."_".$this->userId;
$requiredpermissions = explode(",",$scope);
// first check cookie
if (isset($_COOKIE[$cookiename])) {
$return = true;
$permissions = json_decode($_COOKIE[$cookiename],true);
foreach ($requiredpermissions as $perm) {
if ($permissions['data'][0][$perm] != 1) {
$return = false;
break;
}
}
}
// if didn't have all in cookie, then see if it is in graph
if ($return == false) {
$permissions = $this->getGraphObject("me/permissions");
if ($permissions !== false) {
$this->setCookie($cookiename,json_encode($permissions),0);
$return = true;
foreach ($requiredpermissions as $perm) {
if ($permissions['data'][0][$perm] != 1) {
$return = false;
break;
}
}
}
}
return $return;
}
/* sets a cookie with p3p headers */
public function setCookie($name,$value,$expires) {
if ($this->p3p != '') {
header($this->p3p);
$this->p3p = '';
}
setcookie ($name,$value,$expires,"/");
}
/* returns url for oauth authorization
redirect_uri = url to return after user has authorized
scope = comma separted list of permissions */
public function getAuthUrl($redirect_uri,$scope=false) {
$url = "https://www.facebook.com/dialog/oauth/?client_id=".$this->appId."&redirect_uri=".rawurlencode($redirect_uri);
if ($scope !== false) $url .= "&scope=".rawurlencode($scope);
return $url;
}
/* returns url to app canvas page, $page like mypage.php?foo=bar */
public function getCanvasUrl($page) {
if ($_SERVER['HTTPS'] == "on") $protocol = "https";
else $protocol = "http";
return $protocol."://apps.facebook.com/".$this->nameSpace."/".$page;
}
/* parses signed_request parameter and returns data object, returns false if sigs don't match */
public function parseSignedRequest($signed_request) {
list($encoded_sig, $payload) = explode('.', $signed_request, 2);
$data = json_decode(base64_decode(strtr($payload, '-_', '+/')), true);
$sig = base64_decode(strtr($encoded_sig, '-_', '+/'));
$expected_sig = hash_hmac('sha256', $payload, $this->appSecret, true);
if ($sig == $expected_sig) {
return $data;
} else {
return false;
}
}
}
Here is how to use it on a page:
$facebookapp = new FacebookApp($GLOBALS['facebookAppId'],$GLOBALS['facebookAppSecret'],$GLOBALS['facebookNamespace']);
$facebookapp->requireAuthorization($GLOBALS['facebookRedirectPage']);
$friends = $facebookapp->getGraphObjectWithPaging("me/friends");

Related

Infinite loop when using cURL to access a REST API, what is causing it?

I am trying to write a connector using cURL to connect to a REST API.
The first step the user have to do is creates a session using createSession(). This will send a POST call to the API with a username and a password. The API will respond with a sessionId, a cookie value and couple of custom header.
The session is only valid for 3 minutes after each valid request. If I make a request after the session has expired I will get http error code 401 which indicates that the user is unauthorized to make the request because the sessionId is invalid or timed out.
Instead of asking the user to login again manually, I would like to automatically reconnect by calling the createSession() method when I get error 401. The reason why I need to do this because the sessionId is save in the client cookies and so the client does not know if the session is expired or active. My code will try to call methods using the sessionId that is saved in the cookies weather it is active or expired.
The API will renew the session 3 minutes each time a request is made as long as the session is still active. The only time I will need to reconnect is only when the user have not made a request for 3 minutes.
The issue that I am running into is when I try to reconnnect, I go into an infinite loop that I can't figure out how to stop it.
Here is my code
<?php namespace API;
/**
* ICWS API
*
* #package ICWS
*/
class ICWS {
private $_myAppName = 'ICWS API connector';
private $_authenticationType = 'Basic'; //Not used yet
private $_languageID = 'en-US';
private $_protocol = 'http';
private $_sessionIdKey = 'sessionId';
private $_interactionIdKey = 'interactionIdKey';
private $_maxLoginAttempts = 3;
private $_loginAttempts = 0;
private $_debug = false;
//No need to edit beyond this line
private $_isSubscribledToQueue = false;
private $_alternateHostList = array();
private $_interactionId = 0;
private $_queueType = 1;
private $_userID;
private $_password;
private $_workstation;
private $_queueName;
private $_cainfo;
private $_baseURL;
private $_csrfToken;
private $_sessionId;
private $_ININ_ICWS_CSRF_Token;
private $_Location;
private $_subscriptionId;
private $_curlHeader;
private $_requestFile;
public function __construct($config)
{
//Make sure cURL is enabled on the server
if(!is_callable('curl_init')){
throw new ApiException('cURL is disabled on this server. Before making API calls cURL extension must be enabled.');
}
//Make sure all required config are set
if( !isset($config['host']) || empty($config['host'])
|| !isset($config['port']) || empty($config['port'])
|| !isset($config['userID']) || empty($config['userID'])
|| !isset($config['password']) || empty($config['password'])
|| !isset($config['workstation']) || empty($config['workstation'])
){
throw new ApiException('Host, Port, userID, password, workstation are required!');
}
$this->_userID = $config['userID'];
$this->_password = $config['password'];
$this->_workstation = $config['workstation'];
//override the default queueType
if( isset($config['queueType']) && !empty($config['queueType']) ){
$this->_queueType = $config['queueType'];
}
//override the default queueName
if( isset($config['queueName']) && !empty($config['queueName']) ){
$this->_queueName = $config['queueName'];
}
//override the default appName
if( isset($config['appName']) && !empty($config['appName']) ){
$this->_myAppName = $config['appName'];
}
//override the default session Key
if( isset($config['sessionKey']) && !empty($config['sessionKey']) ){
$this->_sessionKey = $config['sessionKey'];
}
//override the default protocol
if( isset($config['isSecured']) && $config['isSecured'] == true){
if(!isset($config['cainfo']) || empty($config['cainfo'])){
throw new ApiException('To enable SSL you must provide CA Info file (.cert)');
} else {
$this->_protocol = 'https';
$this->cainfo = $config['cainfo'];
}
}
//override the default server Language
if( isset($config['languageID']) && !empty($config['languageID']) ){
$this->_languageID = $config['languageID'];
}
//override the default debug mode
if( isset($config['debug']) && !empty($config['debug']) ){
$this->_debug = $config['debug'];
}
//override the default authentication type
if( isset($config['authenticationType']) && !empty($config['authenticationType']) ){
$this->_authenticationType = $config['authenticationType'];
}
//set the sessionId if it already exists
if( isset( $_COOKIE[$this->_sessionIdKey] ) && !empty( $_COOKIE[$this->_sessionIdKey] )){
$this->_sessionId = $_COOKIE[$this->_sessionIdKey];
}
//set the _interactionIdKey if it already exists
if( isset( $_COOKIE[$this->_interactionIdKey] ) && !empty( $_COOKIE[$this->_interactionIdKey] )){
$this->_interactionId = $this->_bigint($_COOKIE[$this->_interactionIdKey]);
}
if(isset($_COOKIE['ININ-ICWS-CSRF-Token']) && !empty($_COOKIE['ININ-ICWS-CSRF-Token'])){
$this->_ININ_ICWS_CSRF_Token = $_COOKIE['ININ-ICWS-CSRF-Token'];
}
$this->_baseURL = $this->_protocol . '://' . $config['host'] . ':' . $config['port'] . '/icws/';
$this->_subscriptionId = $this->_userID;
}
/**
* Authentication the user and generated a sessionId
*
* #param string $userID
* #param string $password
* #param boolean $forceNewSession
* #catch exception
* #return void
*/
public function createSession($forceNewSession = false){
if( !empty($this->_sessionId) && ! $forceNewSession ){
return;
}
if($forceNewSession){
$this->destroySession();
}
$this->_requestFile = 'connection';
$type = 'urn:inin.com:connection:icAuthConnectionRequestSettings';
$data = array('__type' => $type,
'applicationName' => $this->_myAppName,
'userID' => $this->_userID,
'password' => $this->_password);
$this->_curlHeader = array('Accept-Language: ' . $this->_languageID,
'Content-Type: application/json');
$httpCode = 0;
try {
$data = $this->_processRequest('POST', 'connection', $data, $httpCode, false);
if($this->_debug){
new showVar($data, false, 'HTTP Code: ' . $httpCode);
}
$this->_csrfToken = $data['csrfToken'];
$this->_sessionId = $data['sessionId'];
$this->_alternateHostList = $data['alternateHostList'];
if(!empty($this->_sessionId)){
setCookie($this->_sessionIdKey, $this->_sessionId);
$this->_loginAttempts = 0;
}
} catch (\Exception $e){
$this->_displayError($e);
}
}
/**
* Destroy the IC session
*
* #return void
*/
public function destroySession(){
//destroy the sessionId
$this->_sessionId = NULL;
$this->_destroy($this->_sessionIdKey);
//destroy the sessionId
$this->_interactionIdKey = 0;
$this->_destroy($this->_interactionIdKey);
//destroy the CSRF-Token
$this->_ININ_ICWS_CSRF_Token = NULL;
$this->_destroy('ININ-ICWS-CSRF-Token');
}
/**
* Calls any Method after a session is created
*
* #param string $method GET/POST/PUT
* #param string $uri
* #param array $data
* #catch exception
* #return array or false
*/
private function _sendRequest($method, $uri, $data = false, &$httpCode = 0){
if( !$this->_sessionId ){
return false;
}
$uri = $this->_sessionId . '/' . $uri;
$return = false;
//,'Cookie: ' . $this->_ININ_ICWS_Cookie
$this->_curlHeader = array('ININ-ICWS-CSRF-Token: ' . $this->_ININ_ICWS_CSRF_Token,
'ININ-ICWS-Session-ID: ' . $this->_sessionId,
'Content-Type: application/json');
try {
$return = $this->_processRequest($method, $uri, $data, $httpCode);
} catch (\Exception $e){
$this->_displayError($e);
} finally {
return $return;
}
}
/**
* Handle the cURL call to the API
*
* #throws ApiException
* #param string $method GET/POST/PUT
* #param string $uri
* #param array $data
* #param array &$httpCode
* #return array
*/
private function _processRequest($method, $uri, $data = false, &$httpCode = NULL, $allowReconnect = true)
{
$ch = curl_init();
$url = $this->_baseURL . $uri;
if(
($method == 'POST' || $method == 'PUT')
&& $data
){
$jsonString = json_encode($data);
curl_setopt( $ch, CURLOPT_POSTFIELDS, $jsonString );
}
if($method == 'POST'){
curl_setopt($ch, CURLOPT_POST, true);
} elseif( $method == 'PUT'){
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
} else {
if ($data){
$url = sprintf("%s?%s", $url, http_build_query($data));
}
}
//set the URL
curl_setopt($ch, CURLOPT_URL, $url);
//disable the use of cached connection
curl_setopt($ch, CURLOPT_FRESH_CONNECT, true);
//return the respond from the API
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
//return the HEADER respond from the API
curl_setopt($ch, CURLOPT_HEADER, true);
//add custom headers
if(!empty($this->_curlHeader)){
curl_setopt($ch, CURLOPT_HTTPHEADER, $this->_curlHeader);
}
//add the cookie value
$cookiesFile = 'icwsCookies';
curl_setopt($ch, CURLOPT_COOKIEJAR, $cookiesFile); // write
curl_setopt($ch, CURLOPT_COOKIEFILE, $cookiesFile); // read
//enable SSL
if( $this->_protocol == 'https' ){
curl_setopt($ch, CURLOPT_CAINFO, $this->_cainfo);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, true);
}
//send the request to the API
$respond = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
//throw cURL exception
if($respond === false){
$errorNo = curl_errno($ch);
$errorMessage = curl_error($ch);
throw new ApiException($errorMessage, $errorNo);
}
list($header, $body) = explode("\r\n\r\n", $respond, 2);
if($uri == 'connection'){
$this->_handleReceivedHeaders($header);
}
//if user gets unauthorized error attempt to login as long as the attempt are under 3
if($httpCode == 401 && $allowReconnect){
if( $this->_loginAttempts > $this->_maxLoginAttempts){
throw new ApiException('All Attempts to create a session have been used! Please check your credentials and try again');
} else {
$this->_reconnect($method, $uri, $data);
}
}
//convert respond to an array
return json_decode($body, true);
}
/**
* Reconnect to the Api and generate a new sessionId
*
* #return boolean
*/
private function _reconnect($method, $uri, $data){
$this->createSession(true);
$httpCode = 0;
$this->_processRequest($method, $uri, $data, $httpCode);
if($httpCode == 200 || $httpCode == 201){
return true;
}
return false;
}
/**
* Get the cookie HTTP headers and set them as cookie
*
* #param array $httpRespond
* #return void
*/
private function _handleReceivedHeaders($httpRespond){
$header = $this->_http_parse_headers($httpRespond);
//set the ININ-ICWS-CSRF-Token value
if( isset($header['ININ-ICWS-CSRF-Token']) ){
$this->_ININ_ICWS_CSRF_Token = $header['ININ-ICWS-CSRF-Token'];
setCookie('ININ-ICWS-CSRF-Token', $this->_ININ_ICWS_CSRF_Token);
}
}
/**
* Checks if the API return an error
*
* #param array $result
* #return boolean
*/
private function _hasAPIError($result){
if( isset($result['errorId']) && !empty($result['errorId'])
&& isset($result['message']) && !empty($result['message'])
){
return true;
}
return false;
}
/**
* Displays the exception details
*
* #param ApiException $e
*/
private function _displayError(ApiException $e){
echo 'Error Number: ' . $e->getCode() . "<br>";
echo $e->getMessage() . "<br><br>";
}
/**
* convert cURL header into an array
*
* #param string $raw_headers
* #return array
*/
private function _http_parse_headers($raw_headers)
{
$headers = array();
$key = '';
foreach(explode("\n", $raw_headers) as $i => $h)
{
$h = explode(':', $h, 2);
if (isset($h[1])){
if (!isset($headers[$h[0]])){
$headers[$h[0]] = trim($h[1]);
} elseif (is_array($headers[$h[0]])){
$headers[$h[0]] = array_merge($headers[$h[0]], array(trim($h[1]))); // [+]
} else {
$headers[$h[0]] = array_merge(array($headers[$h[0]]), array(trim($h[1]))); // [+]
}
$key = $h[0];
} else {
if (substr($h[0], 0, 1) == "\t"){
$headers[$key] .= "\r\n\t".trim($h[0]);
} elseif (!$key){
$headers[0] = trim($h[0]);trim($h[0]);
}
}
}
return $headers;
}
/**
* return a valid numeric value
*
* #param string $val
* #return big integer
*/
private function _bigint($val){
$val = filter_var($val, FILTER_SANITIZE_NUMBER_INT);
if(empty($val)){
$val = 0;
}
return $val;
}
/**
* Destroy a cookie
* #return void
*/
private function _destroy($name){
setcookie($name, null);
unset($_COOKIE[$name]);
}
}
?>
This snipit below is where I am trying reconnect to the API. which is causing the loop for some reason.
if($httpCode == 401 && $allowReconnect){
if( $this->_loginAttempts > $this->_maxLoginAttempts){
throw new ApiException('All Attempts to create a session have been used! Please check your credentials and try again');
} else {
$this->_reconnect($method, $uri, $data);
}
}
Here is a summary of my code.
a session is created via $this->createSession(true);
then multiple _processRequests() methods are called at different time. If a the _processRequests() method return 401 then $this->createSession(true); is called until it return code 201 or 200 or the $this->createSession(true); is called more than 3 times then I will need to quite. the problem is even when $this->createSession(true); return code 200 or 201 it keeps looping and it does not stop
The cause of the loop is that _processRequests() calls itself infinite when error 401 is reached. It does not recognize that the second calls returns 201.
In _reconnect method:
$this->createSession(true);
In createSession method:
$data = $this->_processRequest('POST', 'connection', $data, $httpCode, false);
In _processRequest method:
//if user gets unauthorized error attempt to login as long as the attempt are under 3
if($httpCode == 401 && $allowReconnect){
if( $this->_loginAttempts > $this->_maxLoginAttempts){
throw new ApiException('All Attempts to create a session have been used! Please check your credentials and try again');
} else {
$this->_reconnect($method, $uri, $data);
}
}
My guess is that you got an unauthorized error, and since you're never incrementing $this->_loginAttempts anywhere in the code, it can't never be greater than $this->_maxLoginAttempts, so the code will call again the _reconnect mehtod, causing it to enter in an infinite loop.

How to Read/ Parse Data of Signed_Request from Registration Script in Php 5.1.6

I'm trying to implement the Facebook registration script.
The form is getting submitted fine and the server is receiving the signed request. However, it is not able to read/parse the signed request.
I used the script recommended on the registration page https://developers.facebook.com/docs/plugins/registration/ (code below) and all I see for output is:
signed_request contents:
I have verified that the signed_Request is being received. If I pass it to: http://developers.facebook.com/tools/echo?signed_request= I see data.
However on my server with the script below nothing.
The server is http NOT https and using php 5.1.6 (which doesn't have some of the JSON support) Do I need PHP SDK installed? Or the jsonwrapper? I've tried the jsonwrapper but not PHP SDK.
Any help on why the signed_request can not be read would be appreciated.
Code below from facebook
<?php
include ('jsonwrapper/jsonwrapper.php');
define('FACEBOOK_APP_ID', 'XXX');
define('FACEBOOK_SECRET', 'XXX');
function parse_signed_request($signed_request, $secret) {
list($encoded_sig, $payload) = explode('.', $signed_request, 2);
// decode the data
$sig = base64_url_decode($encoded_sig);
$data = json_decode(base64_url_decode($payload), true);
if (strtoupper($data['algorithm']) !== 'HMAC-SHA256') {
error_log('Unknown algorithm. Expected HMAC-SHA256');
return null;
}
// check sig
$expected_sig = hash_hmac('sha256', $payload, $secret, $raw = true);
if ($sig !== $expected_sig) {
error_log('Bad Signed JSON signature!');
return null;
}
return $data;
}
function base64_url_decode($input) {
return base64_decode(strtr($input, '-_', '+/'));
}
if ($_REQUEST) {
echo '<p>signed_request contents:</p>';
$response = parse_signed_request($_REQUEST['signed_request'],
FACEBOOK_SECRET);
echo '<pre>';
print_r($response);
echo '</pre>';
} else {
echo '$_REQUEST is empty';
}
?>
output is
"signed_request contents:"
If I add:
print_r($_REQUEST); to the script I do see the request but can't parse it
You don't need the PHP SDK for this. It may make it easier to do this and various other things, but it is not necessary if you want to do the decode yourself.
Are you sure you actually have a json_decode function? I don't think it's usually part of jsonwrapper.php, so I suspect your script is crashing on that function call. You can use the following function as a substitute, just change the call to usr_json_decode and include the following at the bottom of your script:
function usr_json_decode($json, $assoc=FALSE, $limit=512, $n=0, $state=0, $waitfor=0)
{
$val=NULL;
static $lang_eq = array("true" => TRUE, "false" => FALSE, "null" => NULL);
static $str_eq = array("n"=>"\012", "r"=>"\015", "\\"=>"\\", '"'=>'"', "f"=>"\f", "b"=>"\b", "t"=>"\t", "/"=>"/");
for (; $n<strlen($json); /*n*/)
{
$c=$json[$n];
if ($state==='"')
{
if ($c=='\\')
{
$c=$json[++$n];
if (isset($str_eq[$c]))
$val.=$str_eq[$c];
else if ($c=='u')
{
$hex=hexdec(substr($json, $n+1, 4));
$n+=4;
if ($hex<0x80) $val .= chr($hex);
else if ($hex<0x800) $val.=chr(0xC0+$hex>>6).chr(0x80+$hex&63);
else if ($hex<=0xFFFF) $val.=chr(0xE0+$hex>>12).chr(0x80+($hex>>6)&63).chr(0x80+$hex&63);
}
else
$val.="\\".$c;
}
else if ($c=='"') $state=0;
else $val.=$c;
}
else if ($waitfor && (strpos($waitfor, $c)!==false))
return array($val, $n);
else if ($state===']')
{
list($v, $n)=usr_json_decode($json, $assoc, $limit, $n, 0, ",]");
$val[]=$v;
if ($json[$n]=="]") return array($val, $n);
}
else
{
if (preg_match("/\s/", $c)) { }
else if ($c=='"') $state='"';
else if ($c=="{")
{
list($val, $n)=usr_json_decode($json, $assoc, $limit-1, $n+1, '}', "}");
if ($val && $n) $val=$assoc?(array)$val:(object)$val;
}
else if ($c=="[")
list($val, $n)=usr_json_decode($json, $assoc, $limit-1, $n+1, ']', "]");
elseif (($c=="/") && ($json[$n+1]=="*"))
($n=strpos($json, "*/", $n+1)) or ($n=strlen($json));
elseif (preg_match("#^(-?\d+(?:\.\d+)?)(?:[eE]([-+]?\d+))?#", substr($json, $n), $uu))
{
$val = $uu[1];
$n+=strlen($uu[0])-1;
if (strpos($val, ".")) $val=(float)$val;
else if ($val[0]=="0") $val=octdec($val);
else $val=(int)$val;
if (isset($uu[2])) $val*=pow(10, (int)$uu[2]);
}
else if (preg_match("#^(true|false|null)\b#", substr($json, $n), $uu))
{
$val=$lang_eq[$uu[1]];
$n+=strlen($uu[1])-1;
}
else
{
return $waitfor ? array(NULL, 1<<30) : NULL;
}
}
if ($n===NULL) return NULL;
$n++;
}
return ($val);
}
BTW though, this should be very easy to track down using your error log, turning on extra debugging and adding some echo or var_dump statements as necessary.
I had something similar with the signed request coming back blank. On your application make sure you first download and inlude the php sdk from http://developers.facebook.com/docs/reference/php/. Next add
require_once("facebook.php");
to your script at the top, or to where you uploaded it to. Now in your application settings for the application, in Facebook, make sure your url to the application has the www in it or not. For example: In the application you have it pointing to example.com/index.php?tab=test but when you put it in the browser it always comes up www,example.com/index.php?tab=test. Not including the www can mess it up.
EDIT - WORKED FOR ME
<?php
#error_reporting(E_ALL);
include ('{{PATH TO facebook.php}}');
$appapikey = 'xxxx';
$appsecret = 'xxxx';
$facebook = new Facebook($appapikey, $appsecret);
function parsePageSignedRequest() {
if (isset($_REQUEST['signed_request'])) {
$encoded_sig = null;
$payload = null;
list($encoded_sig, $payload) = explode('.', $_REQUEST['signed_request'], 2);
$sig = base64_decode(strtr($encoded_sig, '-_', '+/'));
$data = json_decode(base64_decode(strtr($payload, '-_', '+/'), true));
return $data;
}
return false;
}
function parse_signed_request($signed_request, $secret) {
list($encoded_sig, $payload) = explode('.', $signed_request, 2);
// decode the data
$sig = base64_url_decode($encoded_sig);
$data = json_decode(base64_url_decode($payload), true);
if (strtoupper($data['algorithm']) !== 'HMAC-SHA256') {
error_log('Unknown algorithm. Expected HMAC-SHA256');
return null;
}
// check sig
$expected_sig = hash_hmac('sha256', $payload, $secret, $raw = true);
if ($sig !== $expected_sig) {
error_log('Bad Signed JSON signature!');
return null;
}
return $data;
}
function base64_url_decode($input) {
return base64_decode(strtr($input, '-_', '+/'));
}
if (isset($_REQUEST['signed_request'])) {
echo '<p>signed_request contents:</p>';
$response = parse_signed_request($_REQUEST['signed_request'],
$appsecret);
echo '<pre>';
print_r($response);
echo '</pre>';
} else {
echo '$_REQUEST is empty';
}
?>
<iframe src="https://www.facebook.com/plugins/registration.php?
client_id=134219456661289&
redirect_uri={{YOUR SITE URL ENCODED}}&fields=name,birthday,gender,location,email"
scrolling="auto"
frameborder="no"
style="border:none"
allowTransparency="true"
width="100%"
height="330">
</iframe>
function getDefinedVars($varList, $excludeList)
{
$temp1 = array_values(array_diff(array_keys($varList), $excludeList));
$temp2 = array();
while (list($key, $value) = each($temp1)) {
global $$value;
$temp2[$value] = $$value;
}
return $temp2;
}
To view All SYSTEM Variables (except globals/files/cookies/post/get) to make sure Signed Request is passed you can use this snippet of code
/**
* #desc holds the variable that are to be excluded from the list.
* Add or drop new elements as per your preference.
* #var array
*/
$excludeList = array('GLOBALS', '_FILES', '_COOKIE', '_POST', '_GET', 'excludeList');
//some dummy variables; add your own or include a file.
$firstName = 'kailash';
$lastName = 'Badu';
$test = array('Pratistha', 'sanu', 'fuchhi');
//get all variables defined in current scope
$varList = get_defined_vars();
//Time to call the function
print "<pre>";
print_r(getDefinedVars($varList, $excludeList));
print "</pre>";

Simple Twitter Oauth authorization asking for credentials every time

I am making a simple twitter based login/signup system using the tutorial here. I get the oauth_token as well as oauth token secret every time I get the user to login. However, even when the user is already logged in, he is being asked to login again. I just wanted to know how do I check if the user is already logged in?
Do I need to store the oauth_token and oauth token secret in session? If I do store these in a session, how do i authenticate if they are valid?
The library used has something like this:
<?php
session_start();
class EpiOAuth
{
public $version = '1.0';
protected $requestTokenUrl;
protected $accessTokenUrl;
protected $authorizeUrl;
protected $consumerKey;
protected $consumerSecret;
protected $token;
protected $tokenSecret;
protected $signatureMethod;
public function getAccessToken()
{
$resp = $this->httpRequest('GET', $this->accessTokenUrl);
return new EpiOAuthResponse($resp);
}
public function getAuthorizationUrl()
{
$retval = "{$this->authorizeUrl}?";
$token = $this->getRequestToken();
return $this->authorizeUrl . '?oauth_token=' . $token->oauth_token;
}
public function getRequestToken()
{
$resp = $this->httpRequest('GET', $this->requestTokenUrl);
return new EpiOAuthResponse($resp);
}
public function httpRequest($method = null, $url = null, $params = null)
{
if(empty($method) || empty($url))
return false;
if(empty($params['oauth_signature']))
$params = $this->prepareParameters($method, $url, $params);
switch($method)
{
case 'GET':
return $this->httpGet($url, $params);
break;
case 'POST':
return $this->httpPost($url, $params);
break;
}
}
public function setToken($token = null, $secret = null)
{
$params = func_get_args();
$this->token = $token;
$this->tokenSecret = $secret;
}
public function encode($string)
{
return rawurlencode(utf8_encode($string));
}
protected function addOAuthHeaders(&$ch, $url, $oauthHeaders)
{
$_h = array('Expect:');
$urlParts = parse_url($url);
$oauth = 'Authorization: OAuth realm="' . $urlParts['path'] . '",';
foreach($oauthHeaders as $name => $value)
{
$oauth .= "{$name}=\"{$value}\",";
}
$_h[] = substr($oauth, 0, -1);
curl_setopt($ch, CURLOPT_HTTPHEADER, $_h);
}
protected function generateNonce()
{
if(isset($this->nonce)) // for unit testing
return $this->nonce;
return md5(uniqid(rand(), true));
}
protected function generateSignature($method = null, $url = null, $params = null)
{
if(empty($method) || empty($url))
return false;
// concatenating
$concatenatedParams = '';
foreach($params as $k => $v)
{
$v = $this->encode($v);
$concatenatedParams .= "{$k}={$v}&";
}
$concatenatedParams = $this->encode(substr($concatenatedParams, 0, -1));
// normalize url
$normalizedUrl = $this->encode($this->normalizeUrl($url));
$method = $this->encode($method); // don't need this but why not?
$signatureBaseString = "{$method}&{$normalizedUrl}&{$concatenatedParams}";
return $this->signString($signatureBaseString);
}
protected function httpGet($url, $params = null)
{
if(count($params['request']) > 0)
{
$url .= '?';
foreach($params['request'] as $k => $v)
{
$url .= "{$k}={$v}&";
}
$url = substr($url, 0, -1);
}
$ch = curl_init($url);
$this->addOAuthHeaders($ch, $url, $params['oauth']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$resp = $this->curl->addCurl($ch);
return $resp;
}
protected function httpPost($url, $params = null)
{
$ch = curl_init($url);
$this->addOAuthHeaders($ch, $url, $params['oauth']);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($params['request']));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$resp = $this->curl->addCurl($ch);
return $resp;
}
protected function normalizeUrl($url = null)
{
$urlParts = parse_url($url);
$scheme = strtolower($urlParts['scheme']);
$host = strtolower($urlParts['host']);
$port = intval($urlParts['port']);
$retval = "{$scheme}://{$host}";
if($port > 0 && ($scheme === 'http' && $port !== 80) || ($scheme === 'https' && $port !== 443))
{
$retval .= ":{$port}";
}
$retval .= $urlParts['path'];
if(!empty($urlParts['query']))
{
$retval .= "?{$urlParts['query']}";
}
return $retval;
}
protected function prepareParameters($method = null, $url = null, $params = null)
{
if(empty($method) || empty($url))
return false;
$oauth['oauth_consumer_key'] = $this->consumerKey;
$oauth['oauth_token'] = $this->token;
$oauth['oauth_nonce'] = $this->generateNonce();
$oauth['oauth_timestamp'] = !isset($this->timestamp) ? time() : $this->timestamp; // for unit test
$oauth['oauth_signature_method'] = $this->signatureMethod;
$oauth['oauth_version'] = $this->version;
// encoding
array_walk($oauth, array($this, 'encode'));
if(is_array($params))
array_walk($params, array($this, 'encode'));
$encodedParams = array_merge($oauth, (array)$params);
// sorting
ksort($encodedParams);
// signing
$oauth['oauth_signature'] = $this->encode($this->generateSignature($method, $url, $encodedParams));
return array('request' => $params, 'oauth' => $oauth);
}
protected function signString($string = null)
{
$retval = false;
switch($this->signatureMethod)
{
case 'HMAC-SHA1':
$key = $this->encode($this->consumerSecret) . '&' . $this->encode($this->tokenSecret);
$retval = base64_encode(hash_hmac('sha1', $string, $key, true));
break;
}
return $retval;
}
public function __construct($consumerKey, $consumerSecret, $signatureMethod='HMAC-SHA1')
{
$this->consumerKey = $consumerKey;
$this->consumerSecret = $consumerSecret;
$this->signatureMethod = $signatureMethod;
$this->curl = EpiCurl::getInstance();
}
}
class EpiOAuthResponse
{
private $__resp;
public function __construct($resp)
{
$this->__resp = $resp;
}
public function __get($name)
{
if($this->__resp->code < 200 || $this->__resp->code > 299)
return false;
parse_str($this->__resp->data, $result);
foreach($result as $k => $v)
{
$this->$k = $v;
}
return $result[$name];
}
}
The normal flow dictates that applications send request tokens to oauth/authorize in Twitter's implementation of the OAuth Specification. To take advantage of "Sign in with Twitter", applications should send request tokens received in the oauth_token parameter to oauth/authenticate instead.
(c) https://dev.twitter.com/docs/auth/sign-in-with-twitter
So find where their library (or your code) performs request to /authorize endpoint and replace it with /authenticate
About tokens: as long as you've received user tokens - store it in some persistent storage (database, file, etc) since that tokens are permanent (they will be valid until user haven't revoked them manually).
Enable option "Sign in with Twitter" for application OAuth Settings

Has anyone worked with this Highrise API PHP Wrapper library? I need help authenticating

So I downloaded a wrapper class from this github link:
https://github.com/ignaciovazquez/Highrise-PHP-Api
and I'm just trying to get any response whatsoever. So far, I can't even authenticate with my credentials so I was wondering if any who has used the API could help me.
I tried running one of the test files on Terminal with no arguments and this is what it told me:
Usage: php users.test.php [account-name] [access-token]
Alright, so then decided to get my credentials. So this is what I understand, and, please, correct if I'm wrong:
the account-name is that part that goes in the url to your highrise account. So if your url is:
https://exampleaccount.highrisehq.com/
then your account name is: "exampleaccount"
and your access token is your authentication token that you can find by going clicking on My info > API token inside your Highrise account.
Is that right?
Well anyways, I enter this info and script terminates with a fatal error and this message:
Fatal error: Uncaught exception 'Exception' with message 'API for User returned Status Code: 0 Expected Code: 200' in /Users/me/Sites/sandbox/PHP/highrise_api_class/lib/HighriseAPI.class.php:137
Stack trace:
#0 /Users/me/Sites/sandbox/PHP/highrise_api_class/lib/HighriseAPI.class.php(166): HighriseAPI->checkForErrors('User')
#1 /Users/me/Sites/sandbox/PHP/highrise_api_class/test/users.test.php(13): HighriseAPI->findMe()
#2 {main}
thrown in /Users/me/Sites/sandbox/PHP/highrise_api_class/lib/HighriseAPI.class.php on line 137
I'm complete n00b and I don't really understand what it's saying so I was wondering if any could help. It would be greatly appreciated.
The source of the test script (users.test.php) is:
<?php
require_once("../lib/HighriseAPI.class.php");
if (count($argv) != 3)
die("Usage: php users.test.php [account-name] [access-token]\n");
$hr = new HighriseAPI();
$hr->debug = false;
$hr->setAccount($argv[1]);
$hr->setToken($argv[2]);
print "Finding my user...\n";
$user = $hr->findMe();
print_r($user);
print "Finding all users...\n";
$users = $hr->findAllUsers();
print_r($users);
?>
and the source to the Highrise API wrapper file (Highrise.API.class) is:
<?php
/*
* http://developer.37signals.com/highrise/people
*
* TODO LIST:
* Add Tasks support
* Get comments for Notes / Emails
* findPeopleByTagName
* Get Company Name, etc proxy
* Convenience methods for saving Notes $person->saveNotes() to check if notes were modified, etc.
* Add Tags to Person
*/
class HighriseAPI
{
public $account;
public $token;
protected $curl;
public $debug;
public function __construct()
{
$this->curl = curl_init();
curl_setopt($this->curl,CURLOPT_RETURNTRANSFER,true);
curl_setopt($this->curl, CURLOPT_HTTPHEADER, array('Accept: application/xml', 'Content-Type: application/xml'));
// curl_setopt($curl,CURLOPT_POST,true);
curl_setopt($this->curl,CURLOPT_SSL_VERIFYPEER,0);
curl_setopt($this->curl,CURLOPT_SSL_VERIFYHOST,0);
}
public function setAccount($account)
{
$this->account = $account;
}
public function setToken($token)
{
$this->token = $token;
curl_setopt($this->curl,CURLOPT_USERPWD,$this->token.':x');
}
protected function postDataWithVerb($path, $request_body, $verb = "POST")
{
$this->curl = curl_init();
$url = "https://" . $this->account . ".highrisehq.com" . $path;
if ($this->debug)
print "postDataWithVerb $verb $url ============================\n";
curl_setopt($this->curl, CURLOPT_URL,$url);
curl_setopt($this->curl, CURLOPT_POSTFIELDS, $request_body);
if ($this->debug == true)
curl_setopt($this->curl, CURLOPT_VERBOSE, true);
curl_setopt($this->curl, CURLOPT_HTTPHEADER, array('Accept: application/xml', 'Content-Type: application/xml'));
curl_setopt($this->curl, CURLOPT_USERPWD,$this->token.':x');
curl_setopt($this->curl, CURLOPT_SSL_VERIFYPEER,0);
curl_setopt($this->curl, CURLOPT_SSL_VERIFYHOST,0);
curl_setopt($this->curl, CURLOPT_RETURNTRANSFER,true);
if ($verb != "POST")
curl_setopt($this->curl, CURLOPT_CUSTOMREQUEST, $verb);
else
curl_setopt($this->curl, CURLOPT_POST, true);
$ret = curl_exec($this->curl);
if ($this->debug == true)
print "Begin Request Body ============================\n" . $request_body . "End Request Body ==============================\n";
curl_setopt($this->curl,CURLOPT_HTTPGET, true);
return $ret;
}
protected function getURL($path)
{
curl_setopt($this->curl, CURLOPT_HTTPHEADER, array('Accept: application/xml', 'Content-Type: application/xml'));
curl_setopt($this->curl, CURLOPT_USERPWD,$this->token.':x');
curl_setopt($this->curl, CURLOPT_SSL_VERIFYPEER,0);
curl_setopt($this->curl, CURLOPT_SSL_VERIFYHOST,0);
curl_setopt($this->curl, CURLOPT_RETURNTRANSFER,true);
$url = "https://" . $this->account . ".highrisehq.com" . $path;
if ($this->debug == true)
curl_setopt($this->curl, CURLOPT_VERBOSE, true);
curl_setopt($this->curl,CURLOPT_URL,$url);
$response = curl_exec($this->curl);
if ($this->debug == true)
print "Response: =============\n" . $response . "============\n";
return $response;
}
protected function getLastReturnStatus()
{
return curl_getinfo($this->curl, CURLINFO_HTTP_CODE);
}
protected function getXMLObjectForUrl($url)
{
$xml = $this->getURL($url);
$xml_object = simplexml_load_string($xml);
return $xml_object;
}
protected function checkForErrors($type, $expected_status_codes = 200)
{
if (!is_array($expected_status_codes))
$expected_status_codes = array($expected_status_codes);
if (!in_array($this->getLastReturnStatus(), $expected_status_codes))
{
switch($this->getLastReturnStatus())
{
case 404:
throw new Exception("$type not found");
break;
case 403:
throw new Exception("Access denied to $type resource");
break;
case 507:
throw new Exception("Cannot create $type: Insufficient storage in your Highrise Account");
break;
default:
throw new Exception("API for $type returned Status Code: " . $this->getLastReturnStatus() . " Expected Code: " . implode(",", $expected_status_codes));
break;
}
}
}
/* Users */
public function findAllUsers()
{
$xml = $this->getUrl("/users.xml");
$this->checkForErrors("User");
$xml_object = simplexml_load_string($xml);
$ret = array();
foreach($xml_object->user as $xml_user)
{
$user = new HighriseUser();
$user->loadFromXMLObject($xml_user);
$ret[] = $user;
}
return $ret;
}
public function findMe()
{
$xml = $this->getUrl("/me.xml");
$this->checkForErrors("User");
$xml_obj = simplexml_load_string($xml);
$user = new HighriseUser();
$user->loadFromXMLObject($xml_obj);
return $user;
}
/* Tasks */
public function findCompletedTasks()
{
$xml = $this->getUrl("/tasks/completed.xml");
$this->checkForErrors("Tasks");
return $this->parseTasks($xml);
}
public function findAssignedTasks()
{
$xml = $this->getUrl("/tasks/assigned.xml");
$this->checkForErrors("Tasks");
return $this->parseTasks($xml);
}
public function findUpcomingTasks()
{
$xml = $this->getUrl("/tasks/upcoming.xml");
$this->checkForErrors("Tasks");
return $this->parseTasks($xml);
}
private function parseTasks($xml)
{
$xml_object = simplexml_load_string($xml);
$ret = array();
foreach($xml_object->task as $xml_task)
{
$task = new HighriseTask($this);
$task->loadFromXMLObject($xml_task);
$ret[] = $task;
}
return $ret;
}
public function findTaskById($id)
{
$xml = $this->getURL("/tasks/$id.xml");
$this->checkForErrors("Task");
$task_xml = simplexml_load_string($xml);
$task = new HighriseTask($this);
$task->loadFromXMLObject($task_xml);
return $task;
}
/* Notes & Emails */
public function findEmailById($id)
{
$xml = $this->getURL("/emails/$id.xml");
$this->checkForErrors("Email");
$email_xml = simplexml_load_string($xml);
$email = new HighriseEmail($this);
$email->loadFromXMLObject($email_xml);
return $email;
}
public function findNoteById($id)
{
$xml = $this->getURL("/notes/$id.xml");
$this->checkForErrors("Note");
$note_xml = simplexml_load_string($xml);
$note = new HighriseNote($this);
$note->loadFromXMLObject($note_xml);
return $note;
}
public function findPersonById($id)
{
$xml = $this->getURL("/people/$id.xml");
$this->checkForErrors("Person");
$xml_object = simplexml_load_string($xml);
$person = new HighrisePerson($this);
$person->loadFromXMLObject($xml_object);
return $person;
}
public function findAllTags()
{
$xml = $this->getUrl("/tags.xml");
$this->checkForErrors("Tags");
$xml_object = simplexml_load_string($xml);
$ret = array();
foreach($xml_object->tag as $tag)
{
$ret[(string)$tag->name] = new HighriseTag((string)$tag->id, (string)$tag->name);
}
return $ret;
}
public function findAllPeople()
{
return $this->parsePeopleListing("/people.xml");
}
public function findPeopleByTagName($tag_name)
{
$tags = $this->findAllTags();
foreach($tags as $tag)
{
if ($tag->name == $tag_name)
$tag_id = $tag->id;
}
if (!isset($tag_id))
throw new Excepcion("Tag $tag_name not found");
return $this->findPeopleByTagId($tag_id);
}
public function findPeopleByTagId($tag_id)
{
$url = "/people.xml?tag_id=" . $tag_id;
$people = $this->parsePeopleListing($url);
return $people;
}
public function findPeopleByEmail($email)
{
return $this->findPeopleBySearchCriteria(array("email"=>$email));
}
public function findPeopleByTitle($title)
{
$url = "/people.xml?title=" . urlencode($title);
$people = $this->parsePeopleListing($url);
return $people;
}
public function findPeopleByCompanyId($company_id)
{
$url = "/companies/" . urlencode($company_id) . "/people.xml";
$people = $this->parsePeopleListing($url);
return $people;
}
public function findPeopleBySearchTerm($search_term)
{
$url = "/people/search.xml?term=" . urlencode($search_term);
$people = $this->parsePeopleListing($url, 25);
return $people;
}
public function findPeopleBySearchCriteria($search_criteria)
{
$url = "/people/search.xml";
$sep = "?";
foreach($search_criteria as $criteria=>$value)
{
$url .= $sep . "criteria[" . urlencode($criteria) . "]=" . urlencode($value);
$sep = "&";
}
$people = $this->parsePeopleListing($url, 25);
return $people;
}
public function findPeopleSinceTime($time)
{
$url = "/people/search.xml?since=" . urlencode($time);
$people = $this->parsePeopleListing($url);
return $people;
}
public function parsePeopleListing($url, $paging_results = 500)
{
if (strstr($url, "?"))
$sep = "&";
else
$sep = "?";
$offset = 0;
$return = array();
while(true) // pagination
{
$xml_url = $url . $sep . "n=$offset";
// print $xml_url;
$xml = $this->getUrl($xml_url);
$this->checkForErrors("People");
$xml_object = simplexml_load_string($xml);
foreach($xml_object->person as $xml_person)
{
// print_r($xml_person);
$person = new HighrisePerson($this);
$person->loadFromXMLObject($xml_person);
$return[] = $person;
}
if (count($xml_object) != $paging_results)
break;
$offset += $paging_results;
}
return $return;
}
}
Sorry it's such a long file but if it helps, then so be it.
EDIT: So I guess I got it to work. I should've said that I was trying to test this library out on my local server and for some reason it would keep failing but when I moved the script to my development server on Rackspace cloud then it would work. This just puzzles me. Both servers have support for PHP curl so I can't really understand where the problem is.
EDIT: I'm not sure what the difference between the two server configurations could be but anyways here's a couple of screenshots from my phpinfo function output from both servers of my curl configuration:
Localhost server:
and the rackspace cloud server:
The fork of the API at...
https://github.com/AppSaloon/Highrise-PHP-Api
...seems more developed and better maintained.
Not so much as to provide an answer, but more a better starting point.
Ah, since there is really no HTTP error code 0 I expect that your request isn't being made to Highrise's website, or you are not correctly passing in the account name and token to the class. Can you include the source of your users.test.php class?
EDIT: tested the class and your code, and it works for me. You probably either copied the library file wrong or have your token copied wrong.
I had the same issue. I definitely had the wrong account. I had https://foo.highrisehq.com instead of just foo.

php twitter class not working anymore

So I have been using an open source twitter php class I got a few months back, and all of a sudden, it started to throw me errors last night. You can see what is happening here:
www.campusmediawatch.org
It says it requires authentication but I do authenticate and it has been working for months since last night. Any ideas? Here are the functions:
public function getFriends($id = null, $page = null)
{
// build parameters
$aParameters = array();
if($page !== null) $aParameters['page'] = (int) $page;
// build url
$url = 'statuses/friends.xml';
if($id !== null) $url = 'statuses/friends/'. urlencode($id) .'.xml';
// do the call
$response = $this->doCall($url, $aParameters, true, false);
// convert into xml-object
$xml = #simplexml_load_string($response);
// validate
if($xml == false) throw new TwitterException('invalid body');
// init var
$aUsers = array();
// loop statuses
foreach ($xml->user as $user) $aUsers[] = $this->userXMLToArray($user);
// return
return (array) $aUsers;
}
And here is the code that makes the curl call:
private function doCall($url, $aParameters = array(), $authenticate = false, $usePost = true)
{
// redefine
$url = (string) $url;
$aParameters = (array) $aParameters;
$authenticate = (bool) $authenticate;
$usePost = (bool) $usePost;
// build url
$url = self::TWITTER_API_URL .'/'. $url;
// validate needed authentication
if($authenticate && ($this->getUsername() == '' || $this->getPassword() == '')) throw new TwitterException('No username or password was set.');
// rebuild url if we don't use post
if(!empty($aParameters) && !$usePost)
{
// init var
$queryString = '';
// loop parameters and add them to the queryString
foreach($aParameters as $key => $value) $queryString .= '&'. $key .'='. urlencode(utf8_encode($value));
// cleanup querystring
$queryString = trim($queryString, '&');
// append to url
$url .= '?'. $queryString;
}
// set options
$options[CURLOPT_URL] = $url;
$options[CURLOPT_PORT] = self::TWITTER_API_PORT;
$options[CURLOPT_USERAGENT] = $this->getUserAgent();
$options[CURLOPT_FOLLOWLOCATION] = true;
$options[CURLOPT_RETURNTRANSFER] = true;
$options[CURLOPT_TIMEOUT] = (int) $this->getTimeOut();
// should we authenticate?
if($authenticate)
{
$options[CURLOPT_HTTPAUTH] = CURLAUTH_BASIC;
$options[CURLOPT_USERPWD] = $this->getUsername() .':'. $this->getPassword();
}
// are there any parameters?
if(!empty($aParameters) && $usePost)
{
$var = '';
// rebuild parameters
foreach($aParameters as $key => $value) $var .= '&'. $key .'='. urlencode($value);
// set extra options
$options[CURLOPT_POST] = true;
$options[CURLOPT_POSTFIELDS] = trim($var, '&');
// Probaly Twitter's webserver doesn't support the Expect: 100-continue header. So we reset it.
$options[CURLOPT_HTTPHEADER] = array('Expect:');
}
// init
$curl = curl_init();
// set options
curl_setopt_array($curl, $options);
// execute
$response = curl_exec($curl);
$headers = curl_getinfo($curl);
// fetch errors
$errorNumber = curl_errno($curl);
$errorMessage = curl_error($curl);
// close
curl_close($curl);
// validate body
$xml = #simplexml_load_string($response);
if($xml !== false && isset($xml->error)) throw new TwitterException((string) $xml->error);
// invalid headers
if(!in_array($headers['http_code'], array(0, 200)))
{
// should we provide debug information
if(self::DEBUG)
{
// make it output proper
echo '<pre>';
// dump the header-information
var_dump($headers);
// dump the raw response
var_dump($response);
// end proper format
echo '</pre>';
// stop the script
exit;
}
// throw error
throw new TwitterException(null, (int) $headers['http_code']);
}
// error?
if($errorNumber != '') throw new TwitterException($errorMessage, $errorNumber);
// return
return $response;
}
I managed to find the twitter library you are using in a wordpress plugins repository. I hope it is the same one.
I played around with my account using it and I managed to get it working alright. I think you might have to try and log into your twitter account because that error only seems to occur when your account username and password are invalid (thus failed to authenticate on twitter)
So try and log in to your account and make sure your username and password are the same as what you using to initialize the twitter class.
e.g.
$twitter_api = new Twitter(<username>, <password>);

Categories