Skip to content

[Feature] Implementation of Text::maskValue()#19404

Open
SadiHassan wants to merge 3 commits intocakephp:5.nextfrom
SadiHassan:Text-MaskValue-v0
Open

[Feature] Implementation of Text::maskValue()#19404
SadiHassan wants to merge 3 commits intocakephp:5.nextfrom
SadiHassan:Text-MaskValue-v0

Conversation

@SadiHassan
Copy link
Copy Markdown

Issue

Proposal for Text::maskValue()

Summary

Introduce a Text::maskValue() static method to Cake\Utility\Text for masking portions of strings (that match any of an array of substrings) with a repeated character.

This utility addresses a common need when displaying sensitive data (e.g., credit card numbers, API tokens, email addresses) and provides a consistent, reusable implementation. We already implemented mask() function, which works with the index and length of the interest area to mask. This one will be a variation of that.

This approach, ideated by @dereuromark here, will fully redact known values found within the input string.

Problem / Use Case

Applications frequently need to partially obscure sensitive data while preserving readability:

Card on file: **** **** **** 4242
API Key:      sk_live_************XyZ9
Email:        j***@example.com

Proposed API

/**
 * Masks all occurrences of given substrings within a string using a repeated character.
 *
 * Each occurrence of the provided substrings will be replaced by a sequence
 * of the masking character of equal length.
 *
 * @param string $string The input string.
 * @param string[] $needles List of substrings to mask.
 * @param string $character Masking character
 * @return string
 */
public static function maskValue(string $string, array $needles, string $character = '*') : string

Behavior

  • As normal behavior, it will mask all strings given in the input list.
  • In case of multiple occurrences of a mask-qualified string, it will mask all of them.
  • In case of overlapping of mask-qualified strings, it will mask the first string appeared in the list.

Edge Cases

  • Empty $needles will return the original string.
  • Empty strings in $needles will be ignored.
  • Matching is case-sensitive.
  • Multibyte strings are supported (if applicable).
  • If the $character is empty, * is used as the default value.

Sample Input Output

use Cake\Utility\Text;

// Mask normal
Text::maskValue('4111111111111234', ['411', '112'], '*');
// → '***11111111***34'

// Mask multiple occurrences and no overlapping
Text::maskValue('4111111111111234', ['11111', '112'], '*');
// Step-1, mask all 11111s → '4**********11234'
// Step-2, mask '112' → '4*************34'

// Mask multiple occurrences and overlapping
Text::maskValue('4111111111111234', ['11', '112'], '*');
// Step-1, mask all 11s → '4************234'
// Step-2, '112' is overlapped with the last '11', so it will be omitted

CakePHP Version

5.next

@SadiHassan
Copy link
Copy Markdown
Author

SadiHassan commented Apr 18, 2026

@dereuromark, some checks are not working, perhaps composer.json needs to be updated with PHP version 8.4.1?

Problem 1
    - Root composer.json requires phpunit/phpunit ^11.5.3 || ^12.1.3 || ^13.0 -> satisfiable by phpunit/phpunit[12.5.22, 13.1.6].
    - phpunit/phpunit 12.5.22 requires php >=8.3 -> your php version (8.2.30) does not satisfy that requirement.
    - phpunit/phpunit 13.1.6 requires php >=8.4.1 -> your php version (8.2.30) does not satisfy that requirement.

Comment thread src/Utility/Text.php Outdated
Comment thread src/Utility/Text.php Outdated
@SadiHassan SadiHassan requested a review from ADmad April 18, 2026 17:47
@dereuromark dereuromark added this to the 5.4.0 milestone Apr 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants