I have created an online store with Paystack gateway implemented.
Up till now it's been successful, but I need a little help with creating a webhook event script, such that if user never redirects to the callback URL to be given value, I can get notified to give user value.
The functionality of my script should throw more light on this..
INITIALIZE.PHP SCRIPT
<?php
session_start();
if(isset($_POST["pay"])){
$curl = curl_init();
$email = $_SESSION["order_details"]["email"];
$amount = $_SESSION["order_details"]["total"]; //the amount in kobo. This value is actually NGN 300
// url to go to after payment
$callback_url = 'http://localhost:8080/phpmyadmin/online_store/order.php';
curl_setopt_array($curl, array(
CURLOPT_URL => "https://api.paystack.co/transaction/initialize",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'amount'=>$amount,
'email'=>$email,
'callback_url' => $callback_url
]),
CURLOPT_HTTPHEADER => [
"authorization: Bearer sk_test_2563a843c7ddd24e92450fe2ce91f3f18a57ad27", //replace this with your own test key
"content-type: application/json",
"cache-control: no-cache"
],
));
$response = curl_exec($curl);
$err = curl_error($curl);
if($err){
// there was an error contacting the Paystack API
die('Curl returned error: ' . $err);
}
$tranx = json_decode($response, true);
if(!$tranx['status']){
// there was an error from the API
print_r('API returned error: ' . $tranx['message']);
}
// comment out this line if you want to redirect the user to the payment page print_r($tranx);
// redirect to page so User can pay
// uncomment this line to allow the user redirect to the payment page
header('Location: ' .
$tranx['data']['authorization_url']);
}
?>
CALLBACK SCRIPT
$curl = curl_init();
$reference = isset($_GET['reference']) ? $_GET['reference'] : '';
if(!$reference){
die('No reference supplied');
}
curl_setopt_array($curl, array(
CURLOPT_URL => "https://api.paystack.co/transaction/verify/" . rawurlencode($reference),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
"accept: application/json",
"authorization: Bearer sk_test_2563a843c7ddd24e92450fe2ce91f3f18a57ad27",
"cache-control: no-cache"
],
));
$response = curl_exec($curl);
$err = curl_error($curl);
if($err){
// there was an error contacting the Paystack API
die('Curl returned error: ' . $err);
}
$tranx = json_decode($response);
if(!$tranx->status){
// there was an error from the API
die('API returned error: ' . $tranx->message);
}
if('success' == $tranx->data->status){
// Rest part of the code that gives value to user, adds ordered items and payment info to database, sends email and delete the cart items or unset session (depending if a client or guest)
}
My script allows the user to make payments first by processing the payment through the initialize.php file before inserting Information into the Database through the call back script(order.php)
The problem is something can occur after successful payment and user might not be directed to the callback script to be given value to, so how do I use a webhook to give value to user if he/she wasn't directed to the callback script ?
Thanks in Advance
Go through this documentation. It has all your answer related to webhooks.
You can specify your webhook URL (SITEURL/path/to/webhook.php) on your dashboard where paystack would send POST requests to whenever an event occurs.
All you have to do to receive the event is to create an unauthenticated POST route on your application (SITEURL/path/to/webhook.php). The event object is sent as JSON in the request body.
You can use this type of code in webhook.php to receive webhook response
<?php
// Retrieve the request's body and parse it as JSON
$input = #file_get_contents("php://input");
$event = json_decode($input);
// Do something with $event
http_response_code(200); // PHP 5.4 or greater
?>
Between the web hook event and call back event, which one occurs first? If the callback happens first, then with the web hook, a check can be made in the database to know if transact exist.
Related
I need to add some functionality to my site to connect via REST to a provider and exchange data. I've used Postman for several years to test these APIs for myself and customers, but this is the first time I have tried to add the functionality to my site.
I've Googled numerous sites. I tried a few different things. First I tried the league/oauth2-client library. The requests went through without any errors, but all I received back was a response like this.
JSON response = {"status":"400","timeStamp":"2022-01-22T16:21:19+0000","error":{"errorId":"ea7bc74d-21ca-4503-92ad-3a76b05d7554","message":null,"code":"invalid_request","description":"Cannot generate token. Bad request","details":null}}
So I went to look at other examples. I found this nice and simple code from
UC San Diego Example for Client Credentials. I tried it and got the same type of results. "Cannot generate token. Bad request." For now, I like the simple option of the UCSD example if I can make it work.
As I said, I can successfully make this request and use the API all day long in Postman. So I know the Client ID, Client Secret, and URL are correct.
Unfortunately, I don't know how to troubleshoot this in PHP. I looked in the server log and I didn't find any errors. I tried to echo something out to see if I could see what was wrong, but I couldn't get the request to echo to the page. I tried using Fiddler to see if I could find the request with no luck.
Here's where I am right now. Any suggestions for what I am missing?
Thanks in advance for your help!
<?php
$token_url = "https://xxxx.xxxxx.com/services/api/oauth2/token";
$test_api_url = "https://xxxx.xxxxx.com/services/api/x/users/v2/employees/12345";
// client (application) credentials on xxxx.xxxxxx.com
$client_id = "xxxxxxxxxxx";
$client_secret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
$access_token = getAccessToken();
$resource = getResource($access_token);
echo "</br>access_token = " . $access_token;
echo "</br>resource = " . $resource;
// step A, B - single call with client credentials as the basic auth header
// will return access_token
function getAccessToken() {
global $token_url, $client_id, $client_secret;
$content = "grant_type=client_credentials";
$authorization = base64_encode("$client_id:$client_secret");
$header = array("Authorization: Basic {$authorization}","Content-Type: application/x-www-form-urlencoded");
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => $token_url,
CURLOPT_HTTPHEADER => $header,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $content
));
$response = curl_exec($curl);
curl_close($curl);
echo "</br>JSON response = " . $response;
return json_decode($response)->access_token;
}
// step B - with the returned access_token we can make as many calls as we want
function getResource($access_token) {
global $test_api_url;
$header = array("Authorization: Bearer {$access_token}");
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => $test_api_url,
CURLOPT_HTTPHEADER => $header,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_RETURNTRANSFER => true
));
$response = curl_exec($curl);
curl_close($curl);
return json_decode($response, true);
}
?>
So it seems that with a little bit of research and learning on my part the answer to my question was in Postman. Postman includes a feature that will translate your request into any number of code languages.
All I had to do was select the PHP option and copy and paste the results into my project. Boom, there you go. That was easy.
Here's a YouTube video showing how it works.
Postman: Import/Export and Generating Code Samples
Hi I know that there are similar questions already in there but I have ruled them out.
So I am trying to make a simple POST method with curl and keep getting error 500. Have I missed something ?
// Get cURL resource
$curl = curl_init();
//POST request body
$post_data = array(
'subscription_uuid' => $subscription_uuid,
'merchant' => $merchant_id
);
echo "JSON in POSTFIELDS:" . json_encode($post_data, JSON_PRETTY_PRINT) . "\n";
// Set Headers, endpoint and option to output response as string
curl_setopt_array($curl, array(
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_URL => 'https://subscriptions-jwt.fortumo.io/subscriptions/cancel',
CURLOPT_POST => 1,
CURLOPT_HTTPHEADER => array(
'Content Type: application/json' ,
'Authorization: Bearer' . " " . $jwt
),
CURLOPT_POSTFIELDS => json_encode($post_data)
));
// Send the request & save response
$unsubscribe_response = curl_exec($curl);
$statusCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
//Request URL:
echo "Unsubscribe Request URL:\n" . curl_getinfo($curl, CURLINFO_EFFECTIVE_URL) . "\n";
echo "Error Code:" . $statusCode . "\n";
And here is the response I get from that code block(simplified this using echo-s):
JSON in POSTFIELDS:{
"subscription_uuid": "<<MY-TOKEN>>",
"merchant": "<<MY-TOKEN>>"
}
Unsubscribe Request URL:
https://subscriptions-jwt.fortumo.io/subscriptions/cancel
Error Code:500
Wierd thing is that using exactly same set of headers, JSON postfields and URL in a tool such as Advanced REST client everything works fine and I get 200 response with no problem.
Something is wrong with my code. Can anyone please spot the issue? Thanks in advance!
I am integrating some custom pages into WordPress. These pages are link to another external application using APIs.
I have this section that links to PayPal, and upon receiving POST data from PayPal will run a file.
basically this is my file structure :-
wp-content/themes/myTheme/ipn
wp-content/themes/myTheme/ipn/ipnconfig.php
wp-content/themes/myTheme/ipn/ipn.php
After successful payment, I need to call ipn.php
Thus my $notify_url is "ipn/ipn.php" or should it be "ipn.php" ? I tried several other methods like putting in full path, use dirname , etc but it seems that the file is not being called.
Anyone tried something similar before? How do you handle the post back URL ?
Thank you in advance!
Before using IPN you should enable it from paypal/paypal-sandbox
go to profile-> my selling tools-> Instant payment notifications -> click on update-> turn it on
also type the notification URL (your callback-listener url, ipn.php).
then in your ipn.php file catch the callback from paypal.
$ipn_post_data = $_POST;
if(array_key_exists('test_ipn', $ipn_post_data) && 1 === (int) $ipn_post_data['test_ipn'])
$url = 'https://www.sandbox.paypal.com/cgi-bin/webscr';
else
$url = 'https://www.paypal.com/cgi-bin/webscr';
// Set up request to PayPal
$request = curl_init();
curl_setopt_array($request, array
(
CURLOPT_URL => $url,
CURLOPT_POST => TRUE,
CURLOPT_POSTFIELDS => http_build_query(array('cmd' => '_notify-validate') + $ipn_post_data),
CURLOPT_RETURNTRANSFER => TRUE,
CURLOPT_HEADER => FALSE,
));
// Execute request and get response and status code
$response = curl_exec($request);
$status = curl_getinfo($request, CURLINFO_HTTP_CODE);
// Close connection
curl_close($request);
if($status == 200 && $response == 'VERIFIED')
{
// All good! Proceed...
}
else
{
// Not good. Ignore, or log for investigation...
}
I have been trying to hook into the WordPress registration action so that I can store the new user's account info on my Parse.com User database. However, since I am using BuddyPress, the WP hook user_register does not seem to work.
After doing research online, it seems like I am supposed to use the BP hook bp_core_signup_user, but that does not seem to be working, and all the info online on how it should be implemented are years old and may be outdated. Problematically, BuddyPress does not have a good Codex at all, so I am kind of stuck. I've been at this for hours, but cannot figure it out.
This is the function I created in an attempt to hook into the registration process:
<?php
// Saves the newly registered BP user account to the Parse DB.
add_action('bp_core_signup_user', 'saveNewParseUser', 10, 5);
function saveNewParseUser($userId, $userLogin, $userPass, $userEmail, $userMeta) {
//Commit new user data to an HTTP POST request to Parse.
$url = 'https://api.parse.com/1/users';
$postdata = array(
"wpUserId" => $userId,
"username" => $userLogin,
"password" => $userPass,
"email" => $userEmail,
"fullName" => $userMeta[display_name],
"firstName" => $userMeta[first_name],
"lastName" => $userMeta[last_name]
);
$appID = "a5TtlVG52JKTC************************";
$restAPIKey = "Qc86jA8dy1FpcB**************************";
$options = array();
$options[] = "Content-type: application/json";
$options[] = "X-Parse-Application-Id: $appID";
$options[] = "X-Parse-REST-API-Key: $restAPIKey";
$options[] = "X-Parse-Revocable-Session: 1";
//open connection
$ch = curl_init($url);
//sets the number of POST vars & POST data
curl_setopt_array($ch, array(
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($postdata),
CURLOPT_HTTPHEADER => $options,
CURLOPT_RETURNTRANSFER => true
));
//execute post
$result = curl_exec($ch);
$resultArray = json_decode($result, true);
//Error check
if (curl_errno($ch)) {
echo "Error Code " . curl_errno() . ": " . curl_error($ch);
}
//Retrieve and place Parse user session token & ID into WP DB user account.
add_user_meta($userId, 'parseSessionToken', $resultArray[sessionToken]);
add_user_meta($userId, 'parseObjId', $resultArray[objectId]);
curl_close($ch);
}
What am I doing wrong? Is this not even being hooked and run as it is meant to?
I know it does not work because I check the Parse User DB after registering an account and a new row is not created, and the meta info I put into the WP account do not show there at all.
Interestingly, this DID work when I hooked into WP's user_register (with the appropriate parameter and postdata array setup) when I included an exit; call at the end of the function, which essentially prevented the registration process from going through BuddyPress' and its activation procedure, and instead went straight to registering through Wordpress directly. That also left the web page displaying the output response from the HTTP request - it was the JSON response body as expected from Parse, so I know it did in fact work. Why would it be working when avoiding BuddyPress? BuddyPress seems to be causing the problem here. (If you would like to see the code for what I had done differently for this, then I can post it.)
Thank you for any assistance.
I figured out what was wrong, and I feel like a complete idiot because it should have been obvious.
There is nothing wrong with my function - I just did not realize the custom plugin it is contained in was disabled! Apparently that happened when I renamed the PHP file, deleted the one on the server, and put the new one in, before my question became an issue.
I learned my lesson. And now I know that changing the plugin's files will deactivate the plugin as a whole.
As such, my hook to user_registration still works just fine, and it is not necessary to go through the bp_core_signup_user hook, so I have reverted to the former. For future reference for anyone wanting to know, this is my final function I used:
<?php
// Saves the newly registered WP user account to the Parse DB.
add_action('user_register', 'saveNewParseUser');
function saveNewParseUser($newUserId) {
//Retrieve the new User object from WP's DB.
$newUser = get_userdata($newUserId);
//Commit new user data to an HTTP POST request to Parse.
$url = 'https://api.parse.com/1/users';
$postdata = array(
"wpUserId" => $newUserId,
"username" => $newUser->user_login,
"password" => $newUser->user_pass,
"email" => $newUser->user_email,
"fullName" => $newUser->display_name,
"firstName" => $newUser->first_name,
"lastName" => $newUser->last_name
);
$appID = "a5TtlVG52JKTCbc*******************";
$restAPIKey = "Qc86jA8dy1F************************";
$options = array();
$options[] = "Content-type: application/json";
$options[] = "X-Parse-Application-Id: $appID";
$options[] = "X-Parse-REST-API-Key: $restAPIKey";
$options[] = "X-Parse-Revocable-Session: 1";
//open connection
$ch = curl_init($url);
//sets the number of POST vars & POST data
curl_setopt_array($ch, array(
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($postdata),
CURLOPT_HTTPHEADER => $options,
CURLOPT_RETURNTRANSFER => true
));
//execute post
$result = curl_exec($ch);
$resultArray = json_decode($result, true);
//Error check
if (curl_errno($ch)) {
echo "Error Code " . curl_errno() . ": " . curl_error($ch);
}
//Retrieve and place Parse user session token & ID into WP DB user account.
add_user_meta($newUserId, 'parseSessionToken', $resultArray[sessionToken]);
add_user_meta($newUserId, 'parseObjId', $resultArray[objectId]);
curl_close($ch);
}
Does anyone here know about how to access Google Photos API now that Google has started using OAuth2? The PHP client library in their developer website is now obsolete and does not work!
I have used OAuth to work with Google Drive but Photos does not work! :(
First I use Google_Client to successfully authenticate user. Then in the redirect page I am trying following:
require_once("Google/Client.php");
//set up path for Zend GData, because Google Documentation uses that lib
$clientLibraryPath = '/path/to/ZendGData/library';
$oldPath = set_include_path(get_include_path() . PATH_SEPARATOR . $clientLibraryPath);
require_once 'Zend/Loader.php';
Zend_Loader::loadClass('Zend_Gdata_Photos');
try
{
$authCode = $_GET['code']; //authorization code returned from google
//next create google OAuth Client object and validate...
$webAuth= new Google_Client();
$webAuth->setClientId($clientId);
$webAuth->setClientSecret($clientSecret);
$webAuth->authenticate($authCode); //this authenticate() works fine...
//now my problem is HOW do I tie this to GData API for Picasa :(
//I tried following but it throws error
//*Token invalid - Invalid token: Request token used when not allowed.*
$client = Zend_Gdata_AuthSub::getHttpClient($authCode);
$gp = new Zend_Gdata_Photos($client, "GData:2.0");
$userFeed = $gp->getUserFeed("default");
I have also tried a bunch of third party libraries, tried hooking up my $webAuth into Zend_GData_Photos in everywhich way I can try...I even tried raw curl calls, but nothing is working!
Can anyone help me please? I am at my wits end....I can't believe Google left a fully functional library (PicasaWeb PHP API Ver 1.0) hanging like that when they updated their authentication to OAuth.
I had the same problem but finally I got it working again.
The best thing is, that you do not need any client library to get access to private photos.
I have spent two days trying to make it work with 'service account' but with no luck.
Then I have found this page:
https://holtstrom.com/michael/blog/post/522/Google-OAuth2-with-PicasaWeb.html
which helped me to achieve what I wanted.
It is pretty long article but it should not take to long to sort it out and get it working. Basically you will need to use 'OAuth 2.0 client ID' instead of 'Service account' in your project at https://console.developers.google.com
Within your 'OAuth 2.0 client ID' you will have following information:
Client ID (something-random.apps.googleusercontent.com)
Client Secret (random-client-secret)
Name (www.yoursite.com)
Authorized JavaScript origins (https://www.yoursite.com)
Authorized redirect URIs (https://www.yoursite.com/oauth2.php)
You will use this data in your verification process.
Before you begin, you will need to complete OAuth Consent Screen.
In that tutorial there is a note to store these tokens in DB, but in this case I'd rather suggest to display them directly in web page. This is much easier.
There is suggestion to use https rather than http but it should work on both.
I have used https for my application.
This is shorter version of the article from the link above.
Create oauth2.php file and place it on https://www.yoursite.com/oauth2.php
<?php
if (isset($_GET['code']))
{
$clientId = 'your-client-id.apps.googleusercontent.com';
$clientSecret = 'your-client-secret';
$referer = 'https://www.yoursite.com/oauth2.php';
$postBody = 'code='.urlencode($_GET['code'])
.'&grant_type=authorization_code'
.'&redirect_uri='.urlencode($referer)
.'&client_id='.urlencode($clientId)
.'&client_secret='.urlencode($clientSecret);
$curl = curl_init();
curl_setopt_array( $curl,
array( CURLOPT_CUSTOMREQUEST => 'POST'
, CURLOPT_URL => 'https://accounts.google.com/o/oauth2/token'
, CURLOPT_HTTPHEADER => array( 'Content-Type: application/x-www-form-urlencoded'
, 'Content-Length: '.strlen($postBody)
, 'User-Agent: www.yoursite.com/0.1 +https://www.yoursite.com/'
)
, CURLOPT_POSTFIELDS => $postBody
, CURLOPT_REFERER => $referer
, CURLOPT_RETURNTRANSFER => 1 // means output will be a return value from curl_exec() instead of simply echoed
, CURLOPT_TIMEOUT => 15 // max seconds to wait
, CURLOPT_FOLLOWLOCATION => 0 // don't follow any Location headers, use only the CURLOPT_URL, this is for security
, CURLOPT_FAILONERROR => 0 // do not fail verbosely fi the http_code is an error, this is for security
, CURLOPT_SSL_VERIFYPEER => 1 // do verify the SSL of CURLOPT_URL, this is for security
, CURLOPT_VERBOSE => 0 // don't output verbosely to stderr, this is for security
) );
$response = curl_exec($curl);
$http_code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
curl_close($curl);
echo($response);
echo($http_code);
}
else { echo 'Code was not provided.'; }
?>
Prepare and visit this link:
https://accounts.google.com/o/oauth2/auth?scope=https://picasaweb.google.com/data/&response_type=code&access_type=offline&redirect_uri=https://www.yoursite.com/oauth2.php&approval_prompt=force&client_id=your-client-id.googleusercontent.com
fields to adjust: redirect_uri and client_id
After visiting link from step 2. you should see your consent screen where you will have to approve it and you will be redirected to your oauth.php page but this time with code parameter:
https://www.yoursite.com/oauth2.php?code=some-random-code
'code' parameter will be then sent by oauth.php to: https://accounts.google.com/o/oauth2/token
which will return(print) json formatted data containing: access_token, token_type, expires_in and refresh_token.
Http Response code should be 200.
Access_token will be the one to use to get privet albums data.
Create index.php with content:
<?php
$curl = curl_init();
$url = 'https://picasaweb.google.com/data/entry/api/user/default';
curl_setopt_array( $curl,
array( CURLOPT_CUSTOMREQUEST => 'GET'
, CURLOPT_URL => $url
, CURLOPT_HTTPHEADER => array( 'GData-Version: 2'
, 'Authorization: Bearer '.'your-access-token' )
, CURLOPT_RETURNTRANSFER => 1 // means output will be a return value from curl_exec() instead of simply echoed
) );
$response = curl_exec($curl);
$http_code = curl_getinfo($curl,CURLINFO_HTTP_CODE);
curl_close($curl);
echo($response . '<br/>');
echo($http_code);
?>
After running script from step 5. you should receive your default feed from picasaweb API. When I say 'default' it ,eans default when you are logged that is with private albums. From now on, you should be able to use that approach to get access to your picasa photo library.
Access token will expire after 3600 seconds (1 hour) so you will have to get new one. this can be achieved with script like this one below:
$clientId = 'your-client-id.apps.googleusercontent.com';
$clientSecret = 'your-client-secret';
$referer = 'https://www.yoursite.com/oauth2.php';
$refreshToken = 'your-refresh-token';
$postBody = 'client_id='.urlencode($clientId)
.'&client_secret='.urlencode($clientSecret)
.'&refresh_token='.urlencode($refreshToken)
.'&grant_type=refresh_token';
$curl = curl_init();
curl_setopt_array( $curl,
array( CURLOPT_CUSTOMREQUEST => 'POST'
, CURLOPT_URL => 'https://www.googleapis.com/oauth2/v3/token'
, CURLOPT_HTTPHEADER => array( 'Content-Type: application/x-www-form-urlencoded'
, 'Content-Length: '.strlen($postBody)
, 'User-Agent: www.yoursite.com/0.1 +https://www.yoursite.com/'
)
, CURLOPT_POSTFIELDS => $postBody
, CURLOPT_RETURNTRANSFER => 1 // means output will be a return value from curl_exec() instead of simply echoed
, CURLOPT_TIMEOUT => 15 // max seconds to wait
, CURLOPT_FOLLOWLOCATION => 0 // don't follow any Location headers, use only the CURLOPT_URL, this is for security
, CURLOPT_FAILONERROR => 0 // do not fail verbosely fi the http_code is an error, this is for security
, CURLOPT_SSL_VERIFYPEER => 1 // do verify the SSL of CURLOPT_URL, this is for security
, CURLOPT_VERBOSE => 0 // don't output verbosely to stderr, this is for security
) );
$response = curl_exec($curl);
$http_code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
curl_close($curl);
if (strlen($response) < 1)
{ echo('fail 01'); }
$NOW = time();
$responseDecoded = json_decode($response, true); // convert returned objects into associative arrays
$expires = $NOW - 60 + intval($responseDecoded['expires_in']);
if ( empty($responseDecoded['access_token'])
|| $expires <= $NOW )
{ echo('fail 02'); }
echo($http_code . '<br/>');
echo($response . '<br/>');
echo($expires . '<br/>');
?>
You can run code from step 7. in separate script manually, just to get new access-token for another 3600 seconds, but normally you would want to have it automated so when access_token expires, you automatically ask for new one using a call with refresh_token from step 4.
Ufff. That is is. I hope you'll get this up and running.