WebEngine

だらだらと綴る技術系メモ

filter_input関数を使って簡潔なコードを書こう

filter_input関数ってなに?

(HTMLフォームのinputタグなどから)外部変数を受け取り、フィルタリングする関数。 一般的には、ユーザが入力した値などが妥当であるか調べたりするのに使います。


利点

通常フォームなどから値を受けとるとき、以下のように書くと思います。

$id = $_GET['id'];
$name = $_POST['name'];

しかし、値が入っていなかったり、上手く渡っていなかった場合、Notice: Undefined index なんかが発生します。早い話エラーですね。
そのためissetを使用し、値が入っているか確認する必要性があります。

<?php

if (!isset($_POST['name'])) {
  $name = null;
} elseif (!is_string($_POST['name'])) {
  $name = false;
} else {
  $name = $_POST['name'];
}

filter_inputを使えば上のコードを1行にできます。便利ですね。

$name = filter_input(INPUT_POST, 'name');


構文

filter_input(input_type, variable, filter, options);

  • input_type 入力タイプの指定。HTMLのフォームならば、INPUT_GET、INPUT_POSTなどを指定。
  • variable フィルタする変数の指定。
  • filter 使用するフィルタの種類。たとえば、Eメール以外を弾きたいならばFILTER_VALIDATE_EMAILと記す。
  • options フラグ、オプションの連想配列あるいは単一のフラグ、オプションを指定。

変数(variable)に入っている値が空だとfalseをリターンします。
第1、2引数は必ず指定しなくてはなりません。第3、4引数は任意です。


filter_input関数を使って新規会員登録ページを実装してみよう

以上の知識を駆使して会員登録のデモページを実装してみましょう。

<?php
/*
   新たにユーザ登録するためのページ
*/

// POSTによる送信があった
if (!empty($_POST)) {
    
    if (!$name = filter_input(INPUT_POST, 'name', FILTER_SANITIZE_SPECIAL_CHARS)) {
        $error['name'] = 'ユーザ名が空です';
    }
    if (strlen($name) > 26) {
        $error['name'] = '名前は25文字以内にしてください';
    }
    
    if (!$pass = filter_input(INPUT_POST, 'pass', FILTER_SANITIZE_SPECIAL_CHARS)) {
        $error['pass'] = 'パスワードを入力してください';
    }
    if (!empty($pass) && strlen($pass) <= 4) {
        $error['pass'] = 'パスワードが短すぎます';
    }
    if (!(strlen($pass) === mb_strlen($pass))) {
        $error['pass'] = 'パスワードに全角が含まれています。すべて半角で入力してください';
    }
    
    echo 'ユーザ名'.$name.'<br>';
    echo 'パスワード'.$pass.'<br>';
    
}

/* サニタイジング用関数 */
function sani($str) {
    return htmlspecialchars($str, ENT_QUOTES, 'UTF-8');
}

?>
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>新規会員登録</title>
</head>
<body>
  <h1>新規登録</h1>
  <p>必要事項をご記入ください。パスワードは5文字以上、半角英数字で入力してください</p>
  <form action="" method="post" enctype="multipart/form-data">
  <dl>
    <dt>ユーザー名<font color="red"> 必須</font></dt>
    <dd>
      <input type="text" name="name" size="35" maxlength="25" value="">
    <?php if(!empty($error['name'])): ?>
     <p><font color="red"><?=sani($error['name'])?></font></p>
    <?php endif; ?>
    </dd>
    <dt>パスワード<font color="red"> 必須</font></dt>
    <dd>
      <input type="password" name="pass" size="10" maxlength="20" value="">
    <?php if(!empty($error['pass'])): ?>
    <p><font color="red"><?=sani($error['pass'])?></font></p>
    <?php endif; ?>
    </dd>
  </dl>
  <div><input type="submit" value="入力内容を確認"></div>
  </form>
</body>
</html>

filter_inputの引数に指定してあるFILTER_SANITIZE_SPECIAL_CHARSサニタイジングを実行してくれます。 ためしに、自分自身でXSSによる攻撃をしてみると、無毒化された状態でechoされるのがわかると思います。余談ですが、inputタグのpassword は、コピペにより全角入力される危険性があります。きちんと、全角を弾く処理を実装しましょう。

実際に登録ページとして使いたい場合には、php部分を以下のように改良してみるといいでしょう。

<?php
/*
   新たにユーザ登録するためのページ
   名前とパスワードを入力させ、確認ページへと飛ばす
*/
@session_start();

// POSTによる送信があった
if (!empty($_POST)) {
    
    if (!$name = filter_input(INPUT_POST, 'name', FILTER_SANITIZE_SPECIAL_CHARS)) {
        $error['name'] = 'ユーザ名が空です';
    }
    if (strlen($name) > 26) {
        $error['name'] = '名前は25文字以内にしてください';
    }
    
    if (!$pass = filter_input(INPUT_POST, 'pass', FILTER_SANITIZE_SPECIAL_CHARS)) {
        $error['pass'] = 'パスワードを入力してください';
    }
    if (!empty($pass) && strlen($pass) <= 4) {
        $error['pass'] = 'パスワードが短すぎます';
    }
    if (!(strlen($pass) === mb_strlen($pass))) {
        $error['pass'] = 'パスワードに全角が含まれています。すべて半角で入力してください';
    }
    
    
    // エラーがないとき確認画面へ飛ばす
    if (empty($error)) {
        $_SESSION['join'] = $_POST;
        header('Location: check.php');
        exit();
    }
    
}
// --以下略--

あとは、実際に確認用のページ(ここではcheck.php)を制作すれば良いでしょう。そして、向こう側で送信ボタンが押されればデータベースに 登録、という形にするのがオーソドックスかと思います。ここでは確認用ページにセッション変数に代入して送っているという想定ですが、 $_POSTをそのまま送っているので確認ページで無毒化してあげましょう。

ここではfilter_inputの説明をするためにコードを簡潔にしています。脆弱性があるので、そのまま使用するのは避けましょう。
あと可読性も低いですね。