Last active
September 16, 2021 05:30
-
-
Save kosso/71c957e30a40116e5f98 to your computer and use it in GitHub Desktop.
Test PHP client for Wordpress REST API v2.0 / OAuth1.0a 0.3.0
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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; | |
} | |
} | |
?> |
Hello Kosso,
First of all thank you for this magnificant client example. Unfortunatly i stumbled across a problem with the Media Upload.
The error I'm getting is:
( [code] => json_oauth1_signature_mismatch [message] => OAuth signature does not match [data] => stdClass Object ( [status] => 401 )
I really would like this to work.. so i hope you can help me!
Thanks in advance!
Notice: Undefined index: logout in C:\xampp\htdocs\example\scripts\curl_post_request.php on line 86
This is showing when I'm running the script on localhost! How to solve that issue?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
When I am going to exchange the token, it returned 'ERROR: Failed to get access tokens '