CVE-2015-10117: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting') (CWE-79)
value: A vulnerability, which was classified as problematic, was found in Gravity Forms DPS PxPay Plugin up to 1.4.2 on WordPress. Affected is an unknown function. The manipulation leads to cross site scripting. It is possible to launch the attack remotely. Upgrading to version 1.4.3 is able to address this issue. The name of the patch is 5966a5e6343e3d5610bdfa126a5cfbae95e629b6. It is recommended to upgrade the affected component. The identifier of this vulnerability is VDB-230664.
CWE description: The product does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users.
CVSS v3 base score: 6.1
Published: 2023-06-06T02:15Z
Repository: https://github.com/wp-plugins/gravity-forms-dps-pxpay
Language: PHP
Files changed: gravityforms-dps-pxpay.php, includes/class.GFDpsPxPayAdmin.php, includes/class.GFDpsPxPayFeedAdmin.php, includes/class.GFDpsPxPayPayment.php, includes/class.GFDpsPxPayPlugin.php, includes/class.GFDpsPxPayResult.php, readme.md, readme.txt, views/metabox-save.php, views/requires-extensions.php
Commit date: 2015-05-01 02:50:24 +0000
Commit message: gravity-forms-dps-pxpay 1.4.3: XSS, error handling, new hooks

git-svn-id: https://plugins.svn.wordpress.org/gravity-forms-dps-pxpay/trunk@1150713 b8457f37-d9ea-0310-8a92-e5e31aec5664

Diff: diff --git a/gravityforms-dps-pxpay.php b/gravityforms-dps-pxpay.php
index 790f82c..1de89a8 100644
--- a/gravityforms-dps-pxpay.php
+++ b/gravityforms-dps-pxpay.php
@@ -1,17 +1,17 @@
 <?php
 /*
 Plugin Name: Gravity Forms DPS PxPay
 Plugin URI: http://shop.webaware.com.au/downloads/gravity-forms-dps-pxpay/
 Description: Integrates Gravity Forms with DPS PxPay payment gateway, enabling end users to purchase goods and services through Gravity Forms.
-Version: 1.4.2
+Version: 1.4.3
 Author: WebAware
 Author URI: http://webaware.com.au/
 */
 
 /*
-copyright (c) 2013-2014 WebAware Pty Ltd (email : support@webaware.com.au)
+copyright (c) 2013-2015 WebAware Pty Ltd (email : support@webaware.com.au)
 
 This program 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 2
 of the License, or (at your option) any later version.
@@ -32,11 +32,11 @@ if (!defined('ABSPATH')) {
 
 define('GFDPSPXPAY_PLUGIN_ROOT', dirname(__FILE__) . '/');
 define('GFDPSPXPAY_PLUGIN_NAME', basename(dirname(__FILE__)) . '/' . basename(__FILE__));
 define('GFDPSPXPAY_PLUGIN_FILE', __FILE__);
 define('GFDPSPXPAY_PLUGIN_OPTIONS', 'gfdpspxpay_plugin');
-define('GFDPSPXPAY_PLUGIN_VERSION', '1.4.2');
+define('GFDPSPXPAY_PLUGIN_VERSION', '1.4.3');
 
 // custom post types
 define('GFDPSPXPAY_TYPE_FEED', 'gfdpspxpay_feed');
 
 /**
diff --git a/includes/class.GFDpsPxPayAdmin.php b/includes/class.GFDpsPxPayAdmin.php
index f206933..c28e75e 100644
--- a/includes/class.GFDpsPxPayAdmin.php
+++ b/includes/class.GFDpsPxPayAdmin.php
@@ -132,11 +132,11 @@ class GFDpsPxPayAdmin {
 	* action hook for adding plugin action links
 	*/
 	public function addPluginActionLinks($links) {
 		// add settings link, but only if GravityForms plugin is active
 		if (self::isGfActive()) {
-			$settings_link = sprintf('<a href="%s">Settings</a>', admin_url('admin.php?page=gf_settings&subview=DPS+PxPay'));
+			$settings_link = sprintf('<a href="%s">Settings</a>', esc_url(admin_url('admin.php?page=gf_settings&subview=DPS+PxPay')));
 			array_unshift($links, $settings_link);
 		}
 
 		return $links;
 	}
