-
Notifications
You must be signed in to change notification settings - Fork 2
Create CreditCard formatters #5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,114 @@ | ||
| <!-- | ||
| SPDX-FileCopyrightText: (c) Respect Project Contributors | ||
| SPDX-License-Identifier: ISC | ||
| SPDX-FileContributor: Henrique Moody <henriquemoody@gmail.com> | ||
| --> | ||
|
|
||
| # CreditCardFormatter | ||
|
|
||
| The `CreditCardFormatter` formats credit card numbers with automatic card type detection. It supports major card networks including Visa, MasterCard, American Express, Discover, JCB, Diners Club, UnionPay, and RuPay. | ||
|
|
||
| ## Usage | ||
|
|
||
| ### Basic Usage with Auto-Detection | ||
|
|
||
| ```php | ||
| use Respect\StringFormatter\CreditCardFormatter; | ||
|
|
||
| $formatter = new CreditCardFormatter(); | ||
|
|
||
| echo $formatter->format('4123456789012345'); | ||
| // Outputs: "4123 4567 8901 2345" (Visa detected) | ||
|
|
||
| echo $formatter->format('371234567890123'); | ||
| // Outputs: "3712 345678 90123" (Amex, 4-6-5 format) | ||
|
|
||
| echo $formatter->format('5112345678901234'); | ||
| // Outputs: "5112 3456 7890 1234" (MasterCard detected) | ||
|
|
||
| echo $formatter->format('36123456789012'); | ||
| // Outputs: "3612 345678 9012" (Diners Club, 4-6-4 format) | ||
|
|
||
| echo $formatter->format('4123456789012345678'); | ||
| // Outputs: "4123 4567 8901 2345 678" (Visa 19-digit) | ||
| ``` | ||
|
|
||
| ### Input Cleaning | ||
|
|
||
| The formatter automatically removes non-digit characters from the input: | ||
|
|
||
| ```php | ||
| use Respect\StringFormatter\CreditCardFormatter; | ||
|
|
||
| $formatter = new CreditCardFormatter(); | ||
|
|
||
| echo $formatter->format('4123-4567-8901-2345'); | ||
| // Outputs: "4123 4567 8901 2345" | ||
|
|
||
| echo $formatter->format('4123 4567 8901 2345'); | ||
| // Outputs: "4123 4567 8901 2345" | ||
|
|
||
| echo $formatter->format('4123.4567.8901.2345'); | ||
| // Outputs: "4123 4567 8901 2345" | ||
| ``` | ||
|
|
||
| ## API | ||
|
|
||
| ### `format` | ||
|
|
||
| - `format(string $input): string` | ||
|
|
||
| Formats the input credit card number. | ||
|
|
||
| **Parameters:** | ||
|
|
||
| - `$input`: The credit card number (can include spaces, dashes, dots, etc.) | ||
|
|
||
| **Returns:** The formatted credit card number | ||
|
|
||
| ## Auto-Detection | ||
|
|
||
| The formatter automatically detects card type based on prefix and length: | ||
|
|
||
| | Card Type | Prefix Ranges | Length | Format | | ||
| | -------------------- | -------------------- | ---------- | --------------------- | | ||
| | **American Express** | 34, 37 | 15 | `#### ###### #####` | | ||
| | **Diners Club** | 300-305, 309, 36, 38 | 14 | `#### ###### ####` | | ||
| | **Diners Club** | 36 | 16 | `#### #### #### ####` | | ||
| | **Visa** | 4 | 13, 16 | `#### #### #### ####` | | ||
| | **Visa** | 4 | 19 | `#### #### #### #### ###` | | ||
| | **MasterCard** | 51-55, 2221-2720 | 16 | `#### #### #### ####` | | ||
| | **Discover** | 6011, 644-649, 65 | 16 | `#### #### #### ####` | | ||
| | **Discover** | 6011, 644-649, 65 | 19 | `#### #### #### #### ###` | | ||
| | **JCB** | 3528-3589 | 16 | `#### #### #### ####` | | ||
| | **JCB** | 3528-3589 | 19 | `#### #### #### #### ###` | | ||
| | **UnionPay** | 62 | 16 | `#### #### #### ####` | | ||
| | **UnionPay** | 62 | 19 | `#### #### #### #### ###` | | ||
| | **RuPay** | 60, 65, 81, 82, 508 | 16 | `#### #### #### ####` | | ||
|
|
||
| Cards with more than 16 digits automatically use the 19-digit pattern: `#### #### #### #### ###` | ||
|
|
||
| ## Examples | ||
|
|
||
| | Input | Output | Card Type | | ||
| | --------------------- | ------------------------- | ------------ | | ||
| | `4123456789012345` | `4123 4567 8901 2345` | Visa | | ||
| | `4123456789012345678` | `4123 4567 8901 2345 678` | Visa (19) | | ||
| | `5112345678901234` | `5112 3456 7890 1234` | MasterCard | | ||
| | `341234567890123` | `3412 345678 90123` | Amex | | ||
| | `371234567890123` | `3712 345678 90123` | Amex | | ||
| | `6011000990139424` | `6011 0009 9013 9424` | Discover | | ||
| | `3528000012345678` | `3528 0000 1234 5678` | JCB | | ||
| | `36123456789012` | `3612 345678 9012` | Diners Club | | ||
| | `6212345678901234` | `6212 3456 7890 1234` | UnionPay | | ||
| | `8112345678901234` | `8112 3456 7890 1234` | RuPay | | ||
| | `1234567890123456` | `1234 5678 9012 3456` | Unknown | | ||
| | `4123-4567-8901-2345` | `4123 4567 8901 2345` | Visa (clean) | | ||
|
|
||
| ## Notes | ||
|
|
||
| - Non-digit characters are automatically removed from the input | ||
| - Card type detection is based on card prefix and length (not Luhn validation) | ||
| - If card type cannot be determined, uses the default 4-4-4-4 pattern | ||
| - Uses `PatternFormatter` internally for formatting | ||
| - For custom formatting patterns, use `PatternFormatter` directly |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,123 @@ | ||
| <!-- | ||
| SPDX-FileCopyrightText: (c) Respect Project Contributors | ||
| SPDX-License-Identifier: ISC | ||
| SPDX-FileContributor: Henrique Moody <henriquemoody@gmail.com> | ||
| --> | ||
|
|
||
| # SecureCreditCardFormatter | ||
|
|
||
| The `SecureCreditCardFormatter` formats and masks credit card numbers for secure display. It automatically detects card types, formats them appropriately, and masks sensitive portions. | ||
|
|
||
| ## Usage | ||
|
|
||
| ### Basic Usage | ||
|
|
||
| ```php | ||
| use Respect\StringFormatter\SecureCreditCardFormatter; | ||
|
|
||
| $formatter = new SecureCreditCardFormatter(); | ||
|
|
||
| echo $formatter->format('4123456789012345'); | ||
| // Outputs: "4123 **** **** 2345" (Visa) | ||
|
|
||
| echo $formatter->format('341234567890123'); | ||
| // Outputs: "3412 ****** 90123" (Amex, 4-6-5 format) | ||
|
|
||
| echo $formatter->format('5112345678901234'); | ||
| // Outputs: "5112 **** **** 1234" (MasterCard) | ||
|
|
||
| echo $formatter->format('36123456789012'); | ||
| // Outputs: "3612 ****** 9012" (Diners Club, 4-6-4 format) | ||
|
|
||
| echo $formatter->format('4123456789012345678'); | ||
| // Outputs: "4123 **** **** **** 678" (Visa 19-digit) | ||
| ``` | ||
|
|
||
| ### Custom Mask Character | ||
|
|
||
| ```php | ||
| use Respect\StringFormatter\SecureCreditCardFormatter; | ||
|
|
||
| $formatter = new SecureCreditCardFormatter('X'); | ||
|
|
||
| echo $formatter->format('4123456789012345'); | ||
| // Outputs: "4123 XXXX XXXX 2345" | ||
| ``` | ||
|
|
||
| ### Input Cleaning | ||
|
|
||
| The formatter automatically removes non-digit characters from the input: | ||
|
|
||
| ```php | ||
| use Respect\StringFormatter\SecureCreditCardFormatter; | ||
|
|
||
| $formatter = new SecureCreditCardFormatter(); | ||
|
|
||
| echo $formatter->format('4123-4567-8901-2345'); | ||
| // Outputs: "4123 **** **** 2345" | ||
| ``` | ||
|
|
||
| ## API | ||
|
|
||
| ### `SecureCreditCardFormatter::__construct` | ||
|
|
||
| - `__construct(string $maskChar = '*')` | ||
|
|
||
| Creates a new secure credit card formatter instance. | ||
|
|
||
| **Parameters:** | ||
|
|
||
| - `$maskChar`: Character to use for masking (default: '\*') | ||
|
|
||
| ### `format` | ||
|
|
||
| - `format(string $input): string` | ||
|
|
||
| Formats and masks the input credit card number. | ||
|
|
||
| **Parameters:** | ||
|
|
||
| - `$input`: The credit card number (can include spaces, dashes, dots, etc.) | ||
|
|
||
| **Returns:** The formatted and masked credit card number | ||
|
|
||
| ## Masking | ||
|
|
||
| The formatter applies masking after formatting to ensure predictable positions: | ||
|
|
||
| | Card Type | Example Input | Mask Range | Output | | ||
| | -------------------- | --------------------- | ----------------- | ------------------------- | | ||
| | **Visa** (16) | `4123456789012345` | `6-9,11-14` | `4123 **** **** 2345` | | ||
| | **Visa** (19) | `4123456789012345678` | `6-9,11-14,16-19` | `4123 **** **** **** 678` | | ||
| | **MasterCard** | `5112345678901234` | `6-9,11-14` | `5112 **** **** 1234` | | ||
| | **American Express** | `341234567890123` | `6-11` | `3412 ****** 90123` | | ||
| | **Discover** | `6011000990139424` | `6-9,11-14` | `6011 **** **** 9424` | | ||
| | **JCB** | `3528000012345678` | `6-9,11-14` | `3528 **** **** 5678` | | ||
| | **Diners Club** (14) | `36123456789012` | `6-11` | `3612 ****** 9012` | | ||
| | **UnionPay** | `6212345678901234` | `6-9,11-14` | `6212 **** **** 1234` | | ||
| | **RuPay** | `8112345678901234` | `6-9,11-14` | `8112 **** **** 1234` | | ||
|
|
||
| ## Examples | ||
|
|
||
| | Input | Output | Card Type | | ||
| | --------------------- | ------------------------- | ------------ | | ||
| | `4123456789012345` | `4123 **** **** 2345` | Visa | | ||
| | `4123456789012345678` | `4123 **** **** **** 678` | Visa (19) | | ||
| | `5112345678901234` | `5112 **** **** 1234` | MasterCard | | ||
| | `341234567890123` | `3412 ****** 90123` | Amex | | ||
| | `371234567890123` | `3712 ****** 90123` | Amex | | ||
| | `6011000990139424` | `6011 **** **** 9424` | Discover | | ||
| | `3528000012345678` | `3528 **** **** 5678` | JCB | | ||
| | `36123456789012` | `3612 ****** 9012` | Diners Club | | ||
| | `6212345678901234` | `6212 **** **** 1234` | UnionPay | | ||
| | `8112345678901234` | `8112 **** **** 1234` | RuPay | | ||
| | `4123-4567-8901-2345` | `4123 **** **** 2345` | Visa (clean) | | ||
|
|
||
| ## Notes | ||
|
|
||
| - Composes `CreditCardFormatter` for formatting and `MaskFormatter` for masking | ||
| - Formats the card number first, then applies masking to the formatted string | ||
| - Mask ranges are applied to 1-based positions in the formatted string | ||
| - Non-digit characters are automatically removed from input | ||
| - Inputs with fewer than 9 digits are returned as cleaned digits without formatting or masking | ||
| - Uses `CreditCardFormatter` for card type detection and formatting | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| <?php | ||
|
|
||
| /* | ||
| * SPDX-FileCopyrightText: (c) Respect Project Contributors | ||
| * SPDX-License-Identifier: ISC | ||
| * SPDX-FileContributor: Henrique Moody <henriquemoody@gmail.com> | ||
| */ | ||
|
|
||
| declare(strict_types=1); | ||
|
|
||
| namespace Respect\StringFormatter; | ||
|
|
||
| use function mb_strlen; | ||
| use function mb_substr; | ||
| use function preg_replace; | ||
|
|
||
| final readonly class CreditCardFormatter implements Formatter | ||
| { | ||
| private const string DEFAULT_16 = '#### #### #### ####'; | ||
| private const string DEFAULT_19 = '#### #### #### #### ###'; | ||
| private const string AMEX = '#### ###### #####'; | ||
| private const string DINERS_14 = '#### ###### ####'; | ||
|
|
||
| public function format(string $input): string | ||
| { | ||
| $cleaned = $this->cleanInput($input); | ||
| $pattern = $this->detectPattern($cleaned); | ||
|
|
||
| $formatter = new PatternFormatter($pattern); | ||
|
|
||
| return $formatter->format($cleaned); | ||
| } | ||
|
|
||
| public function cleanInput(string $input): string | ||
| { | ||
| return preg_replace('/[^0-9]/', '', $input) ?? ''; | ||
| } | ||
|
|
||
| public function detectPattern(string $input): string | ||
| { | ||
| $length = mb_strlen($input); | ||
| $firstTwo = mb_substr($input, 0, 2); | ||
| $firstThree = mb_substr($input, 0, 3); | ||
|
|
||
| // American Express: starts with 34 or 37 (15 digits, 4-6-5 format) | ||
| if ($firstTwo === '34' || $firstTwo === '37') { | ||
| return self::AMEX; | ||
| } | ||
|
|
||
| // Diners Club International: 14 digits, starts with 300-305, 309, 36, 38 | ||
| if ($length === 14) { | ||
| $prefix3 = (int) $firstThree; | ||
| if (($prefix3 >= 300 && $prefix3 <= 305) || $prefix3 === 309 || $firstTwo === '36' || $firstTwo === '38') { | ||
| return self::DINERS_14; | ||
| } | ||
| } | ||
|
|
||
| // 19-digit cards (some Visa, Discover, JCB, UnionPay) | ||
| if ($length > 16) { | ||
| return self::DEFAULT_19; | ||
| } | ||
|
|
||
| // Default 4-4-4-4: Visa, Mastercard, Discover, JCB, UnionPay, RuPay, etc. | ||
| return self::DEFAULT_16; | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.