如何在PDO中加载sqlite扩展?

问题描述 投票:0回答:4

首先我想告知一下案件情况,以免引起误会。

说到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 这样的方法来加载扩展

知道我该如何处理这个问题吗?

php sqlite pdo
4个回答
10
投票

找不到编译器标志,我们通过 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);
    }

2
投票

我已经为 PHP 7.4+ 实现了一个库,并提供了针对此问题的解决方案,其中不涉及重新编译 PDO 驱动程序。简而言之,它使用 PHP 的 FFI 扩展和 Z-Engine(使用 FFI 读取 PHP 的内部内存结构)来直接调用 SQLite C API。您可以在这篇博文中找到更详细的背景信息。我还不会在生产中推荐此解决方案,但它可能是测试或开发工作流程的可行解决方法。


1
投票

除了上面提到的解决方法之外,现在没有其他办法。如果您想在将来的某个地方检查进度,请参阅 PHP bugtracker 上的问题


0
投票

正如 @yagmur 回答了这个问题,有一个解决方法是编译 pdo_sqlite 扩展。对于那些不知道如何做到这一点的人,就像我几天前一样,这个过程非常简单(我将假设一个 Linux 环境,因为我没有在 Windows 中编译这些东西的经验):

  1. 克隆 PHP 源存储库
  2. 访问您要使用的 PHP 版本的分支,例如PHP-8.2(您可以使用
    git checkout -b PHP-8.2.9 origin/PHP-8.2.9
    访问分支)
  3. 在文件夹
    ext/pdo_sqlite
    中,在
    sqlite3_enable_load_extension(H->db, 1);
    文件上调用
    sqlite3_set_authorizer
    函数的部分上方添加行
    sqlite_driver.c
    (该函数可能只调用一次),正如@yagmur 告诉的那样
  4. 编译扩展(下面我会解释编译的步骤)
  5. 将新编译的扩展,生成的
    pdo_sqlite.so
    文件复制到您喜欢的文件夹中
  6. 配置您的
    php.ini
    文件以将 pdo_sqlite 路径与新路径匹配
  7. 重新启动 PHP 服务器
  8. 测试加载一个扩展

要编译扩展,您只需在终端中访问文件夹

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 扩展的影响,如果您可以使用更大或更大的扩展较低版本也能正常工作。

© www.soinside.com 2019 - 2024. All rights reserved.