1 | <?php |
||
7 | class ResponseDataValidator |
||
8 | { |
||
9 | /** |
||
10 | * @var \Omnipay\Common\Message\RequestInterface | AbstractRequest |
||
11 | */ |
||
12 | private $request; |
||
13 | |||
14 | private $data; |
||
15 | |||
16 | private $response; |
||
17 | |||
18 | 10 | public function __construct(CompletePurchaseResponse $response) |
|
24 | |||
25 | 10 | public function validateTransactionRef($expectedRef, $returnedRef) |
|
32 | |||
33 | 10 | public static function compareStrings($one, $two) |
|
37 | |||
38 | 8 | public function verifyHashValue($gatewayHash, $expectedHash) |
|
42 | |||
43 | /** |
||
44 | * checks if amount paid is identical to amount due |
||
45 | * @param float $gatewayAmount Amount returned by the gateway |
||
46 | * @param float $dueAmount Expected Amount to be returned |
||
47 | * @return bool |
||
48 | */ |
||
49 | 2 | public function verifyCorrectAmount($gatewayAmount, $dueAmount) |
|
56 | |||
57 | /** |
||
58 | * @todo move most of this into a validator class |
||
59 | * @throws FailedPaymentException |
||
60 | * @throws ValidationException |
||
61 | */ |
||
62 | 10 | public function validate() |
|
63 | { |
||
64 | 10 | $statusCode = $this->data['gtpay_tranx_status_code']; |
|
65 | |||
66 | 10 | if (!$this->validateTransactionRef( |
|
67 | 10 | $this->request->getTransactionId(), |
|
68 | 10 | $this->data['gtpay_tranx_id'] |
|
69 | ) |
||
70 | ) { |
||
71 | 1 | throw $this->determineException(sprintf( |
|
72 | 1 | "Invalid Transaction ref: %s", |
|
73 | 1 | $this->data['gtpay_tranx_id'] |
|
74 | 1 | ), $statusCode); |
|
75 | } |
||
76 | |||
77 | 9 | if (self::compareStrings(CompletePurchaseResponse::CANCELED_GATEWAY_CODE, $statusCode) |
|
78 | ) { |
||
79 | 1 | throw $this->determineException("Customer Cancellation", $statusCode); |
|
80 | } |
||
81 | |||
82 | 8 | if (!$this->verifyHashValue( |
|
83 | 8 | $this->data['gtpay_full_verification_hash'], |
|
84 | 8 | $this->getFullVerificationHash($statusCode) |
|
85 | )) { |
||
86 | 1 | $msg = "Data incompatibility reported. Please contact support"; |
|
87 | 1 | throw $this->determineException($msg, $statusCode); |
|
88 | } |
||
89 | 7 | if (!self::compareStrings($this->data['gtpay_cust_id'], $this->request->getCustomerId())) { |
|
|
|||
90 | 1 | $msg = "Received Customer Id: {$this->data['gtpay_cust_id']} does not match expected Customer Id"; |
|
91 | 1 | throw $this->determineException($msg, $statusCode); |
|
92 | } |
||
93 | 6 | if (!self::compareStrings($this->data['site_redirect_url'], $this->request->getNotifyUrl())) { |
|
94 | 1 | throw $this->determineException("Redirect Url is wrong.", $statusCode); |
|
95 | } |
||
96 | 5 | } |
|
97 | |||
98 | 4 | public function successValidate() |
|
99 | { |
||
100 | |||
101 | 4 | if (isset($this->data['TransactionCurrency'])) { |
|
102 | 1 | if (!self::compareStrings($this->data['TransactionCurrency'], $this->request->getCurrency())) { |
|
103 | 1 | throw new ValidationException("Transaction currency does not match expected currency."); |
|
104 | } |
||
105 | } |
||
106 | |||
107 | 3 | if (!self::compareStrings($this->data['MertID'], $this->request->getMerchantId())) { |
|
108 | 1 | throw new ValidationException("Wrong Merchant ID returned."); |
|
109 | } |
||
110 | 2 | if (!$this->verifyCorrectAmount($this->data['Amount'], $this->request->getAmountInteger())) { |
|
111 | 1 | throw new ValidationException( |
|
112 | 1 | sprintf( |
|
113 | 1 | "Incorrect Amount Paid. Expected Amount: %s, Amount Paid: %s", |
|
114 | 1 | $this->response->formatIntegerAmount($this->request->getAmountInteger()), |
|
115 | 1 | $this->response->formatIntegerAmount($this->data['Amount']) |
|
116 | ) |
||
117 | ); |
||
118 | } |
||
119 | 1 | } |
|
120 | |||
121 | /** |
||
122 | * Distinguishes between exceptions that have a failed status code from the gateway |
||
123 | * and exceptions when the status code indicates success. The later may indicate fraud. |
||
124 | * For validation exception, you may want to consider sending an email to admin as further investigation |
||
125 | * may be required |
||
126 | * @param $msg |
||
127 | * @param $statusCode |
||
128 | * @return FailedPaymentException|ValidationException |
||
129 | */ |
||
130 | 5 | private function determineException($msg, $statusCode) |
|
138 | |||
139 | 8 | public function getFullVerificationHash($statusCode) |
|
148 | } |
||
149 |
Let’s take a look at an example:
In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.
Available Fixes
Change the type-hint for the parameter:
Add an additional type-check:
Add the method to the interface: