忍者ブログ

VB.NET-TIPS などプログラミングについて

VB.NETのTIPS(小技集)を中心に、Javascript、PHP その他のプログラミングについて少し役に立つ情報を発信します。いわゆる個人的な忘備録ですが、みなさんのお役に立てれば幸いです。

PHP 問合せフォーム等の入力文字列の半角・全角変換について


Webサイトの 問合せフォーム などでいろんな項目を入力して問合せを行うわけですが、 電話番号や郵便番号などで半角文字しか受け付けないページをたまに見かけます。

番号入力のテキストボックスで、入力時にIMEがONの状態で全角文字の数字をいれて、フォームの登録ボタンを押下すると 「半角文字の数字で入力して下さい。」などとエラーメッセージが表示されます。

必要な情報は半角文字なので PHP には全角から半角への変換ができる mb_convert_kana 関数があるので、 これを使ってできる限り欲しいデータに変換するべきだと思います。
(ただし、住所などの場合、全角と半角の混在が必要なときもあるので、強制的に半角⇒全角の変換はそれぞれのシステムによるとは思います)

それでは、簡単な 問合せフォーム を作成しましたので、以下にスクリプトを示します。
このスクリプトは以下の様な構成になっています。

  • $_POST から受け取る各データ変数の宣言を行う。
  • $_POST から各データを取得する。
  • 各データのエラーチェックを行う。
  • HTML内でエラーメッセージがあれば表示を行う。
  • FORMタグ内で各入力データの表示を行う。
<?php
//  初期化
$strName  = "";
$strZipno = "";
$strAddr  = "";
$strTelno = "";

//  $POSTから取得
if((isset($_POST['pname'])== true) && ($_POST['pname'] != "")){
    $strName = trim($_POST['pname']);
}
if((isset($_POST['zipno'])== true) && ($_POST['zipno'] != "")){
    $strZipno = trim($_POST['zipno']);
}
if((isset($_POST['addr'])== true) && ($_POST['addr'] != "")){
    $strAddr = trim($_POST['addr']);
}
if((isset($_POST['telno'])== true) && ($_POST['telno'] != "")){
    $strTelno = trim($_POST['telno']);
}

//  エラーチェック
$strErr  = "";
//  名前
if ($strName == "") {
    $strErr .= "名前を入力して下さい。<br />";
}
//  郵便番号
if ($strZipno == "") {
    $strErr .= "郵便番号を入力して下さい。<br />";
} else {
    //  郵便番号チェック(数字3桁または、数字3桁-4桁)
    if(!preg_match('/^([0-9]{3})(-[0-9]{4})?$/i', $strZipno)){
        $strErr .= $strZipno.'は不正な郵便番号です。<br />';
    }
}
//  住所
if ($strAddr == "") {
    $strErr .= "住所を入力して下さい。<br />";
}
//  電話番号
if ($strTelno == "") {
    $strErr .= "電話番号を入力して下さい。<br />";
} else {
    //  電話番号チェック(数字のみのチェック)
    if(!preg_match('/^[0-9]+$/i', $strTelno)){
        $strErr .= $strTelno.'は不正な電話番号です。<br />';
    }
}
?>
<html>
<head>
  <meta charset="utf-8">
  <title>問合せ・個人情報</title>
</head>
<body>
<h1>問合せ・個人情報</h1>
<?php
//  エラーメッセージ処理
if ($strErr != "") {
?>
<div id="ErrorMessage" style="color:red">
  <h2>エラーメッセージ</h2>
  <p>
    以下のエラーがあります!<br />
    <?php echo $strErr; ?>
  </p>
</div>
<?php
}
?>
<form name="enqform" action="enq1.php" method="post">
  名前  :<input type="text" name="pname" maxlength="20" value="<?php echo $strName;  ?>" /><br />
  郵便番号:<input type="text" name="zipno" maxlength="8"  value="<?php echo $strZipno; ?>" /><br />
  住所  :<input type="text" name="addr"  maxlength="30" value="<?php echo $strAddr;  ?>" /><br />
  電話番号:<input type="text" name="telno" maxlength="13" value="<?php echo $strTelno; ?>" /><br />
  <input type="submit" value="送信" />
</form>
</body>
</html>

エラーが表示される様なデータを入力し「送信」ボタンを押下すると以下の表示になります。

「郵便番号」「電話番号」には全角の数字を入力しましたので、エラーメッセージが表示されます。

