Skip to content

Commit d7af692

Browse files
committed
Issue #17 better validation of amount values.
1 parent 7494358 commit d7af692

File tree

2 files changed

+64
-9
lines changed

2 files changed

+64
-9
lines changed

src/Omnipay/Common/Message/AbstractRequest.php

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -161,14 +161,40 @@ public function setCardReference($value)
161161
public function getAmount()
162162
{
163163
$amount = $this->getParameter('amount');
164-
if ($amount) {
165-
if (!is_float($amount) &&
166-
$this->getCurrencyDecimalPlaces() > 0 &&
167-
false === strpos((string) $amount, '.')) {
168-
throw new InvalidRequestException(
169-
'Please specify amount as a string or float, ' .
170-
'with decimal places (e.g. \'10.00\' to represent $10.00).'
171-
);
164+
$message = 'Please specify amount as a string or float, '
165+
. 'with decimal places (e.g. \'10.00\' to represent $10.00).';
166+
167+
if (isset($amount)) {
168+
// Don't allow integers for currencies that support decimals.
169+
// This is for legacy reasons - upgrades from v0.9
170+
if (is_int($amount) && $this->getCurrencyDecimalPlaces() > 0) {
171+
throw new InvalidRequestException($message);
172+
}
173+
174+
if (is_string($amount)) {
175+
// A '-' is not considered a valid character, so a negative amounts will be invalid.
176+
if (preg_match('/[^0-9\.]/', $amount)) {
177+
throw new InvalidRequestException('Invalid character in amount.');
178+
}
179+
180+
// Generic number, with optional decimals.
181+
if (!preg_match('/^[0-9]+(\.[0-9]*)?$/', $amount)) {
182+
throw new InvalidRequestException('Amount string is not a valid decimal number.');
183+
}
184+
185+
// Don't allow integers for currencies that support decimals (legacy v0.9).
186+
if ($this->getCurrencyDecimalPlaces() > 0 && false === strpos((string) $amount, '.')) {
187+
throw new InvalidRequestException($message);
188+
}
189+
}
190+
191+
// The number_format() used later requires a float.
192+
$amount = (float)$amount;
193+
194+
// Check for rounding that may occur if too many decimal places are supplied.
195+
$decimal_count = strlen(substr(strrchr((string)$amount, '.'), 1));
196+
if ($decimal_count > $this->getCurrencyDecimalPlaces()) {
197+
throw new InvalidRequestException('Amount precision is too high for currency.');
172198
}
173199

174200
return $this->formatCurrency($amount);

tests/Omnipay/Common/Message/AbstractRequestTest.php

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,18 +87,28 @@ public function testAmountWithEmpty()
8787
$this->assertSame(null, $this->request->getAmount());
8888
}
8989

90+
public function testAmountZero()
91+
{
92+
$this->assertSame($this->request, $this->request->setAmount(0.0));
93+
$this->assertSame('0.00', $this->request->getAmount());
94+
}
95+
9096
public function testGetAmountNoDecimals()
9197
{
9298
$this->assertSame($this->request, $this->request->setCurrency('JPY'));
9399
$this->assertSame($this->request, $this->request->setAmount('1366'));
94100
$this->assertSame('1366', $this->request->getAmount());
95101
}
96102

103+
/**
104+
* @expectedException Omnipay\Common\Exception\InvalidRequestException
105+
*/
97106
public function testGetAmountNoDecimalsRounding()
98107
{
108+
// There will not be any rounding; the amount is sent as requested or not at all.
99109
$this->assertSame($this->request, $this->request->setAmount('136.5'));
100110
$this->assertSame($this->request, $this->request->setCurrency('JPY'));
101-
$this->assertSame('137', $this->request->getAmount());
111+
$this->request->getAmount();
102112
}
103113

104114
/**
@@ -117,6 +127,7 @@ public function testAmountWithIntThrowsException()
117127
public function testAmountWithIntStringThrowsException()
118128
{
119129
// ambiguous value, avoid errors upgrading from v0.9
130+
// Some currencies only take integers, so an integer (in a string) should be valid.
120131
$this->assertSame($this->request, $this->request->setAmount('10'));
121132
$this->request->getAmount();
122133
}
@@ -134,6 +145,24 @@ public function testGetAmountIntegerNoDecimals()
134145
$this->assertSame(1366, $this->request->getAmountInteger());
135146
}
136147

148+
/**
149+
* @expectedException Omnipay\Common\Exception\InvalidRequestException
150+
*/
151+
public function testAmountThousandsSepThrowsException()
152+
{
153+
$this->assertSame($this->request, $this->request->setAmount('1,234.00'));
154+
$this->request->getAmount();
155+
}
156+
157+
/**
158+
* @expectedException Omnipay\Common\Exception\InvalidRequestException
159+
*/
160+
public function testAmountInvalidFormatThrowsException()
161+
{
162+
$this->assertSame($this->request, $this->request->setAmount('1.234.00'));
163+
$this->request->getAmount();
164+
}
165+
137166
public function testCurrency()
138167
{
139168
$this->assertSame($this->request, $this->request->setCurrency('USD'));

0 commit comments

Comments
 (0)