Skip to content
38 changes: 34 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,43 @@ CHANGELOG
* Custom input validation now rejects integer keys and array or object values
with `InvalidInputException` instead of a type error or conversion warning.
When validation is disabled, these values pass through unchanged.
* When input validation is disabled, billing, shipping, and credit card
country fields no longer fail in string validators. Billing and shipping
region and phone country code fields, and credit card bank phone country
codes, also pass through unchanged.
* A request value with the wrong type, such as an array where a string is
expected, now causes an `InvalidInputException`, including when input

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Low: the CHANGELOG does not say that removeString() now accepts integers.

On main with validation on, withAccount(['user_id' => 123]), withBilling(['postal' => 6510]), and report([..., 'transaction_id' => 123]) throw InvalidInputException. With this PR they send "123" and "6510". This applies to about 25 free-form string fields. It is a user-facing change, and the repo CLAUDE.md says to update CHANGELOG.md for user-facing changes. Only the commit message records it now.

馃 Comment by Claude Opus 5.5.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems okay to leave it out

validation is disabled. This applies to the array arguments of the
`with*()` methods of `MaxMind\MinFraud`, except for custom inputs, and of
`MaxMind\MinFraud\ReportTransaction::report()`. Before, with validation
disabled, such a value caused a type error, a conversion warning, or an
error, or was sent to the web service, depending on the field. A value with
the right type that fails a check is still sent unchanged when validation
is disabled.
* The order `amount`, shopping cart `price` and `quantity`, and device
`session_age` inputs now accept numeric strings, such as `"12.50"`. They are
sent unchanged, except `session_age`, which is converted to a number as
before. A `session_age` string that is not numeric is now always rejected.
* The RFC 3339 check for the event `time` input now accepts any number of
fractional second digits. Before, it rejected values with more than three
digits, such as `2026-10-01T14:30:00.123456Z`.
* The RFC 3339 check for the event `time` input now rejects the values that
the web service rejects. Before, it accepted out-of-range date and time
values, such as `2026-02-30T10:00:00Z`, because PHP rolled them over. It
also accepted time zone names, such as `EST`, offsets without a colon, such
as `+0000`, and a lowercase `z`.
* The PHPDoc for the `with()` and `with*()` methods of `MaxMind\MinFraud` now
lists the `InvalidInputException` they throw when input validation is
enabled.
* Input validation now rejects a trailing newline in fields with a fixed
format, such as country, region, and currency codes, the credit card
`issuer_id_number`, custom input keys, and the minFraud ID of
`MaxMind\MinFraud\ReportTransaction`. Before, it accepted values such as
`"US\n"`.
* Added the `phone_verification_method`, `phone_was_verification_successful`,
and `phone_verification_time` inputs to the `/billing` and `/shipping`
objects. These describe the most recent verification of the billing or
shipping phone number. Use them with `withBilling()` and `withShipping()` as
array keys or as the `phoneVerificationMethod`,
`phoneWasVerificationSuccessful`, and `phoneVerificationTime` named
arguments. Omit `phone_was_verification_successful` if no verification was
attempted.

3.7.0 (2026-07-21)
------------------
Expand Down
9 changes: 8 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,14 +107,21 @@ The library validates input by default (can be disabled with `validateInput: fal
```php
private function verifyCountryCode(string $country): void
{
if (!preg_match('/^[A-Z]{2}$/', $country)) {
if (!preg_match('/\A[A-Z]{2}\z/', $country)) {
$this->maybeThrowInvalidInputException("...");
}
}
```

- Validation methods throw `InvalidInputException` when enabled
- `maybeThrowInvalidInputException()` respects the `validateInput` option
- Use the `\A` and `\z` anchors in a regex. `$` and `\Z` also match before a
trailing newline
- `remove()` always rejects a value with the wrong type, so checks after it

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Low: the example in this section still uses the $-anchored pattern.

The real target is line 110: preg_match('/^[A-Z]{2}$/', $country). This PR fixes that pattern in the code because $ matches before a trailing newline. Contributors and agents copy this example for new validators, so it can bring the bug back. Change the example to '/\A[A-Z]{2}\z/' and maybe add a bullet that says to use \A...\z.

馃 Comment by Claude Opus 5.5.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 791430d.

Reply by Claude Opus 5.5 on Greg's behalf.

can rely on the type without a `validateInput` guard
- Use `removeString()` for a free-form string field with no other check, or
for a field that already accepted an integer, such as `session_id`. It also
accepts an integer and converts it to a string
- Common validations: country codes, region codes, phone codes, email addresses, IP addresses

#### 6. **Dual Array/Named Arguments Pattern**
Expand Down
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ validation can be disabled by setting `validateInput` to `false` in the
options array for `\MaxMind\MinFraud`, but it is recommended that you keep it
on at least through development as it will help ensure that you are sending
valid data to the web service.
A value with the wrong type in an array argument, such as an array where a
string is expected, is always rejected, except in custom inputs.

After creating the request object, send a Score request by calling
`->score()`, an Insights request by calling `->insights()`, or a Factors
Expand Down Expand Up @@ -182,7 +184,10 @@ $request = $mf->withDevice(
country: 'US',
postal: '06510',
phoneNumber: '123-456-7890',
phoneCountryCode: '1'
phoneCountryCode: '1',
phoneVerificationMethod: 'delivered_code',
phoneWasVerificationSuccessful: true,
phoneVerificationTime: '2026-10-01T14:30:00Z'
)->withShipping(
firstName: 'ShipFirst',
lastName: 'ShipLast',
Expand All @@ -195,6 +200,9 @@ $request = $mf->withDevice(
postal: '73003',
phoneNumber: '123-456-0000',
phoneCountryCode: '1',
phoneVerificationMethod: 'network',
phoneWasVerificationSuccessful: false,
phoneVerificationTime: '2026-10-01T14:31:00Z',
deliverySpeed: 'same_day'
)->withPayment(
method: 'card',
Expand Down Expand Up @@ -279,6 +287,8 @@ setting `validateInput` to `false` in the options array for
`\MaxMind\MinFraud\ReportTransaction`, but it is recommended that you keep it
on at least through development as it will help ensure that you are sending
valid data to the web service.
A value with the wrong type in the array argument, such as an array where a
string is expected, is always rejected.

If the report is successful, nothing is returned. If the report fails, an
exception will be thrown.
Expand Down
Loading
Loading