MDL-23381 Added group info on the group memberships page (still a table, needs to...
[moodle.git] / enrol / paypal / ipn.php
CommitLineData
4317f92f 1<?php
04f47a89 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");
3b120e46 18 require_once($CFG->libdir.'/eventslib.php');
3d970777 19
04f47a89 20/// Keep out casual intruders
3d970777 21 if (empty($_POST) or !empty($_GET)) {
5a2a5331 22 print_error("Sorry, you can not use the script that way.");
04f47a89 23 }
24
934bdbee 25/// Read all the data from PayPal and get it ready for later;
26/// we expect only valid UTF-8 encoding, it is the responsibility
27/// of user to set it up properly in PayPal business acount,
28/// it is documented in docs wiki.
04f47a89 29
30 $req = 'cmd=_notify-validate';
31
934bdbee 32 $data = new object();
33
04f47a89 34 foreach ($_POST as $key => $value) {
934bdbee 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
50c5bef4 49 if (! $user = $DB->get_record("user", array("id"=>$data->userid))) {
3b120e46 50 message_paypal_error_to_admin("Not a valid user id", $data);
597342b0 51 die;
52 }
53
50c5bef4 54 if (! $course = $DB->get_record("course", array("id"=>$data->courseid))) {
3b120e46 55 message_paypal_error_to_admin("Not a valid course id", $data);
597342b0 56 die;
57 }
58
22003ada 59 if (! $context = get_context_instance(CONTEXT_COURSE, $course->id)) {
3b120e46 60 message_paypal_error_to_admin("Not a valid context id", $data);
22003ada 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>";
3b120e46 75 message_paypal_error_to_admin("Could not access paypal.com to verify payment", $data);
04f47a89 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") {
df997f84 96 role_unassign_all(array('userid'=>$data->userid, 'contextid'=>$context->id, 'component'=>'enrol_paypal'), true, true);
3b120e46 97 message_paypal_error_to_admin("Status not completed or pending. User unenrolled from course", $data);
04f47a89 98 die;
99 }
100
4317f92f 101 // If currency is incorrectly set then someone maybe trying to cheat the system
8e605b76 102
103 if ($data->mc_currency != $course->currency) {
104 email_paypal_error_to_admin("Currency does not match course settings, received: ".addslashes($data->mc_currency), $data);
105 die;
106 }
107
597342b0 108 // If status is pending and reason is other than echeck then we are on hold until further notice
109 // Email user to let them know. Email admin.
110
111 if ($data->payment_status == "Pending" and $data->pending_reason != "echeck") {
3b120e46 112 $eventdata = new object();
113 $eventdata->modulename = 'moodle';
114 $eventdata->userfrom = get_admin();
115 $eventdata->userto = $user;
116 $eventdata->subject = "Moodle: PayPal payment";
117 $eventdata->fullmessage = "Your PayPal payment is pending.";
118 $eventdata->fullmessageformat = FORMAT_PLAIN;
119 $eventdata->fullmessagehtml = '';
120 $eventdata->smallmessage = '';
7c7d3afa 121 message_send($eventdata);
3b120e46 122
3b120e46 123 message_paypal_error_to_admin("Payment pending", $data);
597342b0 124 die;
125 }
126
127 // If our status is not completed or not pending on an echeck clearance then ignore and die
128 // This check is redundant at present but may be useful if paypal extend the return codes in the future
129
934bdbee 130 if (! ( $data->payment_status == "Completed" or
597342b0 131 ($data->payment_status == "Pending" and $data->pending_reason == "echeck") ) ) {
132 die;
133 }
134
135 // At this point we only proceed with a status of completed or pending with a reason of echeck
136
137
138
50c5bef4 139 if ($existing = $DB->get_record("enrol_paypal", array("txn_id"=>$data->txn_id))) { // Make sure this transaction doesn't exist already
3b120e46 140 message_paypal_error_to_admin("Transaction $data->txn_id is being repeated!", $data);
3d970777 141 die;
04f47a89 142
934bdbee 143 }
144
3d970777 145 if ($data->business != $CFG->enrol_paypalbusiness) { // Check that the email is the one we want it to be
3b120e46 146 message_paypal_error_to_admin("Business email is $data->business (not $CFG->enrol_paypalbusiness)", $data);
3d970777 147 die;
04f47a89 148
934bdbee 149 }
150
50c5bef4 151 if (!$user = $DB->get_record('user', array('id'=>$data->userid))) { // Check that user exists
3b120e46 152 message_paypal_error_to_admin("User $data->userid doesn't exist", $data);
3d970777 153 die;
04f47a89 154 }
155
50c5bef4 156 if (!$course = $DB->get_record('course', array('id'=>$data->courseid))) { // Check that course exists
3b120e46 157 message_paypal_error_to_admin("Course $data->courseid doesn't exist", $data);;
3d970777 158 die;
04f47a89 159 }
160
3d970777 161 // Check that amount paid is the correct amount
162 if ( (float) $course->cost < 0 ) {
163 $cost = (float) $CFG->enrol_cost;
164 } else {
165 $cost = (float) $course->cost;
166 }
3d970777 167
934bdbee 168 if ($data->payment_gross < $cost) {
76317c73 169 $cost = format_float($cost, 2);
3b120e46 170 message_paypal_error_to_admin("Amount paid is not enough ($data->payment_gross < $cost))", $data);
3d970777 171 die;
04f47a89 172
173 }
174
175 // ALL CLEAR !
176
fc29e51b 177 $DB->insert_record("enrol_paypal", $data);
04f47a89 178
8f425a8f 179 if (!enrol_into_course($course, $user, 'paypal')) {
3b120e46 180 message_paypal_error_to_admin("Error while trying to enrol ".fullname($user)." in '$course->fullname'", $data);
3d970777 181 die;
04f47a89 182 } else {
6e08d1f1 183 // Pass $view=true to filter hidden caps if the user cannot see them
184 if ($users = get_users_by_capability($context, 'moodle/course:update', 'u.*', 'u.id ASC',
185 '', '', '', '', false, true)) {
186 $users = sort_by_roleassignment_authority($users, $context);
187 $teacher = array_shift($users);
188 } else {
189 $teacher = false;
190 }
191
70beecd4 192
0f093efa 193 if (!empty($CFG->enrol_mailstudents)) {
6ba65fa0 194 $a->coursename = $course->fullname;
631cba64 195 $a->profileurl = "$CFG->wwwroot/user/view.php?id=$user->id";
4317f92f 196
3b120e46 197 $eventdata = new object();
198 $eventdata->modulename = 'moodle';
199 $eventdata->userfrom = $teacher;
200 $eventdata->userto = $user;
201 $eventdata->subject = get_string("enrolmentnew", '', $course->shortname);
202 $eventdata->fullmessage = get_string('welcometocoursetext', '', $a);
203 $eventdata->fullmessageformat = FORMAT_PLAIN;
204 $eventdata->fullmessagehtml = '';
205 $eventdata->smallmessage = '';
7c7d3afa 206 message_send($eventdata);
4317f92f 207
70beecd4 208 }
209
0f093efa 210 if (!empty($CFG->enrol_mailteachers)) {
6ba65fa0 211 $a->course = $course->fullname;
0f093efa 212 $a->user = fullname($user);
4317f92f 213
3b120e46 214 $eventdata = new object();
215 $eventdata->modulename = 'moodle';
216 $eventdata->userfrom = $user;
217 $eventdata->userto = $teacher;
218 $eventdata->subject = get_string("enrolmentnew", '', $course->shortname);
219 $eventdata->fullmessage = get_string('enrolmentnewuser', '', $a);
220 $eventdata->fullmessageformat = FORMAT_PLAIN;
221 $eventdata->fullmessagehtml = '';
4454447d 222 $eventdata->smallmessage = '';
7c7d3afa 223 message_send($eventdata);
04f47a89 224 }
0f093efa 225
226 if (!empty($CFG->enrol_mailadmins)) {
6ba65fa0 227 $a->course = $course->fullname;
0f093efa 228 $a->user = fullname($user);
229 $admins = get_admins();
4317f92f 230 foreach ($admins as $admin) {
3b120e46 231 $eventdata = new object();
232 $eventdata->modulename = 'moodle';
233 $eventdata->userfrom = $user;
234 $eventdata->userto = $admin;
235 $eventdata->subject = get_string("enrolmentnew", '', $course->shortname);
236 $eventdata->fullmessage = get_string('enrolmentnewuser', '', $a);
237 $eventdata->fullmessageformat = FORMAT_PLAIN;
238 $eventdata->fullmessagehtml = '';
239 $eventdata->smallmessage = '';
7c7d3afa 240 message_send($eventdata);
0f093efa 241 }
242 }
243
04f47a89 244 }
245
246
247 } else if (strcmp ($result, "INVALID") == 0) { // ERROR
50c5bef4 248 $DB->insert_record("enrol_paypal", $data, false);
3b120e46 249 message_paypal_error_to_admin("Received an invalid payment notification!! (Fake payment?)", $data);
04f47a89 250 }
251 }
252
253 fclose($fp);
254 exit;
255
256
257
258/// FUNCTIONS //////////////////////////////////////////////////////////////////
259
260
3b120e46 261function message_paypal_error_to_admin($subject, $data) {
04f47a89 262 $admin = get_admin();
8f425a8f 263 $site = get_site();
04f47a89 264
265 $message = "$site->fullname: Transaction failed.\n\n$subject\n\n";
266
267 foreach ($data as $key => $value) {
268 $message .= "$key => $value\n";
269 }
270
3b120e46 271 $eventdata = new object();
272 $eventdata->modulename = 'moodle';
273 $eventdata->userfrom = $admin;
274 $eventdata->userto = $admin;
275 $eventdata->subject = "PAYPAL ERROR: ".$subject;
276 $eventdata->fullmessage = $message;
277 $eventdata->fullmessageformat = FORMAT_PLAIN;
278 $eventdata->fullmessagehtml = '';
279 $eventdata->smallmessage = '';
7c7d3afa 280 message_send($eventdata);
04f47a89 281}
282
4317f92f 283