Updated the HEAD build version to 20090922
[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");
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") {
22003ada 96 role_unassign(0, $data->userid, 0, $context->id);
3b120e46 97 message_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") {
3b120e46 105 $eventdata = new object();
106 $eventdata->modulename = 'moodle';
107 $eventdata->userfrom = get_admin();
108 $eventdata->userto = $user;
109 $eventdata->subject = "Moodle: PayPal payment";
110 $eventdata->fullmessage = "Your PayPal payment is pending.";
111 $eventdata->fullmessageformat = FORMAT_PLAIN;
112 $eventdata->fullmessagehtml = '';
113 $eventdata->smallmessage = '';
114 events_trigger('message_send', $eventdata);
115
3b120e46 116 message_paypal_error_to_admin("Payment pending", $data);
597342b0 117 die;
118 }
119
120 // If our status is not completed or not pending on an echeck clearance then ignore and die
121 // This check is redundant at present but may be useful if paypal extend the return codes in the future
122
934bdbee 123 if (! ( $data->payment_status == "Completed" or
597342b0 124 ($data->payment_status == "Pending" and $data->pending_reason == "echeck") ) ) {
125 die;
126 }
127
128 // At this point we only proceed with a status of completed or pending with a reason of echeck
129
130
131
50c5bef4 132 if ($existing = $DB->get_record("enrol_paypal", array("txn_id"=>$data->txn_id))) { // Make sure this transaction doesn't exist already
3b120e46 133 message_paypal_error_to_admin("Transaction $data->txn_id is being repeated!", $data);
3d970777 134 die;
04f47a89 135
934bdbee 136 }
137
3d970777 138 if ($data->business != $CFG->enrol_paypalbusiness) { // Check that the email is the one we want it to be
3b120e46 139 message_paypal_error_to_admin("Business email is $data->business (not $CFG->enrol_paypalbusiness)", $data);
3d970777 140 die;
04f47a89 141
934bdbee 142 }
143
50c5bef4 144 if (!$user = $DB->get_record('user', array('id'=>$data->userid))) { // Check that user exists
3b120e46 145 message_paypal_error_to_admin("User $data->userid doesn't exist", $data);
3d970777 146 die;
04f47a89 147 }
148
50c5bef4 149 if (!$course = $DB->get_record('course', array('id'=>$data->courseid))) { // Check that course exists
3b120e46 150 message_paypal_error_to_admin("Course $data->courseid doesn't exist", $data);;
3d970777 151 die;
04f47a89 152 }
153
3d970777 154 // Check that amount paid is the correct amount
155 if ( (float) $course->cost < 0 ) {
156 $cost = (float) $CFG->enrol_cost;
157 } else {
158 $cost = (float) $course->cost;
159 }
3d970777 160
934bdbee 161 if ($data->payment_gross < $cost) {
76317c73 162 $cost = format_float($cost, 2);
3b120e46 163 message_paypal_error_to_admin("Amount paid is not enough ($data->payment_gross < $cost))", $data);
3d970777 164 die;
04f47a89 165
166 }
167
168 // ALL CLEAR !
169
fc29e51b 170 $DB->insert_record("enrol_paypal", $data);
04f47a89 171
8f425a8f 172 if (!enrol_into_course($course, $user, 'paypal')) {
3b120e46 173 message_paypal_error_to_admin("Error while trying to enrol ".fullname($user)." in '$course->fullname'", $data);
3d970777 174 die;
04f47a89 175 } else {
70beecd4 176 $teacher = get_teacher($course->id);
177
0f093efa 178 if (!empty($CFG->enrol_mailstudents)) {
6ba65fa0 179 $a->coursename = $course->fullname;
631cba64 180 $a->profileurl = "$CFG->wwwroot/user/view.php?id=$user->id";
3b120e46 181
182 $eventdata = new object();
183 $eventdata->modulename = 'moodle';
184 $eventdata->userfrom = $teacher;
185 $eventdata->userto = $user;
186 $eventdata->subject = get_string("enrolmentnew", '', $course->shortname);
187 $eventdata->fullmessage = get_string('welcometocoursetext', '', $a);
188 $eventdata->fullmessageformat = FORMAT_PLAIN;
189 $eventdata->fullmessagehtml = '';
190 $eventdata->smallmessage = '';
191 events_trigger('message_send', $eventdata);
192
70beecd4 193 }
194
0f093efa 195 if (!empty($CFG->enrol_mailteachers)) {
6ba65fa0 196 $a->course = $course->fullname;
0f093efa 197 $a->user = fullname($user);
3b120e46 198
199 $eventdata = new object();
200 $eventdata->modulename = 'moodle';
201 $eventdata->userfrom = $user;
202 $eventdata->userto = $teacher;
203 $eventdata->subject = get_string("enrolmentnew", '', $course->shortname);
204 $eventdata->fullmessage = get_string('enrolmentnewuser', '', $a);
205 $eventdata->fullmessageformat = FORMAT_PLAIN;
206 $eventdata->fullmessagehtml = '';
207 $eventdata->smallmessage = '';
208 events_trigger('message_send', $eventdata);
04f47a89 209 }
0f093efa 210
211 if (!empty($CFG->enrol_mailadmins)) {
6ba65fa0 212 $a->course = $course->fullname;
0f093efa 213 $a->user = fullname($user);
214 $admins = get_admins();
3b120e46 215 foreach ($admins as $admin) {
216 $eventdata = new object();
217 $eventdata->modulename = 'moodle';
218 $eventdata->userfrom = $user;
219 $eventdata->userto = $admin;
220 $eventdata->subject = get_string("enrolmentnew", '', $course->shortname);
221 $eventdata->fullmessage = get_string('enrolmentnewuser', '', $a);
222 $eventdata->fullmessageformat = FORMAT_PLAIN;
223 $eventdata->fullmessagehtml = '';
224 $eventdata->smallmessage = '';
225 events_trigger('message_send', $eventdata);
0f093efa 226 }
227 }
228
04f47a89 229 }
230
231
232 } else if (strcmp ($result, "INVALID") == 0) { // ERROR
50c5bef4 233 $DB->insert_record("enrol_paypal", $data, false);
3b120e46 234 message_paypal_error_to_admin("Received an invalid payment notification!! (Fake payment?)", $data);
04f47a89 235 }
236 }
237
238 fclose($fp);
239 exit;
240
241
242
243/// FUNCTIONS //////////////////////////////////////////////////////////////////
244
245
3b120e46 246function message_paypal_error_to_admin($subject, $data) {
04f47a89 247 $admin = get_admin();
8f425a8f 248 $site = get_site();
04f47a89 249
250 $message = "$site->fullname: Transaction failed.\n\n$subject\n\n";
251
252 foreach ($data as $key => $value) {
253 $message .= "$key => $value\n";
254 }
255
3b120e46 256 $eventdata = new object();
257 $eventdata->modulename = 'moodle';
258 $eventdata->userfrom = $admin;
259 $eventdata->userto = $admin;
260 $eventdata->subject = "PAYPAL ERROR: ".$subject;
261 $eventdata->fullmessage = $message;
262 $eventdata->fullmessageformat = FORMAT_PLAIN;
263 $eventdata->fullmessagehtml = '';
264 $eventdata->smallmessage = '';
265 events_trigger('message_send', $eventdata);
04f47a89 266}
267
268?>