Advertisement
Guest User

Untitled

a guest
May 21st, 2016
109
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.79 KB | None | 0 0
  1. <?php
  2. /**
  3. * PayPal IPN Listener
  4. *
  5. * A class to listen for and handle Instant Payment Notifications (IPN) from
  6. * the PayPal server.
  7. *
  8. * https://github.com/Quixotix/PHP-PayPal-IPN
  9. *
  10. * @package PHP-PayPal-IPN
  11. * @author Micah Carrick
  12. * @copyright (c) 2012 - Micah Carrick
  13. * @version 2.1.0
  14. */
  15. class IpnListener {
  16.  
  17. /**
  18. * If true, the recommended cURL PHP library is used to send the post back
  19. * to PayPal. If flase then fsockopen() is used. Default true.
  20. *
  21. * @var boolean
  22. */
  23. public $use_curl = true;
  24.  
  25. /**
  26. * If true, explicitly sets cURL to use SSL version 3. Use this if cURL
  27. * is compiled with GnuTLS SSL.
  28. *
  29. * @var boolean
  30. */
  31. public $force_ssl_v3 = true;
  32.  
  33. /**
  34. * If true, cURL will use the CURLOPT_FOLLOWLOCATION to follow any
  35. * "Location: ..." headers in the response.
  36. *
  37. * @var boolean
  38. */
  39. public $follow_location = false;
  40.  
  41. /**
  42. * If true, an SSL secure connection (port 443) is used for the post back
  43. * as recommended by PayPal. If false, a standard HTTP (port 80) connection
  44. * is used. Default true.
  45. *
  46. * @var boolean
  47. */
  48. public $use_ssl = true;
  49.  
  50. /**
  51. * If true, the paypal sandbox URI www.sandbox.paypal.com is used for the
  52. * post back. If false, the live URI www.paypal.com is used. Default false.
  53. *
  54. * @var boolean
  55. */
  56. public $use_sandbox = true;
  57.  
  58. /**
  59. * The amount of time, in seconds, to wait for the PayPal server to respond
  60. * before timing out. Default 30 seconds.
  61. *
  62. * @var int
  63. */
  64. public $timeout = 30;
  65.  
  66. private $post_data = array();
  67. private $post_uri = '';
  68. private $response_status = '';
  69. private $response = '';
  70.  
  71. const PAYPAL_HOST = 'www.paypal.com';
  72. const SANDBOX_HOST = 'www.sandbox.paypal.com';
  73.  
  74. /**
  75. * Post Back Using cURL
  76. *
  77. * Sends the post back to PayPal using the cURL library. Called by
  78. * the processIpn() method if the use_curl property is true. Throws an
  79. * exception if the post fails. Populates the response, response_status,
  80. * and post_uri properties on success.
  81. *
  82. * @param string The post data as a URL encoded string
  83. */
  84. protected function curlPost($encoded_data) {
  85.  
  86. if ($this->use_ssl) {
  87. $uri = 'https://'.$this->getPaypalHost().'/cgi-bin/webscr';
  88. $this->post_uri = $uri;
  89. } else {
  90. $uri = 'http://'.$this->getPaypalHost().'/cgi-bin/webscr';
  91. $this->post_uri = $uri;
  92. }
  93.  
  94. $ch = curl_init();
  95.  
  96. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
  97. curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
  98. curl_setopt($ch, CURLOPT_CAINFO,
  99. dirname(__FILE__)."/cert/cert.pem");
  100. curl_setopt($ch, CURLOPT_URL, $uri);
  101. curl_setopt($ch, CURLOPT_POST, true);
  102. curl_setopt($ch, CURLOPT_POSTFIELDS, $encoded_data);
  103. curl_setopt($ch, CURLOPT_FOLLOWLOCATION, $this->follow_location);
  104. curl_setopt($ch, CURLOPT_TIMEOUT, $this->timeout);
  105. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  106. curl_setopt($ch, CURLOPT_HEADER, true);
  107.  
  108. if ($this->force_ssl_v3) {
  109. curl_setopt($ch, CURLOPT_SSLVERSION, 4);
  110. }
  111.  
  112. $this->response = curl_exec($ch);
  113. $this->response_status = strval(curl_getinfo($ch, CURLINFO_HTTP_CODE));
  114.  
  115. if ($this->response === false || $this->response_status == '0') {
  116. $errno = curl_errno($ch);
  117. $errstr = curl_error($ch);
  118. throw new Exception("cURL error: [$errno] $errstr");
  119. }
  120. }
  121.  
  122. /**
  123. * Post Back Using fsockopen()
  124. *
  125. * Sends the post back to PayPal using the fsockopen() function. Called by
  126. * the processIpn() method if the use_curl property is false. Throws an
  127. * exception if the post fails. Populates the response, response_status,
  128. * and post_uri properties on success.
  129. *
  130. * @param string The post data as a URL encoded string
  131. */
  132. protected function fsockPost($encoded_data) {
  133.  
  134. if ($this->use_ssl) {
  135. $uri = 'ssl://'.$this->getPaypalHost();
  136. $port = '443';
  137. $this->post_uri = $uri.'/cgi-bin/webscr';
  138. } else {
  139. $uri = $this->getPaypalHost(); // no "http://" in call to fsockopen()
  140. $port = '80';
  141. $this->post_uri = 'http://'.$uri.'/cgi-bin/webscr';
  142. }
  143.  
  144. $fp = fsockopen($uri, $port, $errno, $errstr, $this->timeout);
  145.  
  146. if (!$fp) {
  147. // fsockopen error
  148. throw new Exception("fsockopen error: [$errno] $errstr");
  149. }
  150.  
  151. $header = "POST /cgi-bin/webscr HTTP/1.1\r\n";
  152. $header .= "Host: ".$this->getPaypalHost()."\r\n";
  153. $header .= "Content-Type: application/x-www-form-urlencoded\r\n";
  154. $header .= "Content-Length: ".strlen($encoded_data)."\r\n";
  155. $header .= "Connection: Close\r\n\r\n";
  156.  
  157. fputs($fp, $header.$encoded_data."\r\n\r\n");
  158.  
  159. while(!feof($fp)) {
  160. if (empty($this->response)) {
  161. // extract HTTP status from first line
  162. $this->response .= $status = fgets($fp, 1024);
  163. $this->response_status = trim(substr($status, 9, 4));
  164. } else {
  165. $this->response .= fgets($fp, 1024);
  166. }
  167. }
  168.  
  169. fclose($fp);
  170. }
  171.  
  172. private function getPaypalHost() {
  173. if ($this->use_sandbox) return self::SANDBOX_HOST;
  174. else return self::PAYPAL_HOST;
  175. }
  176.  
  177. /**
  178. * Get POST URI
  179. *
  180. * Returns the URI that was used to send the post back to PayPal. This can
  181. * be useful for troubleshooting connection problems. The default URI
  182. * would be "ssl://www.sandbox.paypal.com:443/cgi-bin/webscr"
  183. *
  184. * @return string
  185. */
  186. public function getPostUri() {
  187. return $this->post_uri;
  188. }
  189.  
  190. /**
  191. * Get Response
  192. *
  193. * Returns the entire response from PayPal as a string including all the
  194. * HTTP headers.
  195. *
  196. * @return string
  197. */
  198. public function getResponse() {
  199. return $this->response;
  200. }
  201.  
  202. /**
  203. * Get Response Status
  204. *
  205. * Returns the HTTP response status code from PayPal. This should be "200"
  206. * if the post back was successful.
  207. *
  208. * @return string
  209. */
  210. public function getResponseStatus() {
  211. return $this->response_status;
  212. }
  213.  
  214. /**
  215. * Get Text Report
  216. *
  217. * Returns a report of the IPN transaction in plain text format. This is
  218. * useful in emails to order processors and system administrators. Override
  219. * this method in your own class to customize the report.
  220. *
  221. * @return string
  222. */
  223. public function getTextReport() {
  224.  
  225. $r = '';
  226.  
  227. // date and POST url
  228. for ($i=0; $i<80; $i++) { $r .= '-'; }
  229. $r .= "\n[".date('m/d/Y g:i A').'] - '.$this->getPostUri();
  230. if ($this->use_curl) $r .= " (curl)\n";
  231. else $r .= " (fsockopen)\n";
  232.  
  233. // HTTP Response
  234. for ($i=0; $i<80; $i++) { $r .= '-'; }
  235. $r .= "\n{$this->getResponse()}\n";
  236.  
  237. // POST vars
  238. for ($i=0; $i<80; $i++) { $r .= '-'; }
  239. $r .= "\n";
  240.  
  241. foreach ($this->post_data as $key => $value) {
  242. $r .= str_pad($key, 25)."$value\n";
  243. }
  244. $r .= "\n\n";
  245.  
  246. return $r;
  247. }
  248.  
  249. /**
  250. * Process IPN
  251. *
  252. * Handles the IPN post back to PayPal and parsing the response. Call this
  253. * method from your IPN listener script. Returns true if the response came
  254. * back as "VERIFIED", false if the response came back "INVALID", and
  255. * throws an exception if there is an error.
  256. *
  257. * @param array
  258. *
  259. * @return boolean
  260. */
  261. public function processIpn($post_data=null) {
  262.  
  263. $encoded_data = 'cmd=_notify-validate';
  264.  
  265. if ($post_data === null) {
  266. // use raw POST data
  267. if (!empty($_POST)) {
  268. $this->post_data = $_POST;
  269. $encoded_data .= '&'.file_get_contents('php://input');
  270. } else {
  271. throw new Exception("No POST data found.");
  272. }
  273. } else {
  274. // use provided data array
  275. $this->post_data = $post_data;
  276.  
  277. foreach ($this->post_data as $key => $value) {
  278. $encoded_data .= "&$key=".urlencode($value);
  279. }
  280. }
  281.  
  282. if ($this->use_curl) $this->curlPost($encoded_data);
  283. else $this->fsockPost($encoded_data);
  284.  
  285. if (strpos($this->response_status, '200') === false) {
  286. throw new Exception("Invalid response status: ".$this->response_status);
  287. }
  288.  
  289. if (strpos($this->response, "VERIFIED") !== false) {
  290. return true;
  291. } elseif (strpos($this->response, "INVALID") !== false) {
  292. return false;
  293. } else {
  294. throw new Exception("Unexpected response from PayPal.");
  295. }
  296. }
  297.  
  298. /**
  299. * Require Post Method
  300. *
  301. * Throws an exception and sets a HTTP 405 response header if the request
  302. * method was not POST.
  303. */
  304. public function requirePostMethod() {
  305. // require POST requests
  306. if ($_SERVER['REQUEST_METHOD'] && $_SERVER['REQUEST_METHOD'] != 'POST') {
  307. header('Allow: POST', true, 405);
  308. throw new Exception("Invalid HTTP request method.");
  309. }
  310. }
  311. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement