首先我想告知一下案件情况,以免引起误会。
说到sqlite扩展,我提到的是Sqlite的扩展如FTS,而不是PHP的sqlite扩展。
我的应用程序中一直使用PDO Sqlite,它无法更改。
正如我在here看到的,Sqlite 扩展可以作为查询加载,如下所示:
SELECT load_extension('xyz.so');
$db = new PDO ( 'sqlite:qwert.db' );
$db->query("SELECT load_extension('myextension.so');");
$db->query("SELECT myfunction(name) FROM table");
$rows = $db->fetchAll(PDO::FETCH_CLASS, 'stdClass');
注意:myfunction 是 myextension 的方法
但是当我使用 PDO 的此查询进行测试时,它返回“未授权”消息。
仅出于测试目的,我尝试使用以下代码使用PHP的Sqlite3扩展加载扩展:
$db = new SQLite3('qwer.db');
$db->loadExtension('xyz.so');
有效
据我所知,PDO Sqlite 没有像 loadExtension 这样的方法来加载扩展
知道我该如何处理这个问题吗?
找不到编译器标志,我们通过 pdo_sqlite 扩展中的快速肮脏的 hack 解决了这个问题。使用 sqlite3 API 中的 sqlite3_enable_load_extension() 修补了 sqlite_driver.c。
--- php-5.3.7.old/ext/pdo_sqlite/sqlite_driver.c 2012-01-06 11:04:44.000000000 -0500
+++ sqlite_driver.c 2012-01-06 08:16:58.000000000 -0500
@@ -718,6 +718,8 @@
goto cleanup;
}
+ sqlite3_enable_load_extension(H->db, 1);
+
if (PG(safe_mode) || (PG(open_basedir) && *PG(open_basedir))) {
sqlite3_set_authorizer(H->db, authorizer, NULL);
}
除了上面提到的解决方法之外,现在没有其他办法。如果您想在将来的某个地方检查进度,请参阅 PHP bugtracker 上的问题。
正如 @yagmur 回答了这个问题,有一个解决方法是编译 pdo_sqlite 扩展。对于那些不知道如何做到这一点的人,就像我几天前一样,这个过程非常简单(我将假设一个 Linux 环境,因为我没有在 Windows 中编译这些东西的经验):
git checkout -b PHP-8.2.9 origin/PHP-8.2.9
访问分支)ext/pdo_sqlite
中,在 sqlite3_enable_load_extension(H->db, 1);
文件上调用 sqlite3_set_authorizer
函数的部分上方添加行 sqlite_driver.c
(该函数可能只调用一次),正如@yagmur 告诉的那样pdo_sqlite.so
文件复制到您喜欢的文件夹中php.ini
文件以将 pdo_sqlite 路径与新路径匹配要编译扩展,您只需在终端中访问文件夹
ext/pdo_sqlite
并执行以下命令:
phpize
./configure
make
扩展名可能位于
ext/pdo_sqlite/modules
文件夹中。
要配置
php.ini
,可以使用cli命令php --ini
,找到路径并编辑配置。可能会在 php.ini
文件中包含这一行: extension=pdo_sqlite
,但也可以在特定文件中进行 pdo_sqlite
配置。将值更改为已编译扩展的路径。
如果您想测试它是否正常工作,您可以尝试类似的操作,在本例中加载 SpatiaLite 扩展:
$pdo = new PDO('sqlite:db/test.sqlite3');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$query = "CREATE TABLE IF NOT EXISTS test (id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, area POLYGON)";
$pdo->exec($query);
$query = "SELECT load_extension('/usr/local/lib/mod_spatialite')";
try{
$pdo->exec($query);
$geom = "POLYGON((-3.692895967970722 40.589246298614356,-3.489648897658222 40.687204044606595,-3.357812960158222 40.50367643938022,-3.585779268751972 40.413815011684214,-3.692895967970722 40.589246298614356))";
$query = "INSERT INTO test (area) VALUES (ST_geomFromText('$geom'))";
$rs = $pdo->exec($query);
$query = "SELECT ST_asText(area), ST_area(area) from test";
$statement = $pdo->prepare($query);
$statement->execute();
echo "<pre>";
echo print_r($statement->fetchAll(), true);
echo "</pre>";
}catch(Throwable $e){
var_dump($e);
}
但只需使用
SELECT spatialite_version()
打印 SpatiaLite 版本也是最快的测试。
P.S.:我必须说实话,我不知道这是否对每个版本的 sqlite_pdo 都有效,也不知道 PHP 分支的版本对 pdo_sqlite 扩展的影响,如果您可以使用更大或更大的扩展较低版本也能正常工作。