I hope someone can help me with this:
I have 2 php file to elaborate paypal IPN, paypalIPN.php and ipnlistener.php.
ipnlistener.php contains IpnListener class with many functions inside as follow:
class IpnListener
{
/**
* If true, the recommended cURL PHP library is used to send the post back
* to PayPal. If flase then fsockopen() is used. Default true.
*
* #var boolean
*/
public $use_curl = true;
/**
* If true, cURL will use the CURLOPT_FOLLOWLOCATION to follow any
* "Location: ..." headers in the response.
*
* #var boolean
*/
public $follow_location = false;
/**
* If true, the paypal sandbox URI www.sandbox.paypal.com is used for the
* post back. If false, the live URI www.paypal.com is used. Default false.
*
* #var boolean
*/
public $use_sandbox = true;
/**
* The amount of time, in seconds, to wait for the PayPal server to respond
* before timing out. Default 30 seconds.
*
* #var int
*/
public $timeout = 30;
/**
* If true, enable SSL certification validation when using cURL
*
* #var boolean
*/
public $verify_ssl = true;
private $_errors = array();
private $post_data;
private $rawPostData; // raw data from php://input
private $post_uri = '';
private $response_status = '';
private $response = '';
const PAYPAL_HOST = 'www.paypal.com';
const SANDBOX_HOST = 'www.sandbox.paypal.com';
/**
* Post Back Using cURL
*
* Sends the post back to PayPal using the cURL library. Called by
* the processIpn() method if the use_curl property is true. Throws an
* exception if the post fails. Populates the response, response_status,
* and post_uri properties on success.
*
* #todo add URL param so function is more dynamic
*
* #param string The post data as a URL encoded string
*/
protected function curlPost($encoded_data)
{
$uri = 'https://'.$this->getPaypalHost().'/cgi-bin/webscr';
$this->post_uri = $uri;
$ch = curl_init();
if ($this->verify_ssl) {
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_CAINFO, dirname(dirname(__FILE__)) . '/pp/cert/api_cert_chain.crt');
}
curl_setopt($ch, CURLOPT_URL, $uri);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $encoded_data);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, $this->follow_location);
curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeout);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, true);
$this->response = curl_exec($ch);
$this->response_status = strval(curl_getinfo($ch, CURLINFO_HTTP_CODE));
if ($this->response === false || $this->response_status == '0') {
$errno = curl_errno($ch);
$errstr = curl_error($ch);
throw new Exception("cURL error: [$errno] $errstr");
}
return $this->response;
}
/**
* Post Back Using fsockopen()
*
* Sends the post back to PayPal using the fsockopen() function. Called by
* the processIpn() method if the use_curl property is false. Throws an
* exception if the post fails. Populates the response, response_status,
* and post_uri properties on success.
*
* #todo add URL param so function is more dynamic
*
* #param string The post data as a URL encoded string
*/
protected function fsockPost($encoded_data)
{
$uri = 'ssl://'.$this->getPaypalHost();
$port = '443';
$this->post_uri = $uri.'/cgi-bin/webscr';
$fp = fsockopen($uri, $port, $errno, $errstr, $this->timeout);
if (!$fp) {
// fsockopen error
throw new Exception("fsockopen error: [$errno] $errstr");
}
$header = "POST /cgi-bin/webscr HTTP/1.1\r\n";
$header .= "Host: ".$this->getPaypalHost()."\r\n";
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
$header .= "Content-Length: ".strlen($encoded_data)."\r\n";
$header .= "Connection: Close\r\n\r\n";
fputs($fp, $header.$encoded_data."\r\n\r\n");
while(!feof($fp)) {
if (empty($this->response)) {
// extract HTTP status from first line
$this->response .= $status = fgets($fp, 1024);
$this->response_status = trim(substr($status, 9, 4));
} else {
$this->response .= fgets($fp, 1024);
}
}
fclose($fp);
return $this->response;
}
private function getPaypalHost()
{
return ($this->use_sandbox) ? self::SANDBOX_HOST : self::PAYPAL_HOST;
}
public function getErrors()
{
return $this->_errors;
}
private function addError($error)
{
$this->_errors[] .= $error;
}
public function getPostData()
{
return $this->post_data;
}
public function getRawPostData()
{
return $this->rawPostData;
}
/**
* Get POST URI
*
* Returns the URI that was used to send the post back to PayPal. This can
* be useful for troubleshooting connection problems. The default URI
* would be "ssl://www.sandbox.paypal.com:443/cgi-bin/webscr"
*
* #return string
*/
public function getPostUri()
{
return $this->post_uri;
}
/**
* Get Response
*
* Returns the entire response from PayPal as a string including all the
* HTTP headers.
*
* #return string
*/
public function getResponse()
{
return $this->response;
}
/**
* Get Response Status
*
* Returns the HTTP response status code from PayPal. This should be "200"
* if the post back was successful.
*
* #return string
*/
public function getResponseStatus()
{
return $this->response_status;
}
/**
* Get Text Report
*
* Returns a report of the IPN transaction in plain text format. This is
* useful in emails to order processors and system administrators. Override
* this method in your own class to customize the report.
*
* #return string
*/
public function getTextReport()
{
$r = '';
// date and POST url
for ($i=0; $i<80; $i++) { $r .= '-'; }
$r .= "\n[".date('m/d/Y g:i A').'] - '.$this->getPostUri();
if ($this->use_curl) {
$r .= " (curl)\n";
} else {
$r .= " (fsockopen)\n";
}
// HTTP Response
for ($i=0; $i<80; $i++) { $r .= '-'; }
$r .= "\n{$this->getResponse()}\n";
// POST vars
for ($i=0; $i<80; $i++) { $r .= '-'; }
$r .= "\n";
foreach ($this->post_data as $key => $value) {
$r .= str_pad($key, 25)."$value\n";
}
$r .= "\n\n";
return $r;
}
/**
* Process IPN
*
* Handles the IPN post back to PayPal and parsing the response. Call this
* method from your IPN listener script. Returns true if the response came
* back as "VERIFIED", false if the response came back "INVALID", and
* throws an exception if there is an error.
*
* #param array
*
* #return boolean
*/
public function processIpn($post_data=null)
{
try
{
$this->requirePostMethod(); // processIpn() should check itself if data is POST
// Read POST data
// reading posted data directly from $_POST causes serialization
// issues with array data in POST. Reading raw POST data from input stream instead.
if ($post_data === null) {
$raw_post_data = file_get_contents('php://input');
} else {
$raw_post_data = $post_data;
}
$this->rawPostData = $raw_post_data; // set raw post data for Class use
// if post_data is php input stream, make it an array.
if ( ! is_array($raw_post_data) ) {
$raw_post_array = explode('&', $raw_post_data);
$this->post_data = $raw_post_array; // use post array because it's same as $_POST
} else {
$this->post_data = $raw_post_data; // use post array because it's same as $_POST
}
$myPost = array();
if (isset($raw_post_array)) {
foreach ($raw_post_array as $keyval) {
$keyval = explode('=', $keyval);
if (count($keyval) == 2) {
$myPost[$keyval[0]] = urldecode($keyval[1]);
}
}
}
// read the post from PayPal system and add 'cmd'
$req = 'cmd=_notify-validate';
foreach ($myPost as $key => $value) {
if (function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc() == 1) {
$value = urlencode(stripslashes($value));
} else {
$value = urlencode($value);
}
$req .= "&$key=$value";
}
//XXX Debug log
$file = fopen('lastresponse.log', 'w');
fwrite($file, $req);
fclose($file);
file_put_contents('dati.log', print_r($myPost, true));
file_put_contents('dato.log', print_r("numero transazione: ".$myPost['txn_id'], true));
//mail("mail#gmail.com","test",print_r($myPost,true));
if ($this->use_curl) {
$res = $this->curlPost($req);
} else {
$res = $this->fsockPost($req);
}
if (strpos($res, '200') === false) {
throw new Exception("Invalid response status: " . $res);
}
// Split response headers and payload, a better way for strcmp
$tokens = explode("\r\n\r\n", trim($res));
$res = trim(end($tokens));
if (strpos ($res, "VERIFIED") !== false) {
return true;
} else if (strpos ($res, "INVALID") !== false) {
return false;
} else {
throw new Exception("Unexpected response from PayPal: " . $res);
}
} catch (Exception $e) {
$this->addError($e->getMessage());
return false;
}
return false;
}
/**
* Require Post Method
*
* Throws an exception and sets a HTTP 405 response header if the request
* method was not POST.
*/
public function requirePostMethod()
{
// require POST requests
if ($_SERVER['REQUEST_METHOD'] && $_SERVER['REQUEST_METHOD'] != 'POST') {
header('Allow: POST', true, 405);
throw new Exception("Invalid HTTP request method.");
}
}
}
thanks to this part:
file_put_contents('dati.log', print_r($myPost, true));
file_put_contents('dato.log', print_r("numero transazione: ".$myPost['txn_id'], true));
I'm able to save a log file with an array of all elements or just only one element of a PayPal transaction.
what I need to do is to print $myPost outside the IpnListener class.
How can I do it?
You could either return value from a method using
return $myPost;
or (better way) pass a buffering logger object as method parameter and then after method is finished, fetch and print all logger content. See example here:
https://github.com/symfony/console/blob/5.3/Output/BufferedOutput.php
You could go in the class, declare a $tempMyPost as public.
each time you iterate and add something to $myPost, also do $this->tempMyPost
for example if you have
$myPost[$keyval[0]] = urldecode($keyval[1]);
also do
$this->tempMyPost[$keyval[0]] = urldecode($keyval[1]);
then, go outside the object, below the place you instantiate it and do
print_r($object->tempMyPost);
where $object is the name of the variable that holds your object.
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 have a project that was written with vimeo-php-lib which has been deprecated, so I have changed it to the new php library. Which can be found at https://github.com/vimeo/vimeo.php
However, the old code has had caching enabled using the line below:
$api->enableCache(phpVimeo::CACHE_FILE, realpath(dirname(APPLICATION_PATH) . DIRECTORY_SEPARATOR .'data' .DIRECTORY_SEPARATOR. 'cache' .DIRECTORY_SEPARATOR. 'vimeo'), 3600);
How do I go about implementing it for the new API? It doesn't seem to be included in the examples.
I edited the current Vimeo.php library so that it will cache the results, it currently expires every 24 hours.
The _request function was modified, and two more functions were added.
const CACHE_FILE = 'file';
private $_cache_enabled = 'file';
private $_cache_dir = '';
/**
* Internal function to handle requests, both authenticated and by the upload function.
*
* #param string $url
* #param array $curl_opts
* #return array
*/
private function _request($url, $curl_opts = array())
{
// Returned cached value
if ($this->_cache_enabled && ($response = $this->_getCached($url))) {
return $response;
}
// Merge the options (custom options take precedence).
$curl_opts = $this->_curl_opts + $curl_opts + $this->CURL_DEFAULTS;
// Call the API.
$curl = curl_init($url);
curl_setopt_array($curl, $curl_opts);
$response = curl_exec($curl);
$curl_info = curl_getinfo($curl);
if (isset($curl_info['http_code']) && $curl_info['http_code'] === 0) {
$curl_error = curl_error($curl);
$curl_error = !empty($curl_error) ? '[' . $curl_error .']' : '';
throw new VimeoRequestException('Unable to complete request.' . $curl_error);
}
curl_close($curl);
// Retrieve the info
$header_size = $curl_info['header_size'];
$headers = substr($response, 0, $header_size);
$body = substr($response, $header_size);
$final_response = array(
'body' => $body,
'status' => $curl_info['http_code'],
'headers' => self::parse_headers($headers)
);
if ($this->_cache_enabled) {
$this->_cache($url, $final_response);
}
// Return it raw.
return $final_response;
}
/**
* Cache a response.
*
* #param string $url The parameters for the response.
* #param string $response The serialized response data.
*/
private function _cache($url, $response)
{
$hash = md5(serialize($url));
$response = json_encode($response);
if ($this->_cache_enabled == self::CACHE_FILE) {
$file = $this->_cache_dir.'/'.$hash.'.cache';
if (file_exists($file)) {
unlink($file);
}
return file_put_contents($file, $response);
}
}
/**
* Get the unserialized contents of the cached request.
*
* #param array $url The full list of api parameters for the request.
*/
private function _getCached($url)
{
$hash = md5(serialize($url));
$expire = 86400;
if ($this->_cache_enabled == self::CACHE_FILE) {
$file = $this->_cache_dir.'/'.$hash.'.cache';
if (file_exists($file)) {
$last_modified = filemtime($file);
if (substr($file, -6) == '.cache' && ($last_modified + $expire) < time()) {
unlink($file);
}
}
if (file_exists($file)) {
return json_decode(file_get_contents($file), true);
}
}
}
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. :)