I'm new to PHP development
I'm trying to learn by implementing some real projects for fun.
So I tried to build a bitcoin app where customers can pay in cryptocurrency.
So I start with Coinbase commerce API
I successfully implement the charge page and everything is working well until I reached the point where I have to deal with WEBHOOKS 😔
I'm following this documentation
https://github.com/coinbase/coinbase-commerce-php/blob/master/README.md
And that's the WEBHOOKs code
`<?php
require_once __DIR__ . "/vendor/autoload.php";
use CoinbaseCommerce\Webhook;
/**
* To run this example please read README.md file
* Past your Webhook Secret Key from Settings/Webhook section
* Make sure you don't store your Secret Key in your source code!
*/
$secret = 'SECRET_KEY';
$headerName = 'X-Cc-Webhook-Signature';
$headers = getallheaders();
$signraturHeader = isset($headers[$headerName]) ? $headers[$headerName] : null;
$payload = trim(file_get_contents('php://input'));
try {
$event = Webhook::buildEvent($payload, $signraturHeader, $secret);
http_response_code(200);
echo sprintf('Successully verified event with id %s and type %s.', $event->id, $event->type);
} catch (\Exception $exception) {
http_response_code(400);
echo 'Error occured. ' . $exception->getMessage();
}
`
When I access to the we hooks URL I got this error
Error occured. Invalid payload provided. No JSON object could be decoded
Please 🙏 I want someone to explain to me this error
Thanks in advance.
Seems like you are making a GET (No payload data) request to a url that is expecting a POST (Has payload data) request from the web-hook.
To test API's with POST, PUT, GET requests, you can use tools like PostMan.
You can build JSON payloads manually and test your endpoints.
Try this
$headerName = 'x-cc-webhook-signature';
$signraturHeader = isset($headers[$headerName]) ? $headers[$headerName] : null;
instead of
$headerName = 'X-Cc-Webhook-Signature';
$signraturHeader = isset($headers[$headerName]) ? $headers[$headerName] : null;
Related
I am trying to implement the new "Sign in with Google" button as described in https://developers.google.com/identity/gsi/web/guides/display-button.
Everything is fine, and I am able to get a response from the button with "credential" and "g_csrf_token" elements, which I can send to my server. However, using the Google API Client to decode the credential doesn't work. I'm trying to follow the instructions.
Here's my code:
$id_token = filter_input(INPUT_POST, 'credential');
$csrfToken = filter_input(INPUT_POST, 'g_csrf_token'); //??? Do we need this?
$client = new Google_Client(['client_id' => $clientid]);
$client->addScope("email"); // Recommended in another StackOverflow answer but makes no difference
try {
$payload = $client->verifyIdToken($id_token);
} catch(Exception $ex) {
$errorMessage = "Error in verifyIdToken():" . $ex->getMessage();
// ...do stuff with the error message
}
// ...do stuff with the returned payload
The result is the error message id_token must be passed in or set as part of setAccessToken.
I've updated my Google API Client to v2.11.
I assume that I've missed a step somewhere - can someone help?
Have found a solution, by trial and error! Turns out that $id_token needs to be passed to the client twice, once in setAccessToken() and then again in verifyIdToken(). Omitting setAccessToken fails (like the error message says), but if you pass it in setAccessToken but NOT in verifyIdToken, that doesn't work either.
$id_token = filter_input(INPUT_POST, 'credential');
$client = new Google_Client(['client_id' => $clientid]);
try {
$client->setAccessToken($id_token);
$payload = $client->verifyIdToken($id_token);
} catch(Exception $ex) {
$errorMessage = "Error in verifyIdToken():" . $ex->getMessage();
// ...do stuff with the error message
}
// ...do stuff with the returned payload
It would nice, if you're at Google and picking this up, if you updated the documentation.
While developing Recaptcha Enterprise for use of the V2 "I am not a robot" checkbox, I am stuck on this error:
Fatal error: Uncaught DomainException: Could not load the default credentials. Browse to https://developers.google.com/accounts/docs/application-default-credentials for more information
I follow the link and have settled on this to authenticate:
use Google\Cloud\Storage\StorageClient;
$storage = new StorageClient([
'keyFile' => json_decode(file_get_contents($path_to_keyfile), true),
'projectId' => 'MY_PROJECT'
]);
I cannot find anything else that suggests I need to do anything more than this, and this link to the constructor API doesn't suggest I can pass it in as a parameter and then proceed. I do not want to use environment variables for this project, I want to connect manually in the code. What am I missing? I can confirm I have a working service account.
If it's helpful, the code I'm trying to run after I presumably authenticate is this:
// ==================== CAPTCHA ===================
use Google\Cloud\RecaptchaEnterprise\V1\RecaptchaEnterpriseServiceClient;
use Google\Cloud\RecaptchaEnterprise\V1\Event;
use Google\Cloud\RecaptchaEnterprise\V1\Assessment;
use Google\Cloud\RecaptchaEnterprise\V1\TokenProperties\InvalidReason;
$captcha_response = $_POST['g-recaptcha-response'];
$site_key = "123456789abc";
$client = new RecaptchaEnterpriseServiceClient();
define('SITE_KEY', $site_key);
define('TOKEN', $captcha_response);
define('PROTECTED_ACTION', 'signup');
define('PARENT_PROJECT', 'projects/MY_PROJECT');
$event = (new Event())
->setSiteKey(SITE_KEY)
->setExpectedAction(PROTECTED_ACTION)
->setToken(TOKEN);
$assessment = (new Assessment())
->setEvent($event);
try {
$response = $client->createAssessment(
PARENT_PROJECT,
$assessment
);
if ($response->getTokenProperties()->getValid() == false) {
printf('The CreateAssessment() call failed because the token was invalid for the following reason: ');
printf(InvalidReason::name($response->getTokenProperties()->getInvalidReason()));
} else {
if ($response->getEvent()->getExpectedAction() == PROTECTED_ACTION) {
printf('The score for the protection action is:');
printf($response->getRiskAnalysis()->getScore());
}
else
{
printf('The action attribute in your reCAPTCHA tag does not match the action you are expecting to score');
}
}
} catch (exception $e) {
printf('CreateAssessment() call failed with the following error: ');
printf($e);
}
Here's how I got it working. Thanks to John Hanley for the help in a previous answer. The documentation had lead me to believe that (for whatever reason) Storage was required, but that was not the case: it was as simple as providing the path to the key via the credentials parameter. Not the keyFile parameter.
if (empty($_POST['g-recaptcha-response']))
die("You have failed the not-a-robot check.");
$captcha_response = $_POST['g-recaptcha-response'];
require 'composer/vendor/autoload.php';
use Google\Cloud\RecaptchaEnterprise\V1\RecaptchaEnterpriseServiceClient;
use Google\Cloud\RecaptchaEnterprise\V1\Event;
use Google\Cloud\RecaptchaEnterprise\V1\Assessment;
use Google\Cloud\RecaptchaEnterprise\V1\TokenProperties\InvalidReason;
$path_to_keyfile = "MY_PROJECT-1234567890abc.json";
$site_key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
$client = new RecaptchaEnterpriseServiceClient([
'credentials' => $path_to_keyfile,
'projectId' => 'MY_PROJECT'
]);
define('SITE_KEY', $site_key);
define('TOKEN', $captcha_response);
define('PROTECTED_ACTION', 'signup');
define('PARENT_PROJECT', 'projects/MY_PROJECT');
$event = (new Event())
->setSiteKey(SITE_KEY)
->setExpectedAction(PROTECTED_ACTION)
->setToken(TOKEN);
$assessment = (new Assessment())
->setEvent($event);
try {
$response = $client->createAssessment(PARENT_PROJECT, $assessment);
if ($response->getTokenProperties()->getValid() == false) {
printf('The CreateAssessment() call failed because the token was invalid for the following reason: ');
printf(InvalidReason::name($response->getTokenProperties()->getInvalidReason()));
exit;
} else {
if ($response->getEvent()->getExpectedAction() == PROTECTED_ACTION) {
// Closer to 1 = human, to 0 = robot.
$bot_score = $response->getRiskAnalysis()->getScore();
// do what you want with the score here...
} else {
die('The action attribute in your reCAPTCHA tag does not match the action you are expecting to score');
}
}
} catch (exception $e) {
printf('CreateAssessment() call failed with the following error: ');
printf($e);
exit;
}
Your problem is that you are not specifying the service account to use in the client constructor and the system is falling back to using ADC (Application Default Credentials).
ADC will check the environment variable GOOGLE_APPLICATION_CREDENTIALS for the service account JSON key file.
You can set the environment variable before running your program:
Windows:
set GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account.json
Linux:
export GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account.json
Or modify your program by changing this line of code:
$client = new RecaptchaEnterpriseServiceClient();
To this:
$options = ['keyFile' => $path_to_keyfile];
$client = new RecaptchaEnterpriseServiceClient($options);
Note 1:
If you are running your program on a Google Cloud computer service such as Compute Engine, App Engine, Cloud Run, ... the default service account will be used if neither of the above methods are implemented.
Note 2:
While developing, another method is to use the CLI's application default credentials. Run the following command using the Google Cloud SDK CLI:
gcloud auth application-default login
However, I have not verified that the reCAPTCHA Enterprise library checks for this type of credential.
I am using twitter account activity api's to send/receive messages. In it i am facing problem in generating webhook. First time it was created successfully. In webhook file i am saving messages in database when each time message sent or received. But when I sent message nothing goes in database. Here is webhook file:
const APP_CONSUMER_SECRET = '**********';
// Example token provided by incoming GET request
if(isset($_REQUEST['crc_token'])) {
$token = $_REQUEST['crc_token'];
/**
* Creates a HMAC SHA-256 hash created from the app TOKEN and
* your app Consumer Secret.
* #param token the token provided by the incoming GET request
* #return string
*/
function get_challenge_response($token) {
$hash = hash_hmac('sha256', $token, APP_CONSUMER_SECRET, true);
$response = array(
'response_token' => 'sha256=' . base64_encode($hash)
);
return json_encode($response);
}
}else{
$feedData = file_get_contents('php://input');
$handleData = fopen('twitterDemo.txt', "w" );
fwrite($handleData,$feedData);
fclose($handleData);
$array = json_decode(file_get_contents('php://input'), true);
if (isset($array['direct_message_events'][0]['type']) && $array['direct_message_events'][0]['type'] == 'message_create' ) {
include_once ('config.php');
include_once ('database-queries.php');
$message = $array['direct_message_events'][0]['message_create']['message_data']['text'];
$sender = $array['direct_message_events'][0]['message_create']['sender_id'];
$from = $array['direct_message_events'][0]['message_create']['target']['recipient_id'];
$message_type = 'incoming';
$message_status = 'unread';
$userId = $sender;
$account_name = 'twitter';
$image_url = '';
if(isset($array['direct_message_events'][0]['message_create']['message_data']['attachment'])){
$image_url = "Not Image";
}
$data = array('to'=>$from, 'from'=>$sender, 'msg'=>$message,'image_url' =>$image_url);
insert($data, $account_name, $message_type, $message_status, $conn);
}
}
I thought there might be webhook problem so i deleted the existing app and create new one and set development environment label for it with new name. But for it when i tried to create webhook it gives me error:
[code] => 214 [message] => Webhook URL does not meet the requirements.
Invalid CRC token or json response format.
I dont know whats happening here now. I am using this api to create webhook url
$url = "https://example.com/twitter/webhook.php";
$result = $connection->post("account_activity/all/env_name/webhooks", ["url" => $url]);
Can anyone please help me this out. Any help will be appreciated.
Thanks!
I ran into the same error message.
The problem seem to be that the
if(isset($_REQUEST['crc_token']))
is not working anymore. Though the token is set. I don't know what is causing the problem but when I let the code just fetch the $_REQUEST['crc_token'] and create and print the hash its working.
But I see your code is not calling the get_challenge_response($token) function.
I think
print get_challenge_response($token)
may help? If the Webhook was deactivated by twitter you have to initiate another CRC check:
https://developer.twitter.com/en/docs/twitter-api/v1/accounts-and-users/subscribe-account-activity/guides/securing-webhooks
Your app can also trigger a CRC when needed by making a PUT request with your webhook id. Triggering a CRC is useful as you develop your webhook application, after deploying new code and restarting your service.
I would like to use dailymotion api to get infos of my own private videos.
SO ...
I have a Dailymotion account
I have created an API key and secret key
I downloaded the PHP class
I would like to get infos of my privates videos to diplay it on my website...
So i think I need to authenticate my account and after get the code...
but it does not work :'(
Please could you give me a sample code to do this ?
my test code is like that for now
<?php
error_reporting(E_ALL & ~E_NOTICE);
ini_set('display_errors', 1);
$apiKey = 'xxxx';
$apiSecret = 'xxxx';
require_once 'Dailymotion.php';
// Instanciate the PHP SDK.
$api = new Dailymotion();
// Tell the SDK what kind of authentication you'd like to use.
// Because the SDK works with lazy authentication, no request is performed at this point.
$api->setGrantType(Dailymotion::GRANT_TYPE_AUTHORIZATION, $apiKey, $apiSecret);
$api = new Dailymotion();
try
{
$result = $api->get(
'/video/privateVideoId',
array('fields' => array('id', 'title', 'owner'))
);
}
catch (DailymotionAuthRequiredException $e)
{
echo $e->getMessage();
// If the SDK doesn't have any access token stored in memory, it tries to
// redirect the user to the Dailymotion authorization page for authentication.
//return header('Location: ' . $api->getAuthorizationUrl());
}
catch (DailymotionAuthRefusedException $e)
{
echo $e->getMessage();
// Handle the situation when the user refused to authorize and came back here.
// <YOUR CODE>
}
trace($result);
function trace($d) {
echo '<pre>';
var_dump($d);
echo '</pre>';
}
?>
and the result is :
This user is not allowed to access this video.
so i think there is a problem with authentication ... but i do not understant how to do that only with php
thanks a lot for your help
It looks like there are a couple of issues in your code and in the way you authenticate:
1) your code: you call $api = new Dailymotion(); and then set the authorization grant type with your api key and secret. But next line, you override all that by re-writing $api = new Dailymotion();. So I recommend you to remove this line, otherwise it is like you have not set any grant type!
2) There is an interesting code sample regarding authorization grant type in php, doing exactly what you're trying to do, at https://developer.dailymotion.com/tools/sdks#sdk-php-grant-authorization
Your code is very similar, why did you comment the return header('Location: ' . $api->getAuthorizationUrl()); part when catching DailymotionAuthRequiredException ? This part redirects the user to the auth page so he/she can authenticate.
I also recommend to have a look at others grant types for authentication, such as password grant type (https://developer.dailymotion.com/tools/sdks#sdk-php-grant-password)
I want to allow anyone register on my site, to upload their videos on my own youtube user channel.
I don't want them to comment any videos, or anything that requires their own login credentials.
Should I use: ClientLogin authorization ?
If so, how can I get a token so that I can allow my site to interact with my youtube channel account?
Any lights here will be greatly appreciated, since I'm kinda lost here.
I have accomplished this using ClientLogin. A basic class is below. This class returns an instance of Zend HTTP Client that is ready to make authenticated requests.
<?php
class GoogleAuthenticator {
public static function authenticate($logger) {
$tokenObj = new Token();
try {
$token = $tokenObj->get($token_name);
if(!empty($token)) {
//load a new HTTP client with our token
$logger->info('Using cached token: ' . $token);
$httpClient = new Zend_Gdata_HttpClient();
$httpClient->setConfig(array(
'maxredirects' => 0,
'strictredirects' => true,
'useragent' => 'uploader/v1' . ' Zend_Framework_Gdata/' . Zend_Version::VERSION
)
);
$httpClient->setClientLoginToken($token);
//attempt to use our token to make an authenticated request. If the token is invalid
// an exception will be raised and we can catch this below
$yt = new Zend_Gdata_YouTube($httpClient, 'uploader/v1', '', $youtube_api_key);
$query = new Zend_Gdata_YouTube_VideoQuery();
$query->setFeedType('top rated');
$query->setMaxResults(1);
$yt->getPlaylistListFeed(null, $query); //ignore the response!
} else {
$logger->info('Generating new HTTP client');
// Need to create a brand new client+authentication
$authenticationURL= 'https://www.google.com/youtube/accounts/ClientLogin';
$httpClient =
Zend_Gdata_ClientLogin::getHttpClient(
$username = YOUTUBE_USERNAME_PROD,
$password = YOUTUBE_PASSWORD_PROD,
$service = 'youtube',
$client = null,
$source = 'uploader/v1',
$loginToken = null,
$loginCaptcha = null,
$authenticationURL);
// get the token so we can cache it for later
$token = $httpClient->getClientLoginToken();
$tokenObj->destroy($token_name);
$tokenObj->insert($token, $token_name);
}
return $httpClient;
}catch(Zend_Gdata_App_AuthException $e) {
$tokenObj->destroy($token_name);
die("Google Authentication error: " . $e->getMessage());
}catch(Exception $e) {
$tokenObj->destroy($token_name);
die("General error: " . $e->getMessage());
}
} // authenticate()
} // GoogleAuthenticator
?>
You'll need to have these constants defined:
YOUTUBE_USERNAME_PROD
YOUTUBE_PASSWORD_PROD
Or modify the class to pass them in. The try/catch is needed because tokens can expire, so you need to a way to refresh them. Also, you need to make a dummy request to ensure the Token is valid even after you create it.
Keep in mind that YouTube (well, as of 2 years ago or so) prevented you from uploading a video more of than every 10 minutes, which makes your use-case pretty difficult. That is, you cannot allow multiple videos being uploaded on a single accounts behalf, more of than every 10 min. But YouTube might have lifted this since then. Good luck
Since I didn't find any complete solutions for API V3 in the documentation I've been exploring the Internet for a solution. In the end I ported the Python example to PHP and wrote a blog post about it for other people that have the same problem:
Uploading a video to youtube through api version 3 in PHP
This blogpost uses the Youtube V3 api with OAuth2 so you don't have to worry about it being deprecated. All other functions (ClientLogin, AuthSub and OAuth 1.0) in V2 are all deprecated as of April 20, 2012.