Stripe API PHP Invalid Callback - php

In summary: Stripe API: CurlClient.php has a CURLOPT_HEADERFUNCTION that cannot be found by curl on execution of the curl_exec command.
Stripe API version 3.2.0 (the newer version that uses namespace) using PHP version 5.4.45 and CURL version 7.36.0. I downloaded the library from GitHub and am using the init.php routine provided with the Library to bind the Stripe classes.
I can get a token using Stripe.js, pass to my server, authenticate and post a charge:
\Stripe\Charge::create(array(
"amount" => 400,
"currency" => "cad",
"source" => "tok_74MBD61UgMTtN7", // obtained with Stripe.js
"description" => "Charge for test#example.com"
), array(
"idempotency_key" => "yfwO6fUZh4qHctt6",
));
I get an error: Unexpected error communicating with Stripe. If this problem persists, let us know at support#stripe.com. (I have contacted Stripe and haven't heard from them in 3 days.)
My error routine shows: Invalid callback , no array or string given file (...)stripe-php-3.2.0/lib/HttpClient/CurlClient.php. Investigation shows the curl_exec in CurlClient.php throws the error because it can't find $headerCallback. If I comment out this line:
$opts[CURLOPT_HEADERFUNCTION] = $headerCallback;
then everything works fine, except of course I don't get any headers passed back to the calling functions. However, I do get json returned and the successful charge can be seen from the Stripe Control Panel.
So, any ideas on why Strip API won't function properly?
Posting CurlClient.php here:
<?php
namespace Stripe\HttpClient;
use Stripe\Stripe;
use Stripe\Error;
use Stripe\Util;
class CurlClient implements ClientInterface
{
private static $instance;
public static function instance()
{
if (!self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
public function request($method, $absUrl, $headers, $params, $hasFile)
{
$curl = curl_init();
$method = strtolower($method);
$opts = array();
if ($method == 'get') {
if ($hasFile) {
throw new Error\Api(
"Issuing a GET request with a file parameter"
);
}
$opts[CURLOPT_HTTPGET] = 1;
if (count($params) > 0) {
$encoded = self::encode($params);
$absUrl = "$absUrl?$encoded";
}
} elseif ($method == 'post') {
$opts[CURLOPT_POST] = 1;
$opts[CURLOPT_POSTFIELDS] = $hasFile ? $params : self::encode($params);
} elseif ($method == 'delete') {
$opts[CURLOPT_CUSTOMREQUEST] = 'DELETE';
if (count($params) > 0) {
$encoded = self::encode($params);
$absUrl = "$absUrl?$encoded";
}
} else {
throw new Error\Api("Unrecognized method $method");
}
// Create a callback to capture HTTP headers for the response
$rheaders = array();
$headerCallback = function ($curl, $header_line) use (&$rheaders) {
// Ignore the HTTP request line (HTTP/1.1 200 OK)
if (strpos($header_line, ":") === false) {
return strlen($header_line);
}
list($key, $value) = explode(":", trim($header_line), 2);
$rheaders[trim($key)] = trim($value);
return strlen($header_line);
};
$absUrl = Util\Util::utf8($absUrl);
$opts[CURLOPT_URL] = $absUrl;
$opts[CURLOPT_RETURNTRANSFER] = true;
$opts[CURLOPT_CONNECTTIMEOUT] = 30;
$opts[CURLOPT_TIMEOUT] = 80;
$opts[CURLOPT_RETURNTRANSFER] = true;
$opts[CURLOPT_HEADERFUNCTION] = $headerCallback;
$opts[CURLOPT_HTTPHEADER] = $headers;
if (!Stripe::$verifySslCerts) {
$opts[CURLOPT_SSL_VERIFYPEER] = false;
}
curl_setopt_array($curl, $opts);
$rbody = curl_exec($curl);
if (!defined('CURLE_SSL_CACERT_BADFILE')) {
define('CURLE_SSL_CACERT_BADFILE', 77); // constant not defined in PHP
}
$errno = curl_errno($curl);
if ($errno == CURLE_SSL_CACERT ||
$errno == CURLE_SSL_PEER_CERTIFICATE ||
$errno == CURLE_SSL_CACERT_BADFILE
) {
array_push(
$headers,
'X-Stripe-Client-Info: {"ca":"using Stripe-supplied CA bundle"}'
);
$cert = self::caBundle();
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
curl_setopt($curl, CURLOPT_CAINFO, $cert);
$rbody = curl_exec($curl);
}
if ($rbody === false) {
$errno = curl_errno($curl);
$message = curl_error($curl);
curl_close($curl);
$this->handleCurlError($absUrl, $errno, $message);
}
$rcode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
curl_close($curl);
return array($rbody, $rcode, $rheaders);
}
/**
* #param number $errno
* #param string $message
* #throws Error\ApiConnection
*/
private function handleCurlError($url, $errno, $message)
{
switch ($errno) {
case CURLE_COULDNT_CONNECT:
case CURLE_COULDNT_RESOLVE_HOST:
case CURLE_OPERATION_TIMEOUTED:
$msg = "Could not connect to Stripe ($url). Please check your "
. "internet connection and try again. If this problem persists, "
. "you should check Stripe's service status at "
. "https://twitter.com/stripestatus, or";
break;
case CURLE_SSL_CACERT:
case CURLE_SSL_PEER_CERTIFICATE:
$msg = "Could not verify Stripe's SSL certificate. Please make sure "
. "that your network is not intercepting certificates. "
. "(Try going to $url in your browser.) "
. "If this problem persists,";
break;
default:
$msg = "Unexpected error communicating with Stripe. "
. "If this problem persists,";
}
$msg .= " let us know at support#stripe.com.";
$msg .= "\n\n(Network error [errno $errno]: $message)";
throw new Error\ApiConnection($msg);
}
private static function caBundle()
{
return dirname(__FILE__) . '/../../data/ca-certificates.crt';
}
/**
* #param array $arr An map of param keys to values.
* #param string|null $prefix
*
* Only public for testability, should not be called outside of CurlClient
*
* #return string A querystring, essentially.
*/
public static function encode($arr, $prefix = null)
{
if (!is_array($arr)) {
return $arr;
}
$r = array();
foreach ($arr as $k => $v) {
if (is_null($v)) {
continue;
}
if ($prefix && $k && !is_int($k)) {
$k = $prefix."[".$k."]";
} elseif ($prefix) {
$k = $prefix."[]";
}
if (is_array($v)) {
$enc = self::encode($v, $k);
if ($enc) {
$r[] = $enc;
}
} else {
$r[] = urlencode($k)."=".urlencode($v);
}
}
return implode("&", $r);
}
}

The problem turned out to be environmental. My PHP (5.4.45) was installed using CageFS and I used the 5.4 version that was NOT native, allowing for selection of various PHP modules. When I switched to native version of PHP 5.4 then stripe API started working just fine. Also works well in PHP 5.5. This may be of interest to other Cloud Linux users working with CageFS and PHP Selector.

Related

Undefined property: stdClass::$followers_count

I am developing a social followers count via Hybrid auth frame work.I am learning this kinda beginer in PHP/MYSQL and API.I don't understand the error why I am getting this.
This is Hybrid auth example code with my followers count code. Help
<?php
// start a new session (required for Hybridauth)
session_start();
// change the following paths if necessary
$config = dirname(__FILE__) . '/hybridauth/hybridauth/config.php';
require_once( "hybridauth/hybridauth/Hybrid/Auth.php" );
try{
// create an instance for Hybridauth with the configuration file path as parameter
$hybridauth = new Hybrid_Auth( $config );
// try to authenticate the user with twitter,
// user will be redirected to Twitter for authentication,
// if he already did, then Hybridauth will ignore this step and return an instance of the adapter
$twitter = $hybridauth->authenticate( "Twitter" );
// get the user profile
$twitter_user_profile = $twitter->getUserProfile();
echo "Ohai there! U are connected with: <b>{$twitter->id}</b><br />";
echo "As: <b>{$twitter_user_profile->displayName}</b><br />";
// echo "As: <b>{$twitter_user_profile->following}</b><br />";
// debug the user profile
}
catch( Exception $e ){
// Display the recived error,
// to know more please refer to Exceptions handling section on the userguide
switch( $e->getCode() ){
case 0 : echo "Unspecified error."; break;
case 1 : echo "Hybriauth configuration error."; break;
case 2 : echo "Provider not properly configured."; break;
case 3 : echo "Unknown or disabled provider."; break;
case 4 : echo "Missing provider application credentials."; break;
case 5 : echo "Authentification failed. "
. "The user has canceled the authentication or the provider refused the connection.";
break;
case 6 : echo "User profile request failed. Most likely the user is not connected "
. "to the provider and he should authenticate again.";
$twitter->logout();
break;
case 7 : echo "User not connected to the provider.";
$twitter->logout();
break;
case 8 : echo "Provider does not support this feature."; break;
}
// well, basically your should not display this to the end user, just give him a hint and move on..
echo "<br /><br /><b>Original error message:</b> " . $e->getMessage();
}
require_once 'twitteroauth-master/src/twitteroauth.php';
require_once 'config.php';
require "twitteroauth-master/vendor/autoload.php";
use Abraham\TwitterOAuth\TwitterOAuth;
define("CONSUMER_KEY", "*****");
define("CONSUMER_SECRET", "****");
define("OAUTH_TOKEN", "*****");
define("OAUTH_SECRET", "******");
$username = 'kodeordie'; //Your twitter screen name or page name
$connection = new TwitterOAuth(CONSUMER_KEY, CONSUMER_SECRET, OAUTH_TOKEN, OAUTH_SECRET);
$followers = $connection->get('users/show', array('screen_name' => $username));
$followers = json_decode($followers,true);
$f = $followers['followers_count'];
echo $f;
?>
Twitteroauth.php
<?php
/*
* Abraham Williams (abraham#abrah.am) http://abrah.am
*
* The first PHP Library to support OAuth for Twitter's REST API.
*/
/**
* Twitter OAuth class
*/
class TwitterOAuth {
/* Contains the last HTTP status code returned. */
public $http_code;
/* Contains the last API call. */
public $url;
/* Set up the API root URL. */
public $host = "https://api.twitter.com/1.1/";
/* Set timeout default. */
public $timeout = 30;
/* Set connect timeout. */
public $connecttimeout = 30;
/* Verify SSL Cert. */
public $ssl_verifypeer = FALSE;
/* Respons format. */
public $format = 'json';
/* Decode returned json data. */
public $decode_json = TRUE;
/* Contains the last HTTP headers returned. */
public $http_info;
/* Set the useragnet. */
public $useragent = 'TwitterOAuth v0.2.0-beta2';
/* Immediately retry the API call if the response was not successful. */
//public $retry = TRUE;
/**
* Set API URLS
*/
function accessTokenURL() { return 'https://api.twitter.com/oauth/access_token'; }
function authenticateURL() { return 'https://api.twitter.com/oauth/authenticate'; }
function authorizeURL() { return 'https://api.twitter.com/oauth/authorize'; }
function requestTokenURL() { return 'https://api.twitter.com/oauth/request_token'; }
/**
* Debug helpers
*/
function lastStatusCode() { return $this->http_status; }
function lastAPICall() { return $this->last_api_call; }
/**
* construct TwitterOAuth object
*/
function __construct($consumer_key, $consumer_secret, $oauth_token = NULL, $oauth_token_secret = NULL) {
$this->sha1_method = new OAuthSignatureMethod_HMAC_SHA1();
$this->consumer = new OAuthConsumer($consumer_key, $consumer_secret);
if (!empty($oauth_token) && !empty($oauth_token_secret)) {
$this->token = new OAuthConsumer($oauth_token, $oauth_token_secret);
} else {
$this->token = NULL;
}
}
/**
* Get a request_token from Twitter
*
* #returns a key/value array containing oauth_token and oauth_token_secret
*/
function getRequestToken($oauth_callback) {
$parameters = array();
$parameters['oauth_callback'] = $oauth_callback;
$request = $this->oAuthRequest($this->requestTokenURL(), 'GET', $parameters);
$token = OAuthUtil::parse_parameters($request);
$this->token = new OAuthConsumer($token['oauth_token'], $token['oauth_token_secret']);
return $token;
}
/**
* Get the authorize URL
*
* #returns a string
*/
function getAuthorizeURL($token, $sign_in_with_twitter = TRUE) {
if (is_array($token)) {
$token = $token['oauth_token'];
}
if (empty($sign_in_with_twitter)) {
return $this->authorizeURL() . "?oauth_token={$token}";
} else {
return $this->authenticateURL() . "?oauth_token={$token}";
}
}
/**
* Exchange request token and secret for an access token and
* secret, to sign API calls.
*
* #returns array("oauth_token" => "the-access-token",
* "oauth_token_secret" => "the-access-secret",
* "user_id" => "9436992",
* "screen_name" => "abraham")
*/
function getAccessToken($oauth_verifier) {
$parameters = array();
$parameters['oauth_verifier'] = $oauth_verifier;
$request = $this->oAuthRequest($this->accessTokenURL(), 'GET', $parameters);
$token = OAuthUtil::parse_parameters($request);
$this->token = new OAuthConsumer($token['oauth_token'], $token['oauth_token_secret']);
return $token;
}
/**
* One time exchange of username and password for access token and secret.
*
* #returns array("oauth_token" => "the-access-token",
* "oauth_token_secret" => "the-access-secret",
* "user_id" => "9436992",
* "screen_name" => "abraham",
* "x_auth_expires" => "0")
*/
function getXAuthToken($username, $password) {
$parameters = array();
$parameters['x_auth_username'] = $username;
$parameters['x_auth_password'] = $password;
$parameters['x_auth_mode'] = 'client_auth';
$request = $this->oAuthRequest($this->accessTokenURL(), 'POST', $parameters);
$token = OAuthUtil::parse_parameters($request);
$this->token = new OAuthConsumer($token['oauth_token'], $token['oauth_token_secret']);
return $token;
}
/**
* GET wrapper for oAuthRequest.
*/
function get($url, $parameters = array()) {
$response = $this->oAuthRequest($url, 'GET', $parameters);
if ($this->format === 'json' && $this->decode_json) {
return json_decode($response);
}
return $response;
}
/**
* POST wrapper for oAuthRequest.
*/
function post($url, $parameters = array()) {
$response = $this->oAuthRequest($url, 'POST', $parameters);
if ($this->format === 'json' && $this->decode_json) {
return json_decode($response);
}
return $response;
}
/**
* DELETE wrapper for oAuthReqeust.
*/
function delete($url, $parameters = array()) {
$response = $this->oAuthRequest($url, 'DELETE', $parameters);
if ($this->format === 'json' && $this->decode_json) {
return json_decode($response);
}
return $response;
}
/**
* Format and sign an OAuth / API request
*/
function oAuthRequest($url, $method, $parameters) {
if (strrpos($url, 'https://') !== 0 && strrpos($url, 'http://') !== 0) {
$url = "{$this->host}{$url}.{$this->format}";
}
$request = OAuthRequest::from_consumer_and_token($this->consumer, $this->token, $method, $url, $parameters);
$request->sign_request($this->sha1_method, $this->consumer, $this->token);
switch ($method) {
case 'GET':
return $this->http($request->to_url(), 'GET');
default:
return $this->http($request->get_normalized_http_url(), $method, $request->to_postdata());
}
}
/**
* Make an HTTP request
*
* #return API results
*/
function http($url, $method, $postfields = NULL) {
$this->http_info = array();
$ci = curl_init();
/* Curl settings */
curl_setopt($ci, CURLOPT_USERAGENT, $this->useragent);
curl_setopt($ci, CURLOPT_CONNECTTIMEOUT, $this->connecttimeout);
curl_setopt($ci, CURLOPT_TIMEOUT, $this->timeout);
curl_setopt($ci, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ci, CURLOPT_HTTPHEADER, array('Expect:'));
curl_setopt($ci, CURLOPT_SSL_VERIFYPEER, $this->ssl_verifypeer);
curl_setopt($ci, CURLOPT_HEADERFUNCTION, array($this, 'getHeader'));
curl_setopt($ci, CURLOPT_HEADER, FALSE);
switch ($method) {
case 'POST':
curl_setopt($ci, CURLOPT_POST, TRUE);
if (!empty($postfields)) {
curl_setopt($ci, CURLOPT_POSTFIELDS, $postfields);
}
break;
case 'DELETE':
curl_setopt($ci, CURLOPT_CUSTOMREQUEST, 'DELETE');
if (!empty($postfields)) {
$url = "{$url}?{$postfields}";
}
}
curl_setopt($ci, CURLOPT_URL, $url);
$response = curl_exec($ci);
$this->http_code = curl_getinfo($ci, CURLINFO_HTTP_CODE);
$this->http_info = array_merge($this->http_info, curl_getinfo($ci));
$this->url = $url;
curl_close ($ci);
return $response;
}
/**
* Get the header info to store.
*/
function getHeader($ch, $header) {
$i = strpos($header, ':');
if (!empty($i)) {
$key = str_replace('-', '_', strtolower(substr($header, 0, $i)));
$value = trim(substr($header, $i + 2));
$this->http_header[$key] = $value;
}
return strlen($header);
}
}
$followers = $connection->get('users/show', array('screen_name' => $username));
$f = $followers->followers_count;
You are trying to access $followers as a stdClass which JSON returns sometimes.
Instead try to access it as an array
$f = $followers['followers_count'];
I had a very similar error:
Undefined property: stdClass::$email
It was caused by the "request email address" field in Twitter's Oauth settings being disabled.
When I enabled it, it took a few minutes to propagate, and then it started working.
Check this sequence:
Navigate to https://developer.twitter.com
Click Developer Portal (at the top right)
Click Projects & Apps (in the left sidebar)
Click your project name
Under Authentication settings, click Edit
Make sure Request email address from users is enabled
My answer here might be moderately useful in other cases. Twitter's oauth settings are quite strict in terms of fields.
If your Oauth is working in localhost environment and not production, compare the two apps together. Look at every field and make sure they are congruent.
NOTE about followers_count
Based on my answer, if your controller is expecting followers_count field to be sent by Twitter and it is omitted, you could see this error. That could mean a simple setting somewhere is disabled or otherwise incorrect.

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 use paging in the Facebook Graph API?

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");

Has any one got class.openid.php working with google openID?

I am trying to study class.openid.php because it is simpler and smaller than
lightopenid. for my purposes 200 lines do matter. But class.openid.php does not work with google openID https://www.google.com/accounts/o8/id, prints to me such error:
ERROR CODE: OPENID_NOSERVERSFOUND
ERROR DESCRIPTION: Cannot find OpenID Server TAG on Identity page.
is it possible to make class.openid.php (any version) work with google openID and how to do such thing?
class.openid.php can be taken here but it did not worked for me out of the box so I had to find all <? and replace tham with <?php in case someone would like to see code I've got:
html interface page:
<?php
require('class.openid.v3.php');
if ($_POST['openid_action'] == "login"){ // Get identity from user and redirect browser to OpenID Server
$openid = new SimpleOpenID;
$openid->SetIdentity($_POST['openid_url']);
$openid->SetTrustRoot('http://' . $_SERVER["HTTP_HOST"]);
$openid->SetRequiredFields(array('email','fullname'));
$openid->SetOptionalFields(array('dob','gender','postcode','country','language','timezone'));
if ($openid->GetOpenIDServer()){
$openid->SetApprovedURL('http://' . $_SERVER["HTTP_HOST"] . $_SERVER["PATH_INFO"]); // Send Response from OpenID server to this script
$openid->Redirect(); // This will redirect user to OpenID Server
}else{
$error = $openid->GetError();
echo "ERROR CODE: " . $error['code'] . "<br>";
echo "ERROR DESCRIPTION: " . $error['description'] . "<br>";
}
exit;
}
else if($_GET['openid_mode'] == 'id_res'){ // Perform HTTP Request to OpenID server to validate key
$openid = new SimpleOpenID;
$openid->SetIdentity($_GET['openid_identity']);
$openid_validation_result = $openid->ValidateWithServer();
if ($openid_validation_result == true){ // OK HERE KEY IS VALID
echo "VALID";
}else if($openid->IsError() == true){ // ON THE WAY, WE GOT SOME ERROR
$error = $openid->GetError();
echo "ERROR CODE: " . $error['code'] . "<br>";
echo "ERROR DESCRIPTION: " . $error['description'] . "<br>";
}else{ // Signature Verification Failed
echo "INVALID AUTHORIZATION";
}
}else if ($_GET['openid_mode'] == 'cancel'){ // User Canceled your Request
echo "USER CANCELED REQUEST";
}
?>
<html>
<head>
<title>OpenID Example</title>
</head>
<body>
<div>
<fieldset id="openid">
<legend>OpenID Login</legend>
<form action="<?php echo 'http://' . $_SERVER["HTTP_HOST"] . $_SERVER["PATH_INFO"]; ?>" method="post" onsubmit="this.login.disabled=true;">
<input type="hidden" name="openid_action" value="login">
<div><input type="text" name="openid_url" class="openid_login"><input type="submit" name="login" value="login >>"></div>
<div><a href="http://www.myopenid.com/" class="link" >Get an OpenID</a></div>
</form>
</fieldset>
</div>
<div style="margin-top: 2em; font-family: arial; font-size: 0.8em; border-top:1px solid gray; padding: 4px;">Sponsored by: FiveStores - get your free online store; includes extensive API for developers; <i style="color: gray;">integrated with OpenID</i></div>
</body>
</html>
and php class
<?php
/*
FREE TO USE Under License: GPLv3
Simple OpenID PHP Class
Some modifications by Eddie Roosenmaallen, eddie#roosenmaallen.com
*/
class SimpleOpenID{
var $openid_url_identity;
var $URLs = array();
var $error = array();
var $fields = array(
'required' => array(),
'optional' => array(),
);
function SimpleOpenID(){
if (!function_exists('curl_exec')) {
die('Error: Class SimpleOpenID requires curl extension to work');
}
}
function SetOpenIDServer($a){
$this->URLs['openid_server'] = $a;
}
function SetTrustRoot($a){
$this->URLs['trust_root'] = $a;
}
function SetCancelURL($a){
$this->URLs['cancel'] = $a;
}
function SetApprovedURL($a){
$this->URLs['approved'] = $a;
}
function SetRequiredFields($a){
if (is_array($a)){
$this->fields['required'] = $a;
}else{
$this->fields['required'][] = $a;
}
}
function SetOptionalFields($a){
if (is_array($a)){
$this->fields['optional'] = $a;
}else{
$this->fields['optional'][] = $a;
}
}
function SetIdentity($a){ // Set Identity URL
if ((stripos($a, 'http://') === false)
&& (stripos($a, 'https://') === false)){
$a = 'http://'.$a;
}
$this->openid_url_identity = $a;
}
function GetIdentity(){ // Get Identity
return $this->openid_url_identity;
}
function GetError(){
$e = $this->error;
return array('code'=>$e[0],'description'=>$e[1]);
}
function ErrorStore($code, $desc = null){
$errs['OPENID_NOSERVERSFOUND'] = 'Cannot find OpenID Server TAG on Identity page.';
if ($desc == null){
$desc = $errs[$code];
}
$this->error = array($code,$desc);
}
function IsError(){
if (count($this->error) > 0){
return true;
}else{
return false;
}
}
function splitResponse($response) {
$r = array();
$response = explode("\n", $response);
foreach($response as $line) {
$line = trim($line);
if ($line != "") {
list($key, $value) = explode(":", $line, 2);
$r[trim($key)] = trim($value);
}
}
return $r;
}
function OpenID_Standarize($openid_identity = null){
if ($openid_identity === null)
$openid_identity = $this->openid_url_identity;
$u = parse_url(strtolower(trim($openid_identity)));
if (!isset($u['path']) || ($u['path'] == '/')) {
$u['path'] = '';
}
if(substr($u['path'],-1,1) == '/'){
$u['path'] = substr($u['path'], 0, strlen($u['path'])-1);
}
if (isset($u['query'])){ // If there is a query string, then use identity as is
return $u['host'] . $u['path'] . '?' . $u['query'];
}else{
return $u['host'] . $u['path'];
}
}
function array2url($arr){ // converts associated array to URL Query String
if (!is_array($arr)){
return false;
}
$query = '';
foreach($arr as $key => $value){
$query .= $key . "=" . $value . "&";
}
return $query;
}
function CURL_Request($url, $method="GET", $params = "") { // Remember, SSL MUST BE SUPPORTED
if (is_array($params)) $params = $this->array2url($params);
$curl = curl_init($url . ($method == "GET" && $params != "" ? "?" . $params : ""));
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($curl, CURLOPT_HEADER, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_HTTPGET, ($method == "GET"));
curl_setopt($curl, CURLOPT_POST, ($method == "POST"));
if ($method == "POST") curl_setopt($curl, CURLOPT_POSTFIELDS, $params);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($curl);
if (curl_errno($curl) == 0){
$response;
}else{
$this->ErrorStore('OPENID_CURL', curl_error($curl));
}
return $response;
}
function HTML2OpenIDServer($content) {
$get = array();
// Get details of their OpenID server and (optional) delegate
preg_match_all('/<link[^>]*rel=[\'"]openid.server[\'"][^>]*href=[\'"]([^\'"]+)[\'"][^>]*\/?>/i', $content, $matches1);
preg_match_all('/<link[^>]*href=\'"([^\'"]+)[\'"][^>]*rel=[\'"]openid.server[\'"][^>]*\/?>/i', $content, $matches2);
$servers = array_merge($matches1[1], $matches2[1]);
preg_match_all('/<link[^>]*rel=[\'"]openid.delegate[\'"][^>]*href=[\'"]([^\'"]+)[\'"][^>]*\/?>/i', $content, $matches1);
preg_match_all('/<link[^>]*href=[\'"]([^\'"]+)[\'"][^>]*rel=[\'"]openid.delegate[\'"][^>]*\/?>/i', $content, $matches2);
$delegates = array_merge($matches1[1], $matches2[1]);
$ret = array($servers, $delegates);
return $ret;
}
function GetOpenIDServer(){
$response = $this->CURL_Request($this->openid_url_identity);
list($servers, $delegates) = $this->HTML2OpenIDServer($response);
if (count($servers) == 0){
$this->ErrorStore('OPENID_NOSERVERSFOUND');
return false;
}
if (isset($delegates[0])
&& ($delegates[0] != "")){
$this->SetIdentity($delegates[0]);
}
$this->SetOpenIDServer($servers[0]);
return $servers[0];
}
function GetRedirectURL(){
$params = array();
$params['openid.return_to'] = urlencode($this->URLs['approved']);
$params['openid.mode'] = 'checkid_setup';
$params['openid.identity'] = urlencode($this->openid_url_identity);
$params['openid.trust_root'] = urlencode($this->URLs['trust_root']);
if (isset($this->fields['required'])
&& (count($this->fields['required']) > 0)) {
$params['openid.sreg.required'] = implode(',',$this->fields['required']);
}
if (isset($this->fields['optional'])
&& (count($this->fields['optional']) > 0)) {
$params['openid.sreg.optional'] = implode(',',$this->fields['optional']);
}
return $this->URLs['openid_server'] . "?". $this->array2url($params);
}
function Redirect(){
$redirect_to = $this->GetRedirectURL();
if (headers_sent()){ // Use JavaScript to redirect if content has been previously sent (not recommended, but safe)
echo '<script language="JavaScript" type="text/javascript">window.location=\'';
echo $redirect_to;
echo '\';</script>';
}else{ // Default Header Redirect
header('Location: ' . $redirect_to);
}
}
function ValidateWithServer(){
$params = array(
'openid.assoc_handle' => urlencode($_GET['openid_assoc_handle']),
'openid.signed' => urlencode($_GET['openid_signed']),
'openid.sig' => urlencode($_GET['openid_sig'])
);
// Send only required parameters to confirm validity
$arr_signed = explode(",",str_replace('sreg.','sreg_',$_GET['openid_signed']));
for ($i=0; $i<count($arr_signed); $i++){
$s = str_replace('sreg_','sreg.', $arr_signed[$i]);
$c = $_GET['openid_' . $arr_signed[$i]];
// if ($c != ""){
$params['openid.' . $s] = urlencode($c);
// }
}
$params['openid.mode'] = "check_authentication";
$openid_server = $this->GetOpenIDServer();
if ($openid_server == false){
return false;
}
$response = $this->CURL_Request($openid_server,'POST',$params);
$data = $this->splitResponse($response);
if ($data['is_valid'] == "true") {
return true;
}else{
return false;
}
}
}
?>
The problem is that Google doesn't just supply an OpenID endpoint.
OpenId endpoints include an identifier for the user.
What we are having here is called a Discovery Url.
This is a static url that you can direct any user to, and the service itself will recognise the user and return a per-user unique identifying url.
This however is NOT implemented correctly by most openid client libraries, including the majority linked on the official openid website.
Even the Zend Framework libraries are incapable of handling that.
However I found a class that I analysed from various perspectives and that I am very satisfied with. At the company I work at we already integrated it successfully in several production environments and have not experienced any problems.
You may also be interested in another post of mine dealing with the issue of making Facebook an openid Provider. The class I am using, that also supports Google, can also be found there:
Best way to implement Single-Sign-On with all major providers?
The class in your question does not support OpenID 2.0 at all. Therefore, it will not work with Google without adding a lot of code.
Are you searching something like :
http://wiki.openid.net/w/page/12995176/Libraries
?
There is a PHP section in that.

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.

Categories