@@ -144,12 +144,12 @@ class GFDpsPxPayAdmin {
 	/**
 	* action hook for adding plugin details links
 	*/
 	public static function addPluginDetailsLinks($links, $file) {
 		if ($file == GFDPSPXPAY_PLUGIN_NAME) {
-			$links[] = '<a href="http://wordpress.org/support/plugin/gravity-forms-dps-pxpay">' . __('Get help') . '</a>';
-			$links[] = '<a href="http://wordpress.org/plugins/gravity-forms-dps-pxpay/">' . __('Rating') . '</a>';
+			$links[] = '<a href="https://wordpress.org/support/plugin/gravity-forms-dps-pxpay">' . __('Get help') . '</a>';
+			$links[] = '<a href="https://wordpress.org/plugins/gravity-forms-dps-pxpay/">' . __('Rating') . '</a>';
 			$links[] = '<a href="http://shop.webaware.com.au/downloads/gravity-forms-dps-pxpay/">' . __('Donate') . '</a>';
 		}
 
 		return $links;
 	}
@@ -215,10 +215,12 @@ class GFDpsPxPayAdmin {
 	* validate settings on save
 	* @param array $input
 	* @return array
 	*/
 	public function settingsValidate($input) {
+		$output = array();
+
 		$output['userID']			= trim($input['userID']);
 		$output['userKey']			= trim($input['userKey']);
 		$output['testID']			= trim($input['testID']);
 		$output['testKey']			= trim($input['testKey']);
 		$output['useTest']			= empty($input['useTest']) ? 0 : 1;
diff --git a/includes/class.GFDpsPxPayFeedAdmin.php b/includes/class.GFDpsPxPayFeedAdmin.php
index 88e9206..a219dcc 100644
--- a/includes/class.GFDpsPxPayFeedAdmin.php
+++ b/includes/class.GFDpsPxPayFeedAdmin.php
@@ -103,12 +103,12 @@ class GFDpsPxPayFeedAdmin {
 	* metabox for Return to List link
 	* @param WP_Post $post
 	* @param array $metabox has metabox id, title, callback, and args elements.
 	*/
 	public function metaboxList($post, $metabox) {
-		$feedsURL = 'edit.php?post_type=' . GFDPSPXPAY_TYPE_FEED;
-		echo "<a href=\"$feedsURL\">Click to return to list</a>.\n";
+		$feedsURL = admin_url('edit.php?post_type=' . GFDPSPXPAY_TYPE_FEED);
+		printf('<a href="%s">Click to return to list</a>', esc_url($feedsURL));
 	}
 
 	/**
 	* metabox for custom save/publish
 	* @param WP_Post $post
@@ -265,12 +265,12 @@ class GFDpsPxPayFeedAdmin {
 				$feed = new GFDpsPxPayFeed();
 				$feed->loadFromPost($post);
 
 				$delete = array_pop($actions);		// pop the end link, so that we can "insert" ours before it
 
-				$actions['entries'] = sprintf('<a href="%s" title="%s">%s</a>',
-					add_query_arg(array('page' => 'gf_entries', 'id' => $feed->FormID), admin_url('admin.php')), 'View Entries', 'Entries');
+				$url = add_query_arg(array('page' => 'gf_entries', 'id' => $feed->FormID), admin_url('admin.php'));
+				$actions['entries'] = sprintf('<a href="%s" title="%s">%s</a>', esc_url($url), 'View Entries', 'Entries');
 
 				$actions['delete'] = $delete;		// replace the end link
 			}
 			catch (GFDpsPxPayException $e) {
 				// NOP -- we'll have an empty feed
diff --git a/includes/class.GFDpsPxPayPayment.php b/includes/class.GFDpsPxPayPayment.php
index 73f48c6..dd23a7d 100644
--- a/includes/class.GFDpsPxPayPayment.php
+++ b/includes/class.GFDpsPxPayPayment.php
@@ -234,10 +234,12 @@ class GFDpsPxPayPaymentResponse {
 	* URL to redirect browser to where credit card details can be entered
 	* @var string
 	*/
 	public $paymentURL;
 
+	protected $errorMessage;
+
 	/**
 	* load DPS PxPay response data as XML string
 	* @param string $response DPS PxPay response as a string (hopefully of XML data)
 	* @throws GFDpsPxPayException
 	*/
@@ -254,26 +256,49 @@ class GFDpsPxPayPaymentResponse {
 					$errmsg .= $error->message;
 				}
 				throw new Exception($errmsg);
 			}
 
-			$this->isValid = ('1' === ((string) $xml['valid']));
-			$this->paymentURL = (string) $xml->URI;
+			if ('1' === ((string) $xml['valid'])) {
+				$this->isValid = true;
+				$this->paymentURL = (string) $xml->URI;
+
+				if (empty($this->paymentURL)) {
+					$this->isValid = false;
+
+					$this->errorMessage = (string) $xml->ResponseText;
+					if (empty($this->errorMessage)) {
+						$this->errorMessage = 'no hosted page URI given';
+					}
+				}
+			}
+			else {
+				$this->isValid = false;
+				$this->errorMessage = (string) $xml->ResponseText;
+				if (empty($this->errorMessage)) {
+					// API 1.0 passed error message in URI
+					$this->errorMessage = (string) $xml->URI;
+
+					if (empty($this->errorMessage)) {
+						$this->errorMessage = 'invalid request';
+					}
+				}
+			}
 
 			// restore old libxml settings
 			libxml_disable_entity_loader($oldDisableEntityLoader);
 			libxml_use_internal_errors($oldUseInternalErrors);
 		}
 		catch (Exception $e) {
 			// restore old libxml settings
 			libxml_disable_entity_loader($oldDisableEntityLoader);
 			libxml_use_internal_errors($oldUseInternalErrors);
 
-			throw new GFDpsPxPayException('Error parsing DPS PxPay generate response: ' . $e->getMessage());
+			throw new GFDpsPxPayException('Error parsing DPS PxPay request: ' . $e->getMessage());
 		}
 
-		// if response is "invalid", throw error with message given in URI field
+		// if response is "invalid", throw error with message
 		if (!$this->isValid) {
-			throw new GFDpsPxPayException('Error from DPS PxPay generate response: ' . $this->paymentURL);
+			throw new GFDpsPxPayException('Error from DPS PxPay request: ' . $this->errorMessage);
 		}
 	}
 }
