'https://api-3t.sandbox.paypal.com/nvp', 'live' => 'https://api-3t.paypal.com/nvp' ); /** * @var array URLs for sandbox and live */ private $_url = array( 'sandbox' => 'https://www.sandbox.paypal.com/webscr', 'live' => 'https://www.paypal.com/webscr' ); /** * @access private * @var string Query var for listener to watch for */ private $_listener_query_var = 'paypalListener'; /** * @access private * @var string Value that query var must be for listener to take overs */ private $_listener_query_var_value = 'IPN'; private $_currencies = array(); /** * This is our constructor, which is private to force the use of * getInstance() to make this a Singleton * * @return wpPayPalFramework */ private function __construct() { $this->_getSettings(); $this->_fixDebugEmails(); $this->_currencies = array( 'AUD' => __( 'Australian Dollar', 'paypal-framework' ), 'CAD' => __( 'Canadian Dollar', 'paypal-framework' ), 'CZK' => __( 'Czech Koruna', 'paypal-framework' ), 'DKK' => __( 'Danish Krone', 'paypal-framework' ), 'EUR' => __( 'Euro', 'paypal-framework' ), 'HKD' => __( 'Hong Kong Dollar', 'paypal-framework' ), 'HUF' => __( 'Hungarian Forint', 'paypal-framework' ), 'ILS' => __( 'Israeli New Sheqel', 'paypal-framework' ), 'JPY' => __( 'Japanese Yen', 'paypal-framework' ), 'MXN' => __( 'Mexican Peso', 'paypal-framework' ), 'NOK' => __( 'Norwegian Krone', 'paypal-framework' ), 'NZD' => __( 'New Zealand Dollar', 'paypal-framework' ), 'PLN' => __( 'Polish Zloty', 'paypal-framework' ), 'GBP' => __( 'Pound Sterling', 'paypal-framework' ), 'SGD' => __( 'Singapore Dollar', 'paypal-framework' ), 'SEK' => __( 'Swedish Krona', 'paypal-framework' ), 'CHF' => __( 'Swiss Franc', 'paypal-framework' ), 'USD' => __( 'U.S. Dollar', 'paypal-framework' ) ); /** * Add filters and actions */ add_action( 'admin_init', array($this,'registerOptions') ); add_action( 'admin_menu', array($this,'adminMenu') ); add_action( 'template_redirect', array( $this, 'listener' ) ); add_filter( 'query_vars', array( $this, 'addPaypalListenerVar' ) ); add_filter( 'init', array( $this, 'init_locale' ) ); if ( 'on' == $this->_settings['legacy_support'] ) add_action( 'init', 'paypalFramework_legacy_function' ); } /** * If an instance exists, this returns it. If not, it creates one and * retuns it. * * @return wpPayPalFramework */ public static function getInstance() { if ( !self::$instance ) self::$instance = new self; return self::$instance; } public function init_locale() { load_plugin_textdomain( 'paypal-framework', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' ); } private function _getSettings() { if (empty($this->_settings)) $this->_settings = get_option( $this->_optionsName ); if ( !is_array( $this->_settings ) ) $this->_settings = array(); $defaults = array( 'sandbox' => 'sandbox', 'username-sandbox' => '', 'password-sandbox' => '', 'signature-sandbox' => '', 'username-live' => '', 'password-live' => '', 'signature-live' => '', 'version' => '58.0', 'currency' => 'USD', 'debugging' => 'on', 'debugging_email' => '', 'legacy_support' => 'off', ); $this->_settings = wp_parse_args( $this->_settings, $defaults ); } public function getSetting( $settingName, $default = false ) { if (empty($this->_settings)) $this->_getSettings(); if ( isset($this->_settings[$settingName]) ) return $this->_settings[$settingName]; else return $default; } public function registerOptions() { register_setting( $this->_optionsGroup, $this->_optionsName ); } public function adminMenu() { $page = add_options_page( __( 'PayPal Settings', 'paypal-framework' ), __( 'PayPal', 'paypal-framework' ), 'manage_options', 'PayPalFramework', array( $this, 'options' ) ); add_action( 'admin_print_styles-' . $page, array( $this, 'admin_css' ) ); } public function admin_css() { wp_enqueue_style( 'paypal-framework', plugin_dir_url( __FILE__ ) . 'paypal-framework.css', array(), '0.0.1' ); } /** * This is used to display the options page for this plugin */ public function options() { ?>

_optionsGroup ); ?>
_show_help( 'live' ); ?>
_show_help( 'live' ); ?>
_show_help( 'live' ); ?>
_show_help( 'sandbox' ); ?>
_show_help( 'sandbox' ); ?>
_show_help( 'sandbox' ); ?>
_settings['sandbox']); ?> />
_settings['sandbox']); ?> />
most recent version.", 'paypal-framework' ), 'http://developer.paypal-portal.com/pdn/board/message?board.id=nvp&thread.id=4475' ); ?>
_settings['debugging']); ?> />
_settings['debugging']); ?> />
_settings['legacy_support']); ?> />
_settings['legacy_support']); ?> />
This could conflict with an existing %2$s function if you have it defined elsewhere.', 'paypal-framework'), 'hashCall()', 'hash_call()' ); ?> This could conflict with an existing %2$s function if you have it defined elsewhere.', 'paypal-framework'), 'hashCall()', 'hash_call()' ); ?>
_listener_query_var.'='.urlencode($this->_listener_query_var_value); ?> _show_help( 'listener' ); ?>

