-
-
Save kosso/71c957e30a40116e5f98 to your computer and use it in GitHub Desktop.
<?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; | |
} | |
} | |
?> |
Hmm.. I just tried it on a fresh Wordpress 4.7.3 on one domain, running this script from another domain and it all worked fine.
Do you have the application client id/secret and the callback url all set up correctly?
Which version of Wordpress and also PHP are you running this on?
Hi, i tried to implement this oAuth too. All flows are working fine.
The only problem is when I tried to fetch current user data, it always returned me unauthorized response like:
{"code":"rest_not_logged_in","message":"You are not currently logged in.","data":{"status":401}}
Any thought?
Works for me on 4.8, awesome job and thank you.
I spoke too soon... When talking to a WP instance on a domain, I am getting the "No OAuth parameters supplied" message also, I tried different domains, different instances, works only if I run it on a local instance.
It turns out, my hosting company has a policy for Authorization headers.
Adding :
SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1
at the end of the .httaccess file solves the problem.
@bojanseirovski Thank you very much. It works now.
When I am going to exchange the token, it returned 'ERROR: Failed to get access tokens '
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?
Currently this line
$request_token_string = $auth->oauthRequest($oauth_config['uri_request'],'POST', null, null);
produces
http://www.site.com/oauth1/authorize?No%20OAuth%20parameters%20supplied&oauth_callback=http%3A%2F%2Fwww.site.com%2Ftest.php
See the No%20OAuth%20parameters%20supplied.
In that function
oauthRequest
$json_response = $this->_http($final_url, $method, $post_params, $post_headers, $post_json);
returns
No OAuth parameters supplied
.In function
_http
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
returns
No OAuth parameters supplied
and
echo "<br>status: ".$this->http_status."<br>";
returns
status: 400
Any idea?