パラメータをエスケープする

広告

今までの例でSELECTやINSERTを実行する時に、SQL文中で使われている値が固定の値として記述している場合は問題無いですが、例えばフォームなどから条件を入力してもらってSQL文を作成する時に、SQLインジェクション攻撃などを防ぐ為にパラメータをエスケープしておく必要があります。

PHPではエスケープ用の関数が用意されています。

string mysql_real_escape_string(string unescaped_string [, resource link_identifier])

現在の接続の文字セットで unescaped_string の特殊文字をエスケープし、
mysql_query() で安全に利用できる形式に変換します。バイナリデータを
挿入しようとしている場合、必ずこの関数を利用しなければなりません。

引数:
  unescaped_string  エスケープされる文字列。
  link_identifier  MySQLリンクID
返り値:
  成功した場合にエスケープ後の文字列、失敗した場合に FALSE を返します。

マジッククオートをオンにしてる場合も似たような効果が得られますが、マジッククオートはオフにしてこの関数を使って必要に応じてエスケープすることが推奨されています。具体的には例えばINSERTする値にシングルクォーテーション(')などが含まれていた場合SQL文がおかしくなってしまいますが、この関数を通すことでSQL文の中で直接記述できないような値に対して「\」を使ってエスケープ処理を行ってくれます。

$test = "book's";

mysql_real_escape_string($test);
// $test = "book\'s"

実際の使い方の例として下記のようなサンプルが記載されています。

function quote_smart($value)
{
    // 数値以外をクオートする
    if (!is_numeric($value)) {
        $value = "'" . mysql_real_escape_string($value) . "'";
    }
    return $value;
}

$query = sprintf("SELECT * FROM users WHERE user=%s AND password=%s",
            quote_smart($_POST['username']),
            quote_smart($_POST['password']));

mysql_query($query);

上記ではPOSTで送られてきたユーザー名とパスワードをエスケープ処理した値を、「sprintf」関数を使ってSQL文を作成しています。

では前のページで使ったINSERTのサンプルを書き直してみます。

<html>
<head>
<title>PHP TEST</title>
</head>

<body>

<?php

function quote_smart($value)
{
    // 数値以外をクオートする
    if (!is_numeric($value)) {
        $value = "'" . mysql_real_escape_string($value) . "'";
    }
    return $value;
}

$link = mysql_connect('localhost', 'testuser', 'testuser');
if (!$link) {
    die('接続失敗です。'.mysql_error());
}

print('<p>接続に成功しました。</p>');

$db_selected = mysql_select_db('uriage', $link);
if (!$db_selected){
    die('データベース選択失敗です。'.mysql_error());
}

print('<p>uriageデータベースを選択しました。</p>');

mysql_set_charset('utf8');

print('<p>データを追加します。</p>');

$id = 5;
$name = "Toyama's Wine";

$sql = sprintf("INSERT INTO shouhin (id, name) VALUES (%s, %s)"
         , quote_smart($id), quote_smart($name));

print('<p>エスケープ後のデータ:'.quote_smart($name).'</p>');

$result_flag = mysql_query($sql);

if (!$result_flag) {
    die('INSERTクエリーが失敗しました。'.mysql_error());
}

print('<p>追加後のデータを取得します。</p>');

$result = mysql_query('SELECT id,name FROM shouhin');
if (!$result) {
    die('SELECTクエリーが失敗しました。'.mysql_error());
}

while ($row = mysql_fetch_assoc($result)) {
    print('<p>');
    print('id='.$row['id']);
    print(',name='.$row['name']);
    print('</p>');
}

$close_flag = mysql_close($link);

if ($close_flag){
    print('<p>切断に成功しました。</p>');
}

?>
</body>
</html>

上記を「test6.php」としてローカル環境で稼動しているApacheのドキュメントルート以下に設置し、ブラウザでアクセスします。

p8-1

今回は対象となる値を使ってSELECT文などを作成しているわけではなく、どのようにエスケープが行われるのかを確認だけ行います。実際に試してみると追加するデータの中に含まれていたシングルクオーテーションがエスケープ処理されて Toyama\'s Wine となっているのが確認できます。これで「'」のような特殊な意味を持つ文字も単なる文字の「'」として処理されます。

( Written by Tatsuo Ikura )

プロフィール画像

著者 / TATSUO IKURA

これから IT 関連の知識を学ばれる方を対象に、色々な言語でのプログラミング方法や関連する技術、開発環境構築などに関する解説サイトを運営しています。