' . __( 'Help', 'paypal-framework' ) . ''; switch ( $help ) { case 'live': ?>
  1. sign up for one.', 'paypal-framework'), 'https://www.paypal.com/us/mrb/pal=TJ287296FD8KW'); ?>
  2. sign up for it.', 'paypal-framework'), 'https://www.paypal.com/us/cgi-bin/webscr?cmd=_wp-pro-overview'); ?>
  3. set it up.", 'paypal-framework' ), 'https://www.paypal.com/cgi-bin/webscr?cmd=xpt/cps/general/DPRPLaunch-outside'); ?>
  4. "Profile" -> "Request API credentials" -> "PayPal API" -> "Set up PayPal API credentials and permissions". If asked, you want to request an "API signature" not a certificate. All the data that you are given should easily fit in this form.', 'paypal-framework'); ?>

PayPal sandbox account.', 'paypal-framework'), 'https://developer.paypal.com/'); ?>

  1. Profile on the My Account tab.', 'paypal-framework'); ?>
  2. Instant Payment Notification Preferences in the Selling Preferences column.', 'paypal-framework'); ?>
  3. Edit IPN Settings to specify your listener's URL and activate the listener.", 'paypal-framework'); ?>
  4. Save.', 'paypal-framework'); ?>
  5. Back to Profile Summary to return to the Profile after activating your listener.", 'paypal-framework'); ?>
