Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,40 @@ CHANGELOG
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.
* When input validation is disabled, the event `party` and `type`, shipping
`delivery_speed`, and payment `method` and `processor` fields now pass
through unchanged. Before, an array or object value in one of these fields
caused a conversion warning or an error.
* When input validation is disabled, `MaxMind\MinFraud\ReportTransaction`
now sends the `ip_address`, `maxmind_id`, `minfraud_id`, and `tag` fields
unchanged. Before, an array or object value in one of these fields caused a
type error, a conversion warning, or an error.
* When input validation is disabled, all other `MaxMind\MinFraud` request
fields now also pass through unchanged. Before, an unexpected value type in
fields such as the device `ip_address`, the email `address` and `domain`,
the event `time`, or the credit card `token` caused a type error, a
conversion warning, or an error. The device `session_age` and `session_id`
and the shopping cart `item_id` are still converted for valid values, but
other values are no longer converted. Before, for example, a non-numeric
`session_age` was sent as `0`. With `hashEmail` enabled, an email address
that is not a string is sent without hashing.
* 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 out-of-range date
and time values, such as `2026-02-30T10:00:00Z` or `2026-01-01T25:00:00Z`.
Before, PHP rolled these values over and the check accepted them.
* The PHPDoc for the `with()` and `with*()` methods of `MaxMind\MinFraud` now
lists the `InvalidInputException` they throw when input validation is
enabled.
* 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
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,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 +198,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
540 changes: 320 additions & 220 deletions src/MinFraud.php

Large diffs are not rendered by default.

10 changes: 6 additions & 4 deletions src/MinFraud/ReportTransaction.php
Original file line number Diff line number Diff line change
Expand Up @@ -129,21 +129,21 @@ public function report(
}

if ($ipAddress !== null) {
if (!filter_var($ipAddress, \FILTER_VALIDATE_IP)) {
if ($this->validateInput && !filter_var($ipAddress, \FILTER_VALIDATE_IP)) {
$this->maybeThrowInvalidInputException("$ipAddress is an invalid IP address");
}
$values['ip_address'] = $ipAddress;
}

if ($maxmindId !== null) {
if (\strlen($maxmindId) !== 8) {
if ($this->validateInput && \strlen($maxmindId) !== 8) {
$this->maybeThrowInvalidInputException("$maxmindId must be 8 characters long");
}
$values['maxmind_id'] = $maxmindId;
}

if ($minfraudId !== null) {
if (!preg_match(
if ($this->validateInput && !preg_match(
'/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/i',
$minfraudId,
)) {
Expand All @@ -161,7 +161,9 @@ public function report(
// This is required so we always throw an exception if it is not set
throw new InvalidInputException('A tag is required');
}
if (!\in_array($tag, ['not_fraud', 'suspected_fraud', 'spam_or_abuse', 'chargeback', 'clear'], true)) {
if ($this->validateInput
&& !\in_array($tag, ['not_fraud', 'suspected_fraud', 'spam_or_abuse', 'chargeback', 'clear'], true)
) {
$this->maybeThrowInvalidInputException(
"$tag must be one of 'not_fraud', 'suspected_fraud', 'spam_or_abuse', 'chargeback', or 'clear'",
);
Expand Down
4 changes: 3 additions & 1 deletion src/MinFraud/Util.php
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,9 @@ class Util
*/
public static function maybeHashEmail(array $values): array
{
if (!isset($values['email']['address'])) {
// A non-string address can only get here when input validation is
// off, and then it is sent unchanged.
if (!isset($values['email']['address']) || !\is_string($values['email']['address'])) {
return $values;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,40 @@ public static function invalidTags(): array
];
}

/**
* @dataProvider allFields
*/
public function testFieldWithoutValidation(string $field): void
{
foreach ([new \stdClass(), ['x'], 12, true] as $value) {
$req = ['ip_address' => '1.1.1.1', 'tag' => 'not_fraud'];
$req[$field] = $value;
// report() sends the fields in alphabetical order.
ksort($req);
$this->createReportTransactionRequest(
$req,
1,
['validateInput' => false]
)->report($req);
}
}

/**
* @return list<list<string>>
*/
public static function allFields(): array
{
return [
['chargeback_code'],
['ip_address'],
['maxmind_id'],
['minfraud_id'],
['notes'],
['tag'],
['transaction_id'],
];
}

/**
* @param array<string, mixed> $requestContent
* @param array<string, mixed> $options
Expand Down
Loading
Loading