(PHP 8)
SQLite3::setAuthorizer — SQL文が出来ることを限定するため、authorizer として使われるコールバックを設定する
SQLite に対して毎回アクション(読み取り、削除、更新など) が実行される度に呼び出されるコールバックを設定します。 これは信頼できないソースがSQL文を準備する時に、 自分たちが許可していないデータにアクセスさせないとか、 データベースに損害を与える不正なSQL文を実行させないといった用途に使います。 たとえば、アプリケーションはデータベースの評価の際は 任意のSQL文の実行を許可しています。しかし、 データベースに対する変更は許可したくありません。 ユーザーが入力したSQL文が準備される間に、 authorizer が割って入り、SELECT 文以外のSQL文を許可しないようにできます。
authorizer コールバックは、
SQLite が文を準備するたびに複数回呼ばれる可能性があります。
SELECT や
UPDATE 文は
個別のカラムが読み取られたり、更新されたりするたびに
authorizer を呼び出します。
authorizer は引数を5つまで指定して呼び出すことが出来ます。
最初の引数は常に与えられます。
これは SQLite3 の定数に一致する
int の値(アクションコード) です。
それ以外の引数は、アクションによっては与えられないことがあります。
以下の表が、アクションに応じた2番目と3番目の引数に関する説明を記しています:
4番目の引数は、適切な場合にだけ指定する("main",
"temp", などの) データベースの名前です。
authorizer コールバックに与える5番目の引数は、 トップレベルのSQLコードから直接アクセスが行われる場合に、 アクセスを試みる責任を持つ一番奥の view やトリガの名前です。
コールバックが SQLite3::OK
を返すと、操作のリクエストが承認されたことになります。
コールバックが SQLite3::DENY
を返すと、authorizer を動かした呼び出しは失敗し、
なぜアクセスが失敗したのかを説明するメッセージが残ります。
アクションが SQLite3::READ で、
さらにコールバックが
SQLite3::IGNORE を返す場合、
準備されたSQL文は、
SQLite3::OK が返された場合に読まれていたテーブルのカラムを null で置き換えるように文を組み立てます。
SQLite3::IGNORE は、
信頼できないユーザーのアクセスが、
テーブルの個別のカラムへのアクセスを拒否する場合に使うことが出来ます。
テーブルを SELECT 文で参照しているが、
そのテーブルからカラムの値を抜き出さない場合
(たとえば、"SELECT count(*) FROM table"
のようなクエリの場合)、
SQLite3::READ の authorizer コールバックは
カラムの情報が空文字列になった状態で一度だけ呼び出されます。
アクションコードが SQLite3::DELETE で、
さらにコールバックが
SQLite3::IGNORE を返した場合、
DELETE の操作は継続しますが、truncate による最適化は無効になります。
この場合、全ての行は個別に削除されます。
接続ひとつにつき、authorizer ひとつだけがデータベースに存在できます。
SQLite3::setAuthorizer() が呼び出されるたびに、
以前の呼び出しは上書きされます。
null をコールバックに指定することで、
authorizer を無効に出来ます。authorizer はデフォルトで無効になっています。
authorizer コールバックは、コールバックを呼び出すデータベース接続に対していかなる変更もしてはいけません。
authorizer はSQL文が準備される時にだけ呼び出されることに注意して下さい。 実行時ではありません。
さらなる詳細は » SQLite3 のドキュメント を参照ください。
このメソッドは例外をスローしません。 しかし、いったん authorizer が有効になり、不正な値を返すと、 SQL文の準備がエラー (または例外。 SQLite3::enableExceptions() の使い方によります) を発生させるようになります。
例1 SQLite3::setAuthorizer() の例
この例は、読み取りだけを許可します。
さらに、users テーブルのいくつかのカラムだけを返します。
他のカラムは null で置き換えられます。
<?php
$db = new SQLite3('data.sqlite');
$db->exec('CREATE TABLE users (id, name, password);');
$db->exec('INSERT INTO users VALUES (1, \'Pauline\', \'Snails4eva\');');
$allowed_columns = ['id', 'name'];
$db->setAuthorizer(function (int $action, ...$args) use ($allowed_columns) {
if ($action === SQLite3::READ) {
list($table, $column) = $args;
if ($table === 'users' && in_array($column, $allowed_columns)) {
return SQLite3::OK;
}
return SQLite3::IGNORE;
}
return SQLite3::DENY;
});
print_r($db->querySingle('SELECT * FROM users WHERE id = 1;'));上の例の出力は以下となります。
Array
(
[id] => 1
[name] => Pauline
[password] =>
)