尚、このスクリプトは最初に表示した時に全ての項目の未入力エラーが表示されます。 これの解消は、自分自身で処理モードを持って最初の表示なのか、「送信」ボタンを押下した時なのかを判定する必要があります。



■全角文字を半角文字に変換する処理を追加したスクリプト

最初にもありましたが mb_convert_kana 関数を使って必要な個所で全角文字を半角文字に変換を行います。

mb_convert_kana 関数ですが以下の様な定義になっています。

 mb_convert_kana ( string $str [, string $option = "KV" [, string $encoding = mb_internal_encoding() ]] ) : string

$str    :変換される文字列。

$option :変換オプションで以下の組み合わせで行う。
   ・"r" 「全角」英字を「半角」に変換します。
   ・"R" 「半角」英字を「全角」に変換します。
   ・"n" 「全角」数字を「半角」に変換します。
   ・"N" 「半角」数字を「全角」に変換します。
   ・"a" 「全角」英数字を「半角」に変換します。
   ・"A" 「半角」英数字を「全角」に変換します。 
       ("a", "A" オプションに含まれる文字は、U+0022, U+0027, U+005C, U+007Eを除く U+0021 - U+007E の範囲です)
   ・"s" 「全角」スペースを「半角」に変換します(U+3000 -> U+0020)。
   ・"S" 「半角」スペースを「全角」に変換します(U+0020 -> U+3000)。
   ・"k" 「全角カタカナ」を「半角カタカナ」に変換します。
   ・"K" 「半角カタカナ」を「全角カタカナ」に変換します。
   ・"h" 「全角ひらがな」を「半角カタカナ」に変換します。
   ・"H" 「半角カタカナ」を「全角ひらがな」に変換します。
   ・"c" 「全角カタカナ」を「全角ひらがな」に変換します。
   ・"C" 「全角ひらがな」を「全角カタカナ」に変換します。
   ・"V" 濁点付きの文字を一文字に変換します。"K", "H" と共に使用します。

$encoding:文字エンコーディングを指定します。省略した場合は、 内部文字エンコーディングを使用します。

今回の電話番号、郵便番号は mb_convert_kana 関数のオプション指定は「全角」英数字を「半角」に変換する "a" となります。

あと一つ問合せフォームなどの入力値の扱いで重要なことがあります。
それは、POSTされてきた値をそのまま input タグの value に設定しないことです。
クロスサイトスクリプトの攻撃を防ぐためには必要です。

これを防ぐためには入力値を htmlspecialchars 関数で特殊文字を HTML エンティティに変換します。
関数には引数が必要なので、ラッパ関数として function h() を宣言しそれを使用します。

以下に改良したスクリプトを示します。

<?php
//  特殊文字を HTML エンティティに変換する関数
function h($s) {
    return htmlspecialchars($s, ENT_QUOTES, "UTF-8");
}

//  処理モード
define('MODE_NEW', 1);  //  新規
define('MODE_REG', 2);  //  登録

//  初期化
$intMode  = 0;
$strName  = "";
$strZipno = "";
$strAddr  = "";
$strTelno = "";

//  $POSTから取得
if((isset($_POST['mode'])== true) && ($_POST['mode'] != "")){
    $intMode = intval($_POST['mode']);
}
if ($intMode == 0) {
    $intMode = MODE_NEW;
}
if((isset($_POST['pname'])== true) && ($_POST['pname'] != "")){
    $strName = trim($_POST['pname']);
}
if((isset($_POST['zipno'])== true) && ($_POST['zipno'] != "")){
    $strZipno = trim($_POST['zipno']);
    $strZipno = mb_convert_kana($strZipno, "a");    //  「全角」⇒「半角」変換
}
if((isset($_POST['addr'])== true) && ($_POST['addr'] != "")){
    $strAddr = trim($_POST['addr']);
}
if((isset($_POST['telno'])== true) && ($_POST['telno'] != "")){
    $strTelno = trim($_POST['telno']);
    $strTelno = mb_convert_kana($strTelno, "a");    //  「全角」⇒「半角」変換
}

