From c19d2c324bb8f6de2c1f80e9d7d8a4b07ce3464c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Mudr=C3=A1k?= Date: Thu, 15 Feb 2018 10:28:31 +0100 Subject: [PATCH] MDL-61392 enrol_paypal: Improve the IPN notifications handling * Notify administrators once incoming IPN request is verified by PayPal. * Fix the HTTP status as expected by the IPN protocol. --- enrol/paypal/classes/util.php | 4 +++ enrol/paypal/ipn.php | 52 +++++++++------------------ enrol/paypal/lang/en/enrol_paypal.php | 3 ++ 3 files changed, 24 insertions(+), 35 deletions(-) diff --git a/enrol/paypal/classes/util.php b/enrol/paypal/classes/util.php index 6f91abd5f47..fcb8f3c0fd3 100644 --- a/enrol/paypal/classes/util.php +++ b/enrol/paypal/classes/util.php @@ -81,6 +81,10 @@ final class util { } error_log($logerrmsg); + if (http_response_code() == 200) { + http_response_code(500); + } + exit(0); }; } diff --git a/enrol/paypal/ipn.php b/enrol/paypal/ipn.php index 4c1f713d21c..b3cde16be30 100644 --- a/enrol/paypal/ipn.php +++ b/enrol/paypal/ipn.php @@ -32,6 +32,7 @@ // comment out when debugging or better look into error log! define('NO_DEBUG_DISPLAY', true); +// @codingStandardsIgnoreLine This script does not require login. require("../../config.php"); require_once("lib.php"); require_once($CFG->libdir.'/eventslib.php'); @@ -42,9 +43,16 @@ require_once($CFG->libdir . '/filelib.php'); // the custom handler just logs exceptions and stops. set_exception_handler(\enrol_paypal\util::get_exception_handler()); +// Make sure we are enabled in the first place. +if (!enrol_is_enabled('paypal')) { + http_response_code(503); + throw new moodle_exception('errdisabled', 'enrol_paypal'); +} + /// Keep out casual intruders if (empty($_POST) or !empty($_GET)) { - print_error("Sorry, you can not use the script that way."); + http_response_code(400); + throw new moodle_exception('invalidrequest', 'core_error'); } /// Read all the data from PayPal and get it ready for later; @@ -69,36 +77,13 @@ $data->payment_gross = $data->mc_gross; $data->payment_currency = $data->mc_currency; $data->timeupdated = time(); -// Required for message_send. -$PAGE->set_context(context_system::instance()); +$user = $DB->get_record("user", array("id" => $data->userid), "*", MUST_EXIST); +$course = $DB->get_record("course", array("id" => $data->courseid), "*", MUST_EXIST); +$context = context_course::instance($course->id, MUST_EXIST); -/// get the user and course records - -if (! $user = $DB->get_record("user", array("id"=>$data->userid))) { - \enrol_paypal\util::message_paypal_error_to_admin("Not a valid user id", $data); - die; -} - -if (! $course = $DB->get_record("course", array("id"=>$data->courseid))) { - \enrol_paypal\util::message_paypal_error_to_admin("Not a valid course id", $data); - die; -} - -if (! $context = context_course::instance($course->id, IGNORE_MISSING)) { - \enrol_paypal\util::message_paypal_error_to_admin("Not a valid context id", $data); - die; -} - -// Now that the course/context has been validated, we can set it. Not that it's wonderful -// to set contexts more than once but system->course switches are accepted. -// Required for message_send. $PAGE->set_context($context); -if (! $plugin_instance = $DB->get_record("enrol", array("id"=>$data->instanceid, "status"=>0))) { - \enrol_paypal\util::message_paypal_error_to_admin("Not a valid instance id", $data); - die; -} - +$plugin_instance = $DB->get_record("enrol", array("id" => $data->instanceid, "enrol" => "paypal", "status" => 0), "*", MUST_EXIST); $plugin = enrol_get_plugin('paypal'); /// Open a connection back to PayPal to validate the data @@ -113,10 +98,9 @@ $options = array( $location = "https://$paypaladdr/cgi-bin/webscr"; $result = $c->post($location, $req, $options); -if (!$result) { /// Could not connect to PayPal - FAIL - echo "

Error: could not access paypal.com

"; - \enrol_paypal\util::message_paypal_error_to_admin("Could not access paypal.com to verify payment", $data); - die; +if ($c->get_errno()) { + throw new moodle_exception('errpaypalconnect', 'enrol_paypal', '', array('url' => $paypaladdr, 'result' => $result), + json_encode($data)); } /// Connection is OK, so now we post the data to validate it @@ -318,8 +302,6 @@ if (strlen($result) > 0) { } else if (strcmp ($result, "INVALID") == 0) { // ERROR $DB->insert_record("enrol_paypal", $data, false); - \enrol_paypal\util::message_paypal_error_to_admin("Received an invalid payment notification!! (Fake payment?)", $data); + throw new moodle_exception('erripninvalid', 'enrol_paypal', '', null, json_encode($data)); } } - -exit; diff --git a/enrol/paypal/lang/en/enrol_paypal.php b/enrol/paypal/lang/en/enrol_paypal.php index aa9c7a50705..80abf1835e6 100644 --- a/enrol/paypal/lang/en/enrol_paypal.php +++ b/enrol/paypal/lang/en/enrol_paypal.php @@ -39,6 +39,9 @@ $string['enrolperiod_desc'] = 'Default length of time that the enrolment is vali $string['enrolperiod_help'] = 'Length of time that the enrolment is valid, starting with the moment the user is enrolled. If disabled, the enrolment duration will be unlimited.'; $string['enrolstartdate'] = 'Start date'; $string['enrolstartdate_help'] = 'If enabled, users can be enrolled from this date onward only.'; +$string['errdisabled'] = 'PayPal plugin is disabled and does not handle payment notifications.'; +$string['erripninvalid'] = 'Instant payment notification has not been verified by PayPal.'; +$string['errpaypalconnect'] = 'Could not connect to {$a->url} to verify the instant payment notification: {$a->result}'; $string['expiredaction'] = 'Enrolment expiry action'; $string['expiredaction_help'] = 'Select action to carry out when user enrolment expires. Please note that some user data and settings are purged from course during course unenrolment.'; $string['mailadmins'] = 'Notify admin';