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

PHP PHP
スポンサーリンク

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

電話番号もメールと同じく、個人をかなり特定できる情報です。
でも業務では、こういうニーズがよく出てきます。

誰のレコードかは判別したい。
ログや画面には「丸裸の番号」は出したくない。

そこで、「電話番号を一部だけ見せて、残りをマスクする」表示用マスクを用意します。

090-1234-5678090-****-5678
03-1234-567803-****-5678

本人や運用者には「だいたい誰か分かる」けれど、
第三者にとってはフルの番号が分からない、という状態を作るのが目的です。


まず「数字だけ」にそろえる、という前処理

電話番号は、いろいろな書き方をされます。

09012345678
090-1234-5678
(090) 1234-5678
090−1234−5678

マスク処理をシンプルにするために、まずは「数字だけ」にそろえます。

function normalize_phone_digits(string $phone): string
{
    // 全角数字を半角に
    $phone = mb_convert_kana($phone, 'n', 'UTF-8');

    // 数字以外を全部削除
    return preg_replace('/\D+/', '', $phone) ?? '';
}
PHP

これで、どんな書き方でも最終的にこうなります。

normalize_phone_digits('090-1234-5678')09012345678
normalize_phone_digits('03−1234−5678')0312345678

この「数字だけの電話番号」をベースにマスクを考えます。


マスクの方針を決める

ここでは、シンプルにこう決めます。

桁数が短い(4 桁以下)なら、そのまま(内線などを想定)。
それ以上なら、「先頭数桁」と「末尾 4 桁」だけ見せて、間を * で埋める。

日本の電話番号をざっくりイメージすると、

携帯:11 桁(090xxxxxxxx)
固定:10 桁(03xxxxxxxx, 045xxxxxxx など)

なので、例えばこういう感じにします。

09012345678090****5678
031234567803****5678

「先頭 2〜3 桁」と「末尾 4 桁」が見えていれば、
誰の番号かはだいたい分かるけれど、真ん中は隠せます。


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

function mask_phone_for_display(string $phone): string
{
    $digits = normalize_phone_digits($phone);

    $len = strlen($digits);

    // 桁数が少なすぎる場合は、そのまま返す(内線など)
    if ($len <= 4) {
        return $digits;
    }

    // 先頭を何桁見せるか(携帯なら 3、固定なら 2 を想定)
    if ($len === 11) {
        $headLen = 3; // 090 / 080 / 070 など
    } else {
        $headLen = 2; // 03 / 06 / 04 など
    }

    // 末尾は 4 桁見せる
    $tailLen = 4;

    // 万が一、長さが足りない場合の保険
    if ($headLen + $tailLen >= $len) {
        // そのまま返すか、簡易マスクにするかは運用次第
        return $digits;
    }

    $head = substr($digits, 0, $headLen);
    $tail = substr($digits, -$tailLen);

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

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

ここでは「数字だけの文字列」を返していますが、
必要なら後で 090-****-5678 のようにハイフンを挿入することもできます。


例題で挙動を確認する

携帯番号の例

echo mask_phone_for_display('090-1234-5678');
// 090****5678

echo mask_phone_for_display('08012345678');
// 080****5678
PHP

先頭 3 桁(キャリア識別)と末尾 4 桁(個人識別)だけ見せて、
真ん中 4 桁を **** にしています。

固定電話の例

echo mask_phone_for_display('03-1234-5678');
// 03****5678

echo mask_phone_for_display('045-123-4567');
// 04***4567
PHP

固定電話は桁構成がいろいろありますが、
ここでは「先頭 2 桁+末尾 4 桁」を見せるシンプルなルールにしています。

短い番号(内線など)の例

echo mask_phone_for_display('1234');
// 1234

echo mask_phone_for_display('12');
// 12
PHP

4 桁以下はそのまま返すようにしているので、
内線番号などはマスクせずに扱えます(ここは運用ポリシー次第で変えてOKです)。


ログ・画面での使いどころ

ログ出力時

$rawPhone = $_POST['phone'] ?? '';

$masked = mask_phone_for_display($rawPhone);

error_log('SMS send failed to phone=' . $masked);
PHP

ログには「どの番号に送ろうとしたか」が分かる形で残りつつ、
フルの番号は見えません。

管理画面の一覧表示

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

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


どこまでマスクするかは「メールと同じくポリシー次第」

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

末尾 4 桁も隠して、先頭だけ見せる。
携帯はより厳しくマスクする。
そもそも電話番号はログに出さない。

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


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

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

まず電話番号を「数字だけ」に正規化する。
桁数に応じて、「先頭数桁+末尾 4 桁」だけ見せて、間を * で埋める。
ログや画面では、必ずこの関数を通した値だけを使う。

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

もう一度、コア部分をまとめておきます。

function normalize_phone_digits(string $phone): string
{
    $phone = mb_convert_kana($phone, 'n', 'UTF-8');
    return preg_replace('/\D+/', '', $phone) ?? '';
}

function mask_phone_for_display(string $phone): string
{
    $digits = normalize_phone_digits($phone);
    $len = strlen($digits);

    if ($len <= 4) {
        return $digits;
    }

    $headLen = ($len === 11) ? 3 : 2;
    $tailLen = 4;

    if ($headLen + $tailLen >= $len) {
        return $digits;
    }

    $head = substr($digits, 0, $headLen);
    $tail = substr($digits, -$tailLen);
    $mask = str_repeat('*', $len - $headLen - $tailLen);

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

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

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