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.
Related
I want to run my PHP file without any error but each time I faced some problem. I explained my problem below.
Could any one can give me any suggestion so that I can solve it with a better way!
Thanks all who participate here.
PHP Warning: curl_setopt(): supplied resource is not a valid cURL handle resource in p_detail.php on line 170
PHP Warning: curl_setopt(): supplied resource is not a valid cURL handle resource in p_detail.php on line 171
PHP Warning: curl_setopt(): supplied resource is not a valid cURL handle resource in p_detail.php on line 172
Here is my php file:
$banggoodAPI = new BanggoodAPI();
//Product Detail
$params = [
'product_id'=>1588753,
];
$banggoodAPI->setParams($params);
$result = $banggoodAPI->getProductDetail();
echo '<pre>';
var_dump($result);
class BanggoodAPI {
private $__apiKey = '***';
private $__apiSecret = '**********';
private $__domain = 'https://affapi.banggood.com/';
private $__accessToken = '';
private $__task = '' ;
private $__method = 'GET';
private $__params = array();
private $__lang = 'en-GB';
private $__currency = 'USD';
private $__waitingTaskInfo = array();
private $__ch = null;
private $__curlExpireTime = 10;
/**
* #desc Construct
* #access public
*/
public function __construct(){
$this->__ch = curl_init();
}
/**
* #desc product/detail
* #access public
*/
public function getProductDetail() {
$this->__task = 'product/detail';
$this->__method = 'GET';
$result = $this->__doRequest();
return $result;
}
/**
* #desc set params
* #access public
*/
public function setParams(Array $params) {
if (!empty($params)) {
$this->__params = $params;
}
}
/**
* #desc get access_token
* #access private
*/
private function __getAccessToken($useCache = true) {
//if access_token is empty, send request to get accessToken
if (empty($this->__accessToken)) {
if (!empty($this->__task)) {
$this->__waitingTaskInfo = array(
'task' => $this->__task,
'method' => $this->__method,
'params' => $this->__params,
);
}
$this->__task = 'getAccessToken';
$rand=rand();
$time=time();
$this->__params = [
'api_key' => $this->__apiKey,
'noncestr' => $rand,
'timestamp' => $time,
];
$preArr = array_merge($this->__params, ['api_secret' => $this->__apiSecret]);
ksort($preArr);
$signature=http_build_query($preArr);
$this->__params['signature']=md5($signature);
$this->__method = 'GET';
$result = $this->__doRequest();
if ($result['code'] == 200) {
$this->__accessToken = $result['result']['access_token'];
//resend request
if (!empty($this->__waitingTaskInfo)) {
$this->__task = $this->__waitingTaskInfo['task'];
$this->__params = $this->__waitingTaskInfo['params'];
$this->__method = $this->__waitingTaskInfo['method'];
$this->__waitingTaskInfo = array();
return $this->__doRequest();
}
} else {
$this->__requestError($result);
}
}
}
/**
* #desc handle request error
* #access private
*/
private function __requestError($error) {
var_dump($error);
exit;
}
/**
* #desc send api request
* #access private
*/
private function __doRequest() {
if (empty($this->__params)) {
$this->__requestError(array('params is empty'));
}
if ($this->__task != 'getAccessToken') {
if (empty($this->__accessToken)) {
$this->__getAccessToken();
}
//头部信息
$header = array(
'access-token:'.$this->__accessToken,
);
if (empty($this->__params['lang']))
$this->__params['lang'] = $this->__lang;
if (empty($this->__params['currency']))
$this->__params['currency'] = $this->__currency;
}
$apiUrl = $this->__domain . $this->__task;
if ($this->__method == 'GET') {
$quote = '?';
foreach ($this->__params as $k => $v) {
$apiUrl .= $quote . $k .'='. $v;
$quote = '&';
}
$preStr = http_build_query($this->__params);
}
curl_setopt($this->__ch, CURLOPT_URL, $apiUrl ); //170 line
curl_setopt($this->__ch, CURLOPT_HEADER, 0); //171 line
curl_setopt($this->__ch, CURLOPT_USERAGENT, $_SERVER ['HTTP_USER_AGENT']); //172 line
curl_setopt($this->__ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($this->__ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($this->__ch, CURLOPT_SSL_VERIFYPEER, false);
if ($this->__method == 'POST') {
curl_setopt($this->__ch, CURLOPT_POST, 1 );
curl_setopt($this->__ch, CURLOPT_POSTFIELDS, http_build_query($this->__params));
}
if ($this->__curlExpireTime > 0) {
curl_setopt($this->__ch, CURLOPT_TIMEOUT, $this->__curlExpireTime);
}
if ($header){
curl_setopt($this->__ch, CURLOPT_HTTPHEADER, $header);
}
$result = curl_exec($this->__ch);
if($error=curl_error($this->__ch)){
die($error);
}
curl_close($this->__ch);
$result = json_decode($result, true);
return $result;
}
}
?>
I want to run my PHP file without any error but each time I faced some problem. I explained my problem below.
Could any one can give me any suggestion so that I can solve it with a better way!
Thanks all who participate here.
You are "closing" your curl handle after every request (curl_close($this->__ch);), but only "initializing" it ($this->__ch = curl_init();) once in the constructor.
Once it's been "closed", you can't re-use it for another request. Since you're setting all the options for each request anyway, you probably want to run curl_init() for every request, at the start of the __doRequest method.
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.
I am trying to use the code from #eyecatchup (https://github.com/eyecatchup/php-webmaster-tools-downloads) to get data via the Google Webmaster Tools API. I am able to get "TOP_PAGES" and "TOP QUERIES" but that is it. What I really want is "EXTERNAL_LINKS" or even "LATEST_LINKS".
Here is the gwtdata.php code:
<pre>
<?php
/**
* PHP class for downloading CSV files from Google Webmaster Tools.
*
* This class does NOT require the Zend gdata package be installed
* in order to run.
*
* Copyright 2012 eyecatchUp UG. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* #author: Stephan Schmitz <eyecatchup#gmail.com>
* #link: https://code.google.com/p/php-webmaster-tools-downloads/
*/
class GWTdata
{
const HOST = "https://www.google.com";
const SERVICEURI = "/webmasters/tools/";
public $_language, $_tables, $_daterange, $_downloaded, $_skipped;
private $_auth, $_logged_in;
public function __construct()
{
$this->_auth = false;
$this->_logged_in = false;
$this->_language = "en";
$this->_daterange = array("","");
$this->_tables = array("TOP_PAGES", "TOP_QUERIES",
"CRAWL_ERRORS", "CONTENT_ERRORS", "CONTENT_KEYWORDS",
"INTERNAL_LINKS", "EXTERNAL_LINKS", "SOCIAL_ACTIVITY"
);
$this->_errTablesSort = array(0 => "http",
1 => "not-found", 2 => "restricted-by-robotsTxt",
3 => "unreachable", 4 => "timeout", 5 => "not-followed",
"kAppErrorSoft-404s" => "soft404", "sitemap" => "in-sitemaps"
);
$this->_errTablesType = array(0 => "web-crawl-errors",
1 => "mobile-wml-xhtml-errors", 2 => "mobile-chtml-errors",
3 => "mobile-operator-errors", 4 => "news-crawl-errors"
);
$this->_downloaded = array();
$this->_skipped = array();
}
/**
* Sets content language.
*
* #param $str String Valid ISO 639-1 language code, supported by Google.
*/
public function SetLanguage($str)
{
$this->_language = $str;
}
/**
* Sets features that should be downloaded.
*
* #param $arr Array Valid array values are:
* "TOP_PAGES", "TOP_QUERIES", "CRAWL_ERRORS", "CONTENT_ERRORS",
* "CONTENT_KEYWORDS", "INTERNAL_LINKS", "EXTERNAL_LINKS",
* "SOCIAL_ACTIVITY".
*/
public function SetTables($arr)
{
if(is_array($arr) && !empty($arr) && sizeof($arr) <= 2) {
$valid = array("TOP_PAGES","TOP_QUERIES","CRAWL_ERRORS","CONTENT_ERRORS",
"CONTENT_KEYWORDS","INTERNAL_LINKS","EXTERNAL_LINKS","SOCIAL_ACTIVITY");
$this->_tables = array();
for($i=0; $i < sizeof($arr); $i++) {
if(in_array($arr[$i], $valid)) {
array_push($this->_tables, $arr[$i]);
} else { throw new Exception("Invalid argument given."); }
}
} else { throw new Exception("Invalid argument given."); }
}
/**
* Sets daterange for download data.
*
* #param $arr Array Array containing two ISO 8601 formatted date strings.
*/
public function SetDaterange($arr)
{
if(is_array($arr) && !empty($arr) && sizeof($arr) == 2) {
if(self::IsISO8601($arr[0]) === true &&
self::IsISO8601($arr[1]) === true) {
$this->_daterange = array(str_replace("-", "", $arr[0]),
str_replace("-", "", $arr[1]));
return true;
} else { throw new Exception("Invalid argument given."); }
} else { throw new Exception("Invalid argument given."); }
}
/**
* Returns array of downloaded filenames.
*
* #return Array Array of filenames that have been written to disk.
*/
public function GetDownloadedFiles()
{
return $this->_downloaded;
}
/**
* Returns array of downloaded filenames.
*
* #return Array Array of filenames that have been written to disk.
*/
public function GetSkippedFiles()
{
return $this->_skipped;
}
/**
* Checks if client has logged into their Google account yet.
*
* #return Boolean Returns true if logged in, or false if not.
*/
private function IsLoggedIn()
{
return $this->_logged_in;
}
/**
* Attempts to log into the specified Google account.
*
* #param $email String User's Google email address.
* #param $pwd String Password for Google account.
* #return Boolean Returns true when Authentication was successful,
* else false.
*/
public function LogIn($email, $pwd)
{
$url = self::HOST . "/accounts/ClientLogin";
$postRequest = array(
'accountType' => 'HOSTED_OR_GOOGLE',
'Email' => $email,
'Passwd' => $pwd,
'service' => "sitemaps",
'source' => "Google-WMTdownloadscript-0.1-php"
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postRequest);
$output = curl_exec($ch);
$info = curl_getinfo($ch);
curl_close($ch);
if($info['http_code'] == 200) {
preg_match('/Auth=(.*)/', $output, $match);
if(isset($match[1])) {
$this->_auth = $match[1];
$this->_logged_in = true;
return true;
} else { return false; }
} else { return false; }
}
/**
* Attempts authenticated GET Request.
*
* #param $url String URL for the GET request.
* #return Mixed Curl result as String,
* or false (Boolean) when Authentication fails.
*/
public function GetData($url)
{
if(self::IsLoggedIn() === true) {
$url = self::HOST . $url;
$head = array("Authorization: GoogleLogin auth=".$this->_auth,
"GData-Version: 2");
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_ENCODING, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $head);
$result = curl_exec($ch);
$info = curl_getinfo($ch);
curl_close($ch);
return ($info['http_code']!=200) ? false : $result;
} else { return false; }
}
/**
* Gets all available sites from Google Webmaster Tools account.
*
* #return Mixed Array with all site URLs registered in GWT account,
* or false (Boolean) if request failed.
*/
public function GetSites()
{
if(self::IsLoggedIn() === true) {
$feed = self::GetData(self::SERVICEURI."feeds/sites/");
if($feed !== false) {
$sites = array();
$doc = new DOMDocument();
$doc->loadXML($feed);
foreach ($doc->getElementsByTagName('entry') as $node) {
array_push($sites,
$node->getElementsByTagName('title')->item(0)->nodeValue);
}
return $sites;
} else { return false; }
} else { return false; }
}
/**
* Gets the download links for an available site
* from the Google Webmaster Tools account.
*
* #param $url String Site URL registered in GWT.
* #return Mixed Array with keys TOP_PAGES and TOP_QUERIES,
* or false (Boolean) when Authentication fails.
*/
public function GetDownloadUrls($url)
{
if(self::IsLoggedIn() === true) {
$_url = sprintf(self::SERVICEURI."downloads-list?hl=%s&siteUrl=%s",
$this->_language,
urlencode($url));
$downloadList = self::GetData($_url);
return json_decode($downloadList, true);
} else { return false; }
}
/**
* Downloads the file based on the given URL.
*
* #param $site String Site URL available in GWT Account.
* #param $savepath String Optional path to save CSV to (no trailing slash!).
*/
public function DownloadCSV($site, $savepath=".")
{
if(self::IsLoggedIn() === true) {
$downloadUrls = self::GetDownloadUrls($site);
$filename = parse_url($site, PHP_URL_HOST) ."-". date("Ymd-His");
$tables = $this->_tables;
foreach($tables as $table) {
if($table=="CRAWL_ERRORS") {
self::DownloadCSV_CrawlErrors($site, $savepath);
}
elseif($table=="CONTENT_ERRORS") {
self::DownloadCSV_XTRA($site, $savepath,
"html-suggestions", "\)", "CONTENT_ERRORS", "content-problems-dl");
}
elseif($table=="CONTENT_KEYWORDS") {
self::DownloadCSV_XTRA($site, $savepath,
"keywords", "\)", "CONTENT_KEYWORDS", "content-words-dl");
}
elseif($table=="INTERNAL_LINKS") {
self::DownloadCSV_XTRA($site, $savepath,
"internal-links", "\)", "INTERNAL_LINKS", "internal-links-dl");
}
elseif($table=="EXTERNAL_LINKS") {
self::DownloadCSV_XTRA($site, $savepath,
"external-links-domain", "\)", "EXTERNAL_LINKS", "external-links-domain-dl");
}
elseif($table=="SOCIAL_ACTIVITY") {
self::DownloadCSV_XTRA($site, $savepath,
"social-activity", "x26", "SOCIAL_ACTIVITY", "social-activity-dl");
}
else {
$finalName = "$savepath/$table-$filename.csv";
$finalUrl = $downloadUrls[$table] ."&prop=ALL&db=%s&de=%s&more=true";
$finalUrl = sprintf($finalUrl, $this->_daterange[0], $this->_daterange[1]);
self::SaveData($finalUrl,$finalName);
}
}
} else { return false; }
}
/**
* Downloads "unofficial" downloads based on the given URL.
*
* #param $site String Site URL available in GWT Account.
* #param $savepath String Optional path to save CSV to (no trailing slash!).
*/
public function DownloadCSV_XTRA($site, $savepath=".", $tokenUri, $tokenDelimiter, $filenamePrefix, $dlUri)
{
if(self::IsLoggedIn() === true) {
$uri = self::SERVICEURI . $tokenUri . "?hl=%s&siteUrl=%s";
$_uri = sprintf($uri, $this->_language, $site);
$token = self::GetToken($_uri, $tokenDelimiter);
$filename = parse_url($site, PHP_URL_HOST) ."-". date("Ymd-His");
$finalName = "$savepath/$filenamePrefix-$filename.csv";
$url = self::SERVICEURI . $dlUri . "?hl=%s&siteUrl=%s&security_token=%s&prop=ALL&db=%s&de=%s&more=true";
$_url = sprintf($url, $this->_language, $site, $token, $this->_daterange[0], $this->_daterange[1]);
self::SaveData($_url,$finalName);
} else { return false; }
}
/**
* Downloads the Crawl Errors file based on the given URL.
*
* #param $site String Site URL available in GWT Account.
* #param $savepath String Optional: Path to save CSV to (no trailing slash!).
* #param $separated Boolean Optional: If true, the method saves separated CSV files
* for each error type. Default: Merge errors in one file.
*/
public function DownloadCSV_CrawlErrors($site, $savepath=".", $separated=false)
{
if(self::IsLoggedIn() === true) {
$type_param = "we";
$filename = parse_url($site, PHP_URL_HOST) ."-". date("Ymd-His");
if($separated) {
foreach($this->_errTablesSort as $sortid => $sortname) {
foreach($this->_errTablesType as $typeid => $typename) {
if($typeid == 1) {
$type_param = "mx";
} else if($typeid == 2) {
$type_param = "mc";
} else {
$type_param = "we";
}
$uri = self::SERVICEURI."crawl-errors?hl=en&siteUrl=$site&tid=$type_param";
$token = self::GetToken($uri,"x26");
$finalName = "$savepath/CRAWL_ERRORS-$typename-$sortname-$filename.csv";
$url = self::SERVICEURI."crawl-errors-dl?hl=%s&siteUrl=%s&security_token=%s&type=%s&sort=%s";
$_url = sprintf($url, $this->_language, $site, $token, $typeid, $sortid);
self::SaveData($_url,$finalName);
}
}
}
else {
$uri = self::SERVICEURI."crawl-errors?hl=en&siteUrl=$site&tid=$type_param";
$token = self::GetToken($uri,"x26");
$finalName = "$savepath/CRAWL_ERRORS-$filename.csv";
$url = self::SERVICEURI."crawl-errors-dl?hl=%s&siteUrl=%s&security_token=%s&type=0";
$_url = sprintf($url, $this->_language, $site, $token);
self::SaveData($_url,$finalName);
}
} else { return false; }
}
/**
* Saves data to a CSV file based on the given URL.
*
* #param $finalUrl String CSV Download URI.
* #param $finalName String Filepointer to save location.
*/
private function SaveData($finalUrl, $finalName)
{
$data = self::GetData($finalUrl);
if(strlen($data) > 1 && file_put_contents($finalName, utf8_decode($data))) {
array_push($this->_downloaded, realpath($finalName));
return true;
} else {
array_push($this->_skipped, $finalName);
return false;
}
}
/**
* Regular Expression to find the Security Token for a download file.
*
* #param $uri String A Webmaster Tools Desktop Service URI.
* #param $delimiter String Trailing delimiter for the regex.
* #return String Returns a security token.
*/
private function GetToken($uri, $delimiter)
{
$matches = array(); $tmp = self::get_data($uri); preg_match_all("#46security_token(.?)$delimiter#si", $tmp, $matches); return #substr($matches[1][0],3,-1);
}
/**
* Validates ISO 8601 date format.
*
* #param $str String Valid ISO 8601 date string (eg. 2012-01-01).
* #return Boolean Returns true if string has valid format, else false.
*/
private function IsISO8601($str)
{
$stamp = strtotime($str);
return (is_numeric($stamp) && checkdate(date('m', $stamp),
date('d', $stamp), date('Y', $stamp))) ? true : false;
}
}
?>
</pre>
And here is the code I am using to try to extract external links:
<pre>
<?php
include 'gwtdata.php';
try {
$email = "***#gmail.com";
$password = "***";
# If hardcoded, don't forget trailing slash!
$website = "***";
# Valid values are "TOP_PAGES", "TOP_QUERIES", "CRAWL_ERRORS",
# "CONTENT_ERRORS", "CONTENT_KEYWORDS", "INTERNAL_LINKS",
# "EXTERNAL_LINKS" and "SOCIAL_ACTIVITY".
$tables = array("EXTERNAL_LINKS");
$gdata = new GWTdata();
if($gdata->LogIn($email, $password) === true)
{
$gdata->SetTables($tables);
$gdata->DownloadCSV($website, "./csv");
}
$files = $gdata->GetDownloadedFiles();
foreach($files as $file)
{
print "Saved $file\n</a>";
}
} catch (Exception $e) {
die($e->getMessage());
}
?>
</pre>
Part of the author's answer here https://stackoverflow.com/a/16002159/624466, is the answer to your question too.
[..] this code is neither released by Google nor makes use of an official
API, but is rather a custom script processing data from the web
interface.
[..] there were some changes to the Google Webmaster Tools web
interface [..]. Thus,
it broke some functionality of the PHP class GWTdata
I have written a class (so I could learn how OAuth works). It is working fine; I can retrieve the access token with the class. But when I try to post an update, it says that I'm not authenticated! What am I doing wrong here?
// By Kevin Jacobs
class OAuth {
private $url = null;
private $debug = false;
private $method = 'POST';
private $oauthData = array();
private $data = array();
private $token = array('key' => '', 'secret' => '');
private $consumer = array('key' => '', 'secret' => '');
/**
* Encode a string in such a way you can use it for OAuth.
* #param string $oauthData Data to encode
* #return string $encData Encoded data
*/
public static function encode($oauthData) {
if (is_string($oauthData)) {
return str_ireplace(
array('+', '%7E'),
array(' ', '~'),
rawurlencode($oauthData)
);
} else {
return '';
}
}
/**
* Generates a relative unique random string of a certain length.
* #param int $length Length of the string
* #return string $strRand A random string
*/
public static function generateString($length = 40) {
// Only strong cryptographic strings are allowed
while (!isset($bStrong) || $bStrong === false) {
$bytes = openssl_random_pseudo_bytes(floor($length / 2), $bStrong);
}
$strRand = bin2hex($bytes);
return sha1($strRand);
}
/**
* Generate a token pair (key and secret).
* #return array $tokenPair
*/
public static function generateTokenPair() {
$tokenPair = array();
$tokenPair['key'] = self::generateString();
$tokenPair['secret'] = self::generateString();
return $tokenPair;
}
/**
* Set the callback URL.
* #param string $callbackURL
*/
public function setCallback($callback = null) {
if ($callback === null) {
$callback = 'http';
if ($_SERVER['SERVER_PORT'] == 443) $callback .= 's';
$callback .= '://' . $_SERVER['SERVER_NAME'];
if ($_SERVER['SERVER_PORT'] != 80 && $_SERVER['SERVER_PORT'] != 443) {
$callback .= ':' . $_SERVER['SERVER_PORT'];
}
$callback .= $_SERVER['REQUEST_URI'];
}
$this->oauthData['oauth_callback'] = $callback;
}
/**
* Get the callback URL.
* #return string $callbackURL
*/
public function getCallback() {
return $this->oauthData['oauth_callback'];
}
/**
* Generate the nonce.
* #return string $nonce
*/
public function setNonce() {
$this->oauthData['oauth_nonce'] = md5(self::generateString(20) . mktime());
return $this->oauthData['oauth_nonce'];
}
/**
* Set the timestamp.
* #return int $timestamp
*/
public function setTimestamp() {
$this->oauthData['oauth_timestamp'] = mktime();
return $this->oauthData['oauth_timestamp'];
}
/**
* Set the OAuth version.
* #param string Version
*/
public function setVersion($version = '1.0') {
$this->oauthData['oauth_version'] = $version;
}
/**
* Set the HTTP method.
* #param string Method
*/
public function setMethod($method = 'POST') {
$this->method = trim(strtoupper($method));
}
/**
* Get the HTTP method.
* #return string Method
*/
public function getMethod() {
return $this->method;
}
/**
* Get the URL to call.
* #return string URL
*/
public function getURL() {
return $this->url;
}
/**
* Set the URL to call.
* #param string URL
*/
public function setURL($URL) {
$this->url = $URL;
}
/**
* Get the token key and secret
* #return array $token Containing token key and secret
*/
public function getToken() {
return $this->token;
}
/**
* Set the token
* #param string $tokenKey Token key
* #param string $tokenSecret Token secret
*/
public function setToken($tokenKey, $tokenSecret = null) {
$this->token['key'] = $tokenKey;
$this->token['secret'] = $tokenSecret;
$this->oauthData['oauth_token'] = $tokenKey;
$this->oauthData['oauth_token_secret'] = $tokenSecret;
}
/**
* Get the consumer
* #return array $consumer Containing consumer key and secret
*/
public function getConsumer() {
return $this->consumer;
}
/**
* Set the consumer
* #param string $consumerKey Consumer key
* #param string $consumerSecret Consumer secret
*/
public function setConsumer($consumerKey, $consumerSecret) {
$this->oauthData['oauth_consumer_key'] = $consumerKey;
$this->consumer['key'] = $consumerKey;
$this->consumer['secret'] = $consumerSecret;
}
/**
* Generate the signature.
* #return array Signature properties
*/
public function setSignature() {
// Set the signature method
$this->oauthData['oauth_signature_method'] = 'HMAC-SHA1';
// First, sort the OAuth data
$oauthData = $this->oauthData;
ksort($oauthData);
// Now combine them in a string
$query = http_build_query($oauthData);
// Make it URL proof
$query = rawurlencode($query);
// Fetch the method and URL
$method = $this->getMethod();
$url = $this->getURL();
// Make the URL URL proof
$url = rawurlencode($url);
// Now bind everything together
$baseString = $method . '&' . $url . '&' . $query;
// Retrieve the key
$consumer = $this->getConsumer();
$token = $this->getToken();
$key = self::encode($consumer['secret']) . '&' . self::encode($token['secret']);
// Encrypt the base string
$signature = hash_hmac('SHA1', $baseString, $key, true);
// And make it URL proof using base64_encode
$signature = base64_encode($signature);
$this->oauthData['oauth_signature'] = $signature;
}
public function setVerifier($verifier) {
$this->oauthData['oauth_verifier'] = $verifier;
}
public function debugOn() {
$this->debug = true;
}
public function debugOff() {
$this->debug = false;
}
public function setData($data) {
$this->data = $data;
}
public function call($url) {
$method = $this->getMethod();
$this->setURL($url);
$this->setNonce();
$this->setTimestamp();
$this->setSignature();
$oauthData = $this->oauthData;
$data = $this->data;
$data = array_merge($data, $oauthData);
if ($method == 'GET') {
$url = explode('#', $url);
$url = reset($url);
if (strpos($url, '?') !== false) {
$binder = '&';
} else {
$binder = '?';
}
$url .= $binder . http_build_query($oauthData);
}
$ch = curl_init();
if (!empty($headers)) {
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
}
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
if ($method == 'POST') {
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $oauthData);
}
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_FAILONERROR, false);
curl_setopt($ch, CURLOPT_MAXREDIRS, 10);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_ENCODING, '');
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Expect:'));
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
}
$x = new OAuth();
$x->debugOn();
$x->setVersion('1.0');
$x->setConsumer('consumerToken', 'consumerSecret');
$x->setToken('accessToken', 'accessSecret');
$x->setMethod('POST');
$x->setData(array('status' => 'Hello World!'));
echo $x->call('http://api.twitter.com/1/statuses/update.json', true);
The following code is working (retrieving the access token):
$x = new OAuth();
$x->debugOn();
$x->setVersion('1.0');
$x->setConsumer('consumerToken', 'consumerSecret');
$x->setToken('accessToken', 'accessSecret');
$x->setMethod('POST');
if (isset($_GET['oauth_verifier']) && isset($_GET['oauth_token'])) {
// Request token -> Access token
$verifier = $_GET['oauth_verifier'];
$token = $_GET['oauth_token'];
$x->setVerifier($verifier);
$x->setToken($token);
$x->setMethod('GET');
$result = $x->call('https://api.twitter.com/oauth/access_token', true);
parse_str($result);
echo 'Access token: ' . $oauth_token . '<br />';
echo 'Access token secret: ' . $oauth_token_secret;
} else {
// Request token
$x->setCallback();
$x->setMethod('GET');
$result = $x->call('https://api.twitter.com/oauth/request_token');
parse_str($result);
header('Location: http://api.twitter.com/oauth/authorize?oauth_token=' . $oauth_token);
}
I'm kind of guessing here, but since you only speak of "retrieving the access token with the class", I suspect you aren't actually following through the entire Twitter OAuth authorization flow. The initial token you get back is just your starting point toward getting the real token you'll be able to use to post updates; you have to jump through a bunch of hoops.
If I'm mistaken and you have actually gone through those hoops, never mind. :)
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.