MDL-14679 towards blocks conversion
[moodle.git] / enrol / paypal / ipn.php
CommitLineData
04f47a89 1<?php // $Id$
2
3/**
5599d142 4* Listens for Instant Payment Notification from PayPal
04f47a89 5*
5599d142 6* This script waits for Payment notification from PayPal,
7* then double checks that data by sending it back to PayPal.
8* If PayPal verifies this then it sets up the enrolment for that
934bdbee 9*
04f47a89 10* Set the $user->timeaccess course array
11*
12* @param user referenced object, must contain $user->id already set
13*/
14
15
3d970777 16 require("../../config.php");
17 require("enrol.php");
18
04f47a89 19/// Keep out casual intruders
3d970777 20 if (empty($_POST) or !empty($_GET)) {
5a2a5331 21 print_error("Sorry, you can not use the script that way.");
04f47a89 22 }
23
934bdbee 24/// Read all the data from PayPal and get it ready for later;
25/// we expect only valid UTF-8 encoding, it is the responsibility
26/// of user to set it up properly in PayPal business acount,
27/// it is documented in docs wiki.
04f47a89 28
29 $req = 'cmd=_notify-validate';
30
934bdbee 31 $data = new object();
32
04f47a89 33 foreach ($_POST as $key => $value) {
934bdbee 34 $value = stripslashes($value);
35 $req .= "&$key=".urlencode($value);
36 $data->$key = $value;
04f47a89 37 }
38
3d970777 39 $custom = explode('-', $data->custom);
2c61c740 40 $data->userid = (int)$custom[0];
41 $data->courseid = (int)$custom[1];
ec11cd9c 42 $data->payment_gross = $data->mc_gross;
04f47a89 43 $data->payment_currency = $data->mc_currency;
470accb7 44 $data->timeupdated = time();
04f47a89 45
46
597342b0 47/// get the user and course records
48
49 if (! $user = get_record("user", "id", $data->userid) ) {
50 email_paypal_error_to_admin("Not a valid user id", $data);
51 die;
52 }
53
54 if (! $course = get_record("course", "id", $data->courseid) ) {
55 email_paypal_error_to_admin("Not a valid course id", $data);
56 die;
57 }
58
22003ada 59 if (! $context = get_context_instance(CONTEXT_COURSE, $course->id)) {
60 email_paypal_error_to_admin("Not a valid context id", $data);
61 die;
62 }
597342b0 63
04f47a89 64/// Open a connection back to PayPal to validate the data
65
66 $header = '';
67 $header .= "POST /cgi-bin/webscr HTTP/1.0\r\n";
68 $header .= "Content-Type: application/x-www-form-urlencoded\r\n";
69 $header .= "Content-Length: " . strlen($req) . "\r\n\r\n";
48494310 70 $paypaladdr = empty($CFG->usepaypalsandbox) ? 'www.paypal.com' : 'www.sandbox.paypal.com';
71 $fp = fsockopen ($paypaladdr, 80, $errno, $errstr, 30);
04f47a89 72
5599d142 73 if (!$fp) { /// Could not open a socket to PayPal - FAIL
04f47a89 74 echo "<p>Error: could not access paypal.com</p>";
75 email_paypal_error_to_admin("Could not access paypal.com to verify payment", $data);
76 die;
77 }
78
79/// Connection is OK, so now we post the data to validate it
80
81 fputs ($fp, $header.$req);
82
83/// Now read the response and check if everything is OK.
84
85 while (!feof($fp)) {
86 $result = fgets($fp, 1024);
87 if (strcmp($result, "VERIFIED") == 0) { // VALID PAYMENT!
88
04f47a89 89
597342b0 90 // check the payment_status and payment_reason
91
92 // If status is not completed or pending then unenrol the student if already enrolled
93 // and notify admin
94
95 if ($data->payment_status != "Completed" and $data->payment_status != "Pending") {
22003ada 96 role_unassign(0, $data->userid, 0, $context->id);
597342b0 97 email_paypal_error_to_admin("Status not completed or pending. User unenrolled from course", $data);
04f47a89 98 die;
99 }
100
597342b0 101 // If status is pending and reason is other than echeck then we are on hold until further notice
102 // Email user to let them know. Email admin.
103
104 if ($data->payment_status == "Pending" and $data->pending_reason != "echeck") {
5599d142 105 email_to_user($user, get_admin(), "Moodle: PayPal payment", "Your PayPal payment is pending.");
597342b0 106 email_paypal_error_to_admin("Payment pending", $data);
107 die;
108 }
109
110 // If our status is not completed or not pending on an echeck clearance then ignore and die
111 // This check is redundant at present but may be useful if paypal extend the return codes in the future
112
934bdbee 113 if (! ( $data->payment_status == "Completed" or
597342b0 114 ($data->payment_status == "Pending" and $data->pending_reason == "echeck") ) ) {
115 die;
116 }
117
118 // At this point we only proceed with a status of completed or pending with a reason of echeck
119
120
121
919da657 122 if ($existing = get_record("enrol_paypal", "txn_id", addslashes($data->txn_id))) { // Make sure this transaction doesn't exist already
3d970777 123 email_paypal_error_to_admin("Transaction $data->txn_id is being repeated!", $data);
124 die;
04f47a89 125
934bdbee 126 }
127
3d970777 128 if ($data->business != $CFG->enrol_paypalbusiness) { // Check that the email is the one we want it to be
129 email_paypal_error_to_admin("Business email is $data->business (not $CFG->enrol_paypalbusiness)", $data);
130 die;
04f47a89 131
934bdbee 132 }
133
04f47a89 134 if (!$user = get_record('user', 'id', $data->userid)) { // Check that user exists
135 email_paypal_error_to_admin("User $data->userid doesn't exist", $data);
3d970777 136 die;
04f47a89 137 }
138
631cba64 139 if (!$course = get_record('course', 'id', $data->courseid)) { // Check that course exists
3d970777 140 email_paypal_error_to_admin("Course $data->courseid doesn't exist", $data);;
141 die;
04f47a89 142 }
143
3d970777 144 // Check that amount paid is the correct amount
145 if ( (float) $course->cost < 0 ) {
146 $cost = (float) $CFG->enrol_cost;
147 } else {
148 $cost = (float) $course->cost;
149 }
3d970777 150
934bdbee 151 if ($data->payment_gross < $cost) {
76317c73 152 $cost = format_float($cost, 2);
3d970777 153 email_paypal_error_to_admin("Amount paid is not enough ($data->payment_gross < $cost))", $data);
154 die;
04f47a89 155
156 }
157
158 // ALL CLEAR !
159
919da657 160 if (!insert_record("enrol_paypal", addslashes_object($data))) { // Insert a transaction record
04f47a89 161 email_paypal_error_to_admin("Error while trying to insert valid transaction", $data);
162 }
163
8f425a8f 164 if (!enrol_into_course($course, $user, 'paypal')) {
04f47a89 165 email_paypal_error_to_admin("Error while trying to enrol ".fullname($user)." in '$course->fullname'", $data);
3d970777 166 die;
04f47a89 167 } else {
70beecd4 168 $teacher = get_teacher($course->id);
169
0f093efa 170 if (!empty($CFG->enrol_mailstudents)) {
6ba65fa0 171 $a->coursename = $course->fullname;
631cba64 172 $a->profileurl = "$CFG->wwwroot/user/view.php?id=$user->id";
934bdbee 173 email_to_user($user, $teacher, get_string("enrolmentnew", '', $course->shortname),
0f093efa 174 get_string('welcometocoursetext', '', $a));
70beecd4 175 }
176
0f093efa 177 if (!empty($CFG->enrol_mailteachers)) {
6ba65fa0 178 $a->course = $course->fullname;
0f093efa 179 $a->user = fullname($user);
934bdbee 180 email_to_user($teacher, $user, get_string("enrolmentnew", '', $course->shortname),
0f093efa 181 get_string('enrolmentnewuser', '', $a));
04f47a89 182 }
0f093efa 183
184 if (!empty($CFG->enrol_mailadmins)) {
6ba65fa0 185 $a->course = $course->fullname;
0f093efa 186 $a->user = fullname($user);
187 $admins = get_admins();
188 foreach ($admins as $admin) {
934bdbee 189 email_to_user($admin, $user, get_string("enrolmentnew", '', $course->shortname),
0f093efa 190 get_string('enrolmentnewuser', '', $a));
191 }
192 }
193
04f47a89 194 }
195
196
197 } else if (strcmp ($result, "INVALID") == 0) { // ERROR
919da657 198 insert_record("enrol_paypal", addslashes_object($data), false);
04f47a89 199 email_paypal_error_to_admin("Received an invalid payment notification!! (Fake payment?)", $data);
200 }
201 }
202
203 fclose($fp);
204 exit;
205
206
207
208/// FUNCTIONS //////////////////////////////////////////////////////////////////
209
210
211function email_paypal_error_to_admin($subject, $data) {
212 $admin = get_admin();
8f425a8f 213 $site = get_site();
04f47a89 214
215 $message = "$site->fullname: Transaction failed.\n\n$subject\n\n";
216
217 foreach ($data as $key => $value) {
218 $message .= "$key => $value\n";
219 }
220
221 email_to_user($admin, $admin, "PAYPAL ERROR: ".$subject, $message);
222
223}
224
225?>