I'm sending data with Laravel HTTP client to a practice PHP API. my Laravel code:
$p = 'img.jpg';
$path = storage_path('app' . DIRECTORY_SEPARATOR . 'public' . DIRECTORY_SEPARATOR . 'images' . DIRECTORY_SEPARATOR . $p);
$response = Http::attach('new_file', file_get_contents($path), 'new_file.jpg')->post('http://localhost/imageresizer/service.php',
['sizes[0][new_width]' => 400, 'sizes[0][new_height]' => 200, 'sizes[1][new_width]' => 300, 'sizes[1][new_height]' => 500]);
$json = json_decode($response);
dd($json);
and i have this in my php scripts:
$response = [
'status' => http_response_code(),
'zip name' => basename($zipname),
'link' => 'http://localhost/imageresizer/zip/' . basename($zipname)
];
header("Content-Type: application/json");
echo json_encode($response);
I want to access each value from $response keys in my PHP API but i fail. How can i do it? (the current result for dd($json); is null). I want to do something like $json->$response['status']; in my Laravel app.
You have to use response() function to send back the requested data;
return response()->json(['data' => $dataToBeSent], 200);
You can use above code at end of that function.
You can see full detail in this official document
Related
TLDR: Trying to post a tweet everytime someone posts on wordpress but can't authenticate correctly with oauth 1 to use the /2/tweets endpoint.
So I was annoyed when Jetpack social on my site decided to start charging for tweet scheduling. Usually I would be fine with this but it just seemed dumb that they were charging for something that I could build in a few days. So I'm planning on making an open source plugin that let's anyone use their wordpress as a tweet scheduler.
I'm currently struggling to properly authenticate with oauth to use the api v2. There's a lot of content out there for v1 but far less for v2 and particuarly v2 with wordpress.
Here's the resources I've used:
-https://www.youtube.com/watch?v=jOlJ5VJ_kSw for the oauth code
-https://developer.wordpress.org/reference/functions/wp_remote_post/ for the wp_remote_post() api call
-Numerous stack articles ie Wordpress twitter api 1.1 search class
which provides a good solution for 1.1 but I have made the possibly
false assumption based on what I've seen that 1.1 is now deprecated
-https://developer.twitter.com/en/docs/authentication/oauth-1-0a/creating-a-signature
shows you how to make a signature for a 1.1 endpoint to post a tweet.
I believe the problem is with the parameters I pass in for oauth, I used all that params from the above twitter docs article but that was 1.1 so possibly an issue.
Here's my code:
function focus_tweet_getSignature($endpoint, $method, $params, $focus_tweet_api_key_secret, $focus_tweet_access_token_secret)
{
uksort($params, 'strcmp');
foreach ($params as $key => $value) {
$params[$key] = rawurlencode($key) . '=' . rawurlencode($value);
}
$signatureBase = array(
rawurlencode($method),
rawurlencode($endpoint),
rawurlencode(implode('&', $params)),
);
$signatureBaseString = implode('&', $signatureBase);
$signatureKey = array(
rawurlencode($focus_tweet_api_key_secret),
rawurlencode($focus_tweet_access_token_secret),
);
$signatureKeyString = implode('&', $signatureKey);
return base64_encode(hash_hmac('sha1', $signatureBaseString, $signatureKeyString, true));
}
// 'oauth_consumer_key',
// 'oauth_nonce',
// 'oauth_signature',
// 'oauth_signature_method',
// 'oauth_timestamp',
// 'oauth_token',
// 'oauth_version',
// 'status'
function focus_tweet_getAuthorizationString($oauth)
{
$authorizationString = 'Authorization OAuth:';
$count = 0;
foreach ($oauth as $key => $value) {
$authorizationString .= !$count ? ' ' : ', ';
$authorizationString .= rawurlencode($key) . '="' . rawurlencode($value) . '"';
$count++;
}
return $authorizationString;
}
function focus_tweet_makeApiCall( $apiParams, $focus_tweet_status ){
$response = wp_remote_post($apiParams['endpoint'], array(
'method' => $apiParams['method'],
'headers' => array(
array(
'Accept: application/json',
$apiParams['authorization'],
'Expect:'
),
),
'body' => "{
'text': $focus_tweet_status
}",
)
);
//If response is not 200, trigger fatal error
if (is_wp_error($response) || wp_remote_retrieve_response_code($response) != 200) {
//Combine response details and build auth header function
$focus_tweet_res_body = wp_remote_retrieve_body($response);
wp_die($apiParams['authorization'] . '&' . $focus_tweet_res_body);
} else {
wp_die("Tweeted!");
}
}
function focus_tweet_tweet($focus_tweet_status)
{
$focus_tweet_api_key = '';
$focus_tweet_api_key_secret = '';
$focus_tweet_access_token = '';
$focus_tweet_access_token_secret = '';
$oauth = array(
'oauth_consumer_key' => $focus_tweet_api_key,
'oauth_nonce' => md5(microtime() . mt_rand()),
'oauth_signature_method' => 'HMAC-SHA1',
'oauth_token' => $focus_tweet_access_token,
'oauth_timestamp' => time(),
'oauth_version' => '1.0',
'status' => $focus_tweet_status,
);
$oauth['oauth_signature'] = focus_tweet_getSignature('https://api.twitter.com/2/tweets', 'POST', $oauth, $focus_tweet_api_key_secret, $focus_tweet_access_token_secret);
$apiParams = array(
'method' => 'POST',
'endpoint' => 'https://api.twitter.com/2/tweets',
'authorization' => focus_tweet_getAuthorizationString($oauth),
'url_params' => array(),
);
focus_tweet_makeApiCall($apiParams, $focus_tweet_status);
}
Triggered when I save a post for now while I'm testing.
Warning: Array to string conversion in C:\Users\Will\Local Sites\plugintestbench\app\public\wp-includes\class-requests.php on line 800
Authorization OAuth: oauth_consumer_key="", oauth_nonce="", oauth_signature_method="HMAC-SHA1", oauth_token="", oauth_timestamp="1672918493", oauth_version="1.0", status="Hello%20World%21", oauth_signature=""&{ "title": "Unauthorized", "type": "about:blank", "status": 401, "detail": "Unauthorized" }
The warning I believe is fine for now although will fix later.
I have used the credentials to post a tweet from postman so that's not the issue.
I initially believed that it was not possible to use curl in wordpress so may try switching to that although I really believe that the issue is with the oauth params.
(Including twitter/flickr api calls on every page load (WordPress))
Will keep this post updated while I work on this and will ofcourse post the finished github code once it's completed.
I'm learning to use an API. They provide an example of the following authentication code:
curl -X POST --header "Content-Type: application/json" --header "Accept: application/json" -d " {\"Username\": \"the_username\",
\"Password\": \"the_password\"}
" "https://someurl.someapi.com:443/api/Login/Authenticate"
However I need to reproduce this with a Guzzle request. Here is what I've been trying
$headers = [
"Content-Type" => "application/json",
"Accept" => 'application/json -d " {\"Username\": \"the_username\", \"Password\": \"the_password\" }" ',
];
// $headers = [
// "Content-Type" => "application/json"
// ];
$extra_data = ["proxy" => $proxy,
"headers" => $headers ];
// Defining the Guzzle Client to communicate with Legacy.com
$client = new Client([
// Base URI is used with relative requests
'base_uri' => 'https://someurl.someapi.com:443/api/Login/Authenticate',
// You can set any number of default request options.
'timeout' => 10.0,
]);
try {
$response = $client->request('POST', '', $extra_data);
}
However no matter what I try (this was the latest of my failed attempts), I can't get anything other than a code 400 error.
So I finally figured how to do this:
This code worked!
$str = json_decode('{ "Username": "' . $username . '", "Password": "' . $password . '"}',true);
var_dump($str);
if ($str == NULL) return;
$url_authenticate = "Login/Authenticate";
$extra_data = ["proxy" => $proxy,
"json" => $str ];
// Defining the Guzzle Client to communicate with Legacy.com
$client = new Client([
// Base URI is used with relative requests
'base_uri' => 'https://someurl.someapi.com:443/api/',
// You can set any number of default request options.
'timeout' => 10.0,
]);
try {
$response = $client->request('POST', $url_authenticate, $extra_data);
}
catch (Exception $e) {
echo 'Exception: ' . $e->getResponse()->getStatusCode() . "\n";
exit;
}
$body = $response->getBody();
echo $body;
The key was use the json field int the extra data and transform the json to php array using json_decode. I hope this helps someone else
I use the following code to make a new folder using the microsoft graph api:
$tokenCache = new TokenCache();
$accessToken = $tokenCache->getAccessToken();
$graph = new Graph();
$graph->setAccessToken($accessToken);
$queryParams = array(
'name' => 'nameOfnewFolder',
'folder' => new \stdClass(),
'microsoft.graph.conflictBehavior' => 'rename'
);
$url = '/me/drive/root/children?' . http_build_query($queryParams);
return $this->graph->createRequest('POST', $url)
->setReturnType(Model\DriveItem::class)
->execute();
This returns the following error:
Empty Payload. JSON content expected.
What am I doing wrong here?
Found the awnser:
One can add the json using:
->attachBody($queryParams)
as seen here:
return $this->graph->createRequest('POST', $url)->addHeaders(array("Content-Type" => "application/json"))
->attachBody($queryParams)
->setReturnType(Model\DriveItem::class)
->execute();
Since the Google Login Auth is disabled since last week I'm trying to get oAuth 2.0 working with a service account. We want to give users on our internal web application the oppurtunity to set there Out of Office.
I downloaded the lastest Google APIs Client Library for PHP. In the Google Developer Console, I have created a new project for my application and created a Service account credentials. I have also enabled the API service: Admin SDK in the Developer Console.
I have granted the account user ID access to the correct scopes (I think):
When I use the service-account.php example and change the details, I recieve an JSON with an access token, but when I do an CURL request (same as before) to get the e-mail settings from a user, the error "You are not authorized to access this API." occur.
My code:
<?php
include_once "templates/base.php";
require_once realpath(dirname(__FILE__) . '/../src/Google/autoload.php');
$client_id = '124331845-DELETEDPART-hbh89pbgl20citf6ko.apps.googleusercontent.com'; //Client ID
$service_account_name = '124331845-DELETEDPART-89pbgl20citf6ko#developer.gserviceaccount.com'; //Email Address
$key_file_location = 'globaltext-4ce09b20cb73.p12'; //key.p12
$client = new Google_Client();
if (isset($_SESSION['service_token'])) {
$client->setAccessToken($_SESSION['service_token']);
}
$key = file_get_contents($key_file_location);
$cred = new Google_Auth_AssertionCredentials(
$service_account_name,
array('https://apps-apis.google.com/a/feeds/emailsettings/2.0/'),
$key
);
$client->setAssertionCredentials($cred);
if ($client->getAuth()->isAccessTokenExpired()) {
$client->getAuth()->refreshTokenWithAssertion($cred);
}
$aOutput = json_decode($client->getAccessToken());
$strEmailAdresSplit = explode('#', "FIRSTNAME.LASTNAME#DOMAIN.EXTENSION");
$strDomein = $strEmailAdresSplit[1];
$strAlias = $strEmailAdresSplit[0];
$resConnectionJobs = curl_init();
$aHeader = array();
$aHeader[] = 'Authorization: Bearer '.$aOutput->access_token;
$aHeader[] = 'Content-Type: application/atom+xml';
curl_setopt($resConnectionJobs, CURLOPT_URL, "https://apps-apis.google.com/a/feeds/emailsettings/2.0/DOMAIN.EXTENSION/FIRSTNAME.LASTNAME/vacation");
curl_setopt($resConnectionJobs, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($resConnectionJobs, CURLOPT_HTTPHEADER, $aHeader);
curl_setopt($resConnectionJobs, CURLOPT_RETURNTRANSFER, true);
curl_setopt($resConnectionJobs, CURLOPT_HEADER, false);
$oCurlData = curl_exec($resConnectionJobs);
curl_close($resConnectionJobs);
echo $oCurlData;
?>
Are you certain your credentials are OK?
Please try the following procedure to make sure you have the right credentials.
Creating your API keys
Go to the developer's console and follow these steps:
Select your project
Choose menu item "APIs & auth"
Choose menu item "Registered app"
Register an app of type "web application"
Choose one of the following options, depending on what kind of app you're creating. Server side languages should use this option :
Key for server apps (with IP locking)
Getting access token & refresh token
Create a file that contains the following code :
<?php
if (isset($_GET['code'])) {
// try to get an access token
$code = $_GET['code'];
$url = 'https://accounts.google.com/o/oauth2/token';
$params = array(
"code" => $code,
"client_id" => YOUR_CLIENT_ID,
"client_secret" => YOUR_CLIENT_SECRET,
"redirect_uri" => 'http://' . $_SERVER["HTTP_HOST"] . $_SERVER["PHP_SELF"],
"grant_type" => "authorization_code"
);
$ch = curl_init();
curl_setopt($ch, constant("CURLOPT_" . 'URL'), $url);
curl_setopt($ch, constant("CURLOPT_" . 'POST'), true);
curl_setopt($ch, constant("CURLOPT_" . 'POSTFIELDS'), $params);
$output = curl_exec($ch);
$info = curl_getinfo($ch);
curl_close($ch);
if ($info['http_code'] === 200) {
header('Content-Type: ' . $info['content_type']);
return $output;
} else {
return 'An error happened';
}
} else {
$url = "https://accounts.google.com/o/oauth2/auth";
$params = array(
"response_type" => "code",
"client_id" => YOUR_CLIENT_ID,
"redirect_uri" => 'http://' . $_SERVER["HTTP_HOST"] . $_SERVER["PHP_SELF"],
"scope" => "https://www.googleapis.com/auth/plus.me"
);
$request_to = $url . '?' . http_build_query($params);
header("Location: " . $request_to);
}
Now, replace YOUR_CLIENT_ID and YOUR_CLIENT_SECRET with your client ID and client secret.
Make sure your scope is correct. For example, it should be https://www.googleapis.com/auth/analytics if you want to get access to Analytics.
If you run the file, you should get an OAuth2 approval screen.
If you now press Accept, you should get a result that looks like this:
{
"access_token" : YOUR_ACCESS_TOKEN,
"token_type" : "Bearer",
"expires_in" : 3600,
"refresh_token" : YOUR_REFRESH_TOKEN
}
The result may contain additional fields, depending on which scope you're applying for.
Connecting with Google's systems in background
Once you get the above to work, your application needs to implement the following workflow:
1) Check if your input contains a GET parameter named "code". If "code" is present, get a new access token and repeat this step (refresh your page)
If "code" is not present, go to step 2.
2) Check if you have credentials stored for your service. If credentials are present, check if your access token has expired or will expire soon. Then go to step 3. If credentials are not present, go to the auth path of your service to get the auth code and go back to step 1 (make sure Google redirects to your current URL).
3) If refresh is needed, refresh your page and go back to step 1.
If refresh is not needed, you're ready to actually do what you wanted to do in the first place.
Google's PHP library takes care if the oAuth2 flow for you, however. If you're using their library, each of the steps in the 3-step process are taken care of by the library and you should just be able to do whatever you want to do with Google's services straight away. I use this strategy myself in my Google Adwords dashboard.
You can, however, just write your custom library and connect with the service directly. Herebelow is some dev code from a project I wrote a few months ago. While it doesn't work out of the box (since it's a controller that's part of a larger application), it should help you understand the flow that Google's library takes care of under the hood.
namespace Application;
class Controller_API_Google_Youtube extends Controller_API {
public function read() {
$scope = "https://www.googleapis.com/auth/youtube";
$this->doOauth($scope);
}
function doOauth($scope) {
$oauth2Credentials = JSON_File::load(__DIR__ . DIRECTORY_SEPARATOR . 'Config.json');
$paths = array(
'token' => 'https://accounts.google.com/o/oauth2/token',
'auth' => "https://accounts.google.com/o/oauth2/auth"
);
$refreshtime = 300;
if (isset($_GET['code'])) {
// Get access code
$query = $_GET;
unset($query['code']);
if (count($query) > 0) {
$query = '?' . http_build_query($query);
} else {
$query = '';
}
$client = \PowerTools\HTTP_Client::factory(
array(
'maps' => array(
'url' => $paths['token'],
'returntransfer' => 1,
'post' => true,
'postfields' => array(
'code' => $_GET['code'],
"client_id" => $oauth2Credentials['client_id'],
"client_secret" => $oauth2Credentials['client_secret'],
"redirect_uri" => HTTP_PROTOCOL . URL_PATH . $query,
"grant_type" => "authorization_code"
)
)
)
)->execute();
$responses = $client->getResponses();
$response = array_pop($responses);
$info = $response['maps']->getInfo();
$content = $response['maps']->getContent();
if ($info['http_code'] === 200) {
$output = JSON::decode($content);
$oauth2Credentials[$scope] = array();
$oauth2Credentials[$scope]['expires'] = time() + $output['expires_in'];
$oauth2Credentials[$scope]['access_token'] = $output['access_token'];
$oauth2Credentials[$scope]['refresh_token'] = $output['refresh_token'];
file_put_contents(__DIR__ . DIRECTORY_SEPARATOR . 'Config.json', JSON::encode($oauth2Credentials));
header("Location: " . HTTP_PROTOCOL . URL_PATH . $query);
} else {
echo "Something went wrong";
}
} elseif (!isset($oauth2Credentials[$scope])) {
// Get auth code
header("Location: " . $paths['auth'] . '?' . http_build_query(
array(
"response_type" => "code",
"client_id" => $oauth2Credentials['client_id'],
"redirect_uri" => HTTP_PROTOCOL . DOMAIN_PATH,
"scope" => $scope
)
));
} elseif ($oauth2Credentials[$scope]['expires'] - $refreshtime < time()) {
// Refresh access code
$client = \PowerTools\HTTP_Client::factory(
array(
'maps' => array(
'url' => $paths['token'],
'returntransfer' => 1,
'post' => true,
'postfields' => array(
"client_id" => $oauth2Credentials['client_id'],
"client_secret" => $oauth2Credentials['client_secret'],
"refresh_token" => $oauth2Credentials[$scope]['refresh_token'],
"grant_type" => "refresh_token"
)
)
)
)->execute();
$responses = $client->getResponses();
$response = array_pop($responses);
$info = $response['maps']->getInfo();
$content = $response['maps']->getContent();
if ($info['http_code'] === 200) {
$output = JSON::decode($response['maps']->getContent());
$oauth2Credentials[$scope]['expires'] = time() + $output['expires_in'];
$oauth2Credentials[$scope]['access_token'] = $output['access_token'];
file_put_contents(__DIR__ . DIRECTORY_SEPARATOR . 'Config.json', JSON::encode($oauth2Credentials));
$this->read();
} else {
$this->output = array("error" => "Something went wrong");
}
} else {
$this->doSomethinguseful($oauth2Credentials, $scope);
}
return $this;
}
function doSomethinguseful($oauth2Credentials, $scope) {
// https://developers.google.com/youtube/v3/sample_requests?hl=nl
$client = \PowerTools\HTTP_Client::factory(
array(
'maps' => array(
'useragent' => 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.13) Gecko/20080311 Firefox/2.0.0.13',
'url' => 'https://www.googleapis.com/youtube/v3/channels?part=contentDetails&mine=true',
'returntransfer' => true,
'httpheader' => array(
'Authorization: Bearer ' . $oauth2Credentials[$scope]['access_token'],
'Accept-Encoding: gzip, deflate'
)
)
)
)->execute();
$responses = $client->getResponses();
$response = array_pop($responses);
$content = $response['maps']->getContent();
$this->output = JSON::decode(gzdecode($content));
}
}
It looks like you may be running into a problem I had as well.
The call to Google_Auth_AssertionCredentials actually requires more parameters than you're sending to work with a service account. (At least, it did in my case.)
You need to pass enough parameters to include sub (which user to take actions on account of).
Without that, I always got an access denied. This clearly isn't obvious, since there's even been a function added to the php library, loadServiceAccountJson, which is supposed to set up a service account client connection, but breaks because it doesn't set sub either.
See working code here: Google php client library loadServiceAccountJson broken - fix enclosed
I have a bucket created in ap-southeast-1 region with ACL set to private-read. I am able to successfully upload files to folders inside the bucket using the AWS PHP SDK 2 S3Client class. However, I also need to display a link to these files in my application. Hence, when a user clicks a button, I send an AJAX request to my server file, and I get the signedURL which is returned back to the user via json string. However, the url always returns with an XML with error SignatureDoesNotMatch.
Code for getting the signedURL below:
//create the AWS reference string
$client = S3Client::factory(
array(
'key' => T_AWS_KEY,
'secret' => T_AWS_SECRET,
'region' => T_BASE_REGION
)
);
//method 1 - using Command Object
$command = $client->getCommand('GetObject', array(
'Bucket' => T_BASE_BUCKET . "/" . $firmId . "/invoices" ,
'Key' => $arr['file_reference_url'] ,
'ResponseContentDisposition' => 'attachment;filename=' . arr['file_reference_url']
));
$signedUrl = $command->createPresignedUrl('+10 minutes');
echo $signedUrl . "\n\n";
//method 2 - using getObjectUrl
echo $client->getObjectUrl(T_BASE_BUCKET . "/" . $firmId . "/invoices", $arr['file_reference_url'], "+10 minutes");
Any help is appreciated.
It seems you may be confused about what buckets are. Buckets are not nested. It's likely that the value of T_BASE_BUCKET is your bucket and the other parts are part of the object key. Give this a shot:
$objectKey = $firmId . '/invoices/' . $arr['file_reference_url'];
echo $client->getObjectUrl(T_BASE_BUCKET, $objectKey, '+10 minutes');