I'm trying to create my first Magento 2 extension and integration and I've been following the guide in their docs here. All good so far, I've completed the auth handshake, stored all the required keys for api requests and can make requests back to my extension fine.
Looking at the OauthClient.php script provided at the foot of the tutorial, the url is hardcoded like so:
return new Uri('http://magento.host/oauth/token/request'); and the tutorial advises you to "Change the instances of http://magento.host in this example to a valid base URL."
<?php
use OAuth\Common\Consumer\Credentials;
use OAuth\Common\Http\Client\ClientInterface;
use OAuth\Common\Http\Exception\TokenResponseException;
use OAuth\Common\Http\Uri\Uri;
use OAuth\Common\Http\Uri\UriInterface;
use OAuth\Common\Storage\TokenStorageInterface;
use OAuth\OAuth1\Service\AbstractService;
use OAuth\OAuth1\Signature\SignatureInterface;
use OAuth\OAuth1\Token\StdOAuth1Token;
use OAuth\OAuth1\Token\TokenInterface;
class OauthClient extends AbstractService
{
/** #var string|null */
protected $_oauthVerifier = null;
public function __construct(
Credentials $credentials,
ClientInterface $httpClient = null,
TokenStorageInterface $storage = null,
SignatureInterface $signature = null,
UriInterface $baseApiUri = null
) {
if (!isset($httpClient)) {
$httpClient = new \OAuth\Common\Http\Client\StreamClient();
}
if (!isset($storage)) {
$storage = new \OAuth\Common\Storage\Session();
}
if (!isset($signature)) {
$signature = new \OAuth\OAuth1\Signature\Signature($credentials);
}
parent::__construct($credentials, $httpClient, $storage, $signature, $baseApiUri);
}
/**
* #return UriInterface
*/
public function getRequestTokenEndpoint()
{
return new Uri('http://magento.host/oauth/token/request');
}
/**
* Returns the authorization API endpoint.
*
* #throws \OAuth\Common\Exception\Exception
*/
public function getAuthorizationEndpoint()
{
throw new \OAuth\Common\Exception\Exception(
'Magento REST API is 2-legged. Current operation is not available.'
);
}
/**
* Returns the access token API endpoint.
*
* #return UriInterface
*/
public function getAccessTokenEndpoint()
{
return new Uri('http://magento.host/oauth/token/access');
}
/**
* Parses the access token response and returns a TokenInterface.
*
* #param string $responseBody
* #return TokenInterface
*/
protected function parseAccessTokenResponse($responseBody)
{
return $this->_parseToken($responseBody);
}
/**
* Parses the request token response and returns a TokenInterface.
*
* #param string $responseBody
* #return TokenInterface
* #throws TokenResponseException
*/
protected function parseRequestTokenResponse($responseBody)
{
$data = $this->_parseResponseBody($responseBody);
if (isset($data['oauth_verifier'])) {
$this->_oauthVerifier = $data['oauth_verifier'];
}
return $this->_parseToken($responseBody);
}
/**
* Parse response body and create oAuth token object based on parameters provided.
*
* #param string $responseBody
* #return StdOAuth1Token
* #throws TokenResponseException
*/
protected function _parseToken($responseBody)
{
$data = $this->_parseResponseBody($responseBody);
$token = new StdOAuth1Token();
$token->setRequestToken($data['oauth_token']);
$token->setRequestTokenSecret($data['oauth_token_secret']);
$token->setAccessToken($data['oauth_token']);
$token->setAccessTokenSecret($data['oauth_token_secret']);
$token->setEndOfLife(StdOAuth1Token::EOL_NEVER_EXPIRES);
unset($data['oauth_token'], $data['oauth_token_secret']);
$token->setExtraParams($data);
return $token;
}
/**
* Parse response body and return data in array.
*
* #param string $responseBody
* #return array
* #throws \OAuth\Common\Http\Exception\TokenResponseException
*/
protected function _parseResponseBody($responseBody)
{
if (!is_string($responseBody)) {
throw new TokenResponseException("Response body is expected to be a string.");
}
parse_str($responseBody, $data);
if (null === $data || !is_array($data)) {
throw new TokenResponseException('Unable to parse response.');
} elseif (isset($data['error'])) {
throw new TokenResponseException("Error occurred: '{$data['error']}'");
}
return $data;
}
/**
* #override to fix since parent implementation from lib not sending the oauth_verifier when requesting access token
* Builds the authorization header for an authenticated API request
*
* #param string $method
* #param UriInterface $uri the uri the request is headed
* #param \OAuth\OAuth1\Token\TokenInterface $token
* #param $bodyParams array
* #return string
*/
protected function buildAuthorizationHeaderForAPIRequest(
$method,
UriInterface $uri,
TokenInterface $token,
$bodyParams = null
) {
$this->signature->setTokenSecret($token->getAccessTokenSecret());
$parameters = $this->getBasicAuthorizationHeaderInfo();
if (isset($parameters['oauth_callback'])) {
unset($parameters['oauth_callback']);
}
$parameters = array_merge($parameters, ['oauth_token' => $token->getAccessToken()]);
$parameters = array_merge($parameters, $bodyParams);
$parameters['oauth_signature'] = $this->signature->getSignature($uri, $parameters, $method);
$authorizationHeader = 'OAuth ';
$delimiter = '';
foreach ($parameters as $key => $value) {
$authorizationHeader .= $delimiter . rawurlencode($key) . '="' . rawurlencode($value) . '"';
$delimiter = ', ';
}
return $authorizationHeader;
}
}
My Question is how do I pass the url from the store that the integration has been set up on back as a variable in here?(I have it stored in my db)
Thanks for taking the time to take a look.
For anyone who might come across this in future after getting the saved data from the table in my db, I added the Url into the call to make the new class on the checklogin.php script in the documentation:
$oAuthClient = new OauthClient($credentials,$magentoBaseUrl);
And then in OauthClient.php, I added the url to the construct and updated the getRequestTokenEndpoint method and the getAcessTokenEndpoint:
public function __construct(
Credentials $credentials,
$magentoBaseUrl = null,
ClientInterface $httpClient = null,
TokenStorageInterface $storage = null,
SignatureInterface $signature = null,
UriInterface $baseApiUri = null
) {
if (!isset($httpClient)) {
$httpClient = new \OAuth\Common\Http\Client\CurlClient();
}
if (!isset($storage)) {
$storage = new \OAuth\Common\Storage\Session();
}
if (!isset($signature)) {
$signature = new \OAuth\OAuth1\Signature\Signature($credentials);
}
if (!isset($magentoBaseUrl)) {
die();
}
$this->magentoBaseUrl = $magentoBaseUrl;
parent::__construct($credentials, $httpClient, $storage, $signature, $baseApiUri);
}
...
/**
* #return UriInterface
*/
public function getRequestTokenEndpoint()
{
return new Uri($this->magentoBaseUrl.'/oauth/token/request');
}
...
/**
* Returns the access token API endpoint.
*
* #return UriInterface
*/
public function getAccessTokenEndpoint()
{
return new Uri($this->magentoBaseUrl.'/oauth/token/access');
}
Related
I have implemented an Mautic API in a website. I use OAuth 2.0 to authenticate the communications between the two. The problem that I have is that I must renew the token from time to time, and in order to do that I have to provide a callback URL, I figured that I just have to use http://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI] as my callback URL, that way, when the authentication or renew is done the user would be redirected to the last called URL. The problem is that sometimes the user is being redirected to the login page of the API to authorize the integration. That, to the best of my knowledge, should be done by me, only once.
In short, how can I avoid my users being shown the API authentication screen?
I haven't finished the integration yet; I still must work on some security issues.
The class responsible for doing that is right below:
<?php
use Mautic\Auth\ApiAuth;
use Mautic\MauticApi;
class Mautic
{
private static $instance;
private $publicKey;
private $secretKey;
private $callback;
private $baseURL;
private $Api;
private $ApiURL;
private $auth;
private $token;
private $companyName;
public function __construct()
{
$config = $this->getConfig();
$this->publicKey = $config['publicKey'];
$this->secretKey = $config['secretKey'];
$this->baseURL = $config['baseURL'];
$this->companyName = $config['companyName'];
$this->Api = new MauticApi();
$this->ApiURL = $this->baseURL . '/api/';
if (!$this->isTokenValid()) {
$this->getToken();
}
}
/**
* Read the config file "mautic.json" located in the root directory and returns an array with config values
*
* #return array
*/
private function getConfig(): array
{
return $this->getJSON('mautic.json');
}
/**
* Instantiates a new API class
*
* #param string $apiName
* #return object
*/
private function setApi(string $apiName): object
{
if(!$this->auth){
$this->getToken();
}
return $this->Api->newApi($apiName, $this->auth, $this->ApiURL);
}
/**
* Retorna la instancia de la clase actual
*
* #return object
*/
public static function getInstance(): object
{
if (!self::$instance)
self::$instance = new self();
return self::$instance;
}
public function isTokenValid(): bool
{
$oldTokenExpiration = $this->checkForToken()['expires'];
if (time() >= $oldTokenExpiration) {
return false;
}
return true;
}
private function getToken($accessToken = null, $tokenExpiration = null, $refreshToken = null)
{
if ($previousToken = $this->checkForToken()) {
$settings['accessToken'] = $previousToken['access_token'];
$settings['accessTokenExpires'] = $previousToken['expires'];
$settings['refreshToken'] = $previousToken['refresh_token'];
}
$settings = [
'baseUrl' => $this->baseURL, // Base URL of the Mautic instance
'version' => 'OAuth2', // Version of the OAuth
'clientKey' => $this->publicKey, // Client/Consumer key from Mautic
'clientSecret' => $this->secretKey, // Client/Consumer secret key from Mautic
'callback' => "http://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]"
];
if (isset($accessToken) && isset($tokenExpiration) && isset($refreshToken)) {
}
$initAuth = new ApiAuth();
$auth = $initAuth->newAuth($settings);
// Initiate process for obtaining an access token; this will redirect the user to the authorize endpoint and/or set the tokens when the user is redirected back after granting authorization
if ($auth->validateAccessToken()) {
if ($auth->accessTokenUpdated()) {
$accessTokenData = $auth->getAccessTokenData();
$this->storeToken($accessTokenData);
$this->auth = $auth;
$this->token = $accessTokenData['access_token'];
return $this->auth;
}
}
}
private function storeToken($accessTokenData)
{
$tokenInfo = json_encode($accessTokenData);
file_put_contents("token.json", $tokenInfo);
}
/**
* Read the file "token.json" located in the root directory and returns an array with any passed token values
*
* #return array
*/
private function checkForToken(): array
{
return $this->getJSON('token.json');
}
/**
* Reads a JSON file and returns its key and values as an array
*
* #param string $filePath
* #return array
*/
private function getJSON($filePath): array
{
if (!file_exists($filePath)) {
return false;
}
$oldToken = file_get_contents($filePath);
$oldToken = json_decode($oldToken);
return (array) $oldToken;
}
/**
* Creates a new contact
*
* #param string $name
* #param string $phone
* #param string $email
* #param string $companyName
* #return array
*/
public function createContact(string $name, string $phone, string $email, int $companyName = null): array
{
if ($companyName == null) {
$companyName = $this->getConfig()['companyName'];
}
$data = array(
'firstname' => $name,
'phone' => $phone,
'email' => $email,
'company' => $companyName,
'ipAddress' => $_SERVER['REMOTE_ADDR'],
'overwriteWithBlank' => true,
);
$contactApi = $this->setApi('contacts');
$newContact = $contactApi->create($data);
return $newContact;
}
/**
* Retorna los datos de un contacto
*
* #param int $contactId
* #return object
*/
public function getContact(int $contactId): object
{
return json_decode($this->curlGET("contacts", array($contactId)));
}
/**
* Ejecuta una requisición GET al servidor de la API
*
* #param string $APIMethod
* #param array $dataToSend
* #return string
*/
private function curlGET(string $APIMethod, array $dataToSend = array()): string
{
$dataToSend["access_token"] = $this->token;
$baseURL = $this->ApiURL . $APIMethod;
$curl = curl_init();
$curlOptions = array(
CURLOPT_URL => $baseURL . '?' . http_build_query($dataToSend),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_SSL_VERIFYHOST => false,
CURLOPT_SSL_VERIFYPEER => false
);
curl_setopt_array($curl, $curlOptions);
$returnedData = curl_exec($curl);
if (!$returnedData) {
return curl_error($curl);
} else {
curl_close($curl);
return $returnedData;
}
}
}
The problem seems to be re-authentication. Once you authenticate successfully you should not need to do that again and again.
You get Token, Token Expires and Refresh Token when the process is complete. Here's complete example(https://tutorialsjoint.com/mautic-rest-api/).
Once you have the token and you are checking if token is expired, you should use refresh token to obtain fresh access token. For some reason if your refresh token becomes invalid then only you need to re-authenticate, that usually happens when you change the client credentials.
In your code I see you are doing authentication But can't see refresh token call, that should be your issue here.
I have a Question about calling a other script.
I want to make an api whit ExactOnline... But i need to call an other script for that I used "require DIR ." That works fine but my code still doesn't get the script. Can someone explane to me why this is not working?
(My script that need to call is in "C:\xampp\htdocs\CM\EO\exactphpclientmaster\vendor\picqer\exactphpclient\src\Picqer\Financials\Exact\Connection.php")
=ERROR=
Fatal error: Class 'vendor\picqer\exactphpclient\src\Picqer\Financials\Exact\Connection' not found in C:\xampp\htdocs\CM\EO\exactphpclientmaster\ConntectEO.php on line 3
=SCRIPT That is calling connection.php=
<?php
require __DIR__ . '\vendor\picqer\exactphpclient\src\Picqer\Financials\Exact\Connection.php';
$connection = new \vendor\picqer\exactphpclient\src\Picqer\Financials\Exact\Connection.php();
$connection->setRedirectUrl('**************************'); // Same as entered online in the App Center
$connection->setExactClientId('****************************************');
$connection->setExactClientSecret('************************');
if (getValue('authorizationcode')) // Retrieves authorizationcode from database
$connection->setAuthorizationCode(getValue('authorizationcode'));
if (getValue('accesstoken')) // Retrieves accesstoken from database
$connection->setAccessToken(unserialize(getValue('accesstoken')));
if (getValue('refreshtoken')) // Retrieves refreshtoken from database
$connection->setRefreshToken(getValue('refreshtoken'));
if (getValue('expires_in')) // Retrieves expires timestamp from database
$connection->setTokenExpires(getValue('expires_in'));
// Make the client connect and exchange tokens
try {
$connection->connect();
} catch (\Exception $e)
{
throw new Exception('Could not connect to Exact: ' . $e->getMessage());
}
// Save the new tokens for next connections
setValue('accesstoken', serialize($connection->getAccessToken()));
setValue('refreshtoken', $connection->getRefreshToken());
// Optionally, save the expiry-timestamp. This prevents exchanging valid tokens (ie. saves you some requests)
setValue('expires_in', $connection->getTokenExpires());
=SCRIPT Connection.php=
<?php namespace Picqer\Financials\Exact;
use Exception;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\BadResponseException;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Psr7\Response;
use GuzzleHttp\Psr7;
/**
* Class Connection
*
* #package Picqer\Financials\Exact
*
*/
class Connection
{
/**
* #var string
*/
private $baseUrl = 'https://start.exactonline.nl';
/**
* #var string
*/
private $apiUrl = '/api/v1';
/**
* #var string
*/
private $authUrl = '/api/oauth2/auth';
/**
* #var string
*/
private $tokenUrl = '/api/oauth2/token';
/**
* #var
*/
private $exactClientId;
/**
* #var
*/
private $exactClientSecret;
/**
* #var
*/
private $authorizationCode;
/**
* #var
*/
private $accessToken;
/**
* #var
*/
private $tokenExpires;
/**
* #var
*/
private $refreshToken;
/**
* #var
*/
private $redirectUrl;
/**
* #var
*/
private $division;
/**
* #var Client
*/
private $client;
/**
* #var callable(Connection)
*/
private $tokenUpdateCallback;
/**
*
*/
protected $middleWares = [];
/**
* #var
*/
public $nextUrl = null;
/**
* #return Client
*/
private function client()
{
if ($this->client) {
return $this->client;
}
$handlerStack = HandlerStack::create();
foreach ($this->middleWares as $middleWare) {
$handlerStack->push($middleWare);
}
$this->client = new Client([
'http_errors' => true,
'handler' => $handlerStack,
'expect' => false,
]);
return $this->client;
}
public function insertMiddleWare($middleWare)
{
$this->middleWares[] = $middleWare;
}
public function connect()
{
// Redirect for authorization if needed (no access token or refresh token given)
if ($this->needsAuthentication()) {
$this->redirectForAuthorization();
}
// If access token is not set or token has expired, acquire new token
if (empty($this->accessToken) || $this->tokenHasExpired()) {
$this->acquireAccessToken();
}
$client = $this->client();
return $client;
}
/**
* #param string $method
* #param $endpoint
* #param null $body
* #param array $params
* #param array $headers
* #return Request
*/
private function createRequest($method = 'GET', $endpoint, $body = null, array $params = [], array $headers = [])
{
// Add default json headers to the request
$headers = array_merge($headers, [
'Accept' => 'application/json',
'Content-Type' => 'application/json',
'Prefer' => 'return=representation'
]);
// If access token is not set or token has expired, acquire new token
if (empty($this->accessToken) || $this->tokenHasExpired()) {
$this->acquireAccessToken();
}
// If we have a token, sign the request
if (!$this->needsAuthentication() && !empty($this->accessToken)) {
$headers['Authorization'] = 'Bearer ' . $this->accessToken;
}
// Create param string
if (!empty($params)) {
$endpoint .= '?' . http_build_query($params);
}
// Create the request
$request = new Request($method, $endpoint, $headers, $body);
return $request;
}
/**
* #param $url
* #param array $params
* #return mixed
* #throws ApiException
*/
public function get($url, array $params = [])
{
$url = $this->formatUrl($url, $url !== 'current/Me', $url == $this->nextUrl);
try {
$request = $this->createRequest('GET', $url, null, $params);
$response = $this->client()->send($request);
return $this->parseResponse($response, $url != $this->nextUrl);
} catch (Exception $e) {
$this->parseExceptionForErrorMessages($e);
}
}
/**
* #param $url
* #param $body
* #return mixed
* #throws ApiException
*/
public function post($url, $body)
{
$url = $this->formatUrl($url);
try {
$request = $this->createRequest('POST', $url, $body);
$response = $this->client()->send($request);
return $this->parseResponse($response);
} catch (Exception $e) {
$this->parseExceptionForErrorMessages($e);
}
}
/**
* #param $url
* #param $body
* #return mixed
* #throws ApiException
*/
public function put($url, $body)
{
$url = $this->formatUrl($url);
try {
$request = $this->createRequest('PUT', $url, $body);
$response = $this->client()->send($request);
return $this->parseResponse($response);
} catch (Exception $e) {
$this->parseExceptionForErrorMessages($e);
}
}
/**
* #param $url
* #return mixed
* #throws ApiException
*/
public function delete($url)
{
$url = $this->formatUrl($url);
try {
$request = $this->createRequest('DELETE', $url);
$response = $this->client()->send($request);
return $this->parseResponse($response);
} catch (Exception $e) {
$this->parseExceptionForErrorMessages($e);
}
}
/**
* #return string
*/
public function getAuthUrl()
{
return $this->baseUrl . $this->authUrl . '?' . http_build_query(array(
'client_id' => $this->exactClientId,
'redirect_uri' => $this->redirectUrl,
'response_type' => 'code'
));
}
/**
* #param mixed $exactClientId
*/
public function setExactClientId($exactClientId)
{
$this->exactClientId = $exactClientId;
}
/**
* #param mixed $exactClientSecret
*/
public function setExactClientSecret($exactClientSecret)
{
$this->exactClientSecret = $exactClientSecret;
}
/**
* #param mixed $authorizationCode
*/
public function setAuthorizationCode($authorizationCode)
{
$this->authorizationCode = $authorizationCode;
}
/**
* #param mixed $accessToken
*/
public function setAccessToken($accessToken)
{
$this->accessToken = $accessToken;
}
/**
* #param mixed $refreshToken
*/
public function setRefreshToken($refreshToken)
{
$this->refreshToken = $refreshToken;
}
/**
*
*/
public function redirectForAuthorization()
{
$authUrl = $this->getAuthUrl();
header('Location: ' . $authUrl);
exit;
}
/**
* #param mixed $redirectUrl
*/
public function setRedirectUrl($redirectUrl)
{
$this->redirectUrl = $redirectUrl;
}
/**
* #return bool
*/
public function needsAuthentication()
{
return empty($this->refreshToken) && empty($this->authorizationCode);
}
/**
* #param Response $response
* #param bool $returnSingleIfPossible
* #return mixed
* #throws ApiException
*/
private function parseResponse(Response $response, $returnSingleIfPossible = true)
{
try {
if ($response->getStatusCode() === 204) {
return [];
}
Psr7\rewind_body($response);
$json = json_decode($response->getBody()->getContents(), true);
if (array_key_exists('d', $json)) {
if (array_key_exists('__next', $json['d'])) {
$this->nextUrl = $json['d']['__next'];
}
else {
$this->nextUrl = null;
}
if (array_key_exists('results', $json['d'])) {
if ($returnSingleIfPossible && count($json['d']['results']) == 1) {
return $json['d']['results'][0];
}
return $json['d']['results'];
}
return $json['d'];
}
return $json;
} catch (\RuntimeException $e) {
throw new ApiException($e->getMessage());
}
}
/**
* #return mixed
*/
private function getCurrentDivisionNumber()
{
if (empty($this->division)) {
$me = new Me($this);
$this->division = $me->find()->CurrentDivision;
}
return $this->division;
}
/**
* #return mixed
*/
public function getRefreshToken()
{
return $this->refreshToken;
}
/**
* #return mixed
*/
public function getAccessToken()
{
return $this->accessToken;
}
private function acquireAccessToken()
{
// If refresh token not yet acquired, do token request
if (empty($this->refreshToken)) {
$body = [
'form_params' => [
'redirect_uri' => $this->redirectUrl,
'grant_type' => 'authorization_code',
'client_id' => $this->exactClientId,
'client_secret' => $this->exactClientSecret,
'code' => $this->authorizationCode
]
];
} else { // else do refresh token request
$body = [
'form_params' => [
'refresh_token' => $this->refreshToken,
'grant_type' => 'refresh_token',
'client_id' => $this->exactClientId,
'client_secret' => $this->exactClientSecret,
]
];
}
$response = $this->client()->post($this->getTokenUrl(), $body);
if ($response->getStatusCode() == 200) {
Psr7\rewind_body($response);
$body = json_decode($response->getBody()->getContents(), true);
if (json_last_error() === JSON_ERROR_NONE) {
$this->accessToken = $body['access_token'];
$this->refreshToken = $body['refresh_token'];
$this->tokenExpires = $this->getDateTimeFromExpires($body['expires_in']);
if (is_callable($this->tokenUpdateCallback)) {
call_user_func($this->tokenUpdateCallback, $this);
}
} else {
throw new ApiException('Could not acquire tokens, json decode failed. Got response: ' . $response->getBody()->getContents());
}
} else {
throw new ApiException('Could not acquire or refresh tokens');
}
}
private function getDateTimeFromExpires($expires)
{
if (!is_numeric($expires)) {
throw new \InvalidArgumentException('Function requires a numeric expires value');
}
return time() + 600;
}
/**
* #return mixed
*/
public function getTokenExpires()
{
return $this->tokenExpires;
}
/**
* #param mixed $tokenExpires
*/
public function setTokenExpires($tokenExpires)
{
$this->tokenExpires = $tokenExpires;
}
private function tokenHasExpired()
{
if (empty($this->tokenExpires)) {
return true;
}
return $this->tokenExpires <= time() + 10;
}
private function formatUrl($endPoint, $includeDivision = true, $formatNextUrl = false)
{
if ($formatNextUrl) {
return $endPoint;
}
if ($includeDivision) {
return implode('/', [
$this->getApiUrl(),
$this->getCurrentDivisionNumber(),
$endPoint
]);
}
return implode('/', [
$this->getApiUrl(),
$endPoint
]);
}
/**
* #return mixed
*/
public function getDivision()
{
return $this->division;
}
/**
* #param mixed $division
*/
public function setDivision($division)
{
$this->division = $division;
}
/**
* #param callable $callback
*/
public function setTokenUpdateCallback($callback) {
$this->tokenUpdateCallback = $callback;
}
/**
* Parse the reponse in the Exception to return the Exact error messages
* #param Exception $e
* #throws ApiException
*/
private function parseExceptionForErrorMessages(Exception $e)
{
if (! $e instanceof BadResponseException) {
throw new ApiException($e->getMessage());
}
$response = $e->getResponse();
Psr7\rewind_body($response);
$responseBody = $response->getBody()->getContents();
$decodedResponseBody = json_decode($responseBody, true);
if (! is_null($decodedResponseBody) && isset($decodedResponseBody['error']['message']['value'])) {
$errorMessage = $decodedResponseBody['error']['message']['value'];
} else {
$errorMessage = $responseBody;
}
throw new ApiException('Error ' . $response->getStatusCode() .': ' . $errorMessage);
}
/**
* #return string
*/
protected function getBaseUrl()
{
return $this->baseUrl;
}
/**
* #return string
*/
private function getApiUrl()
{
return $this->baseUrl . $this->apiUrl;
}
/**
* #return string
*/
private function getTokenUrl()
{
return $this->baseUrl . $this->tokenUrl;
}
/**
* Set base URL for different countries according to
* https://developers.exactonline.com/#Exact%20Online%20sites.html
*
* #param string $baseUrl
*/
public function setBaseUrl($baseUrl)
{
$this->baseUrl = $baseUrl;
}
/**
* #param string $apiUrl
*/
public function setApiUrl($apiUrl)
{
$this->apiUrl = $apiUrl;
}
/**
* #param string $authUrl
*/
public function setAuthUrl($authUrl)
{
$this->authUrl = $authUrl;
}
/**
* #param string $tokenUrl
*/
public function setTokenUrl($tokenUrl)
{
$this->tokenUrl = $tokenUrl;
}
}
The error itself is pretty self-explanatory. You are trying to include a file and it cannot be found with the path you provided.
Try printing what the magic constant __DIR__ contains in order to see the full path you are trying to include.
You can use var_dump(__DIR__);exit; at the start of your script.
As an additional note, you should consider using composer's autoload.
As you mention your trying to load Connection class as below
require __DIR__ . '\vendor\picqer\exactphpclient\src\Picqer\Financials\Exact\Connection.php';
When we using composer, instead of loading individual class files try to use composer auto load, its automatically loads the name spaces of the required class.
If you implement auto load in your code, the code may look like this.
require __DIR__ . '/vendor/autoload.php';
use Picqer\Financials\Exact\Connection;
$connection = new Connection();
I have been trying to design a Signup Page using a tutorial in a Zend framework 2 Book .Problem is that I am unable to complete signup after running it as , clicking on register gives a socket error , which I have no clue.
Zend\Http\Client\Adapter\Exception\RuntimeException
File:
C:\xampp\htdocs\ZF2AD\Chapter10\client\vendor\zendframework\zend-http\src\Client\Adapter\Socket.php:256
Message:
Unable to connect to zf2-api:80 . Error #0: stream_socket_client():unable to connect to zf2-api:80 (php_network_getaddresses: getaddrinfo failed: No such host is known. )
I am using Api to connect to database.Below is the code for my Apiclient.php
<?php
namespace Api\Client;
use Zend\Http\Client;
use Zend\Http\Request;
use Zend\Json\Decoder as JsonDecoder;
use Zend\Json\Json;
use Zend\Log\Logger;
use Zend\Log\Writer\Stream;
/**
* This client manages all the operations needed to interface with the
* social network API
*
* #package default
*/
class ApiClient {
/**
* Holds the client we will reuse in this class
*
* #var Client
*/
protected static $client = null;
/**
* Holds the endpoint urls
*
* #var string
*/
protected static $endpointHost = 'http://zf2-api';
protected static $endpointWall = '/api/wall/%s';
protected static $endpointFeeds = '/api/feeds/%s';
protected static $endpointSpecificFeed = '/api/feeds/%s/%d';
protected static $endpointUsers = '/api/users';
protected static $endpointGetUser = '/api/users/%s';
protected static $endpointUserLogin = '/api/users/login';
/**
* Perform an API reqquest to retrieve the data of the wall
* of an specific user on the social network
*
* #param string $username
* #return Zend\Http\Response
*/
public static function getWall($username)
{
$url = self::$endpointHost . sprintf(self::$endpointWall, $username);
return self::doRequest($url);
}
/**
* Perform an API request to post content on the wall of an specific user
*
* #param string $username
* #param array $data
* #return Zend\Http\Response
*/
public static function postWallContent($username, $data)
{
$url = self::$endpointHost . sprintf(self::$endpointWall, $username);
return self::doRequest($url, $data, Request::METHOD_POST);
}
/**
* Perform an API request to get the list subscriptions of a username
*
* #param string $username
* #return Zend\Http\Response
*/
public static function getFeeds($username)
{
$url = self::$endpointHost . sprintf(self::$endpointFeeds, $username);
return self::doRequest($url);
}
/**
* Perform an API request to add a new subscription
*
* #param string $username
* #param array $postData
* #return Zend\Http\Response
*/
public static function addFeedSubscription($username, $postData)
{
$url = self::$endpointHost . sprintf(self::$endpointFeeds, $username);
return self::doRequest($url, $postData, Request::METHOD_POST);
}
/**
* Perform an API request to remove a subscription
*
* #param string $username
* #param array $postData
* #return Zend\Http\Response
*/
public static function removeFeedSubscription($username, $feedId)
{
$url = self::$endpointHost . sprintf(self::$endpointSpecificFeed, $username, $feedId);
return self::doRequest($url, null, Request::METHOD_DELETE);
}
/**
* Perform an API request to add a new user
*
* #param array $postData
* #return Zend\Http\Response
*/
public static function registerUser($postData)
{
$url = self::$endpointHost . self::$endpointUsers;
return self::doRequest($url, $postData, Request::METHOD_POST);
}
/**
* Perform an API request to get the basic data of a user
*
* #param string $username
* #return Zend\Http\Response
*/
public static function getUser($username)
{
$url = self::$endpointHost . sprintf(self::$endpointGetUser, $username);
return self::doRequest($url, null, Request::METHOD_GET);
}
/**
* Perform an API request to authenticate a user
*
* #param array $postData Array containing username and password on their respective keys
* #return Zend\Http\Response
*/
public static function authenticate($postData)
{
$url = self::$endpointHost . self::$endpointUserLogin;
return self::doRequest($url, $postData, Request::METHOD_POST);
}
/**
* Create a new instance of the Client if we don't have it or
* return the one we already have to reuse
*
* #return Client
*/
protected static function getClientInstance()
{
if (self::$client === null) {
self::$client = new Client();
self::$client->setEncType(Client::ENC_URLENCODED);
}
return self::$client;
}
/**
* Perform a request to the API
*
* #param string $url
* #param array $postData
* #param Client $client
* #return Zend\Http\Response
* #author Christopher
*/
protected static function doRequest($url, array $postData = null, $method = Request::METHOD_GET)
{
$client = self::getClientInstance();
$client->setUri($url);
$client->setMethod($method);
if ($postData !== null) {
$client->setParameterPost($postData);
}
$response = $client->send();
if ($response->isSuccess()) {
return JsonDecoder::decode($response->getBody(), Json::TYPE_ARRAY);
} else {
$logger = new Logger;
$logger->addWriter(new Stream('data/logs/apiclient.log'));
$logger->debug($response->getBody());
return FALSE;
}
}
}
Refining the error , I got to know that this is the main error in all errors
stream_socket_client(): php_network_getaddresses: getaddrinfo failed: No such host is known.
I have tried solutions provided in similar questions , but they didnt helped . If anyone knows about it please help.
The path of the libraries directory of my codeigniter project is like what shown in the image.
I tried to load Facebook.php class using these following codes, but both of them returned the same error : Unable to load the requested class: Facebook
$this->load->library('facebook/facebook', $fb_config);
or
$this->load->library('Facebook/Facebook', $fb_config);
This is so frustrating, the class Facebook.php is clearly there.
Why codeigniter is unable to load the classes under a subfolder of libraries ?
Meanwhile it works fine with the classes in libraries root (without subfolder).
This is what inside Facebook.php
<?php
/**
* Copyright 2014 Facebook, Inc.
*
* You are hereby granted a non-exclusive, worldwide, royalty-free license to
* use, copy, modify, and distribute this software in source code or binary
* form for use in connection with the web services and APIs provided by
* Facebook.
*
* As with any software that integrates with the Facebook platform, your use
* of this software is subject to the Facebook Developer Principles and
* Policies [http://developers.facebook.com/policy/]. This copyright notice
* shall be included in all copies or substantial portions of the software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
*/
namespace Facebook;
use Facebook\Authentication\AccessToken;
use Facebook\Authentication\OAuth2Client;
use Facebook\FileUpload\FacebookFile;
use Facebook\FileUpload\FacebookVideo;
use Facebook\GraphNodes\GraphEdge;
use Facebook\Url\UrlDetectionInterface;
use Facebook\Url\FacebookUrlDetectionHandler;
use Facebook\PseudoRandomString\PseudoRandomStringGeneratorInterface;
use Facebook\PseudoRandomString\McryptPseudoRandomStringGenerator;
use Facebook\PseudoRandomString\OpenSslPseudoRandomStringGenerator;
use Facebook\PseudoRandomString\UrandomPseudoRandomStringGenerator;
use Facebook\HttpClients\FacebookHttpClientInterface;
use Facebook\HttpClients\FacebookCurlHttpClient;
use Facebook\HttpClients\FacebookStreamHttpClient;
use Facebook\HttpClients\FacebookGuzzleHttpClient;
use Facebook\PersistentData\PersistentDataInterface;
use Facebook\PersistentData\FacebookSessionPersistentDataHandler;
use Facebook\PersistentData\FacebookMemoryPersistentDataHandler;
use Facebook\Helpers\FacebookCanvasHelper;
use Facebook\Helpers\FacebookJavaScriptHelper;
use Facebook\Helpers\FacebookPageTabHelper;
use Facebook\Helpers\FacebookRedirectLoginHelper;
use Facebook\Exceptions\FacebookSDKException;
/**
* Class Facebook
*
* #package Facebook
*/
class Facebook
{
/**
* #const string Version number of the Facebook PHP SDK.
*/
const VERSION = '5.0.0';
/**
* #const string Default Graph API version for requests.
*/
const DEFAULT_GRAPH_VERSION = 'v2.4';
/**
* #const string The name of the environment variable that contains the app ID.
*/
const APP_ID_ENV_NAME = 'FACEBOOK_APP_ID';
/**
* #const string The name of the environment variable that contains the app secret.
*/
const APP_SECRET_ENV_NAME = 'FACEBOOK_APP_SECRET';
/**
* #var FacebookApp The FacebookApp entity.
*/
protected $app;
/**
* #var FacebookClient The Facebook client service.
*/
protected $client;
/**
* #var OAuth2Client The OAuth 2.0 client service.
*/
protected $oAuth2Client;
/**
* #var UrlDetectionInterface|null The URL detection handler.
*/
protected $urlDetectionHandler;
/**
* #var PseudoRandomStringGeneratorInterface|null The cryptographically secure pseudo-random string generator.
*/
protected $pseudoRandomStringGenerator;
/**
* #var AccessToken|null The default access token to use with requests.
*/
protected $defaultAccessToken;
/**
* #var string|null The default Graph version we want to use.
*/
protected $defaultGraphVersion;
/**
* #var PersistentDataInterface|null The persistent data handler.
*/
protected $persistentDataHandler;
/**
* #var FacebookResponse|FacebookBatchResponse|null Stores the last request made to Graph.
*/
protected $lastResponse;
/**
* Instantiates a new Facebook super-class object.
*
* #param array $config
*
* #throws FacebookSDKException
*/
public function __construct(array $config = [])
{
$appId = isset($config['app_id']) ? $config['app_id'] : getenv(static::APP_ID_ENV_NAME);
if (!$appId) {
throw new FacebookSDKException('Required "app_id" key not supplied in config and could not find fallback environment variable "' . static::APP_ID_ENV_NAME . '"');
}
$appSecret = isset($config['app_secret']) ? $config['app_secret'] : getenv(static::APP_SECRET_ENV_NAME);
if (!$appSecret) {
throw new FacebookSDKException('Required "app_secret" key not supplied in config and could not find fallback environment variable "' . static::APP_SECRET_ENV_NAME . '"');
}
$this->app = new FacebookApp($appId, $appSecret);
$httpClientHandler = null;
if (isset($config['http_client_handler'])) {
if ($config['http_client_handler'] instanceof FacebookHttpClientInterface) {
$httpClientHandler = $config['http_client_handler'];
} elseif ($config['http_client_handler'] === 'curl') {
$httpClientHandler = new FacebookCurlHttpClient();
} elseif ($config['http_client_handler'] === 'stream') {
$httpClientHandler = new FacebookStreamHttpClient();
} elseif ($config['http_client_handler'] === 'guzzle') {
$httpClientHandler = new FacebookGuzzleHttpClient();
} else {
throw new \InvalidArgumentException('The http_client_handler must be set to "curl", "stream", "guzzle", or be an instance of Facebook\HttpClients\FacebookHttpClientInterface');
}
}
$enableBeta = isset($config['enable_beta_mode']) && $config['enable_beta_mode'] === true;
$this->client = new FacebookClient($httpClientHandler, $enableBeta);
if (isset($config['url_detection_handler'])) {
if ($config['url_detection_handler'] instanceof UrlDetectionInterface) {
$this->urlDetectionHandler = $config['url_detection_handler'];
} else {
throw new \InvalidArgumentException('The url_detection_handler must be an instance of Facebook\Url\UrlDetectionInterface');
}
}
if (isset($config['pseudo_random_string_generator'])) {
if ($config['pseudo_random_string_generator'] instanceof PseudoRandomStringGeneratorInterface) {
$this->pseudoRandomStringGenerator = $config['pseudo_random_string_generator'];
} elseif ($config['pseudo_random_string_generator'] === 'mcrypt') {
$this->pseudoRandomStringGenerator = new McryptPseudoRandomStringGenerator();
} elseif ($config['pseudo_random_string_generator'] === 'openssl') {
$this->pseudoRandomStringGenerator = new OpenSslPseudoRandomStringGenerator();
} elseif ($config['pseudo_random_string_generator'] === 'urandom') {
$this->pseudoRandomStringGenerator = new UrandomPseudoRandomStringGenerator();
} else {
throw new \InvalidArgumentException('The pseudo_random_string_generator must be set to "mcrypt", "openssl", or "urandom", or be an instance of Facebook\PseudoRandomString\PseudoRandomStringGeneratorInterface');
}
}
if (isset($config['persistent_data_handler'])) {
if ($config['persistent_data_handler'] instanceof PersistentDataInterface) {
$this->persistentDataHandler = $config['persistent_data_handler'];
} elseif ($config['persistent_data_handler'] === 'session') {
$this->persistentDataHandler = new FacebookSessionPersistentDataHandler();
} elseif ($config['persistent_data_handler'] === 'memory') {
$this->persistentDataHandler = new FacebookMemoryPersistentDataHandler();
} else {
throw new \InvalidArgumentException('The persistent_data_handler must be set to "session", "memory", or be an instance of Facebook\PersistentData\PersistentDataInterface');
}
}
if (isset($config['default_access_token'])) {
$this->setDefaultAccessToken($config['default_access_token']);
}
if (isset($config['default_graph_version'])) {
$this->defaultGraphVersion = $config['default_graph_version'];
} else {
// #todo v6: Throw an InvalidArgumentException if "default_graph_version" is not set
$this->defaultGraphVersion = static::DEFAULT_GRAPH_VERSION;
}
}
/**
* Returns the FacebookApp entity.
*
* #return FacebookApp
*/
public function getApp()
{
return $this->app;
}
/**
* Returns the FacebookClient service.
*
* #return FacebookClient
*/
public function getClient()
{
return $this->client;
}
/**
* Returns the OAuth 2.0 client service.
*
* #return OAuth2Client
*/
public function getOAuth2Client()
{
if (!$this->oAuth2Client instanceof OAuth2Client) {
$app = $this->getApp();
$client = $this->getClient();
$this->oAuth2Client = new OAuth2Client($app, $client, $this->defaultGraphVersion);
}
return $this->oAuth2Client;
}
/**
* Returns the last response returned from Graph.
*
* #return FacebookResponse|FacebookBatchResponse|null
*/
public function getLastResponse()
{
return $this->lastResponse;
}
/**
* Returns the URL detection handler.
*
* #return UrlDetectionInterface
*/
public function getUrlDetectionHandler()
{
if (!$this->urlDetectionHandler instanceof UrlDetectionInterface) {
$this->urlDetectionHandler = new FacebookUrlDetectionHandler();
}
return $this->urlDetectionHandler;
}
/**
* Returns the default AccessToken entity.
*
* #return AccessToken|null
*/
public function getDefaultAccessToken()
{
return $this->defaultAccessToken;
}
/**
* Sets the default access token to use with requests.
*
* #param AccessToken|string $accessToken The access token to save.
*
* #throws \InvalidArgumentException
*/
public function setDefaultAccessToken($accessToken)
{
if (is_string($accessToken)) {
$this->defaultAccessToken = new AccessToken($accessToken);
return;
}
if ($accessToken instanceof AccessToken) {
$this->defaultAccessToken = $accessToken;
return;
}
throw new \InvalidArgumentException('The default access token must be of type "string" or Facebook\AccessToken');
}
/**
* Returns the default Graph version.
*
* #return string
*/
public function getDefaultGraphVersion()
{
return $this->defaultGraphVersion;
}
/**
* Returns the redirect login helper.
*
* #return FacebookRedirectLoginHelper
*/
public function getRedirectLoginHelper()
{
return new FacebookRedirectLoginHelper(
$this->getOAuth2Client(),
$this->persistentDataHandler,
$this->urlDetectionHandler,
$this->pseudoRandomStringGenerator
);
}
/**
* Returns the JavaScript helper.
*
* #return FacebookJavaScriptHelper
*/
public function getJavaScriptHelper()
{
return new FacebookJavaScriptHelper($this->app, $this->client, $this->defaultGraphVersion);
}
/**
* Returns the canvas helper.
*
* #return FacebookCanvasHelper
*/
public function getCanvasHelper()
{
return new FacebookCanvasHelper($this->app, $this->client, $this->defaultGraphVersion);
}
/**
* Returns the page tab helper.
*
* #return FacebookPageTabHelper
*/
public function getPageTabHelper()
{
return new FacebookPageTabHelper($this->app, $this->client, $this->defaultGraphVersion);
}
/**
* Sends a GET request to Graph and returns the result.
*
* #param string $endpoint
* #param AccessToken|string|null $accessToken
* #param string|null $eTag
* #param string|null $graphVersion
*
* #return FacebookResponse
*
* #throws FacebookSDKException
*/
public function get($endpoint, $accessToken = null, $eTag = null, $graphVersion = null)
{
return $this->sendRequest(
'GET',
$endpoint,
$params = [],
$accessToken,
$eTag,
$graphVersion
);
}
/**
* Sends a POST request to Graph and returns the result.
*
* #param string $endpoint
* #param array $params
* #param AccessToken|string|null $accessToken
* #param string|null $eTag
* #param string|null $graphVersion
*
* #return FacebookResponse
*
* #throws FacebookSDKException
*/
public function post($endpoint, array $params = [], $accessToken = null, $eTag = null, $graphVersion = null)
{
return $this->sendRequest(
'POST',
$endpoint,
$params,
$accessToken,
$eTag,
$graphVersion
);
}
/**
* Sends a DELETE request to Graph and returns the result.
*
* #param string $endpoint
* #param array $params
* #param AccessToken|string|null $accessToken
* #param string|null $eTag
* #param string|null $graphVersion
*
* #return FacebookResponse
*
* #throws FacebookSDKException
*/
public function delete($endpoint, array $params = [], $accessToken = null, $eTag = null, $graphVersion = null)
{
return $this->sendRequest(
'DELETE',
$endpoint,
$params,
$accessToken,
$eTag,
$graphVersion
);
}
/**
* Sends a request to Graph for the next page of results.
*
* #param GraphEdge $graphEdge The GraphEdge to paginate over.
*
* #return GraphEdge|null
*
* #throws FacebookSDKException
*/
public function next(GraphEdge $graphEdge)
{
return $this->getPaginationResults($graphEdge, 'next');
}
/**
* Sends a request to Graph for the previous page of results.
*
* #param GraphEdge $graphEdge The GraphEdge to paginate over.
*
* #return GraphEdge|null
*
* #throws FacebookSDKException
*/
public function previous(GraphEdge $graphEdge)
{
return $this->getPaginationResults($graphEdge, 'previous');
}
/**
* Sends a request to Graph for the next page of results.
*
* #param GraphEdge $graphEdge The GraphEdge to paginate over.
* #param string $direction The direction of the pagination: next|previous.
*
* #return GraphEdge|null
*
* #throws FacebookSDKException
*/
public function getPaginationResults(GraphEdge $graphEdge, $direction)
{
$paginationRequest = $graphEdge->getPaginationRequest($direction);
if (!$paginationRequest) {
return null;
}
$this->lastResponse = $this->client->sendRequest($paginationRequest);
// Keep the same GraphNode subclass
$subClassName = $graphEdge->getSubClassName();
$graphEdge = $this->lastResponse->getGraphEdge($subClassName, false);
return count($graphEdge) > 0 ? $graphEdge : null;
}
/**
* Sends a request to Graph and returns the result.
*
* #param string $method
* #param string $endpoint
* #param array $params
* #param AccessToken|string|null $accessToken
* #param string|null $eTag
* #param string|null $graphVersion
*
* #return FacebookResponse
*
* #throws FacebookSDKException
*/
public function sendRequest($method, $endpoint, array $params = [], $accessToken = null, $eTag = null, $graphVersion = null)
{
$accessToken = $accessToken ?: $this->defaultAccessToken;
$graphVersion = $graphVersion ?: $this->defaultGraphVersion;
$request = $this->request($method, $endpoint, $params, $accessToken, $eTag, $graphVersion);
return $this->lastResponse = $this->client->sendRequest($request);
}
/**
* Sends a batched request to Graph and returns the result.
*
* #param array $requests
* #param AccessToken|string|null $accessToken
* #param string|null $graphVersion
*
* #return FacebookBatchResponse
*
* #throws FacebookSDKException
*/
public function sendBatchRequest(array $requests, $accessToken = null, $graphVersion = null)
{
$accessToken = $accessToken ?: $this->defaultAccessToken;
$graphVersion = $graphVersion ?: $this->defaultGraphVersion;
$batchRequest = new FacebookBatchRequest(
$this->app,
$requests,
$accessToken,
$graphVersion
);
return $this->lastResponse = $this->client->sendBatchRequest($batchRequest);
}
/**
* Instantiates a new FacebookRequest entity.
*
* #param string $method
* #param string $endpoint
* #param array $params
* #param AccessToken|string|null $accessToken
* #param string|null $eTag
* #param string|null $graphVersion
*
* #return FacebookRequest
*
* #throws FacebookSDKException
*/
public function request($method, $endpoint, array $params = [], $accessToken = null, $eTag = null, $graphVersion = null)
{
$accessToken = $accessToken ?: $this->defaultAccessToken;
$graphVersion = $graphVersion ?: $this->defaultGraphVersion;
return new FacebookRequest(
$this->app,
$accessToken,
$method,
$endpoint,
$params,
$eTag,
$graphVersion
);
}
/**
* Factory to create FacebookFile's.
*
* #param string $pathToFile
*
* #return FacebookFile
*
* #throws FacebookSDKException
*/
public function fileToUpload($pathToFile)
{
return new FacebookFile($pathToFile);
}
/**
* Factory to create FacebookVideo's.
*
* #param string $pathToFile
*
* #return FacebookVideo
*
* #throws FacebookSDKException
*/
public function videoToUpload($pathToFile)
{
return new FacebookVideo($pathToFile);
}
}
Note : I am using Ubuntu OS
just use
$this->load->library('facebook/facebook'); // Automatically picks appId and secret from config
// OR
// You can pass different one like this
$this->load->library('facebook/facebook', array(
'appId' => 'APP_ID',
'secret' => 'SECRET',
));
and inside facebook.php class name should be
class Facebook {
Facebook SDK PHP v4 & CodeIgniter and github download
$this->load->library('Facebook\facebook', array('app_id' => 'your value', 'app_secret' => 'your value'));
I did this and the problem was solved (on windows machine) And also add
require_once("autoload.php")
on Facebook class just below namespace so your can get rid of other exception related errors.
I tried to implement json-rpc server on local for some test.
But when I send some request, it returns the "Forbidden Error".
I made a clone from git (https://github.com/fguillot/JsonRPC), but for now I wanted to make sure something could be returned. So I used command line, instead of running program named Client.php.
example.php
<?php
require 'Server.php';
use JsonRPC\Server;
$server = new Server;
$server->register('addition', function ($a, $b) {
return $a + $b;
});
$server->register('random', function ($start, $end) {
return mt_rand($start, $end);
});
echo $server->execute();
?>
Server.php
<?php
namespace JsonRPC;
use Closure;
use BadFunctionCallException;
use Exception;
use InvalidArgumentException;
use LogicException;
use ReflectionFunction;
use ReflectionMethod;
class InvalidJsonRpcFormat extends Exception {};
class InvalidJsonFormat extends Exception {};
/**
* JsonRPC server class
*
* #package JsonRPC
* #author Frederic Guillot
* #license Unlicense http://unlicense.org/
*/
class Server
{
/**
* Data received from the client
*
* #access private
* #var string
*/
private $payload;
/**
* List of procedures
*
* #static
* #access private
* #var array
*/
private $callbacks = array();
/**
* List of classes
*
* #static
* #access private
* #var array
*/
private $classes = array();
/**
* Constructor
*
* #access public
* #param string $payload Client data
* #param array $callbacks Callbacks
* #param array $classes Classes
*/
public function __construct($payload = '', array $callbacks = array(), array $classes = array())
{
$this->payload = $payload;
$this->callbacks = $callbacks;
$this->classes = $classes;
}
/**
* IP based client restrictions
*
* Return an HTTP error 403 if the client is not allowed
*
* #access public
* #param array $hosts List of hosts
*/
public function allowHosts(array $hosts) {
if (! in_array($_SERVER['REMOTE_ADDR'], $hosts)) {
header('Content-Type: application/json');
header('HTTP/1.0 403 Forbidden');
echo '{"error": "Access Forbidden"}';
exit;
}
}
/**
* HTTP Basic authentication
*
* Return an HTTP error 401 if the client is not allowed
*
* #access public
* #param array $users Map of username/password
*/
public function authentication(array $users)
{
if (! isset($_SERVER['PHP_AUTH_USER']) ||
! isset($users[$_SERVER['PHP_AUTH_USER']]) ||
$users[$_SERVER['PHP_AUTH_USER']] !== $_SERVER['PHP_AUTH_PW']) {
header('WWW-Authenticate: Basic realm="JsonRPC"');
header('Content-Type: application/json');
header('HTTP/1.0 401 Unauthorized');
echo '{"error": "Authentication failed"}';
exit;
}
}
/**
* Register a new procedure
*
* #access public
* #param string $procedure Procedure name
* #param closure $callback Callback
*/
public function register($name, Closure $callback)
{
$this->callbacks[$name] = $callback;
}
/**
* Bind a procedure to a class
*
* #access public
* #param string $procedure Procedure name
* #param mixed $class Class name or instance
* #param string $method Procedure name
*/
public function bind($procedure, $class, $method)
{
$this->classes[$procedure] = array($class, $method);
}
/**
* Return the response to the client
*
* #access public
* #param array $data Data to send to the client
* #param array $payload Incoming data
* #return string
*/
public function getResponse(array $data, array $payload = array())
{
if (! array_key_exists('id', $payload)) {
return '';
}
$response = array(
'jsonrpc' => '2.0',
'id' => $payload['id']
);
$response = array_merge($response, $data);
#header('Content-Type: application/json');
return json_encode($response);
}
/**
* Parse the payload and test if the parsed JSON is ok
*
* #access public
*/
public function checkJsonFormat()
{
if (empty($this->payload)) {
$this->payload = file_get_contents('php://input');
}
if (is_string($this->payload)) {
$this->payload = json_decode($this->payload, true);
}
if (! is_array($this->payload)) {
throw new InvalidJsonFormat('Malformed payload');
}
}
/**
* Test if all required JSON-RPC parameters are here
*
* #access public
*/
public function checkRpcFormat()
{
if (! isset($this->payload['jsonrpc']) ||
! isset($this->payload['method']) ||
! is_string($this->payload['method']) ||
$this->payload['jsonrpc'] !== '2.0' ||
(isset($this->payload['params']) && ! is_array($this->payload['params']))) {
throw new InvalidJsonRpcFormat('Invalid JSON RPC payload');
}
}
/**
* Return true if we have a batch request
*
* #access public
* #return boolean
*/
private function isBatchRequest()
{
return array_keys($this->payload) === range(0, count($this->payload) - 1);
}
/**
* Handle batch request
*
* #access private
* #return string
*/
private function handleBatchRequest()
{
$responses = array();
foreach ($this->payload as $payload) {
if (! is_array($payload)) {
$responses[] = $this->getResponse(array(
'error' => array(
'code' => -32600,
'message' => 'Invalid Request'
)),
array('id' => null)
);
}
else {
$server = new Server($payload, $this->callbacks, $this->classes);
$response = $server->execute();
if ($response) {
$responses[] = $response;
}
}
}
return empty($responses) ? '' : '['.implode(',', $responses).']';
}
/**
* Parse incoming requests
*
* #access public
* #return string
*/
public function execute()
{
try {
$this->checkJsonFormat();
if ($this->isBatchRequest()){
return $this->handleBatchRequest();
}
$this->checkRpcFormat();
$result = $this->executeProcedure(
$this->payload['method'],
empty($this->payload['params']) ? array() : $this->payload['params']
);
return $this->getResponse(array('result' => $result), $this->payload);
}
catch (InvalidJsonFormat $e) {
return $this->getResponse(array(
'error' => array(
'code' => -32700,
'message' => 'Parse error'
)),
array('id' => null)
);
}
catch (InvalidJsonRpcFormat $e) {
return $this->getResponse(array(
'error' => array(
'code' => -32600,
'message' => 'Invalid Request'
)),
array('id' => null)
);
}
catch (BadFunctionCallException $e) {
return $this->getResponse(array(
'error' => array(
'code' => -32601,
'message' => 'Method not found'
)),
$this->payload
);
}
catch (InvalidArgumentException $e) {
return $this->getResponse(array(
'error' => array(
'code' => -32602,
'message' => 'Invalid params'
)),
$this->payload
);
}
}
/**
* Execute the procedure
*
* #access public
* #param string $procedure Procedure name
* #param array $params Procedure params
* #return mixed
*/
public function executeProcedure($procedure, array $params = array())
{
if (isset($this->callbacks[$procedure])) {
return $this->executeCallback($this->callbacks[$procedure], $params);
}
else if (isset($this->classes[$procedure])) {
return $this->executeMethod($this->classes[$procedure][0], $this->classes[$procedure][1], $params);
}
throw new BadFunctionCallException('Unable to find the procedure');
}
/**
* Execute a callback
*
* #access public
* #param Closure $callback Callback
* #param array $params Procedure params
* #return mixed
*/
public function executeCallback(Closure $callback, $params)
{
$reflection = new ReflectionFunction($callback);
$arguments = $this->getArguments(
$params,
$reflection->getParameters(),
$reflection->getNumberOfRequiredParameters(),
$reflection->getNumberOfParameters()
);
return $reflection->invokeArgs($arguments);
}
/**
* Execute a method
*
* #access public
* #param mixed $class Class name or instance
* #param string $method Method name
* #param array $params Procedure params
* #return mixed
*/
public function executeMethod($class, $method, $params)
{
$reflection = new ReflectionMethod($class, $method);
$arguments = $this->getArguments(
$params,
$reflection->getParameters(),
$reflection->getNumberOfRequiredParameters(),
$reflection->getNumberOfParameters()
);
return $reflection->invokeArgs(
is_string($class) ? new $class : $class,
$arguments
);
}
/**
* Get procedure arguments
*
* #access public
* #param array $request_params Incoming arguments
* #param array $method_params Procedure arguments
* #param integer $nb_required_params Number of required parameters
* #param integer $nb_max_params Maximum number of parameters
* #return array
*/
public function getArguments(array $request_params, array $method_params, $nb_required_params, $nb_max_params)
{
$nb_params = count($request_params);
if ($nb_params < $nb_required_params) {
throw new InvalidArgumentException('Wrong number of arguments');
}
if ($nb_params > $nb_max_params) {
throw new InvalidArgumentException('Too many arguments');
}
if ($this->isPositionalArguments($request_params, $method_params)) {
return $request_params;
}
return $this->getNamedArguments($request_params, $method_params);
}
/**
* Return true if we have positional parametes
*
* #access public
* #param array $request_params Incoming arguments
* #param array $method_params Procedure arguments
* #return bool
*/
public function isPositionalArguments(array $request_params, array $method_params)
{
return array_keys($request_params) === range(0, count($request_params) - 1);
}
/**
* Get named arguments
*
* #access public
* #param array $request_params Incoming arguments
* #param array $method_params Procedure arguments
* #return array
*/
public function getNamedArguments(array $request_params, array $method_params)
{
$params = array();
foreach ($method_params as $p) {
$name = $p->getName();
if (isset($request_params[$name])) {
$params[$name] = $request_params[$name];
}
else if ($p->isDefaultValueAvailable()) {
$params[$name] = $p->getDefaultValue();
}
else {
throw new InvalidArgumentException('Missing argument: '.$name);
}
}
return $params;
}
}
Commmand Line (I use macOS)
curl --data-binary '{"jsonrpc": "2.0","id":1, "method":"addition","params":[100,200] }' -H 'content-type: text/plain;' http://127.0.0.1/jsonrpcphp3/example.php
Return Value
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>403 Forbidden</title>
</head><body>
<h1>Forbidden</h1>
<p>You don't have permission to access /jsonrpcphp3/example.php
on this server.</p>
</body></html>