SQLite3::setAuthorizer

(PHP 8)

SQLite3::setAuthorizer — SQL文が出来ることを限定するため、authorizer として使われるコールバックを設定する

説明

public function SQLite3::setAuthorizer(?callable $callback): bool

SQLite に対して毎回アクション(読み取り、削除、更新など) が実行される度に呼び出されるコールバックを設定します。 これは信頼できないソースがSQL文を準備する時に、 自分たちが許可していないデータにアクセスさせないとか、 データベースに損害を与える不正なSQL文を実行させないといった用途に使います。 たとえば、アプリケーションはデータベースの評価の際は 任意のSQL文の実行を許可しています。しかし、 データベースに対する変更は許可したくありません。 ユーザーが入力したSQL文が準備される間に、 authorizer が割って入り、SELECT 文以外のSQL文を許可しないようにできます。

authorizer コールバックは、 SQLite が文を準備するたびに複数回呼ばれる可能性があります。 SELECT や UPDATE 文は 個別のカラムが読み取られたり、更新されたりするたびに authorizer を呼び出します。

authorizer は引数を5つまで指定して呼び出すことが出来ます。 最初の引数は常に与えられます。 これは SQLite3 の定数に一致する int の値(アクションコード) です。 それ以外の引数は、アクションによっては与えられないことがあります。 以下の表が、アクションに応じた2番目と3番目の引数に関する説明を記しています:

アクションコードと引数の一覧
アクション 第2引数 第3引数
sqlite3::create_indexインデックス名テーブル名
sqlite3::create_tableテーブル名null
sqlite3::create_temp_indexインデックス名テーブル名
sqlite3::create_temp_tableテーブル名null
sqlite3::create_temp_triggerトリガ名テーブル名
sqlite3::create_temp_viewview名null
sqlite3::create_triggerトリガ名テーブル名
sqlite3::create_viewview名null
sqlite3::deleteテーブル名null
sqlite3::drop_indexインデックス名テーブル名
sqlite3::drop_tableテーブル名null
sqlite3::drop_temp_indexインデックス名テーブル名
sqlite3::drop_temp_tableテーブル名null
sqlite3::drop_temp_triggerトリガ名テーブル名
sqlite3::drop_temp_viewview名null
sqlite3::drop_triggerトリガ名テーブル名
sqlite3::drop_viewview名null
sqlite3::insertテーブル名null
sqlite3::pragmaプラグマの名前プラグマに渡す最初の引数。もしくは null
sqlite3::readテーブル名カラム名
sqlite3::selectnullnull
sqlite3::transaction操作null
sqlite3::updateテーブル名カラム名
sqlite3::attachファイル名null
sqlite3::detachデータベース名null
sqlite3::alter_tableデータベース名テーブル名
sqlite3::reindexインデックス名null
sqlite3::analyzeテーブル名null
sqlite3::create_vtableテーブル名モジュール名
sqlite3::drop_vtableテーブル名モジュール名
sqlite3::functionnullファンクション名
sqlite3::savepoint操作セーブポイントの名前
sqlite3::recursivenullnull

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 のドキュメント を参照ください。

パラメータ

callback

呼び出される callable。

null が渡されると、 現在の authorizer のコールバックが無効になります。

戻り値

成功した場合に true を、失敗した場合に false を返します。

エラー / 例外

このメソッドは例外をスローしません。 しかし、いったん 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] =>
)
+add a note

User Contributed Notes 1 note

up
0
bohwaz at gmail dot com
1 month ago
Note that you shouldn't change the authorizer while a query is still running, or you might end up with unexpected results if other statements are prepared before you fetch the result.

For example:

1. Set an authorizer to return SQLITE_IGNORE on column 'a'
2. Prepare statement
3. Execute statement
4. Store result in variable
5. Set authorizer to return SQLITE_OK on column 'a'
6. Prepare a new statement (eg. `SELECT 1;`), without changing anything to the first statement
7. Query the result set stored in step 4.

If I drop step 6, I get NULL value for 'a' column. If I don't, I get the actual value of the column 'a'.