PHP Tips | 文字列処理:ログ・表示向け - 表示用マスク(名前)

PHP PHP
スポンサーリンク

「表示用マスク(名前)」で何を守りたいのか

名前も、メールや電話と同じく「個人を特定しやすい情報」です。
でも業務では、こういうニーズがよく出てきます。

ログや通知には「誰の処理か」は分かりたい。
サポート画面では「対象ユーザーは分かるが、フルネームは隠したい」。

そこで使うのが「表示用マスク(名前)」です。

山田太郎山田*郎
佐藤花子佐*花子
Taro YamadaT*** Y*****

「本人や運用者には誰か分かるけど、丸見えではない」状態を作るのが目的です。


まず「どうマスクするか」の方針を決める

日本語フルネームのざっくり方針

日本語の名前は、だいたい「姓+名」で構成されますが、
システム上は「姓」「名」が分かれている場合と、「フルネーム 1 本」の場合があります。

ここでは、まず「フルネーム 1 本の文字列」をマスクする方針を決めます。

文字数が 1 文字なら:そのまま(マスクしない)。
文字数が 2 文字なら:先頭 1 文字だけ残して、残りを
文字数が 3 文字以上なら:
先頭 1 文字と末尾 1 文字を残して、間を で埋める。

例としてはこうなります。

山田山*
太郎太*
山田太郎山田*郎
佐藤花子佐*花子

「完全には隠さないけど、全部は見せない」というバランスです。


コアとなるマスク関数を作る

フルネーム 1 本をマスクする関数

日本語を安全に扱うために、mb_strlen / mb_substr を使います。

function mask_name_for_display(string $name): string
{
    $name = trim($name);

    if ($name === '') {
        return $name;
    }

    $len = mb_strlen($name, 'UTF-8');

    if ($len === 1) {
        // 1 文字はそのまま
        return $name;
    }

    if ($len === 2) {
        // 2 文字なら先頭だけ残す
        $head = mb_substr($name, 0, 1, 'UTF-8');
        return $head . '*';
    }

    // 3 文字以上なら、先頭と末尾を残して間をマスク
    $head = mb_substr($name, 0, 1, 'UTF-8');
    $tail = mb_substr($name, -1, 1, 'UTF-8');

    $maskCount = $len - 2;
    $mask = str_repeat('*', $maskCount);

    return $head . $mask . $tail;
}
PHP

ここでは、マスク文字に全角の を使っています(日本語 UI でよく使われるため)。
半角 * を使いたければ、そこだけ変えれば OK です。


例題で挙動を確認する

日本語の例

echo mask_name_for_display('山田');      // 山*
echo mask_name_for_display('太郎');      // 太*
echo mask_name_for_display('山田太郎');  // 山**郎
echo mask_name_for_display('佐藤花子');  // 佐**子
PHP

3 文字以上の場合、「真ん中全部がマスク」されるので、
姓+名がくっついていても、だいたいの雰囲気だけが残ります。

英字名の例

echo mask_name_for_display('Taro');        // T**o
echo mask_name_for_display('Yamada');      // Y***a
echo mask_name_for_display('Taro Yamada'); // T******a
PHP

スペースも 1 文字としてカウントされるので、
「フルネーム全体を 1 つの文字列としてマスク」する挙動になります。
英字名をもう少し丁寧に扱いたい場合は、「スペースで分割して、単語ごとにマスクする」という発展形も作れます。


「姓」「名」が分かれている場合のマスク

姓と名を別々にマスクしてから結合する

多くの業務システムでは、「姓」「名」が別カラムになっていることが多いです。

$lastName  = '山田';
$firstName = '太郎';
PHP

この場合は、それぞれにマスクをかけてから結合するのが分かりやすいです。

$maskedFullName = mask_name_for_display($lastName) . ' ' . mask_name_for_display($firstName);

echo $maskedFullName; // 山* 太*
PHP

姓と名を別々にマスクすることで、「どちらの情報も少しだけ見える」状態になります。
サポート画面などでは、このほうが「誰か」を特定しやすいことが多いです。


実務での使いどころ

ログ出力時のマスク

$rawName = $user['name'] ?? '';

$masked = mask_name_for_display($rawName);

error_log('Password reset requested by name=' . $masked);
PHP

ログには「どのユーザーか」が分かる形で残りつつ、
フルネームは見えません。

管理画面の一覧表示

<td><?= htmlspecialchars(mask_name_for_display($user['name']), ENT_QUOTES, 'UTF-8') ?></td>
PHP

サポート担当は「だいたい誰か」を把握できますが、
画面をチラ見した第三者にはフルの名前は分かりません。


どこまでマスクするかは「ポリシー」で決める

今回のルールはあくまで「一例」です。
実務では、次のようなバリエーションもありえます。

1 文字でも必ずマスクする()。
姓はフル表示、名だけマスクする。
外国人名は別ルールにする。

大事なのは、「マスクルールを 1 箇所(ユーティリティ関数)に閉じ込める」ことです。
そうしておけば、ポリシー変更があっても、その関数だけ直せば全体に反映できます。


まとめ:今日からの「表示用マスク(名前)」ユーティリティ

表示用マスク(名前)の目的は、「運用上の識別はできるが、フルネームは見せない」ことです。
そのために、

名前の長さに応じて「一部だけ残し、残りをマスク文字に置き換える」。
ログや画面では、必ずこの関数を通した値だけを使う。

というルールを徹底します。

もう一度、コア関数を載せておきます。

function mask_name_for_display(string $name): string
{
    $name = trim($name);

    if ($name === '') {
        return $name;
    }

    $len = mb_strlen($name, 'UTF-8');

    if ($len === 1) {
        return $name;
    }

    if ($len === 2) {
        $head = mb_substr($name, 0, 1, 'UTF-8');
        return $head . '*';
    }

    $head = mb_substr($name, 0, 1, 'UTF-8');
    $tail = mb_substr($name, -1, 1, 'UTF-8');

    $maskCount = $len - 2;
    $mask = str_repeat('*', $maskCount);

    return $head . $mask . $tail;
}
PHP

もし、あなたのプロジェクトで「ログや一覧に生の氏名をそのまま出している」箇所があれば、そこがこのユーティリティを差し込むベストポイントです。
その 1 行を差し替えるだけで、「個人情報の見せ方」のレベルが一段上がります。

タイトルとURLをコピーしました