//  エラーチェック
$strErr  = "";
if ($intMode == MODE_NEW) {
    //  新規モードの場合は、登録モードにする
    $intMode = MODE_REG;
} else if ($intMode == MODE_REG) {
    //  名前
    if ($strName == "") {
        $strErr .= "名前を入力して下さい。<br />";
    }
    //  郵便番号
    if ($strZipno == "") {
        $strErr .= "郵便番号を入力して下さい。<br />";
    } else {
        //  郵便番号チェック(数字3桁または、数字3桁-4桁)
        if(!preg_match('/^([0-9]{3})(-[0-9]{4})?$/i', $strZipno)){
            $strErr .= $strZipno.'は不正な郵便番号です。<br />';
        }
    }
    //  住所
    if ($strAddr == "") {
        $strErr .= "住所を入力して下さい。<br />";
    }
    //  電話番号
    if ($strTelno == "") {
        $strErr .= "電話番号を入力して下さい。<br />";
    } else {
        //  電話番号チェック(数字のみのチェック)
        if(!preg_match('/^[0-9]+$/i', $strTelno)){
            $strErr .= $strTelno.'は不正な電話番号です。<br />';
        }
    }
}
?>
<html>
<head>
  <meta charset="utf-8">
  <title>問合せ・個人情報</title>
</head>
<body>
<h1>問合せ・個人情報</h1>
<?php
//  エラーメッセージ処理
if ($strErr != "") {
?>
<div id="ErrorMessage" style="color:red">
  <h2>エラーメッセージ</h2>
  <p>
    以下のエラーがあります!<br />
    <?php echo $strErr; ?>
  </p>
</div>
<?php
}
?>
<form name="enqform" action="enq2.php" method="post">
  名前  :<input type="text" name="pname" maxlength="20" value="<?php echo h($strName);  ?>" /><br />
  郵便番号:<input type="text" name="zipno" maxlength="8"  value="<?php echo h($strZipno); ?>" /><br />
  住所  :<input type="text" name="addr"  maxlength="30" value="<?php echo h($strAddr);  ?>" /><br />
  電話番号:<input type="text" name="telno" maxlength="13" value="<?php echo h($strTelno); ?>" /><br />
  <input type="hidden" name="mode" value="<?php echo $intMode; ?>" /><br />
  <input type="submit" value="送信" />
</form>
</body>
</html>

尚、 htmlspecialchars 関数は以下の様に定義されています。

htmlspecialchars ( string $string [, int $flags = ENT_COMPAT 
                    [, string|null $encoding = NULL [, bool $double_encode = TRUE ]]] ) : string

$string    変換される文字列。
$flags     以下のフラグを組み合わせたビットマスクです。
           クォートや無効な符号単位シーケンス、そして文書型の扱いを指定します。
           デフォルトは ENT_COMPAT | ENT_HTML401 です。 

			・ENT_COMPAT 	   ダブルクオートは変換しますがシングルクオートは変換しません。
			・ENT_QUOTES 	   シングルクオートとダブルクオートを共に変換します。
			・ENT_NOQUOTES   シングルクオートとダブルクオートは共に変換されません。
			・ENT_SUBSTITUTE 無効な符号単位シーケンスを含む文字列を渡したときに、
			               空の文字列を返すのではなく Unicode の置換文字に置き換えます。
			               (UTF-8 の場合は U+FFFD、それ以外の場合は � となります)
			・ENT_DISALLOWED 指定した文書型において無効な符号位置を、
			               Unicode の代替文字である U+FFFD (UTF-8) あるいは � で置き換えます。
			               これを設定しなければ、無効な符号位置をそのまま残します。
			               これは、外部コンテンツを埋め込んだ XML 文書を整形式に保つために有用です。
			・ENT_HTML401    コードを HTML 4.01 として処理します。
			・ENT_XML1       コードを XML 1 として処理します。
			・ENT_XHTML      コードを XHTML として処理します。
			・ENT_HTML5      コードを HTML 5 として処理します。 

$encoding  オプションの引数。文字を変換するときに使うエンコーディングを定義します。 



上記のスクリプトはまだまだ突っ込みどころ満載で以下の様な処理が必要かと思われますので、 皆さんで追加して下さい。

  • 問合せの内容を登録する処理。(データベースに依存)
  • 登録後の処理をどうするのか。(「登録しました」等のメッセージ表示?)
  • 電話番号のエラーチェックが甘い。
  • 住所の情報は1個で良いのか。(データベース・テーブルに依存)
  • 現状メールアドレスはありませんが、メールアドレスへの確認送信。
  • ブラウザのページ戻りの処理をどうするのか?












PR

コメント

コメントを書く