diff --git a/includes/class.GFDpsPxPayPlugin.php b/includes/class.GFDpsPxPayPlugin.php
index 6a23fd7..d19cfb9 100644
--- a/includes/class.GFDpsPxPayPlugin.php
+++ b/includes/class.GFDpsPxPayPlugin.php
@@ -403,15 +403,17 @@ class GFDpsPxPayPlugin {
 				$this->paymentURL = $response->paymentURL;
 			}
 			else {
 				$entry['payment_status'] = 'Failed';
 				$this->errorMessage = 'Payment Express request invalid.';
+				self::log_debug($this->errorMessage);
 			}
 		}
 		catch (GFDpsPxPayException $e) {
 			$entry['payment_status'] = 'Failed';
 			$this->errorMessage = $e->getMessage();
+			self::log_debug($this->errorMessage);
 		}
 
 		// update the entry
 		if (class_exists('GFAPI')) {
 			GFAPI::update_entry($entry);
@@ -430,19 +432,11 @@ class GFDpsPxPayPlugin {
 	* @param array $entry the form entry
 	* @param bool $ajax form submission via AJAX
 	* @return mixed
 	*/
 	public function gformConfirmation($confirmation, $form, $entry, $ajax) {
-		if ($this->paymentURL) {
-			// NB: GF handles redirect via JavaScript if headers already sent, or AJAX
-			$confirmation = array('redirect' => $this->paymentURL);
-			self::log_debug('Payment Express request valid, redirecting...');
-
-			$this->paymentURL = false;
-		}
-
-		elseif ($this->errorMessage) {
+		if ($this->errorMessage) {
 			$feed = $this->getFeed($form['id']);
 			if ($feed) {
 				// create a "confirmation message" in which to display the error
 				$default_anchor = count(GFCommon::get_fields_by_type($form, array('page'))) > 0 ? 1 : 0;
 				$default_anchor = apply_filters('gform_confirmation_anchor_'.$form['id'], apply_filters('gform_confirmation_anchor', $default_anchor));
@@ -452,14 +446,22 @@ class GFDpsPxPayPlugin {
 
 				ob_start();
 				include GFDPSPXPAY_PLUGIN_ROOT . 'views/error-payment-failure.php';
 				$confirmation = ob_get_clean();
 			}
+		}
 
-			$this->errorMessage = false;
+		elseif ($this->paymentURL) {
+			// NB: GF handles redirect via JavaScript if headers already sent, or AJAX
+			$confirmation = array('redirect' => $this->paymentURL);
+			self::log_debug('Payment Express request valid, redirecting to: ' . $this->paymentURL);
 		}
 
+		// reset transient members
+		$this->errorMessage = false;
+		$this->paymentURL = false;
+
 		return $confirmation;
 	}
 
 	/**
 	* return from DPS PxPay website, retrieve and process payment result and redirect to form
@@ -496,10 +498,12 @@ class GFDpsPxPayPlugin {
 
 					$lead = GFFormsModel::get_lead($lead_id);
 					$form = GFFormsModel::get_form_meta($lead['form_id']);
 					$feed = $this->getFeed($form['id']);
 
+					do_action('gfdpspxpay_process_return_parsed', $lead, $form, $feed);
+
 					// update lead entry, with success/fail details
 					if ($response->success) {
 						$lead['payment_status']		= 'Approved';
 						$lead['payment_date']		= date('Y-m-d H:i:s');
 						$lead['payment_amount']		= $response->amount;
@@ -537,19 +541,20 @@ class GFDpsPxPayPlugin {
 					$this->processDelayed($feed, $lead, $form);
 
 					// on failure, redirect to failure page if set, otherwise fall through to redirect back to confirmation page
 					if ($lead['payment_status']	== 'Failed') {
 						if ($feed->UrlFail) {
-							wp_redirect($feed->UrlFail);
+							wp_redirect(esc_url_raw($feed->UrlFail));
 							exit;
 						}
 					}
 
 					// redirect to Gravity Forms page, passing form and lead IDs, encoded to deter simple attacks
 					$query = "form_id={$lead['form_id']}&lead_id={$lead['id']}";
 					$query .= "&hash=" . wp_hash($query);
-					wp_redirect(add_query_arg(array(self::PXPAY_RETURN => base64_encode($query)), $lead['source_url']));
+					$redirect_url = esc_url_raw(add_query_arg(array(self::PXPAY_RETURN => base64_encode($query)), $lead['source_url']));
+					wp_redirect($redirect_url);
 					exit;
 				}
 			}
 			catch (GFDpsPxPayException $e) {
 				// TODO: what now?
@@ -582,10 +587,12 @@ class GFDpsPxPayPlugin {
 
 				// load form and lead data
 				$form = GFFormsModel::get_form_meta($query['form_id']);
 				$lead = GFFormsModel::get_lead($query['lead_id']);
 
+				do_action('gfdpspxpay_process_confirmation_parsed', $lead, $form);
+
 				// get confirmation page
 				if (!class_exists('GFFormDisplay')) {
 					require_once(GFCommon::get_base_path() . '/form_display.php');
 				}
 				$confirmation = GFFormDisplay::handle_confirmation($form, $lead, false);
diff --git a/includes/class.GFDpsPxPayResult.php b/includes/class.GFDpsPxPayResult.php
index ba54f72..d1db5a9 100644
--- a/includes/class.GFDpsPxPayResult.php
+++ b/includes/class.GFDpsPxPayResult.php
@@ -309,11 +309,11 @@ class GFDpsPxPayResultResponse {
 		catch (Exception $e) {
 			// restore old libxml settings
 			libxml_disable_entity_loader($oldDisableEntityLoader);
 			libxml_use_internal_errors($oldUseInternalErrors);
 
-			throw new GFDpsPxPayException('Error parsing DPS PxPay result request: ' . $e->getMessage());
+			throw new GFDpsPxPayException('Error parsing DPS PxPay result: ' . $e->getMessage());
 		}
 
 		// if response is "invalid", throw error with message given in statusText field
 		if (!$this->isValid) {
 			throw new GFDpsPxPayException('Error from DPS PxPay result: ' . $this->statusText);
diff --git a/readme.md b/readme.md
index a1e4fbf..15e0040 100644
--- a/readme.md
+++ b/readme.md
@@ -3,9 +3,9 @@
 Integrate [Gravity Forms](http://webaware.com.au/get-gravity-forms) with the DPS Payment Express PxPay credit card payment gateway
 
 * [Home](http://shop.webaware.com.au/downloads/gravity-forms-dps-pxpay/)
 * [GitHub](https://github.com/webaware/gravity-forms-dps-pxpay/)
 * [Readme](https://github.com/webaware/gravity-forms-dps-pxpay/blob/master/readme.txt)
-* [Download](http://wordpress.org/plugins/gravity-forms-dps-pxpay/)
-* [Documentation](http://wordpress.org/plugins/gravity-forms-dps-pxpay/faq/)
-* [Support](http://wordpress.org/support/plugin/gravity-forms-dps-pxpay)
+* [Download](https://wordpress.org/plugins/gravity-forms-dps-pxpay/)
+* [Documentation](https://wordpress.org/plugins/gravity-forms-dps-pxpay/faq/)
+* [Support](https://wordpress.org/support/plugin/gravity-forms-dps-pxpay)
 * [Donate](http://shop.webaware.com.au/downloads/gravity-forms-dps-pxpay/)
diff --git a/readme.txt b/readme.txt
index 6b5c1f5..a6881df 100644
--- a/readme.txt
+++ b/readme.txt
@@ -4,12 +4,12 @@ Plugin Name: Gravity Forms DPS PxPay
 Plugin URI: http://shop.webaware.com.au/downloads/gravity-forms-dps-pxpay/
 Author URI: http://webaware.com.au/
 Donate link: http://shop.webaware.com.au/downloads/gravity-forms-dps-pxpay/
 Tags: gravityforms, gravity forms, gravity, dps, payment express, pxpay, donation, donations, payment, payment gateway, ecommerce, credit cards, new zealand, australia
 Requires at least: 3.7.1
-Tested up to: 4.2
-Stable tag: 1.4.2
+Tested up to: 4.2.1
+Stable tag: 1.4.3
 License: GPLv2 or later
 License URI: http://www.gnu.org/licenses/gpl-2.0.html
 
 Integrate Gravity Forms with the DPS Payment Express PxPay credit card payment gateway
 
@@ -23,11 +23,11 @@ Gravity Forms DPS PxPay adds a credit card payment gateway for [DPS PxPay](http:
 
 > NB: this plugin extends [Gravity Forms](http://webaware.com.au/get-gravity-forms); you still need to install and activate Gravity Forms!
 
 = Sponsorships =
 
-* creation of this plugin was generously sponsored by [IstanbulMMV](http://profiles.wordpress.org/IstanbulMMV/profile/)
+* creation of this plugin was generously sponsored by [IstanbulMMV](https://profiles.wordpress.org/IstanbulMMV/profile/)
 
 Thanks for sponsoring new features on Gravity Forms DPS PxPay!
 
 = Requirements: =
 
@@ -135,10 +135,18 @@ Developers can run processes on these actions (e.g. load classes required to han
 
 * [Fork me on GitHub](https://github.com/webaware/gravity-forms-dps-pxpay/)
 
 == Changelog ==
 
+= 1.4.3, 2015-05-01 =
+
+* fixed: error reporting when initial request fails, e.g. with API key error
+* fixed: error handling logic with redirect as confirmation
+* added: some more precautionary XSS prevention steps
+* added: action `gfdpspxpay_process_return_parsed` with `$lead`, `$form`, `$feed`
+* added: action `gfdpspxpay_process_confirmation_parsed` with `$entry`, `$form`
+
 = 1.4.2, 2014-12-23 =
 * added: hooks `gfdpspxpay_process_return` and `gfdpspxpay_process_confirmation`
 * changed: merge tags use currency of transaction for amount display
 
 = 1.4.1, 2014-11-22 =
diff --git a/views/metabox-save.php b/views/metabox-save.php
index 6baccfc..2655740 100644
--- a/views/metabox-save.php
+++ b/views/metabox-save.php
@@ -12,11 +12,11 @@ if ( current_user_can( "delete_post", $post->ID ) ) {
 	if ( !EMPTY_TRASH_DAYS )
 		$delete_text = __('Delete Permanently');
 	else
 		$delete_text = __('Move to Trash');
 	?>
-	<a class="submitdelete deletion" href="<?php echo get_delete_post_link($post->ID); ?>"><?php echo $delete_text; ?></a><?php
+	<a class="submitdelete deletion" href="<?php echo esc_url(get_delete_post_link($post->ID)); ?>"><?php echo $delete_text; ?></a><?php
 } ?>
 </div>
 
 <div id="publishing-action">
 <span class="spinner"></span>
diff --git a/views/requires-extensions.php b/views/requires-extensions.php
index dec6180..67d24f0 100644
--- a/views/requires-extensions.php
+++ b/views/requires-extensions.php
@@ -1,9 +1,9 @@
 
 <div class="error">
 	<p>Gravity Forms DPS PxPay requires these missing PHP extensions. Please contact your website host to have these extensions installed.</p>
 	<ul style="list-style-type: disc; padding-left: 2em;">
-	<?php foreach ($missing as $ext): if (!extension_loaded($ext)): ?>
-		<li><?php echo $ext; ?></li>
-	<?php endif; endforeach; ?>
+	<?php foreach ($missing as $ext): ?>
+		<li><?php echo esc_html($ext); ?></li>
+	<?php endforeach; ?>
 	</ul>
 </div>

Vulnerable code: Version: 1.4.2
copyright (c) 2013-2014 WebAware Pty Ltd (email : support@webaware.com.au)
define('GFDPSPXPAY_PLUGIN_VERSION', '1.4.2');
			$settings_link = sprintf('<a href="%s">Settings</a>', admin_url('admin.php?page=gf_settings&subview=DPS+PxPay'));
			$links[] = '<a href="http://wordpress.org/support/plugin/gravity-forms-dps-pxpay">' . __('Get help') . '</a>';
			$links[] = '<a href="http://wordpress.org/plugins/gravity-forms-dps-pxpay/">' . __('Rating') . '</a>';
		$feedsURL = 'edit.php?post_type=' . GFDPSPXPAY_TYPE_FEED;
		echo "<a href=\"$feedsURL\">Click to return to list</a>.\n";
				$actions['entries'] = sprintf('<a href="%s" title="%s">%s</a>',
					add_query_arg(array('page' => 'gf_entries', 'id' => $feed->FormID), admin_url('admin.php')), 'View Entries', 'Entries');
			$this->isValid = ('1' === ((string) $xml['valid']));
			$this->paymentURL = (string) $xml->URI;
			throw new GFDpsPxPayException('Error parsing DPS PxPay generate response: ' . $e->getMessage());
		// if response is "invalid", throw error with message given in URI field
			throw new GFDpsPxPayException('Error from DPS PxPay generate response: ' . $this->paymentURL);
		if ($this->paymentURL) {
			// NB: GF handles redirect via JavaScript if headers already sent, or AJAX
			$confirmation = array('redirect' => $this->paymentURL);
			self::log_debug('Payment Express request valid, redirecting...');

			$this->paymentURL = false;
		}

		elseif ($this->errorMessage) {
			$this->errorMessage = false;
							wp_redirect($feed->UrlFail);
					wp_redirect(add_query_arg(array(self::PXPAY_RETURN => base64_encode($query)), $lead['source_url']));
			throw new GFDpsPxPayException('Error parsing DPS PxPay result request: ' . $e->getMessage());
* [Download](http://wordpress.org/plugins/gravity-forms-dps-pxpay/)
* [Documentation](http://wordpress.org/plugins/gravity-forms-dps-pxpay/faq/)
* [Support](http://wordpress.org/support/plugin/gravity-forms-dps-pxpay)
Tested up to: 4.2
Stable tag: 1.4.2
* creation of this plugin was generously sponsored by [IstanbulMMV](http://profiles.wordpress.org/IstanbulMMV/profile/)
	<a class="submitdelete deletion" href="<?php echo get_delete_post_link($post->ID); ?>"><?php echo $delete_text; ?></a><?php
	<?php foreach ($missing as $ext): if (!extension_loaded($ext)): ?>
		<li><?php echo $ext; ?></li>
	<?php endif; endforeach; ?>
Fixed code: Version: 1.4.3
copyright (c) 2013-2015 WebAware Pty Ltd (email : support@webaware.com.au)
define('GFDPSPXPAY_PLUGIN_VERSION', '1.4.3');
			$settings_link = sprintf('<a href="%s">Settings</a>', esc_url(admin_url('admin.php?page=gf_settings&subview=DPS+PxPay')));
			$links[] = '<a href="https://wordpress.org/support/plugin/gravity-forms-dps-pxpay">' . __('Get help') . '</a>';
			$links[] = '<a href="https://wordpress.org/plugins/gravity-forms-dps-pxpay/">' . __('Rating') . '</a>';
		$output = array();

		$feedsURL = admin_url('edit.php?post_type=' . GFDPSPXPAY_TYPE_FEED);
		printf('<a href="%s">Click to return to list</a>', esc_url($feedsURL));
				$url = add_query_arg(array('page' => 'gf_entries', 'id' => $feed->FormID), admin_url('admin.php'));
				$actions['entries'] = sprintf('<a href="%s" title="%s">%s</a>', esc_url($url), 'View Entries', 'Entries');
	protected $errorMessage;

			if ('1' === ((string) $xml['valid'])) {
				$this->isValid = true;
				$this->paymentURL = (string) $xml->URI;

				if (empty($this->paymentURL)) {
					$this->isValid = false;

					$this->errorMessage = (string) $xml->ResponseText;
					if (empty($this->errorMessage)) {
						$this->errorMessage = 'no hosted page URI given';
					}
				}
			}
			else {
				$this->isValid = false;
				$this->errorMessage = (string) $xml->ResponseText;
				if (empty($this->errorMessage)) {
					// API 1.0 passed error message in URI
					$this->errorMessage = (string) $xml->URI;

					if (empty($this->errorMessage)) {
						$this->errorMessage = 'invalid request';
					}
				}
			}
			throw new GFDpsPxPayException('Error parsing DPS PxPay request: ' . $e->getMessage());
		// if response is "invalid", throw error with message
			throw new GFDpsPxPayException('Error from DPS PxPay request: ' . $this->errorMessage);
				self::log_debug($this->errorMessage);
			self::log_debug($this->errorMessage);
		if ($this->errorMessage) {
		}
		elseif ($this->paymentURL) {
			// NB: GF handles redirect via JavaScript if headers already sent, or AJAX
			$confirmation = array('redirect' => $this->paymentURL);
			self::log_debug('Payment Express request valid, redirecting to: ' . $this->paymentURL);
		// reset transient members
		$this->errorMessage = false;
		$this->paymentURL = false;

					do_action('gfdpspxpay_process_return_parsed', $lead, $form, $feed);

							wp_redirect(esc_url_raw($feed->UrlFail));
					$redirect_url = esc_url_raw(add_query_arg(array(self::PXPAY_RETURN => base64_encode($query)), $lead['source_url']));
					wp_redirect($redirect_url);
				do_action('gfdpspxpay_process_confirmation_parsed', $lead, $form);

			throw new GFDpsPxPayException('Error parsing DPS PxPay result: ' . $e->getMessage());
* [Download](https://wordpress.org/plugins/gravity-forms-dps-pxpay/)
* [Documentation](https://wordpress.org/plugins/gravity-forms-dps-pxpay/faq/)
* [Support](https://wordpress.org/support/plugin/gravity-forms-dps-pxpay)
Tested up to: 4.2.1
Stable tag: 1.4.3
* creation of this plugin was generously sponsored by [IstanbulMMV](https://profiles.wordpress.org/IstanbulMMV/profile/)
= 1.4.3, 2015-05-01 =

* fixed: error reporting when initial request fails, e.g. with API key error
* fixed: error handling logic with redirect as confirmation
* added: some more precautionary XSS prevention steps
* added: action `gfdpspxpay_process_return_parsed` with `$lead`, `$form`, `$feed`
* added: action `gfdpspxpay_process_confirmation_parsed` with `$entry`, `$form`

	<a class="submitdelete deletion" href="<?php echo esc_url(get_delete_post_link($post->ID)); ?>"><?php echo $delete_text; ?></a><?php
	<?php foreach ($missing as $ext): ?>
		<li><?php echo esc_html($ext); ?></li>
	<?php endforeach; ?>