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 | |
211 | function 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 | ?> |