* Copyright 2001-2010 Strangecode, LLC * * This file is part of The Strangecode Codebase. * * The Strangecode Codebase is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as published by the * Free Software Foundation, either version 3 of the License, or (at your option) * any later version. * * The Strangecode Codebase is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * The Strangecode Codebase. If not, see . */ /** * PayPal.inc.php * * The PayPal class provides functions for creating PayPal buttons and for * receiving PayPal's Instant Payment Notification (IPN) service. * * @author Quinn Comendant * @version 1.0 */ class PayPal { // General object parameters. var $_params = array( 'paypal_url' => 'https://www.paypal.com/cgi-bin/webscr', 'test_mode' => false, ); // Options used for specific buttons and links. var $_default_button_options = array(); // Array of buttons created by newButton(). var $_buttons = array(); // Store the response from the last IPN. var $_ipn_response; /** * Constructor. * * @param bool $test_mode Use PayPal sandbox for testing. */ function PayPal($test_mode=false) { if ($test_mode) { $this->setParam(array('test_mode' => true)); // Use PayPal sandbox when in test mode. $url = 'www.sandbox.paypal.com'; } else { $url = 'www.paypal.com'; } $this->_default_button_options = array( '_global' => array( 'business' => null, ), 'web_accept' => array( 'cmd' => '_xclick', 'button_url' => 'https://' . $url . '/cgi-bin/webscr', 'link_url' => 'https://' . $url . '/xclick/', 'submit_img' => 'https://' . $url . '/en_US/i/btn/x-click-but23.gif', 'submit_text' => _("Pay with PayPal"), ), 'subscriptions' => array( 'cmd' => '_xclick-subscriptions', 'button_url' => 'https://' . $url . '/cgi-bin/webscr', 'link_url' => 'https://' . $url . '/subscriptions/', 'submit_img' => 'https://' . $url . '/en_US/i/btn/x-click-but20.gif', 'submit_text' => _("Subscribe with PayPal"), ), ); } /** * Updates the _default_button_options array with options used for * specific buttons, or all buttons if $type is null. * * @access public * * @param mixed $type The type of button to set defaults. If null, * sets the global button types. * @param array $options Options to set for button. * * @return bool True on success, false on failure. */ function setButtonDefaults($type, $options) { $app =& App::getInstance(); if (!is_array($options) || empty($options)) { $app->logMsg(sprintf('Invalid options: %s', truncate(getDump($options, true), 128, 'end')), LOG_WARNING, __FILE__, __LINE__); return false; } if (is_null($type) || '_global' == $type) { $this->_default_button_options['_global'] = array_merge($this->_default_button_options['_global'], $options); } else if (!isset($this->_default_button_options[$type])) { $app->logMsg(sprintf('Invalid button type: %s', $type), LOG_WARNING, __FILE__, __LINE__); return false; } $this->_default_button_options[$type] = array_merge($this->_default_button_options[$type], $options); return true; } /** * Creates a new element in the _buttons array. Uses _default_button_options * merged with provided options. * * @access public * * @param string $type Type of button to create. * @param string $name Name of button to create. * @param array $options Options of button. Overwrites _default_button_options. * * @return bool True on success, false on failure. */ function newButton($type, $name, $options=null) { $app =& App::getInstance(); if (!isset($this->_default_button_options[$type])) { $app->logMsg(sprintf('Invalid button type: %s', $type), LOG_WARNING, __FILE__, __LINE__); return false; } if (!is_array($options) || empty($options)) { $app->logMsg(sprintf('Invalid options: %s', truncate(getDump($options, true), 128, 'end')), LOG_WARNING, __FILE__, __LINE__); return false; } if (isset($this->_buttons[$name])) { $app->logMsg(sprintf('Overwriting existing button name: %s', truncate(getDump($this->_buttons[$name], true), 128, 'end')), LOG_DEBUG, __FILE__, __LINE__); } $this->_buttons[$name] = array( 'type' => $type, 'options' => array_merge($this->_default_button_options['_global'], $this->_default_button_options[$type], $options) ); return true; } /** * Returns the URL link for specified button. * * @access public * * @param string $name Name of button for which to generate link. * * @return mixed Link of button, or false on failure. */ function getLink($name) { $app =& App::getInstance(); if (!isset($this->_buttons[$name])) { $app->logMsg(sprintf('Button does not exist: %s', $name), LOG_WARNING, __FILE__, __LINE__); return false; } $query_string = ''; $delim = ''; if (is_array($this->_buttons[$name]['options']) && !empty($this->_buttons[$name]['options'])) { foreach ($this->_buttons[$name]['options'] as $key=>$val) { if (!in_array($key, array('button_url', 'link_url', 'cmd', 'submit_img', 'submit_text'))) { $query_string .= $delim . $key . '=' . urlencode($val); $delim = '&'; } } } // PayPal links do not like urlencoded slashes for some stupid reason. $search = array('/%2F/'); $replace = array('/'); return $this->_buttons[$name]['options']['link_url'] . preg_replace($search, $replace, $query_string); } /** * Prints the link returned by getLink(). * * @access public * * @param string $name Name of button for which to generate link. */ function printLink($name) { echo $this->getLink($name); } /** * Prints button with specified name. * * @access public * * @param string $name Name of button to print. */ function printButton($name) { ?>
_buttons[$name]['options']) && !empty($this->_buttons[$name]['options'])) { foreach ($this->_buttons[$name]['options'] as $key=>$val) { if (!in_array($key, array('button_url', 'link_url', 'submit_img', 'submit_text'))) { ?>
val pairs). */ function setParam($params) { $app =& App::getInstance(); if (isset($params) && is_array($params)) { // Merge new parameters with old overriding only those passed. $this->_params = array_merge($this->_params, $params); } else { $app->logMsg(sprintf('Parameters are not an array: %s', $params), LOG_ERR, __FILE__, __LINE__); } } /** * Return the value of a parameter, if it exists. * * @access public * @param string $param Which parameter to return. * @return mixed Configured parameter value. */ function getParam($param) { $app =& App::getInstance(); if (isset($this->_params[$param])) { return $this->_params[$param]; } else { $app->logMsg(sprintf('Parameter is not set: %s', $param), LOG_DEBUG, __FILE__, __LINE__); return null; } } /** * Tests if the HTTP request is a valid IPN request from PayPal. * * @access public * * @return bool True if valid, false if invalid. */ function incomingIPNRequest() { if ($_SERVER['REQUEST_METHOD'] == 'POST' && $_SERVER['CONTENT_TYPE'] == 'application/x-www-form-urlencoded' && !empty($_POST)) { return true; } else { return false; } } /** * Process incoming IPN. * * @access public * * @return bool True on success, false on failure. */ function processIPN() { $app =& App::getInstance(); if (getPost('test_ipn') == '1' || $this->getParam('test_mode')) { $app->logMsg(sprintf('Processing PayPal IPN in test mode: %s', truncate(getDump(getFormData(), true), 128, 'end')), LOG_DEBUG, __FILE__, __LINE__); $url = parse_url('https://www.sandbox.paypal.com/cgi-bin/webscr'); } else { $app->logMsg(sprintf('Processing PayPal IPN: %s', truncate(getDump(getFormData(), true), 128, 'end')), LOG_DEBUG, __FILE__, __LINE__); $url = parse_url($this->getParam('paypal_url')); } // Read POST request and add 'cmd'. $received_data = getPost(); $return_data = 'cmd=_notify-validate'; foreach ($received_data as $post_key => $post_val) { $return_data .= '&' . $post_key . '=' . urlencode($post_val); } // Set the port number based on the scheme. if ($url['scheme'] == "https") { $url['port'] = 443; $ssl = 'ssl://'; } else { $url['port'] = 80; $ssl = ''; } // Open connection to PayPal server. $fp = fsockopen($ssl . $url['host'], $url['port'], $errnum, $errstr, 30); if (!$fp) { $app->logMsg(sprintf('Connection to PayPal URL %s failed with error: %s (%s)', $ssl . $url['host'], $errstr, $errnum), LOG_WARNING, __FILE__, __LINE__); return false; } else { fputs($fp, "POST {$url['path']} HTTP/1.1\r\n"); fputs($fp, "Host: {$url['host']}\r\n"); fputs($fp, "Content-type: application/x-www-form-urlencoded\r\n"); fputs($fp, "Content-length: " . mb_strlen($return_data) . "\r\n"); fputs($fp, "Connection: close\r\n\r\n"); fputs($fp, $return_data . "\r\n\r\n"); // Loop through the response lines from the server. $this->_ipn_response = ''; while (!feof($fp)) { $this->_ipn_response .= fgets($fp, 1024); } fclose($fp); $app->logMsg(sprintf('IPN response received: %s', $this->_ipn_response), LOG_NOTICE, __FILE__, __LINE__); return true; } } /** * Checks the response received from PayPal's IPN upon calling processIPN(). * * @access public * * @return bool True if response contains VERIFIED, false otherwise. */ function verifiedIPN() { $app =& App::getInstance(); if (!isset($this->_ipn_response)) { $app->logMsg(sprintf('Cannot verify IPN, response not received.', null), LOG_WARNING, __FILE__, __LINE__); return false; } if (empty($this->_ipn_response)) { $app->logMsg(sprintf('Cannot verify IPN, response empty.', null), LOG_WARNING, __FILE__, __LINE__); return false; } if (preg_match('/VERIFIED/', $this->_ipn_response)) { $app->logMsg(sprintf('IPN verified!', null), LOG_DEBUG, __FILE__, __LINE__); return true; } else if (preg_match('/INVALID/', $this->_ipn_response)) { $app->logMsg(sprintf('IPN invalid.', null), LOG_DEBUG, __FILE__, __LINE__); return false; } else { $app->logMsg(sprintf('IPN unknown.', null), LOG_WARNING, __FILE__, __LINE__); return false; } } } // End of class. ?>