$this->_settings['version'], 'PWD' => $this->_settings["password-{$this->_settings['sandbox']}"], 'USER' => $this->_settings["username-{$this->_settings['sandbox']}"], 'SIGNATURE' => $this->_settings["signature-{$this->_settings['sandbox']}"], 'CURRENCYCODE' => $this->_settings['currency'], ); return wp_parse_args( $req, $defaults ); } /** * Convert an associative array into an NVP string * * @param array Associative array to create NVP string from * @param string[optional] Used to separate arguments (defaults to &) * * @return string NVP string */ public function makeNVP( $reqArray, $sep = '&' ) { if ( !is_array($reqArray) ) return $reqArray; return http_build_query( $reqArray, '', $sep ); } /** * hashCall: Function to perform the API call to PayPal using API signature * @param string|array $args Parameters needed for call * * @return array On success return associtive array containing the response from the server. */ public function hashCall( $args ) { $params = array( 'body' => $this->_prepRequest($args), 'sslverify' => false, 'timeout' => 30, ); // Send the request $resp = wp_remote_post( $this->_endpoint[$this->_settings['sandbox']], $params ); // If the response was valid, decode it and return it. Otherwise return a WP_Error if ( !is_wp_error($resp) && $resp['response']['code'] >= 200 && $resp['response']['code'] < 300 ) { // Used for debugging. $request = $this->_sanitizeRequest($params['body']); $message = __( 'Request:', 'paypal-framework' ); $message .= "\r\n".print_r($request, true)."\r\n\r\n"; $message .= __( 'Response:', 'paypal-framework' ); $message .= "\r\n".print_r(wp_parse_args( $resp['body'] ), true)."\r\n\r\n"; $this->_debug_mail( _( 'PayPal Framework - hashCall sent successfully', 'paypal-framework' ), $message ); return wp_parse_args($resp['body']); } else { $request = $this->_sanitizeRequest($params['body']); $message = __( 'Request:', 'paypal-framework' ); $message .= "\r\n".print_r($request, true)."\r\n\r\n"; $message .= __( 'Response:', 'paypal-framework' ); $message .= "\r\n".print_r($resp, true)."\r\n\r\n"; $this->_debug_mail( __( 'PayPal Framework - hashCall failed', 'paypal-framework' ), $message ); if ( !is_wp_error($resp) ) $resp = new WP_Error('http_request_failed', $resp['response']['message'], $resp['response']); return $resp; } } private function _sanitizeRequest($request) { /** * If this is a live request, hide sensitive data in the debug * E-Mails we send */ if ( $this->_settings['sandbox'] != 'sandbox' ) { if ( !empty( $request['ACCT'] ) ) $request['ACCT'] = str_repeat('*', strlen($request['ACCT'])-4) . substr($request['ACCT'], -4); if ( !empty( $request['EXPDATE'] ) ) $request['EXPDATE'] = str_repeat('*', strlen($request['EXPDATE'])); if ( !empty( $request['CVV2'] ) ) $request['CVV2'] = str_repeat('*', strlen($request['CVV2'])); } return $request; } /** * Used to direct the user to the Express Checkout * * @param string|array $args Parameters needed for call. *token is REQUIRED* */ public function sendToExpressCheckout($args) { $args['cmd'] = '_express-checkout'; $nvpString = $this->makeNVP($args); wp_redirect($this->_url[$this->_settings['sandbox']] . "?{$nvpString}"); exit; } /** * This is our listener. If the proper query var is set correctly it will * attempt to handle the response. */ public function listener() { // Check that the query var is set and is the correct value. if (get_query_var( $this->_listener_query_var ) == $this->_listener_query_var_value) { $_POST = stripslashes_deep($_POST); // Try to validate the response to make sure it's from PayPal if ($this->_validateMessage()) $this->_processMessage(); // Stop WordPress entirely exit; } } /** * Get the PayPal URL based on current setting for sandbox vs live */ public function getUrl() { return $this->_url[$this->_settings['sandbox']]; } public function _fixDebugEmails() { $this->_settings['debugging_email'] = preg_split('/\s*,\s*/', $this->_settings['debugging_email']); $this->_settings['debugging_email'] = array_filter($this->_settings['debugging_email'], 'is_email'); $this->_settings['debugging_email'] = implode(',', $this->_settings['debugging_email']); } private function _debug_mail( $subject, $message ) { // Used for debugging. if ( $this->_settings['debugging'] == 'on' && !empty($this->_settings['debugging_email']) ) wp_mail( $this->_settings['debugging_email'], $subject, $message ); } /** * Validate the message by checking with PayPal to make sure they really * sent it */ private function _validateMessage() { // Set the command that is used to validate the message $_POST['cmd'] = "_notify-validate"; // We need to send the message back to PayPal just as we received it $params = array( 'body' => $_POST ); // Send the request $resp = wp_remote_post( $this->_url[$this->_settings['sandbox']], $params ); // Put the $_POST data back to how it was so we can pass it to the action unset( $_POST['cmd'] ); $message = __('URL:', 'paypal-framework' ); $message .= "\r\n".print_r($this->_url[$this->_settings['sandbox']], true)."\r\n\r\n"; $message .= __('Options:', 'paypal-framework' ); $message .= "\r\n".print_r($this->_settings, true)."\r\n\r\n"; $message .= __('Response:', 'paypal-framework' ); $message .= "\r\n".print_r($resp, true)."\r\n\r\n"; $message .= __('Post:', 'paypal-framework' ); $message .= "\r\n".print_r($_POST, true); // If the response was valid, check to see if the request was valid if ( !is_wp_error($resp) && $resp['response']['code'] >= 200 && $resp['response']['code'] < 300 && (strcmp( $resp['body'], "VERIFIED") == 0)) { $this->_debug_mail( __( 'IPN Listener Test - Validation Succeeded', 'paypal-framework' ), $message ); return true; } else { // If we can't validate the message, assume it's bad $this->_debug_mail( __( 'IPN Listener Test - Validation Failed', 'paypal-framework' ), $message ); return false; } } /** * Add our query var to the list of query vars */ public function addPaypalListenerVar($public_query_vars) { $public_query_vars[] = $this->_listener_query_var; return $public_query_vars; } /** * Throw an action based off the transaction type of the message */ private function _processMessage() { do_action( 'paypal-ipn', $_POST ); $actions = array( 'paypal-ipn' ); $subject = sprintf( __( 'IPN Listener Test - %s', 'paypal-framework' ), '_processMessage()' ); if ( !empty($_POST['txn_type']) ) { do_action("paypal-{$_POST['txn_type']}", $_POST); $actions[] = "paypal-{$_POST['txn_type']}"; } $message = sprintf( __( 'Actions thrown: %s', 'paypal-framework' ), implode( ', ', $actions ) ); $message .= "\r\n\r\n"; $message .= sprintf( __( 'Passed to actions: %s', 'paypal-framework' ), "\r\n" . print_r($_POST, true) ); $this->_debug_mail( $subject, $message ); } } /** * Helper functions */ function hashCall ($args) { $wpPayPalFramework = wpPayPalFramework::getInstance(); return $wpPayPalFramework->hashCall($args); } function paypalFramework_legacy_function() { //Only load if the function doesn't already exist if ( !function_exists('hash_call') ) { /** * Support the old method of using hash_call */ function hash_call($methodName, $nvpStr) { _deprecated_function(__FUNCTION__, '0.1', 'wpPayPalFramework::hashCall()'); $nvpStr = wp_parse_args( $nvpStr ); $nvpStr['METHOD'] = $methodName; $nvpStr = array_map('urldecode', $nvpStr); $wpPayPalFramework = wpPayPalFramework::getInstance(); return $wpPayPalFramework->hashCall($nvpStr); } } } // Instantiate our class $wpPayPalFramework = wpPayPalFramework::getInstance();