diff --git a/ext/pdo_sqlite/pdo_sqlite.stub.php b/ext/pdo_sqlite/pdo_sqlite.stub.php index e22c8ce10fccc..92f7cc4374605 100644 --- a/ext/pdo_sqlite/pdo_sqlite.stub.php +++ b/ext/pdo_sqlite/pdo_sqlite.stub.php @@ -63,4 +63,7 @@ public function openBlob( ?string $dbname = "main", int $flags = \Pdo\Sqlite::OPEN_READONLY ) {} + + /** @return bool */ + public function setAuthorizer(?callable $callback): bool {} } diff --git a/ext/pdo_sqlite/sqlite_driver.c b/ext/pdo_sqlite/sqlite_driver.c index 708abe444c829..afce58406d4ad 100644 --- a/ext/pdo_sqlite/sqlite_driver.c +++ b/ext/pdo_sqlite/sqlite_driver.c @@ -851,6 +851,72 @@ static int pdo_sqlite_handle_factory(pdo_dbh_t *dbh, zval *driver_options) /* {{ } /* }}} */ +typedef struct { + zend_fcall_info fci; + zend_fcall_info_cache fcc; +} pdo_sqlite_authorizer_data; + +static int php_sqlite_authorizer_callback(void *authdata, int action_code, + const char *arg1, const char *arg2, const char *arg3, const char *arg4) +{ + pdo_sqlite_authorizer_data *auth_data = (pdo_sqlite_authorizer_data *)authdata; + zval params[4]; + zval retval; + int result = SQLITE_DENY; + + ZVAL_LONG(¶ms[0], action_code); + ZVAL_STRING(¶ms[1], arg1 ? arg1 : ""); + ZVAL_STRING(¶ms[2], arg2 ? arg2 : ""); + ZVAL_STRING(¶ms[3], arg3 ? arg3 : ""); + + auth_data->fci.param_count = 4; + auth_data->fci.params = params; + auth_data->fci.retval = &retval; + + if (zend_call_function(&auth_data->fci, &auth_data->fcc) == SUCCESS) { + if (Z_TYPE(retval) == IS_TRUE) { + result = SQLITE_OK; + } + zval_ptr_dtor(&retval); + } + + zval_ptr_dtor(¶ms[1]); + zval_ptr_dtor(¶ms[2]); + zval_ptr_dtor(¶ms[3]); + + return result; +} + +static PHP_METHOD(PDO_SQLite_Ext, setAuthorizer) +{ + pdo_dbh_t *dbh = Z_PDO_DBH_P(ZEND_THIS); + pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *)dbh->driver_data; + zend_fcall_info fci = empty_fcall_info; + zend_fcall_info_cache fcc = empty_fcall_info_cache; + pdo_sqlite_authorizer_data *authdata = NULL; + + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_FUNC_OR_NULL(fci, fcc) + ZEND_PARSE_PARAMETERS_END(); + + if (!fci.size) { + // Callback is NULL, remove authorizer + sqlite3_set_authorizer(H->db, NULL, NULL); + RETURN_TRUE; + } + + authdata = ecalloc(1, sizeof(pdo_sqlite_authorizer_data)); + authdata->fci = fci; + authdata->fcc = fcc; + + if (sqlite3_set_authorizer(H->db, php_sqlite_authorizer_callback, authdata) == SQLITE_OK) { + RETURN_TRUE; + } + + efree(authdata); + RETURN_FALSE; +} + const pdo_driver_t pdo_sqlite_driver = { PDO_DRIVER_HEADER(sqlite), pdo_sqlite_handle_factory diff --git a/ext/pdo_sqlite/sqlite_driver_arginfo.h b/ext/pdo_sqlite/sqlite_driver_arginfo.h index 8785c187a97a9..452baec42f049 100644 --- a/ext/pdo_sqlite/sqlite_driver_arginfo.h +++ b/ext/pdo_sqlite/sqlite_driver_arginfo.h @@ -20,13 +20,19 @@ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_PDO_SQLite_Ext_s ZEND_ARG_TYPE_INFO(0, callback, IS_CALLABLE, 0) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_INFO_EX(arginfo_class_PDO_SQLite_setAuthorizer, 0, 0, 1) + ZEND_ARG_TYPE_INFO(0, callback, IS_CALLABLE, 1) +ZEND_END_ARG_INFO() + ZEND_METHOD(PDO_SQLite_Ext, sqliteCreateFunction); ZEND_METHOD(PDO_SQLite_Ext, sqliteCreateAggregate); ZEND_METHOD(PDO_SQLite_Ext, sqliteCreateCollation); +ZEND_METHOD(PDO_SQLite_Ext, setAuthorizer); static const zend_function_entry class_PDO_SQLite_Ext_methods[] = { ZEND_ME(PDO_SQLite_Ext, sqliteCreateFunction, arginfo_class_PDO_SQLite_Ext_sqliteCreateFunction, ZEND_ACC_PUBLIC) ZEND_ME(PDO_SQLite_Ext, sqliteCreateAggregate, arginfo_class_PDO_SQLite_Ext_sqliteCreateAggregate, ZEND_ACC_PUBLIC) ZEND_ME(PDO_SQLite_Ext, sqliteCreateCollation, arginfo_class_PDO_SQLite_Ext_sqliteCreateCollation, ZEND_ACC_PUBLIC) + ZEND_ME(PDO_SQLite_Ext, setAuthorizer, arginfo_class_PDO_SQLite_setAuthorizer, ZEND_ACC_PUBLIC) ZEND_FE_END };