239 lines
7.0 KiB
PHP
239 lines
7.0 KiB
PHP
<?php
|
|
/**
|
|
* PayPal Reference Transaction API Response Class
|
|
*
|
|
* Parses response string received from the PayPal Express Checkout API for Reference Transaction related requests, which is simply a URL-encoded string of parameters
|
|
*
|
|
* @link https://developer.paypal.com/docs/classic/api/NVPAPIOverview/#id084DN080HY4
|
|
*
|
|
* Heavily inspired by the WC_Paypal_Express_API_Payment_Response class developed by the masterful SkyVerge team
|
|
*
|
|
* @package WooCommerce Subscriptions
|
|
* @subpackage Gateways/PayPal
|
|
* @category Class
|
|
* @since 2.0
|
|
*/
|
|
|
|
if ( ! defined( 'ABSPATH' ) ) {
|
|
exit; // Exit if accessed directly
|
|
}
|
|
|
|
class WCS_PayPal_Reference_Transaction_API_Response extends WC_Gateway_Paypal_Response {
|
|
|
|
/** @var array URL-decoded and parsed parameters */
|
|
protected $parameters = array();
|
|
|
|
/**
|
|
* Parse the response parameters from the raw URL-encoded response string
|
|
*
|
|
* @link https://developer.paypal.com/docs/classic/api/NVPAPIOverview/#id084FBM0M0HS
|
|
*
|
|
* @param string $response the raw URL-encoded response string
|
|
* @since 2.0
|
|
*/
|
|
public function __construct( $response ) {
|
|
|
|
// URL decode the response string and parse it
|
|
wp_parse_str( urldecode( $response ), $this->parameters );
|
|
}
|
|
|
|
/**
|
|
* Checks if response contains an API error code
|
|
*
|
|
* @link https://developer.paypal.com/docs/classic/api/errorcodes/
|
|
*
|
|
* @return bool true if has API error, false otherwise
|
|
* @since 2.0
|
|
*/
|
|
public function has_api_error() {
|
|
|
|
// assume something went wrong if ACK is missing
|
|
if ( ! $this->has_parameter( 'ACK' ) ) {
|
|
return true;
|
|
}
|
|
|
|
// any non-success ACK is considered an error, see
|
|
// https://developer.paypal.com/docs/classic/api/NVPAPIOverview/#id09C2F0K30L7
|
|
return ( 'Success' !== $this->get_parameter( 'ACK' ) && 'SuccessWithWarning' !== $this->get_parameter( 'ACK' ) );
|
|
}
|
|
|
|
/**
|
|
* Checks if response contains an API error code or message relating to invalid credentails
|
|
*
|
|
* @link https://developer.paypal.com/docs/classic/api/errorcodes/
|
|
*
|
|
* @return bool true if has API error relating to incorrect credentials, false otherwise
|
|
* @since 2.1
|
|
*/
|
|
public function has_api_error_for_credentials() {
|
|
|
|
$has_api_error_for_credentials = false;
|
|
|
|
// assume something went wrong if ACK is missing
|
|
if ( $this->has_api_error() ) {
|
|
|
|
foreach ( range( 0, 9 ) as $index ) {
|
|
|
|
// Error codes refer to multiple errors, go figure, so we need to compare both error codes and error messages
|
|
$has_credentials_error_code = $this->has_parameter( "L_ERRORCODE{$index}" ) && in_array( $this->get_parameter( "L_ERRORCODE{$index}" ), array( 10002, 10008 ) );
|
|
$has_credentials_error_message = $this->has_parameter( "L_LONGMESSAGE{$index}" ) && in_array( $this->get_parameter( "L_LONGMESSAGE{$index}" ), array( 'Username/Password is incorrect', 'Security header is not valid' ) );
|
|
|
|
if ( $has_credentials_error_code && $has_credentials_error_message ) {
|
|
$has_api_error_for_credentials = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $has_api_error_for_credentials;
|
|
}
|
|
|
|
/**
|
|
* Gets the API error code
|
|
*
|
|
* Note that PayPal can return multiple error codes, which are merged here
|
|
* for convenience
|
|
*
|
|
* @link https://developer.paypal.com/docs/classic/api/errorcodes/
|
|
*
|
|
* @return string
|
|
* @since 2.0
|
|
*/
|
|
public function get_api_error_code() {
|
|
|
|
$error_codes = array();
|
|
|
|
foreach ( range( 0, 9 ) as $index ) {
|
|
|
|
if ( $this->has_parameter( "L_ERRORCODE{$index}" ) ) {
|
|
$error_codes[] = $this->get_parameter( "L_ERRORCODE{$index}" );
|
|
}
|
|
}
|
|
|
|
return empty( $error_codes ) ? 'N/A' : trim( implode( ', ', $error_codes ) );
|
|
}
|
|
|
|
/**
|
|
* Gets the API error message
|
|
*
|
|
* Note that PayPal can return multiple error messages, which are merged here
|
|
* for convenience
|
|
*
|
|
* @link https://developer.paypal.com/docs/classic/api/errorcodes/
|
|
*
|
|
* @return string
|
|
* @since 2.0
|
|
*/
|
|
public function get_api_error_message() {
|
|
|
|
$error_messages = array();
|
|
|
|
foreach ( range( 0, 9 ) as $index ) {
|
|
|
|
if ( $this->has_parameter( "L_SHORTMESSAGE{$index}" ) ) {
|
|
|
|
$error_message = sprintf( '%s: %s - %s',
|
|
$this->has_parameter( "L_SEVERITYCODE{$index}" ) ? $this->get_parameter( "L_SEVERITYCODE{$index}" ) : _x( 'Error', 'used in api error message if there is no severity code from PayPal', 'woocommerce-subscriptions' ),
|
|
$this->get_parameter( "L_SHORTMESSAGE{$index}" ),
|
|
$this->has_parameter( "L_LONGMESSAGE{$index}" ) ? $this->get_parameter( "L_LONGMESSAGE{$index}" ) : _x( 'Unknown error', 'used in api error message if there is no long message', 'woocommerce-subscriptions' )
|
|
);
|
|
|
|
// append additional info if available
|
|
if ( $this->has_parameter( "L_ERRORPARAMID{$index}" ) && $this->has_parameter( "L_ERRORPARAMVALUE{$index}" ) ) {
|
|
$error_message .= sprintf( ' (%s - %s)', $this->get_parameter( "L_ERRORPARAMID{$index}" ), $this->get_parameter( "L_ERRORPARAMVALUE{$index}" ) );
|
|
}
|
|
|
|
$error_messages[] = $error_message;
|
|
}
|
|
}
|
|
|
|
return empty( $error_messages ) ? _x( 'N/A', 'no information about something', 'woocommerce-subscriptions' ) : trim( implode( ', ', $error_messages ) );
|
|
}
|
|
|
|
/**
|
|
* Returns true if the parameter is not empty
|
|
*
|
|
* @param string $name parameter name
|
|
* @return bool
|
|
* @since 2.0
|
|
*/
|
|
protected function has_parameter( $name ) {
|
|
return ! empty( $this->parameters[ $name ] );
|
|
}
|
|
|
|
/**
|
|
* Gets the parameter value, or null if parameter is not set or empty
|
|
*
|
|
* @param string $name parameter name
|
|
* @return string|null
|
|
* @since 2.0
|
|
*/
|
|
protected function get_parameter( $name ) {
|
|
return $this->has_parameter( $name ) ? $this->parameters[ $name ] : null;
|
|
}
|
|
|
|
/**
|
|
* Returns a message appropriate for a frontend user. This should be used
|
|
* to provide enough information to a user to allow them to resolve an
|
|
* issue on their own, but not enough to help nefarious folks fishing for
|
|
* info.
|
|
*
|
|
* @link https://developer.paypal.com/docs/classic/api/errorcodes/
|
|
*
|
|
* @return string user message, if there is one
|
|
* @since 2.0
|
|
*/
|
|
public function get_user_message() {
|
|
|
|
$allowed_user_error_message_codes = array(
|
|
'10445',
|
|
'10474',
|
|
'12126',
|
|
'13113',
|
|
'13122',
|
|
'13112',
|
|
);
|
|
|
|
return in_array( $this->get_api_error_code(), $allowed_user_error_message_codes ) ? $this->get_api_error_message() : null;
|
|
}
|
|
|
|
/**
|
|
* Returns the string representation of this response
|
|
*
|
|
* @return string response
|
|
* @since 2.0
|
|
*/
|
|
public function to_string() {
|
|
|
|
return print_r( $this->parameters, true );
|
|
}
|
|
|
|
/**
|
|
* Returns the string representation of this response with any and all
|
|
* sensitive elements masked or removed
|
|
*
|
|
* @return string response safe for logging/displaying
|
|
* @since 2.0
|
|
*/
|
|
public function to_string_safe() {
|
|
|
|
// no sensitive data to mask
|
|
return $this->to_string();
|
|
}
|
|
|
|
/**
|
|
* Get the order for a request based on the 'custom' response field
|
|
*
|
|
* @see WC_Gateway_Paypal_Response::get_paypal_order()
|
|
* @param string $response the raw URL-encoded response string
|
|
* @since 2.0
|
|
*/
|
|
public function get_order() {
|
|
|
|
// assume something went wrong if ACK is missing
|
|
if ( $this->has_parameter( 'CUSTOM' ) ) {
|
|
return $this->get_paypal_order( $this->get_parameter( 'CUSTOM' ) );
|
|
}
|
|
}
|
|
}
|