I am working on a php application that requires me to interact with each merchants store using the WooCommerce Rest API and i am trying to auto-generate the rest api keys like it was documented on their documentation but my callback_url endpoint won't fire and i don't receive the auto-generated keys sent to the callback endpoint.
Here is my code to Create an authentication endpoint URL
public function integrate()
{
$url = $this->input->post('url');
$title = $this->input->post('title');
$user_id = $this->session->userdata('client_id');
$save = $this->Store_model->save_store($user_id,$url, $title);
$genKeyEndpoint = '/wc-auth/v1/authorize';
$params = [
'app_name' => 'App Name',
'scope' => 'read_write',
'user_id' => $user_id,
'return_url' => base_url('stores/integrateForm'),
'callback_url' => base_url('stores/callback-endpoint')
];
$query_string = http_build_query( $params, null, '&', PHP_QUERY_RFC3986 );
$wooAuth = $url . $genKeyEndpoint . '?' . $query_string;
redirect($wooAuth);
}
and here is my code to retrieve the generated keys and store in my database
public function save_api_key() {
$post_data = json_decode(file_get_contents('php://input'), true);
$wooResponseData = [
'consumer_key' => $post_data['consumer_key'],
'consumer_secret' => $post_data['consumer_secret']
];
$this->Store_model->updateStoreKeys($this->session->userdata('client_id'), $wooResponseData);
}
My application is running on codeigniter.
Related
I have a Webhook on my Xero Account for Invoices. When a new invoice is created I want to access the Xero Api using the data from the Webhook to Send the user the invoice email. I have all the code for this but my issue is that the Webhook expects a response of 200 and when I call the Xero Api code from within the webhook I get an error on Xero saying the response contained a body. This makes sense as I'm submitting and getting data from the Api.
So how can I make my requests to the Xero Api without interfering with the Xero Webhook response?
Webhook Code:
<?php
///////////////////////////////////////////////////////////////////////////
// WEBHOOK AUTHENTICATION - START
///////////////////////////////////////////////////////////////////////////
//hook section
$rawPayload = file_get_contents("php://input");
// Update your webhooks key here
$webhookKey = 'myWebhookKey';
// Compute the payload with HMACSHA256 with base64 encoding
$computedSignatureKey = base64_encode(
hash_hmac('sha256', $rawPayload, $webhookKey, true)
);
// Signature key from Xero request
$xeroSignatureKey = $_SERVER['HTTP_X_XERO_SIGNATURE'];
$isEqual = false;
if (hash_equals($computedSignatureKey, $xeroSignatureKey)) {
$isEqual = true;
http_response_code(200);
// getting and passing the data to the api functionality
$data = json_decode($rawPayload);
xero_api($data);
} else {
http_response_code(401);
}
///////////////////////////////////////////////////////////////////////////
// WEBHOOK AUTHENTICATION - END
///////////////////////////////////////////////////////////////////////////
?>
Api code:
<?php
///////////////////////////////////////////////////////////////////////////
// XERO API FUNCITONALITY - START
///////////////////////////////////////////////////////////////////////////
function xero_api($data) {
if ($data->events[0]->eventType === 'CREATE') {
$resourseId = $data->events[0]->resourceId;
///////////////////////////////////////////////////////////////////////////
// GET XERO CREDENTIALS - START
///////////////////////////////////////////////////////////////////////////
global $wpdb;
$xeroKeys = $wpdb->get_row("SELECT * FROM {$wpdb->prefix}xero_keys WHERE ID = 0", ARRAY_A);
$clientId = $xeroKeys['client_id'];
$clientSecret = $xeroKeys['client_secret'];
$refreshToken = $xeroKeys['refresh_token'];
$tenantId = $xeroKeys['tenant_id'];
///////////////////////////////////////////////////////////////////////////
// GET XERO CREDENTIALS - END
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
// GET ACCESS TOKEN AND GENERATE NEW REFRESH TOKEN - START
///////////////////////////////////////////////////////////////////////////
$args = array(
'headers' => array(
'grant_type' => 'refresh_token',
),
'body' => array(
'grant_type' => 'refresh_token',
'refresh_token' => $refreshToken,
'client_id' => $clientId,
'client_secret' => $clientSecret
)
);
$refreshTokenRes = wp_remote_post('https://identity.xero.com/connect/token?=', $args);
$refreshTokenBody = json_decode($refreshTokenRes['body']);
if (isset($refreshTokenBody->refresh_token) && isset($refreshTokenBody->access_token)) {
$updateTokens = $wpdb->update(
$wpdb->prefix . 'xero_keys',
array(
'refresh_token' => $refreshTokenBody->refresh_token,
'access_token' => $refreshTokenBody->access_token
),
array('ID' => 0),
array('%s', '%s'),
array('%d')
);
}
///////////////////////////////////////////////////////////////////////////
// GET ACCESS TOKEN AND GENERATE NEW REFRESH TOKEN - End
///////////////////////////////////////////////////////////////////////////
$args = array(
'headers' => array(
'xero-tenant-id' => $tenantId,
'Authorization' => 'Bearer ' . $refreshTokenBody->access_token,
'Accept' => 'application/json',
'Content-Type' => 'application/json'
),
);
$response = wp_remote_post('https://api.xero.com/api.xro/2.0/Invoices/' . $resourseId . '/Email', $args);
}
}
///////////////////////////////////////////////////////////////////////////
// XERO API FUNCITONALITY - END
///////////////////////////////////////////////////////////////////////////
?>
The problem is that you need to separate these calls.
As the comment to your question said, you need to first deal with the webhook, then queue the job that will trigger your API. Something like this would do
<?php
///////////////////////////////////////////////////////////////////////////
// WEBHOOK AUTHENTICATION - START
///////////////////////////////////////////////////////////////////////////
//hook section
$rawPayload = file_get_contents("php://input");
// Update your webhooks key here
$webhookKey = 'myWebhookKey';
// Compute the payload with HMACSHA256 with base64 encoding
$computedSignatureKey = base64_encode(
hash_hmac('sha256', $rawPayload, $webhookKey, true)
);
// Signature key from Xero request
$xeroSignatureKey = $_SERVER['HTTP_X_XERO_SIGNATURE'];
$isEqual = false;
if (hash_equals($computedSignatureKey, $xeroSignatureKey)) {
$isEqual = true;
http_response_code(200);
// getting and passing the data to the api functionality
$data = json_decode($rawPayload);
wp_schedule_single_event(
time() + 10,
'send_xero_api_call',
['data' => $data]
);
} else {
http_response_code(401);
}
///////////////////////////////////////////////////////////////////////////
// WEBHOOK AUTHENTICATION - END
///////////////////////////////////////////////////////////////////////////
Then you need to register a WP Cron
add_action('send_xero_api_call', 'xero_api_cron', 10);
function xero_api_cron($data) {
if ($data->events[0]->eventType === 'CREATE') {
$resourseId = $data->events[0]->resourceId;
///////////////////////////////////////////////////////////////////////////
// GET XERO CREDENTIALS - START
///////////////////////////////////////////////////////////////////////////
global $wpdb;
$xeroKeys = $wpdb->get_row("SELECT * FROM {$wpdb->prefix}xero_keys WHERE ID = 0", ARRAY_A);
$clientId = $xeroKeys['client_id'];
$clientSecret = $xeroKeys['client_secret'];
$refreshToken = $xeroKeys['refresh_token'];
$tenantId = $xeroKeys['tenant_id'];
///////////////////////////////////////////////////////////////////////////
// GET XERO CREDENTIALS - END
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
// GET ACCESS TOKEN AND GENERATE NEW REFRESH TOKEN - START
///////////////////////////////////////////////////////////////////////////
$args = array(
'headers' => array(
'grant_type' => 'refresh_token',
),
'body' => array(
'grant_type' => 'refresh_token',
'refresh_token' => $refreshToken,
'client_id' => $clientId,
'client_secret' => $clientSecret
)
);
$refreshTokenRes = wp_remote_post('https://identity.xero.com/connect/token?=', $args);
$refreshTokenBody = json_decode($refreshTokenRes['body']);
if (isset($refreshTokenBody->refresh_token) && isset($refreshTokenBody->access_token)) {
$updateTokens = $wpdb->update(
$wpdb->prefix . 'xero_keys',
array(
'refresh_token' => $refreshTokenBody->refresh_token,
'access_token' => $refreshTokenBody->access_token
),
array('ID' => 0),
array('%s', '%s'),
array('%d')
);
}
///////////////////////////////////////////////////////////////////////////
// GET ACCESS TOKEN AND GENERATE NEW REFRESH TOKEN - End
///////////////////////////////////////////////////////////////////////////
$args = array(
'headers' => array(
'xero-tenant-id' => $tenantId,
'Authorization' => 'Bearer ' . $refreshTokenBody->access_token,
'Accept' => 'application/json',
'Content-Type' => 'application/json'
),
);
$response = wp_remote_post('https://api.xero.com/api.xro/2.0/Invoices/' . $resourseId . '/Email', $args);
}
}
Something to this extent. The $data argument should contain the data you passed (not 100% sure how it looks for you). Also, you'll need to check the throttling by the API, so you might adjust the time of the execution of your job. And make sure you have somewhere stored if your background job finished successfully.
One thing I suggest, since you are storing sensitive info in your DB (access and refresh tokens), is to encrypt them when storing them in the DB, and decrypt when fetching them.
You can check how I implemented background jobs in my plugin
https://github.com/dingo-d/woo-solo-api/tree/develop/src/BackgroundJobs
https://github.com/dingo-d/woo-solo-api/blob/develop/src/Request/SoloApiRequest.php#L428-L438
You can use WP Queue lib from deliciousbrains: https://github.com/deliciousbrains/wp-queue/
It's a wrapper around WP Cron with custom DB tables for handling the queues, which will allow you to check if the jobs executed correctly or not.
we are using the woocommerce Rest API. If there any ways to get client key and secret key in api response for oauth authentication. We referred the below link https://woocommerce.github.io/woocommerce-rest-api-docs/?php#rest-api-keys
$store_url = 'http://example.com';
$endpoint = '/wc-auth/v1/authorize';
$params = [
'app_name' => 'My App Name',
'scope' => 'write',
'user_id' => 123,
'return_url' => 'http://app.com',
'callback_url' => 'https://app.com'
];
$query_string = http_build_query( $params );
echo $store_url . $endpoint . '?' . $query_string;
But it Doesn't return any response. It only returns the post values only send by me.
I'm trying to get the latest changes from my documentlist in Sharepoint using PHP and GetListItemChangesSinceToken. I'm using phpSPO as a SDK since there aren't any official Sharepoint SDK's for PHP.
So far I have this:
$payload = array(
'query' => array(
'__metadata' => array('type' => 'SP.ChangeLogItemQuery'),
'ViewName' => '',
'QueryOptions'=> '<QueryOptions><Folder>Shared Documents</Folder></QueryOptions>'
)
);
$headers = array();
$headers["X-HTTP-Method"] = "MERGE";
$changes = $this->request->executeQueryDirect($this->settings->URL . "/_api/web/Lists/GetByTitle('Documents')/GetListItemChangesSinceToken", $headers, $payload);
Which returns: {"error":{"code":"-2147467261, System.ArgumentNullException","message":{"lang":"en-US","value":"Value cannot be null.\r\nParameter name: query"}}}
I've tried changing the X-HTTP-Method and changing the array to fit the documented JSON/XML request (XML in JSON objects, come on Microsoft)
First approach
The following example demonstrates how to utilize GetListItemChangesSinceToken method:
$listTitle = "Documents";
$payload = array(
'query' => array(
'__metadata' => array('type' => 'SP.ChangeLogItemQuery'),
'ViewName' => '',
'QueryOptions'=> '<QueryOptions><Folder>Shared Documents</Folder></QueryOptions>'
)
);
$request = new ClientRequest($webUrl,$authCtx);
$options = array(
'url' => $webUrl . "/_api/web/Lists/GetByTitle('$listTitle')/GetListItemChangesSinceToken",
'data' => json_encode($payload),
'method' => 'POST'
);
$response = $request->executeQueryDirect($options);
//process results
$xml = simplexml_load_string($response);
$xml->registerXPathNamespace('z', '#RowsetSchema');
$rows = $xml->xpath("//z:row");
foreach($rows as $row) {
print (string)$row->attributes()["ows_FileLeafRef"] . "\n";
}
Second approach
Since SharePoint REST Client SDK for PHP now supports GetListItemChangesSinceToken method, the previous example could be invoked like this:
$list = $ctx->getWeb()->getLists()->getByTitle($listTitle);
$query = new ChangeLogItemQuery();
//to request all the items set ChangeToken property to null
$query->ChangeToken = "1;3;e49a3225-13f6-47d4-a146-30d9caa05362;635969955256400000;10637059";
$items = $list->getListItemChangesSinceToken($query);
$ctx->executeQuery();
foreach ($items->getData() as $item) {
print "[List Item] $item->Title\r\n";
}
More examples could be found here under phpSPO repository.
Im creating a widget for a Wordpress site and i am trying to get the twitter following count, I can get the followers count which is taken from http://www.wpbeginner.com/wp-tutorials/displaying-the-total-number-of-twitter-followers-as-text-on-wordpress/. Any help would be great.
thanks Pierce
Current code in functions.php:
// Twitter
function getTwitterFollowers($screenName = 'hellowWorld')
{
// some variables
$consumerKey = 'hidden';
$consumerSecret = 'hidden';
$token = get_option('cfTwitterToken');
// get follower count from cache
$numberOfFollowers = get_transient('cfTwitterFollowers');
// cache version does not exist or expired
if (false === $numberOfFollowers) {
// getting new auth bearer only if we don't have one
if(!$token) {
// preparing credentials
$credentials = $consumerKey . ':' . $consumerSecret;
$toSend = base64_encode($credentials);
// http post arguments
$args = array(
'method' => 'POST',
'httpversion' => '1.1',
'blocking' => true,
'headers' => array(
'Authorization' => 'Basic ' . $toSend,
'Content-Type' => 'application/x-www-form-urlencoded;charset=UTF-8'
),
'body' => array( 'grant_type' => 'client_credentials' )
);
add_filter('https_ssl_verify', '__return_false');
$response = wp_remote_post('https://api.twitter.com/oauth2/token', $args);
$keys = json_decode(wp_remote_retrieve_body($response));
if($keys) {
// saving token to wp_options table
update_option('cfTwitterToken', $keys->access_token);
$token = $keys->access_token;
}
}
// we have bearer token wether we obtained it from API or from options
$args = array(
'httpversion' => '1.1',
'blocking' => true,
'headers' => array(
'Authorization' => "Bearer $token"
)
);
add_filter('https_ssl_verify', '__return_false');
$api_url = "https://api.twitter.com/1.1/users/show.json?screen_name=$screenName";
$response = wp_remote_get($api_url, $args);
if (!is_wp_error($response)) {
$followers = json_decode(wp_remote_retrieve_body($response));
$numberOfFollowers = $followers->followers_count;
} else {
// get old value and break
$numberOfFollowers = get_option('cfNumberOfFollowers');
// uncomment below to debug
//die($response->get_error_message());
}
// cache for an hour
set_transient('cfTwitterFollowers', $numberOfFollowers, 1*60*60);
update_option('cfNumberOfFollowers', $numberOfFollowers);
}
return $numberOfFollowers;
}
It was pretty simple if I just read the documentation anyway...
Instead of followers_count i replaced it with friends_count as outlined in the API 1.1 documentation. :)
I'm trying to pull my list of Google contacts and display on a page the name and phone number.
I found an interesting post made by Lorna Jane and tried her code. I get a token returned, but every time I revisit the page, it asks me to authenticate again. With current code, no data array is pulled:
$id = 'secret.apps.googleusercontent.com';
$scope = 'https://www.google.com/m8/feeds/default/full/';
$uri = 'http://example.com/callback.php';
$params = array(
'response_type' => 'code',
'client_id' => $id,
'redirect_uri' => $uri,
'scope' => $scope
);
$query = 'https://accounts.google.com/o/oauth2/auth?' . http_build_query($params);
header('Location: ' . filter_var($query, FILTER_SANITIZE_URL));
if (isset($_GET['code']))
{
$code = $_GET['code'];
$token = 'https://accounts.google.com/o/oauth2/token';
$params = array(
'code' => $code,
'client_id' => $id,
'client_secret' => 'clientsecret',
'redirect_uri' => $uri,
'grant_type' => 'authorization_code'
);
$request = new HttpRequest($token, HttpRequest::METH_POST);
$request->setPostFields($params);
$request->send();
$responseObj = json_decode($request->getResponseBody());
var_dump($responseObj);
}
Please let me know what I'm missing. I prefer the pecl_http implementation, over the Google API library.