Skip to content

Instantly share code, notes, and snippets.

@cyberwani
Forked from kosso/WP_API_OAuth_Test_client.php
Created September 16, 2021 05:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cyberwani/c58cd4573a3cceb350d75f6ee43b4ae4 to your computer and use it in GitHub Desktop.
Save cyberwani/c58cd4573a3cceb350d75f6ee43b4ae4 to your computer and use it in GitHub Desktop.
Test PHP client for Wordpress REST API v2.0 / OAuth1.0a 0.3.0
<?php
//opcache_reset(); // Disable local dev MAMP cache
/*
WP_API_OAuth_Test_client.php
Tested with Wordpress 4.7.1
WordPress REST API - OAuth 1.0a Server v.0.3.0 - https://en-gb.wordpress.org/plugins/rest-api-oauth1/
Description : Simple PHP test to obtain access_token and access_token_secret (Access tokens) from a Wordpress with WP-API and WP-OAuth plugins (and WP-CLI for OAuth consumer/app creation) installed.
Author : @kosso
Date : Nov 07, 2014
Updated : Nov 22, 2015
: Jan 16, 2016
: Mar 06, 2016
: Oct 11, 2016
: Jan 23, 2017
*/
/*
Instructions : After installing the WordPress REST API - OAuth 1.0a Server plugin, you can now create a new client application on wp-admin
; Go to Dashboard > Users > Applications.
: Set one up, then use the key/secret pair in the settings below.
: Use the url of *this* PHP test script for the callback url.
.. Now edit the config vars below with the server and client info.
*/
// Edit the config to your requirements.
$wp_site_url = 'http://yourWPdomain.com';
$wp_api_path = '/wp-json/wp/v2';
$oauth_config = array(
'key' => '#_YOUR_APP_CLIENT_KEY_#',
'secret' => '#_YOUR_APP_CLIENT_SECRET#',
'wp_api_domain' => $wp_site_url,
'wp_api_path' => $wp_api_path,
'uri_request' => $wp_site_url.'/oauth1/request',
'uri_authorize' => $wp_site_url.'/oauth1/authorize',
'uri_access' => $wp_site_url.'/oauth1/access',
'uri_user' => $wp_site_url.$wp_api_path.'/users/me?context=edit', // 'embed' context excludes roles and capabilities, so use 'edit' to determine if publishing and uploads are allowed.
'oauth_callback' => 'http://yourREMOTE.client.domain.com/WP_API_OAuth_Test_client.php' // The url where you will run this test. Point to THIS php file.
);
// Clear the cookies to log out.
if($_GET['logout']==1){
setcookie("access_token", $access_token, time() - 1, "/" );
setcookie("access_token_secret", $access_token_secret, time() - 1, "/" );
setcookie("user_object", json_encode($user_object), time() - 1, "/" );
setcookie("oauth_token_secret", "", time() - 1, "/" );
header('Location: '.$_SERVER['PHP_SELF']);
}
// OK.. Here we go...
$auth = new OAuthWP($oauth_config);
// Pick up url query params after the oauth_callback after request token generation. (Also added check to make sure we're coming back from the OAuth server host)
//if(isset( $_REQUEST['oauth_token'] ) && isset( $_REQUEST['oauth_verifier'] ) && parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST) == parse_url($oauth_config['uri_request'], PHP_URL_HOST) ){
if(isset( $_REQUEST['oauth_token'] ) && isset( $_REQUEST['oauth_verifier'] )) {
// Back from Authorisation. Now Generate Access Tokens for this user
// Generate access tokens param string
// Add the required 'oauth_verifier' parameter
$request_data = array(
'oauth_verifier' => $_REQUEST['oauth_verifier']
);
$temp_secret = $_COOKIE['oauth_token_secret']; // from /request token leg
$access_token_string = $auth->oauthRequest($oauth_config['uri_access'],'POST', $_REQUEST['oauth_token'], $temp_secret, $request_data); // no token secret yet...
parse_str($access_token_string, $access_tokens);
if(!isset($access_tokens['oauth_token'])){
echo '<h3>ERROR: Failed to get access tokens</h3>';
print_r($access_tokens);
echo '<hr>';
print_r($access_token_string);
exit;
}
$access_token = $access_tokens['oauth_token'];
$access_token_secret = $access_tokens['oauth_token_secret'];
// Verify user by getting currently looged in user daya from /wp-json/users/me
$user_object = json_decode($auth->oauthRequest($oauth_config['uri_user'],'GET', $access_token, $access_token_secret));
// Store information in a cookie for when the page is reloaded
setcookie("access_token", $access_token, time() + (3600 * 72), "/" ); // expire in 72 hours...
setcookie("access_token_secret", $access_token_secret, time() + (3600 * 72), "/" ); // expire in 72 hours...
setcookie("user_object", json_encode($user_object), time() + (3600 * 72), "/" ); // expire in 72 hours...
// Clear the temp cookie
setcookie("oauth_token_secret", "", time() - 1, "/" );
// Reload the page
header('Location: '.$_SERVER['PHP_SELF']);
exit;
}
if(isset($_COOKIE['access_token']) && isset($_COOKIE['access_token_secret']) && isset($_COOKIE['user_object'])){
// LOGGED-IN : Visitor already appears to have the required cookies set.
$u = json_decode($_COOKIE['user_object']);
$av = $u->avatar_urls;
foreach ($av as $key => $value) {
if($key == 48){ // medium thumbnail
$av = $value;
}
}
echo '<h3><img style="margin:6px;width:50px;height:50px;float:left;vertical-align:middle;" src="'.$av.'"> logged in as: '.$u->name.'</h3>';
echo '<br clear="all"><h4><a href="?logout=1">CLICK HERE TO LOG OUT</a></h4>';
echo '<hr>';
echo 'uncomment code below to try some tests.';
// TESTS /////////////////////////////////////////////
//echo $oauth_config['uri_user'];
// GET CURRENT USER DATA
// Docs : http://wp-api.org/#users_retrieve-current-user
echo '<h3>TEST: GET : '.$oauth_config['uri_user'].' to verify current user</h3>';
$current_user_object = json_decode($auth->oauthRequest($oauth_config['uri_user'],'GET', $_COOKIE['access_token'], $_COOKIE['access_token_secret']));
echo '<h4>RESPONSE:</h4>';
echo '<pre>';
print_r($current_user_object);
echo '</pre>';
// exit;
/*
// TEST : CREATE A NEW POST
// Docs : http://wp-api.org/#posts_create-a-post
echo '<hr><h3>test : Creating new post</h3>';
$post_data = array(
'status' => 'draft',
'title' => 'Heyyyyy Another test at '.date('H:i'),
'content' => 'The quick brown fox jumped over the lazy dogs.'
);
$post_object = $auth->oauthRequest($oauth_config['wp_api_domain'].$oauth_config['wp_api_path'].'/posts','POST', $_COOKIE['access_token'], $_COOKIE['access_token_secret'], $post_data);
echo '<h4>RESPONSE:</h4>';
echo '<pre>';
print_r($post_object);
echo '</pre>';
*/
// Uncomment the sections below to test some other things..
/*
// CREATE NEW ATTACHMENT (Media upload)
// Docs : http://wp-api.org/#media_create-an-attachment
echo '<hr><h3>Test : Create New Attachment (Media upload)</h3>';
$file_data = array(
'file' => '@./some_photo.jpg;type=image/jpeg'
//'file' => '@./some_video.m4v;type=video/m4v'
//'file' => '@./sometune.mp3;type=audio/mpeg'
);
$file_object = json_decode($auth->oauthRequest($oauth_config['wp_api_domain'].$oauth_config['wp_api_path'].'/media',
'POST',
$_COOKIE['access_token'],
$_COOKIE['access_token_secret'],
$file_data
)
);
echo '<h4>UPLOAD RESPONSE:</h4>';
echo '<pre>';
print_r($file_object);
echo '</pre>';
// Naturally, you'll need to do a file upload first, if you want the attachment to be 'attached' or embedded in a post.
/**/
/*
date
date_gmt
password
slug
status - One of: publish, future, draft, pending, private
title
content
author
excerpt
featured_media
comment_status - One of: open, closed
ping_status - One of: open, closed
format - One of: standard, aside, chat, gallery, link, image, quote, status, video, audio
sticky
categories
tags
*/
/*
// UPDATE A (previous) POST
echo '<hr><h3>Test : Updating Post</h3>';
$post_id = $post_object->id;
$update_data = array(
'title' => 'The title was edited immediately after creating it at '.time(),
'excerpt' => 'And this excerpt was added after.',
'categories' => [ 1, 2, 6 ]
);
$update_object = json_decode($auth->oauthRequest($oauth_config['wp_api_domain'].$oauth_config['wp_api_path'].'/posts/'.$post_id,
'POST',
$_COOKIE['access_token'],
$_COOKIE['access_token_secret'],
$update_data,
true // post as JSON
)
);
echo '<h4>UPDATE POST RESPONSE:</h4>';
echo '<pre>';
print_r($update_object);
echo '</pre>';
/**/
// that's it..
} else {
// Not logged in.
$request_token_string = $auth->oauthRequest($oauth_config['uri_request'],'POST', null, null);
parse_str($request_token_string, $request_parts);
// temporarily store the oauth_token_secret for the next step after the callback.
setcookie("oauth_token_secret", $request_parts['oauth_token_secret'], time() + 60, "/" );
// echo '<h4>request_token_string :'.$request_token_string.'</h4>';
// Start OAuth authorisation by obtaining a request token and generating a link to the OAuth server, with a callback here ...
echo '<h3><a href="'.$oauth_config['uri_authorize'].'?'.$request_token_string.'&oauth_callback='.urlencode($oauth_config['oauth_callback']).'">LOGIN USING YOUR '.$oauth_config['wp_api_domain'].' WORDPRESS ACCOUNT</a></h3>';
echo 'Uses WP-API and OAuth 1.0a Server for WordPress via https://github.com/WP-API';
}
// That's it!
// #########################################################################
// OAuth 1.0a library
// #########################################################################
// NB: All the echo and print_r must be commented out for setcookie to work when running logging in tests.
function logIt($text){
return;// comment to activate log
$debugLog = '/path/to/debug/log.txt';
$t = print_r($text, true);
$text = $t;
$handle = fopen($debugLog, "a+");
if (fwrite($handle, $text."\n") === FALSE) {
}
fclose($handle);
}
class OAuthWP
{
function OAuthWP($config)
{
$this->key = $config['key'];
$this->secret = $config['secret'];
$this->uri_request = $config['uri_request'];
$this->uri_authorize = $config['uri_authorize'];
$this->uri_access = $config['uri_access'];
$this->uri_user = $config['uri_user'];
}
function queryStringFromData($data, $queryParams = false, $prevKey = '')
{
if ($initial = (false === $queryParams)) {
$queryParams = array();
}
foreach ($data as $key => $value) {
if ($prevKey) {
$key = $prevKey.'['.$key.']'; // Handle multi-dimensional array
}
$queryParams[] = $this->_urlencode_rfc3986($key.'='.$value); // join with equals sign
}
if ($initial) {
return implode('%26', $queryParams); // join with ampersand
}
return $queryParams;
}
function oauthRequest($url, $method, $oauth_access_token, $oauth_access_token_secret, $post_params=null, $post_json=false){
$params = array(
"oauth_version" => "1.0",
"oauth_nonce" => md5(time().rand()),
"oauth_timestamp" => time(),
"oauth_consumer_key" => $this->key,
"oauth_signature_method" => "HMAC-SHA1",
"oauth_token" => $oauth_access_token
);
// Filter out empty params.
$params = array_filter($params);
// ## BUILD OAUTH SIGNATURE
// Add extra params if present and not JSON
if($post_params!=null && $post_json === false ){
foreach ($post_params as $k => $v){
if(is_array($v)){
$iii = 0;
logIt('***** ARRAY ');
foreach ($v as $kk => $vv){
$params[$k][$iii] = $vv;
$iii++;
}
} else {
$params[$k] = $v;
}
}
// Remove 'file' param from signature base string. Since the server will have nothing to compare it to. Also potentially exposes paths.
unset($params['file']);
ksort($params);
}
// Deal query with any query params in the request_uri
$request_query = parse_url($url, PHP_URL_QUERY);
$request_uri_parts = parse_url($url);
$request_base_uri = $request_uri_parts['scheme'].'://'.$request_uri_parts['host'].$request_uri_parts['path'];
$joiner = '?'; // used for final url concatenation down below
if(!empty($request_query)){
$joiner = '&';
parse_str($request_query, $query_params);
$params = array_merge($query_params, $params);
ksort($params);
}
// Encode params keys, values, join and then sort.
$keys = $this->_urlencode_rfc3986(array_keys($params));
$values = $this->_urlencode_rfc3986(array_values($params));
$params = array_combine($keys, $values);
ksort($params);
// Convert params to string
foreach ($params as $k => $v) {
$pairs[] = $this->_urlencode_rfc3986($k).'='.$this->_urlencode_rfc3986($v);
}
$concatenatedParams = implode('&', $pairs);
$concatenatedParams = str_replace('=', '%3D', $concatenatedParams);
$concatenatedParams = str_replace('&', '%26', $concatenatedParams);
// Form base string (first key)
// echo '<h4>concatenated params</h4><pre>'.$concatenatedParams.'</pre>';
// base string should never use the '?' even if it has one in a GET query
// See : https://developers.google.com/accounts/docs/OAuth_ref#SigningOAuth
$baseString= $method."&".urlencode($request_base_uri)."&".$concatenatedParams;
// Form secret (second key)
$secret = urlencode($this->secret)."&".$oauth_access_token_secret; // concatentate the oauth_token_secret (null when doing initial '1st leg' request token)
// Make signature and append to params
logIt('base : '.$baseString);
logIt('signature key : '.$secret);
$params['oauth_signature'] = rawurlencode(base64_encode(hash_hmac('sha1', $baseString, $secret, TRUE)));
// Re-sort params
ksort($params);
// Remove any added GET query parameters from the params to rebuild the string without duplication ..
if(isset($query_params)){
foreach ($query_params as $key => $value) {
if(isset($params[$key])){
unset($params[$key]);
}
}
ksort($params);
}
// Remove any POST params so they get sent as POST data and not in the query string.
if($post_params!=null && $post_json === false ){
foreach ($post_params as $key => $value) {
if(isset($params[$key])){
unset($params[$key]);
}
}
ksort($params);
}
// Build OAuth Authorization header from oauth_* parameters only.
$post_headers = $this->buildAuthorizationHeader($params);
// Convert params to string
foreach ($params as $k => $v) {
$urlPairs[] = $k."=".$v;
}
$concatenatedUrlParams = implode('&', $urlPairs);
// The final url can use the ? query params....
$final_url = $url; // original url. OAuth data will be set in the Authorization Header of the request, regardless of _GET or _POST (or _FILE)
// Request using cURL
$json_response = $this->_http($final_url, $method, $post_params, $post_headers, $post_json);
// Result JSON
return $json_response;
}
// Send Authorised Request Using Curl ///////////////////////////
function _http($url, $method, $post_data = null, $oauth_headers = null, $post_json=false)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
if($method=='POST')
{
curl_setopt($ch, CURLOPT_POST, 1);
logIt('POST');
logIt($post_data);
if(isset($post_data['file'])){
// Media upload
$header[] = 'Content-Type: multipart/form-data';
if(isset($oauth_headers)){
array_push($header, $oauth_headers);
}
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
} else {
if(isset($oauth_headers)){
if($post_json===true){
$header[] = 'Content-Type: application/json';
array_push($header, $oauth_headers);
} else {
$header[] = $oauth_headers;
}
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
}
if($post_json===true){
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($post_data));
} else {
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data); // application/x-www-form-urlencoded
}
}
} else {
// Not being used yet.
if(isset($oauth_headers))
{
$header[] = $oauth_headers;
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
}
}
$response = curl_exec($ch);
$this->http_status = curl_getinfo($ch, CURLINFO_HTTP_CODE); // 201 = 'Created'
$this->last_api_call = $url;
$this->response = $response;
// echo "<br>status: ".$this->http_status."<br>";
// logit('this');
// logIt($this);
curl_close($ch);
return $response;
}
function _urlencode_rfc3986($input)
{
if (is_array($input)) {
return array_map(array('OAuthWP', '_urlencode_rfc3986'), $input);
}
else if (is_scalar($input)) {
return str_replace('+',' ',str_replace('%7E', '~', rawurlencode($input)));
}
else{
return '';
}
}
private function buildAuthorizationHeader($oauth){
$r = 'Authorization: OAuth ';
$values = array();
foreach($oauth as $key => $value){
$values[] = $key . '="' . rawurlencode($value) . '"';
}
$r .= implode(', ', $values);
return $r;
}
}
?>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment