I have recently received a Facebook developer notification:
Graph API v2.1 Upgrade Notice
foobarapplication has been making recent API calls to Graph API v2.0,
which will reach the end of the 2-year deprecation window on Monday,
August 8, 2016. Please migrate all calls to v2.1 or higher in order to
avoid potential broken experiences.
We recommend using our new Graph API Upgrade Tool to see which of your
calls are affected by this change as well as any replacement calls in
newer versions. You can also use our changelog to see the full list of
changes.
A year ago I have upgraded Facebook for the given PHP application, by extracting the PHP SDK and changing source-code usages. The login review was successful and there were no serious problems since then. However, the app needs to upgrade from Facebook API 2.0 soon. I have an idea as of how to achieve this, but am not sure whether I am correct. Let us consider the following functionalities:
FacebookRedirectLoginHelper class:
/**
* Stores CSRF state and returns a URL to which the user should be sent to
* in order to continue the login process with Facebook. The
* provided redirectUrl should invoke the handleRedirect method.
*
* #param array $scope List of permissions to request during login
* #param string $version Optional Graph API version if not default (v2.0)
* #param boolean $displayAsPopup Indicate if the page will be displayed as a popup
*
* #return string
*/
public function getLoginUrl($scope = array(), $version = null, $displayAsPopup = false)
{
$version = ($version ?: FacebookRequest::GRAPH_API_VERSION);
$this->state = $this->random(16);
$this->storeState($this->state);
$params = array(
'client_id' => $this->appId,
'redirect_uri' => $this->redirectUrl,
'state' => $this->state,
'sdk' => 'php-sdk-' . FacebookRequest::VERSION,
'scope' => implode(',', $scope)
);
if ($displayAsPopup)
{
$params['display'] = 'popup';
}
return 'https://www.facebook.com/' . $version . '/dialog/oauth?' .
http_build_query($params, null, '&');
}
/**
* Returns a URL to which the user should be sent to re-request permissions.
*
* #param array $scope List of permissions to re-request
* #param string $version Optional Graph API version if not default (v2.0)
*
* #return string
*/
public function getReRequestUrl($scope = array(), $version = null)
{
$version = ($version ?: FacebookRequest::GRAPH_API_VERSION);
$this->state = $this->random(16);
$this->storeState($this->state);
$params = array(
'client_id' => $this->appId,
'redirect_uri' => $this->redirectUrl,
'state' => $this->state,
'sdk' => 'php-sdk-' . FacebookRequest::VERSION,
'auth_type' => 'rerequest',
'scope' => implode(',', $scope)
);
return 'https://www.facebook.com/' . $version . '/dialog/oauth?' .
http_build_query($params, null, '&');
}
FacebookRequest class:
/**
* FacebookRequest - Returns a new request using the given session. optional
* parameters hash will be sent with the request. This object is
* immutable.
*
* #param FacebookSession $session
* #param string $method
* #param string $path
* #param array|null $parameters
* #param string|null $version
* #param string|null $etag
*/
public function __construct(
FacebookSession $session, $method, $path, $parameters = null, $version = null, $etag = null
)
{
$this->session = $session;
$this->method = $method;
$this->path = $path;
if ($version) {
$this->version = $version;
} else {
$this->version = static::GRAPH_API_VERSION;
}
$this->etag = $etag;
$params = ($parameters ?: array());
if ($session
&& !isset($params["access_token"])) {
$params["access_token"] = $session->getToken();
}
if (FacebookSession::useAppSecretProof()
&& !isset($params["appsecret_proof"])) {
$params["appsecret_proof"] = $this->getAppSecretProof(
$params["access_token"]
);
}
$this->params = $params;
}
FacebookCurlHttpClient class:
/**
* Detect versions of Curl which report incorrect header lengths when
* using Proxies.
*
* #return boolean
*/
private static function needsCurlProxyFix()
{
$ver = self::$facebookCurl->version();
$version = $ver['version_number'];
return $version < self::CURL_PROXY_QUIRK_VER;
}
My idea is as follows:
getLoginUrl is called from the application; a version of 2.6. should be specified from now on
I do not really use getReRequestUrl, so I will not make changes in the code for it
FacebookRequest will be instantiated with a $version of 2.6
needsCurlProxyFix will be left as it is
Basically, I will use the PHP lib released in 2014, but with specifying $version at calls. Is my approach feasible, or should I use a new client-side library?
As things turned out, my version was up to date and I did not need to do any changes for Facebook's upgrade to version 2.1. except changing the version name used.
Related
I have tried using oAuth2 to use the google cloud platform api, but my redirect url(get_oauth_token.php in PHPMailer is the file I used) couldn't find composer's autoload file : vendor/autoload.php, even though I have composer and guzzle downloaded and running. Are there any other files that I should download or another way to autoload that file?
Here's get_oauth_token.php in case you haven't seen it(didn't post client id on here)
<?php
/**
* Get an OAuth2 token from Google.
* * Install this script on your server so that it's accessible
* as [https/http]://<yourdomain>/<folder>/get_oauth_token.php
* e.g.: http://localhost/phpmail/get_oauth_token.php
* * Ensure dependencies are installed with 'composer install'
* * Set up an app in your Google developer console
* * Set the script address as the app's redirect URL
* If no refresh token is obtained when running this file, revoke access to your app
* using link: https://accounts.google.com/b/0/IssuedAuthSubTokens and run the script again.
* This script requires PHP 5.4 or later
* PHP Version 5.4
*/
namespace League\OAuth2\Client\Provider;
//composer require PHPMailer/PHPMailer;
require 'vendor/autoload.php';
//require_once(__DIR__.'/PHPMailer/PHPMailer-master/vendor/autoload.php');
use League\OAuth2\Client\Provider\Exception\IdentityProviderException;
use League\OAuth2\Client\Token\AccessToken;
use League\OAuth2\Client\Tool\BearerAuthorizationTrait;
use Psr\Http\Message\ResponseInterface;
session_start();
//If this automatic URL doesn't work, set it yourself manually
$redirectUri ='http://localhost:8080/phpmailer/get_oauth_token.php';
//$redirectUri = 'http://localhost/phpmailer/get_oauth_token.php';
//These details obtained are by setting up app in Google developer console.
$clientId = '';
$clientSecret = '';
class Google extends AbstractProvider
{
use BearerAuthorizationTrait;
const ACCESS_TOKEN_RESOURCE_OWNER_ID = 'id';
/**
* #var string If set, this will be sent to google as the "access_type" parameter.
* #link https://developers.google.com/accounts/docs/OAuth2WebServer#offline
*/
protected $accessType;
/**
* #var string If set, this will be sent to google as the "hd" parameter.
* #link https://developers.google.com/accounts/docs/OAuth2Login#hd-param
*/
protected $hostedDomain;
/**
* #var string If set, this will be sent to google as the "scope" parameter.
* #link https://developers.google.com/gmail/api/auth/scopes
*/
protected $scope;
public function getBaseAuthorizationUrl()
{
return 'https://accounts.google.com/o/oauth2/auth';
}
public function getBaseAccessTokenUrl(array $params)
{
return 'https://accounts.google.com/o/oauth2/token';
}
public function getResourceOwnerDetailsUrl(AccessToken $token)
{
return ' ';
}
protected function getAuthorizationParameters(array $options)
{
if (is_array($this->scope)) {
$separator = $this->getScopeSeparator();
$this->scope = implode($separator, $this->scope);
}
$params = array_merge(
parent::getAuthorizationParameters($options),
array_filter([
'hd' => $this->hostedDomain,
'access_type' => $this->accessType,
'scope' => $this->scope,
// if the user is logged in with more than one account ask which one to use for the login!
'authuser' => '-1'
])
);
return $params;
}
protected function getDefaultScopes()
{
return [
'email',
'openid',
'profile',
];
}
protected function getScopeSeparator()
{
return ' ';
}
protected function checkResponse(ResponseInterface $response, $data)
{
if (!empty($data['error'])) {
$code = 0;
$error = $data['error'];
if (is_array($error)) {
$code = $error['code'];
$error = $error['message'];
}
throw new IdentityProviderException($error, $code, $data);
}
}
protected function createResourceOwner(array $response, AccessToken $token)
{
return new GoogleUser($response);
}
}
//Set Redirect URI in Developer Console as [https/http]://<yourdomain>/<folder>/get_oauth_token.php
$provider = new Google(
array(
'clientId' => $clientId,
'clientSecret' => $clientSecret,
'redirectUri' => $redirectUri,
'scope' => array('https://mail.google.com/'),
'accessType' => 'offline'
)
);
if (!isset($_GET['code'])) {
// If we don't have an authorization code then get one
$authUrl = $provider->getAuthorizationUrl();
$_SESSION['oauth2state'] = $provider->getState();
header('Location: ' . $authUrl);
exit;
// Check given state against previously stored one to mitigate CSRF attack
} elseif (empty($_GET['state']) || ($_GET['state'] !== $_SESSION['oauth2state'])) {
unset($_SESSION['oauth2state']);
exit('Invalid state');
} else {
// Try to get an access token (using the authorization code grant)
$token = $provider->getAccessToken(
'authorization_code',
array(
'code' => $_GET['code']
)
);
// Use this to get a new access token if the old one expires
echo 'Refresh Token: ' . $token->getRefreshToken();
}
You might be forgeting the file path in this case.
Try require "/path/to/vendor/autoload.php";
I installed league/oauth2-client with composer and it created this line in composer.json
"league/oauth2-client": "2.2.0"
When I refreshed get_oauth_token.php page, this error still came out:
Fatal error: Class 'League\OAuth2\Client\Provider\AbstractProvider'
not found in C:\xampp\htdocs...\PHPMailer\get_oauth_token.php on
line 35
Here's get_oauth_token.php
<?php
/**
* Get an OAuth2 token from Google.
* * Install this script on your server so that it's accessible
* as [https/http]://<yourdomain>/<folder>/get_oauth_token.php
* e.g.: http://localhost/phpmail/get_oauth_token.php
* * Ensure dependencies are installed with 'composer install'
* * Set up an app in your Google developer console
* * Set the script address as the app's redirect URL
* If no refresh token is obtained when running this file, revoke access to your app
* using link: https://accounts.google.com/b/0/IssuedAuthSubTokens and run the script again.
* This script requires PHP 5.4 or later
* PHP Version 5.4
*/
namespace League\OAuth2\Client\Provider;
require './vendor/autoload.php';
use League\OAuth2\Client\Provider\Exception\IdentityProviderException;
use League\OAuth2\Client\Token\AccessToken;
use League\OAuth2\Client\Tool\BearerAuthorizationTrait;
use Psr\Http\Message\ResponseInterface;
session_start();
//If this automatic URL doesn't work, set it yourself manually
$redirectUri = isset($_SERVER['HTTPS']) ? 'https://' : 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'];
//$redirectUri = 'http://localhost/phpmailer/get_oauth_token.php';
//These details obtained are by setting up app in Google developer console.
$clientId = 'RANDOMCHARS-----duv1n2.apps.googleusercontent.com';
$clientSecret = 'RANDOMCHARS-----lGyjPcRtvP';
class Google extends AbstractProvider
{
use BearerAuthorizationTrait;
const ACCESS_TOKEN_RESOURCE_OWNER_ID = 'id';
/**
* #var string If set, this will be sent to google as the "access_type" parameter.
* #link https://developers.google.com/accounts/docs/OAuth2WebServer#offline
*/
protected $accessType;
/**
* #var string If set, this will be sent to google as the "hd" parameter.
* #link https://developers.google.com/accounts/docs/OAuth2Login#hd-param
*/
protected $hostedDomain;
/**
* #var string If set, this will be sent to google as the "scope" parameter.
* #link https://developers.google.com/gmail/api/auth/scopes
*/
protected $scope;
public function getBaseAuthorizationUrl()
{
return 'https://accounts.google.com/o/oauth2/auth';
}
public function getBaseAccessTokenUrl(array $params)
{
return 'https://accounts.google.com/o/oauth2/token';
}
public function getResourceOwnerDetailsUrl(AccessToken $token)
{
return ' ';
}
protected function getAuthorizationParameters(array $options)
{
if (is_array($this->scope)) {
$separator = $this->getScopeSeparator();
$this->scope = implode($separator, $this->scope);
}
$params = array_merge(
parent::getAuthorizationParameters($options),
array_filter([
'hd' => $this->hostedDomain,
'access_type' => $this->accessType,
'scope' => $this->scope,
// if the user is logged in with more than one account ask which one to use for the login!
'authuser' => '-1'
])
);
return $params;
}
protected function getDefaultScopes()
{
return [
'email',
'openid',
'profile',
];
}
protected function getScopeSeparator()
{
return ' ';
}
protected function checkResponse(ResponseInterface $response, $data)
{
if (!empty($data['error'])) {
$code = 0;
$error = $data['error'];
if (is_array($error)) {
$code = $error['code'];
$error = $error['message'];
}
throw new IdentityProviderException($error, $code, $data);
}
}
protected function createResourceOwner(array $response, AccessToken $token)
{
return new GoogleUser($response);
}
}
//Set Redirect URI in Developer Console as [https/http]://<yourdomain>/<folder>/get_oauth_token.php
$provider = new Google(
array(
'myClientId' => $clientId, //already inserted
'myClientSecret' => $clientSecret, //already inserted
'myRedirectUri' => $redirectUri, //already inserted
'scope' => array('https://mail.google.com/'),
'accessType' => 'offline'
)
);
if (!isset($_GET['code'])) {
// If we don't have an authorization code then get one
$authUrl = $provider->getAuthorizationUrl();
$_SESSION['oauth2state'] = $provider->getState();
header('Location: ' . $authUrl);
exit;
// Check given state against previously stored one to mitigate CSRF attack
} elseif (empty($_GET['state']) || ($_GET['state'] !== $_SESSION['oauth2state'])) {
unset($_SESSION['oauth2state']);
exit('Invalid state');
} else {
// Try to get an access token (using the authorization code grant)
$token = $provider->getAccessToken(
'authorization_code',
array(
'code' => $_GET['code']
)
);
// Use this to get a new access token if the old one expires
echo 'Refresh Token: ' . $token->getRefreshToken();
}
Can you explain me in detail what to do after having installed league/oauth2-client through composer require league/oauth2-client?
Thank you.
Had a similar issue and discovered its not stated explicitly in the official tutorial here.
The library league/oauth2-client requires you to install the provider you need seperately as there are multiple providers both official and third party here.
For google provider you would need
composer require league/oauth2-google
And refer to it like this
use League\OAuth2\Client\Provider\Google;
So after reading the documentation of youtube api I have successfully make an oauth connection for youtube account on my server side app but I failed to find a solution on how to get channel views by using this data I obtained.
So my code looks like this (the PHP part):
class YouTube {
protected $token;
protected $params = [];
/**
* YouTube constructor.
*
* #param null $id
*/
public function __construct($id = null)
{
if ($id) {
$this->token = $this->getToken($id);
}
}
/**
* Get api authorization
*
* #return string
*/
public function getAuthorizationUrl()
{
// Make redirect
$this->params = [
'client_id' => '########',
'redirect_uri' => '######',
'scope' => 'https://gdata.youtube.com&',
'response_type'=> 'code&',
'access_type' => 'offline'
];
$redirect_url = 'https://accounts.google.com/o/oauth2/auth?' . http_build_query($this->params);
return $redirect_url;
}
/**
* Get API token and save account list to db
*
* #param $code
*
* #return \App\Models\DynamicDashboard\ThirdPartyAccounts
*/
public function getCallbackUrl($code)
{
// Grab the returned code and extract the access token.
$this->params = [
'code' => $code,
'client_id' => '####',
'client_secret' => '#####',
'redirect_uri' => '#######',
'grant_type' => 'authorization_code'
];
// Get access token
$command = 'curl --data "' . http_build_query($this->params) . '" https://accounts.google.com/o/oauth2/token';
exec($command, $resultToken);
$resultToken = json_decode($resultToken[0]);
// Do a request using the access token to get the list of accounts.
$command = 'curl -H "Authorization: Bearer ' . $resultToken->access_token . '" https://accounts.google.com/o/oauth2.json';
exec($command, $result);
$result = json_decode($result[0]);
// Save data to db
$account = new ThirdPartyAccounts();
$account->account_id = $result->identity->id;
$account->type = 'youtube';
$account->name = $result->identity->first_name . ' ' . $result->identity->last_name;
$account->extra_details = json_encode([
'access_token' => $resultToken->access_token,
'token_type' => $resultToken->token_type,
'expires_in' => $resultToken->expires_in,
'refresh_token' => $resultToken->refresh_token
]);
$account->save();
return $account;
}
/**
* Get API token
*
* #param $id
*
* #return mixed
*/
private function getToken($id)
{
$mainAccount = ThirdPartyAccounts::find($id);
$youtubeToken = json_decode($mainAccount->extra_details);
return $youtubeToken;
}
}
But I don't know how to make use of this data, I don't know how to write the method required to get the channel views for the last 30 days (with data for every day).
Sorry but I really don't know enough about api connection in order to understand what to do so if you would be so kind as to explain to me what to do any help would be welcomed. Thank you all in advance for your time!
You can use the reports.query method to do this. It lets you retrieve many different Analytics reports. Each request uses query parameters to specify a channel ID or content owner, a start date, an end date, and at least one metric. You can also provide additional query parameters, such as dimensions, filters, or sorting instructions.
There's an example in the link provided to retrieve last 30 days but it's written in App Script:
var analyticsResponse = YouTubeAnalytics.Reports.query(
'channel==' + channelId,
oneMonthAgoFormatted,
todayFormatted,
'views,likes,dislikes,shares',
{
dimensions: 'day',
sort: '-day'
});
To do this in PHP, I suggest looking at the Youtube PHP code samples. It is rife with guide and instructions.
I am trying to implement a PHP API to bitstamp to do a re-occurring transaction by placing the PHP code in the crontab.
I am trying to cause the API to communicate with bitstamp to buy X amount of BTC per execution (and then control the frequency from the crontab), this should be the very definition of the basic implementation.
Here is the joy, I am absolutely not a PHP coder. The guys at BX Media were nice enough to post their PHP frame on github: (https://github.com/willmoss/bitstamp-php-api).
However, the way I understand what they have done is that I must create the "parent" PHP to then include their API code which would also include my credentials
So I put together the most basic PHP code
<?php
require('bitstamp.php');
$KEY = 'XXXXXXXXXXXXXXXX';
$SECRET = 'XXXXXXXXXXXXXXXX';
$CLIENT_ID = 'XXXXX';
$bs = new Bitstamp("KEY","SECRET","CLIENT_ID");
// print_r($bs->ticker());
$bs->buyBTC(0.01); // buy 0.01 bitcoins at ask price
//$bs->bitstamp_query("buy", array('amount'=>'0.05','price'=>'50'));
?>
note: that "bitstamp.php" is in the same directory and is what is presently on Github.
<?php
/**
* #package Bitstamp API
* #author https://bxmediaus.com - BX MEDIA - PHP + Bitcoin. We are ready to work on your next bitcoin project. Only high quality coding. https://bxmediaus.com
* #version 0.1
* #access public
* #license http://www.opensource.org/licenses/LGPL-3.0
*/
class Bitstamp
{
private $key;
private $secret;
private $client_id;
public $redeemd; // Redeemed code information
public $withdrew; // Withdrawal information
public $info; // Result from getInfo()
public $ticker; // Current ticker (getTicker())
public $eurusd; // Current eur/usd
/**
* Bitstamp::__construct()
* Sets required key and secret to allow the script to function
* #param Bitstamp API Key $key
* #param Bitstamp Secret $secret
* #return
*/
public function __construct($key, $secret, $client_id)
{
if (isset($secret) && isset($key) && isset($client_id))
{
$this->key = $key;
$this->secret = $secret;
$this->client_id = $client_id;
} else
die("NO KEY/SECRET/CLIENT ID");
}
/**
* Bitstamp::bitstamp_query()
*
* #param API Path $path
* #param POST Data $req
* #return Array containing data returned from the API path
*/
public function bitstamp_query($path, array $req = array())
{
// API settings
$key = $this->key;
// generate a nonce as microtime, with as-string handling to avoid problems with 32bits systems
$mt = explode(' ', microtime());
$req['nonce'] = $mt[1] . substr($mt[0], 2, 6);
$req['key'] = $key;
$req['signature'] = $this->get_signature($req['nonce']);
// generate the POST data string
$post_data = http_build_query($req, '', '&');
// any extra headers
$headers = array();
// our curl handle (initialize if required)
static $ch = null;
if (is_null($ch))
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERAGENT,
'Mozilla/4.0 (compatible; MtGox PHP client; ' . php_uname('s') . '; PHP/' .
phpversion() . ')');
}
curl_setopt($ch, CURLOPT_URL, 'https://www.bitstamp.net/api/' . $path .'/');
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
// run the query
$res = curl_exec($ch);
if ($res === false)
throw new \Exception('Could not get reply: ' . curl_error($ch));
$dec = json_decode($res, true);
if (!$dec)
throw new \Exception('Invalid data received, please make sure connection is working and requested API exists');
return $dec;
}
/**
* Bitstamp::ticker()
* Returns current ticker from Bitstamp
* #return $ticker
*/
function ticker() {
$ticker = $this->bitstamp_query('ticker');
$this->ticker = $ticker; // Another variable to contain it.
return $ticker;
}
/**
* Bitstamp::eurusd()
* Returns current EUR/USD rate from Bitstamp
* #return $ticker
*/
function eurusd() {
$eurusd = $this->bitstamp_query('eur_usd');
$this->eurusd = $eurusd; // Another variable to contain it.
return $eurusd;
}
/**
* Bitstamp::buyBTC()
*
* #param float $amount
*/
function buyBTC($amount){
if (!isset($ticker))
$this->ticker();
$ticker = $this->ticker;
return $this->bitstamp_query('buy', array('amount' => $amount, 'price' => $ticker['ask']));
}
/**
* Bitstamp::sellBTC()
*
* #param float $amount
* #param float $price
* #param string $currency
*/
function sellBTC($amount){
if (!isset($ticker))
$this->ticker();
$ticker = $this->ticker;
return $this->bitstamp_query('sell', array('amount' => $amount, 'price' => $ticker['bid']));
}
/**
* Bitstamp::get_signature()
* Compute bitstamp signature
* #param float $nonce
*/
private function get_signature($nonce)
{
$message = $nonce.$this->client_id.$this->key;
return strtoupper(hash_hmac('sha256', $message, $this->secret));
}
}
I am getting a failure on the execution. As the author of the Bitstamp API has it apparently working with his clients, I assume the error is on my "parent" PHP code. (Note: I am using the real key and secret on my local version).
Anyone have any experience with this API or in general or suggestions?
I'm not sure if this is just anonymization or the actual code, so let me know if I have this wrong, but you have this line:
$bs = new Bitstamp("KEY","SECRET","CLIENT_ID");
This passes the actual strings "KEY", "SECRET", and "CLIENT_ID" to the function; what you want to do is pass the variables you defined on the lines above, like this:
$bs = new Bitstamp($KEY,$SECRET,$CLIENT_ID);
As the author of this api (I am CEO of Bx Media):
You need to remake the constructor like this:
$bs = new Bitstamp("put your key here","put your secret here","put your client ID here");
Ie. you actually put your key/secret/ID between the speech marks.
In PHP, when you put a $ sign, it sets something as a variable.
See more information here: http://www.w3schools.com/php/php_variables.asp
If you want to use variables, you can also use IMSoP's solution.
Please note, we also updated the library tonight with some new functions. So please update your repo to the latest commit to get the new code.
Cheers!
Is it possible to print to my log files the exact request from Facebook PHP SDK to the Facebook Graphs Server?
Can someone explain me how to modify the Facebook PHP Library https://github.com/facebook/php-sdk
I found:
/**
* Invoke the Graph API.
*
* #param String $path the path (required)
* #param String $method the http method (default 'GET')
* #param Array $params the query/post data
* #return the decoded response object
* #throws FacebookApiException
*/
protected function _graph($path, $method = 'GET', $params = array()) {
if (is_array($method) && empty($params)) {
$params = $method;
$method = 'GET';
}
$params['method'] = $method; // method override as we always do a POST
$result = json_decode($this->_oauthRequest(
$this->getUrl('graph', $path),
$params
), true);
// results are returned, errors are thrown
if (is_array($result) && isset($result['error'])) {
$this->throwAPIException($result);
}
return $result;
}
You should rather have a look at the makeRequest function where the actual http request takes place. Since I wouldn't play around in the api, you could also extend the class and override the method:
class FacebookLogger extends Facebook {
protected function makeRequest($url, $params, $ch=null) {
var_dump($url);
var_dump($params);
parent::makeRequest($url, $params, $ch);
}
}