PayPal-PHP-SDK
PayPal-PHP-SDK copied to clipboard
resource is undefined and verificationStatus is always returning FAILURE
I have two issues. I am using sandbox mode. My $verificationStatus is always returning FAILURE and $responseArray['webhook_event']['resource']['event_type']; always warns that resource is undefined.
include '../../includes/db.class.php';
require 'vendor/autoload.php';
$stmt= $db->prepare('SELECT pp_public, pp_secret, pp_hook FROM api_config');
$stmt->execute();
$row = $stmt->fetch();
$pp_api = $row['pp_public'];
$pp_secret = $row['pp_secret'];
$pp_webhooks = $row['pp_hook'];
use \PayPal\Api\VerifyWebhookSignature;
use \PayPal\Api\WebhookEvent;
$apiContext = new \PayPal\Rest\ApiContext(
new \PayPal\Auth\OAuthTokenCredential(
$pp_api,
$pp_secret
)
);
$bodyReceived = file_get_contents('php://input');
$headers = getallheaders();
$headers = array_change_key_case($headers, CASE_UPPER);
$signatureVerification = new VerifyWebhookSignature();
$signatureVerification->setWebhookId($pp_webhooks);
$signatureVerification->setAuthAlgo($headers['PAYPAL-AUTH-ALGO']);
$signatureVerification->setTransmissionId($headers['PAYPAL-TRANSMISSION-ID']);
$signatureVerification->setCertUrl($headers['PAYPAL-CERT-URL']);
$signatureVerification->setTransmissionSig($headers['PAYPAL-TRANSMISSION-SIG']);
$webhookEvent = new WebhookEvent();
$webhookEvent->fromJson($requestBody);
$signatureVerification->setWebhookEvent($webhookEvent);
$request = clone $signatureVerification;
try {
$output = $signatureVerification->post($apiContext);
} catch (Exception $ex) {
print_r($ex->getMessage());
exit(1);
}
$verificationStatus = $output->getVerificationStatus();
$responseArray = json_decode($request->toJSON(), true);
// this line returns the resource not defined warning and rages on my log files.
$event = $responseArray['webhook_event']['resource']['event_type'];
$outputArray = json_decode($output->toJSON(), true);
if ($verificationStatus == 'SUCCESS') {
switch($event) {
........
Hi @viraladmin, can you help us with PayPal-Debug-ID
for this issue?
Refer Exception Handling to understand your error.
Well I'd love to add the PayPal-Debug-ID but as is the case with all hings relating to the paypal API figuring it out is a nightmare. So I add the exception handling to my webhook and it ends up tossing even more errors in my error logs.
Uncaught Error: Call to a member function create() on null
Undefined variable: payment
I would guess thats because the webhook doesn't have any $payment
so it can't issue a $payment->create
from the webhook. Should I be adding this code to the initial payment request? The return url? Or the webhook?
@viraladmin, did you get a chance to refer this sample code? https://github.com/paypal/PayPal-PHP-SDK/blob/master/sample/notifications/ValidateWebhookEvent.php
I simply have no idea where this code should go. I have tried all the following:
try {
$apiContext = new \PayPal\Rest\ApiContext(
new \PayPal\Auth\OAuthTokenCredential(
$pp_api,
$pp_secret
)
);
} catch (PayPal\Exception\PayPalConnectionException $ex) {
$myfile = fopen("newfile2.txt", "w") or die("Unable to open file!");
$txt = $ex->getCode();
fwrite($myfile, $txt);
$txt = $ex->getData();
fwrite($myfile, $txt);
fclose($myfile);
die($ex);
}
try {
$signatureVerification->setWebhookEvent($webhookEvent);
$request = clone $signatureVerification;
} catch (PayPal\Exception\PayPalConnectionException $ex) {
$myfile = fopen("newfile2.txt", "w") or die("Unable to open file!");
$txt = $ex->getCode();
fwrite($myfile, $txt);
$txt = $ex->getData();
fwrite($myfile, $txt);
fclose($myfile);
die($ex);
}
try {
$output = $signatureVerification->post($apiContext);
} catch (PayPal\Exception\PayPalConnectionException $ex) {
$myfile = fopen("log.txt", "w") or die("Unable to open file!");
$txt = $ex->getCode();
fwrite($myfile, $txt);
$txt = $ex->getData();
fwrite($myfile, $txt);
fclose($myfile);
die($ex);
}
try {
$verificationStatus = $output->getVerificationStatus();
} catch (PayPal\Exception\PayPalConnectionException $ex) {
$myfile = fopen("log.txt", "w") or die("Unable to open file!");
$txt = $ex->getCode();
fwrite($myfile, $txt);
$txt = $ex->getData();
fwrite($myfile, $txt);
fclose($myfile);
die($ex);
}
try {
$responseArray = json_decode($request->toJSON(), true);
} catch (PayPal\Exception\PayPalConnectionException $ex) {
$myfile = fopen("log.txt", "w") or die("Unable to open file!");
$txt = $ex->getCode();
fwrite($myfile, $txt);
$txt = $ex->getData();
fwrite($myfile, $txt);
fclose($myfile);
die($ex);
}
try {
$event = $responseArray['webhook_event']['resource']['event_type'];
} catch (PayPal\Exception\PayPalConnectionException $ex) {
$myfile = fopen("log.txt", "w") or die("Unable to open file!");
$txt = $ex->getCode();
fwrite($myfile, $txt);
$txt = $ex->getData();
fwrite($myfile, $txt);
fclose($myfile);
die($ex);
}
try {
$outputArray = json_decode($output->toJSON(), true);
} catch (PayPal\Exception\PayPalConnectionException $ex) {
$myfile = fopen("log.txt", "w") or die("Unable to open file!");
$txt = $ex->getCode();
fwrite($myfile, $txt);
$txt = $ex->getData();
fwrite($myfile, $txt);
fclose($myfile);
die($ex);
}
Nothing is being saved to log.txt and as its a webhook i cant echo responses. So clearly I have no clue where to implement this sample code.
My guess is its not returning any PayPal-Debug-ID because there is no error. $verificationStatus of "failure" isn't really an error its a proper response that it failed so the "try" is succeeding is just always a failure response. As for why the resource is undefined my guess it that would be because there is no ['resource'] defined in $responseArray['webhook_event']['resource']['event_type']; as it returned failure.
When I'm not blind, you simply forgot this line:
$signatureVerification->setTransmissionTime($headers['PAYPAL-TRANSMISSION-TIME']);
See sample/notifications/ValidateWebhookEvent.php
Please also make sure, that you're accessing those $headers
correct, because I had sub arrays for example:
$signature_verification->setCertUrl($headers['PAYPAL-CERT-URL'][0]);
$signature_verification->setTransmissionTime($headers['PAYPAL-TRANSMISSION-TIME'][0]);
Try the following code and logic, which I've updated from mine to your code example:
// Provide login information
$apiContext = new \PayPal\Rest\ApiContext(
new \PayPal\Auth\OAuthTokenCredential(
$pp_api, // Client ID
$pp_secret, // Secret
)
);
// Define API configuration
// Sandbox: Log and show more than in production (live)
if (config('app.use_sandbox')) {
$apiContext->setConfig(
array(
'mode' => 'sandbox',
'log.LogEnabled' => true,
'log.FileName' => __DIR__.'/paypal.log',
'log.LogLevel' => 'DEBUG'
)
);
} else {
$apiContext->setConfig(
array(
'mode' => 'live',
'log.LogEnabled' => true,
'log.FileName' => __DIR__.'/paypal.log',
'log.LogLevel' => 'WARN'
)
);
}
// Get request details
$request_body = file_get_contents('php://input');
$headers = array_change_key_case(getallheaders(), CASE_UPPER);
// Verify webhook signature
$signature_verification = new \PayPal\Api\VerifyWebhookSignature();
$signature_verification->setAuthAlgo($headers['PAYPAL-AUTH-ALGO'][0]);
$signature_verification->setTransmissionId($headers['PAYPAL-TRANSMISSION-ID'][0]);
$signature_verification->setCertUrl($headers['PAYPAL-CERT-URL'][0]);
$signature_verification->setWebhookId($pp_webhooks);
$signature_verification->setTransmissionSig($headers['PAYPAL-TRANSMISSION-SIG'][0]);
$signature_verification->setTransmissionTime($headers['PAYPAL-TRANSMISSION-TIME'][0]);
$signature_verification->setRequestBody($request_body);
try {
$output = $signature_verification->post($apiContext);
} catch (\Exception $ex) {
return response('Error: Could not verify signature.', 500)->header('Content-Type', 'text/plain');
}
$status = $output->getVerificationStatus(); // 'SUCCESS' or 'FAILURE'
switch(strtoupper($status)) {
case "SUCCESS":
$json = json_decode($request_body, 1);
default:
return response('Forbidden: Invalid signature.', 403)->header('Content-Type', 'text/plain');
}
switch(strtoupper($json['event_type'])) {
case "BILLING.PLAN.CREATED":
// DO SOMETHING with $json (contains the webhook data)
return response($status, 200)->header('Content-Type', 'text/plain');
}
return response('Error: Invalid webhook.', 500)->header('Content-Type', 'text/plain');
This should work. You may only need to replace all return
lines with an echo
or something else since return
statements will only work in a function.
HI @viraladmin , I hope @Sebi94nbg's above comment helps your query and do you still facing any challenges?