]> granicus.if.org Git - php/commitdiff
Allow specifying sqlite3 DSN (file:/) in PDO SQLite
authortzmfreedom <makoto_tajitsu@hotmail.co.jp>
Sun, 17 Jan 2021 05:13:19 +0000 (14:13 +0900)
committerNikita Popov <nikita.ppv@gmail.com>
Mon, 25 Jan 2021 13:44:56 +0000 (14:44 +0100)
Closes GH-6610.

UPGRADING
ext/pdo_sqlite/sqlite_driver.c
ext/pdo_sqlite/tests/open_basedir.phpt [new file with mode: 0644]
ext/pdo_sqlite/tests/pdo_sqlite_filename_uri.phpt [new file with mode: 0644]

index facdf303773b5898f97443c234c13472155fafa8..29701c37141f80c933e9e3aa36016c80c4737b1e 100644 (file)
--- a/UPGRADING
+++ b/UPGRADING
@@ -126,6 +126,13 @@ PHP 8.1 UPGRADE NOTES
     echo $h, "\n";
     ```
 
+- PDO SQLite:
+  . SQLite's "file:" DSN syntax is now supported, which allows specifying
+    additional flags. This feature is not available if open_basedir is set.
+    Example:
+
+        new PDO('sqlite:file:path/to/sqlite.db?mode=ro')
+
 - Posix:
   . Added POSIX_RLIMIT_KQUEUES and POSIX_RLIMIT_NPTS. These rlimits are only
     available on FreeBSD.
index a48c77f9e88bcf7b285f5cbc24964dcf3ad82592..217833f6ad8cae00aec1abcf40052363bd9540c4 100644 (file)
@@ -731,6 +731,12 @@ static const struct pdo_dbh_methods sqlite_methods = {
 
 static char *make_filename_safe(const char *filename)
 {
+       if (*filename && strncasecmp(filename, "file:", 5) == 0) {
+               if (PG(open_basedir) && *PG(open_basedir)) {
+                       return NULL;
+               }
+               return estrdup(filename);
+       }
        if (*filename && memcmp(filename, ":memory:", sizeof(":memory:"))) {
                char *fullpath = expand_filepath(filename, NULL);
 
@@ -803,6 +809,9 @@ static int pdo_sqlite_handle_factory(pdo_dbh_t *dbh, zval *driver_options) /* {{
 
        flags = pdo_attr_lval(driver_options, PDO_SQLITE_ATTR_OPEN_FLAGS, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE);
 
+       if (!(PG(open_basedir) && *PG(open_basedir))) {
+               flags |= SQLITE_OPEN_URI;
+       }
        i = sqlite3_open_v2(filename, &H->db, flags, NULL);
 
        efree(filename);
diff --git a/ext/pdo_sqlite/tests/open_basedir.phpt b/ext/pdo_sqlite/tests/open_basedir.phpt
new file mode 100644 (file)
index 0000000..8041b47
--- /dev/null
@@ -0,0 +1,31 @@
+--TEST--
+PDO SQLite open_basedir check
+--SKIPIF--
+<?php if (!extension_loaded('pdo_sqlite')) print 'skip not loaded'; ?>
+--INI--
+open_basedir=.
+--FILE--
+<?php
+chdir(__DIR__);
+
+try {
+    $db = new PDO('sqlite:../not_in_open_basedir.sqlite');
+} catch (Exception $e) {
+    echo $e->getMessage() . "\n";
+}
+try {
+    $db = new PDO('sqlite:file:../not_in_open_basedir.sqlite');
+} catch (Exception $e) {
+    echo $e->getMessage() . "\n";
+}
+try {
+    $db = new PDO('sqlite:file:../not_in_open_basedir.sqlite?mode=ro');
+} catch (Exception $e) {
+    echo $e->getMessage() . "\n";
+}
+
+?>
+--EXPECT--
+open_basedir prohibits opening ../not_in_open_basedir.sqlite
+open_basedir prohibits opening file:../not_in_open_basedir.sqlite
+open_basedir prohibits opening file:../not_in_open_basedir.sqlite?mode=ro
diff --git a/ext/pdo_sqlite/tests/pdo_sqlite_filename_uri.phpt b/ext/pdo_sqlite/tests/pdo_sqlite_filename_uri.phpt
new file mode 100644 (file)
index 0000000..7eec264
--- /dev/null
@@ -0,0 +1,37 @@
+--TEST--
+PDO_sqlite: Testing filename uri
+--SKIPIF--
+<?php if (!extension_loaded('pdo_sqlite')) print 'skip not loaded'; ?>
+--FILE--
+<?php
+
+// create with default read-write|create mode
+$filename = "file:" . __DIR__ . DIRECTORY_SEPARATOR . "pdo_sqlite_filename_uri.db";
+
+$db = new PDO('sqlite:' . $filename);
+
+var_dump($db->exec('CREATE TABLE test1 (id INT);'));
+
+// create with readonly mode
+$filename = "file:" . __DIR__ . DIRECTORY_SEPARATOR . "pdo_sqlite_filename_uri.db?mode=ro";
+
+$db = new PDO('sqlite:' . $filename);
+
+var_dump($db->exec('CREATE TABLE test2 (id INT);'));
+
+?>
+--CLEAN--
+<?php
+$filename = __DIR__ . DIRECTORY_SEPARATOR . "pdo_sqlite_filename_uri.db";
+if (file_exists($filename)) {
+    unlink($filename);
+}
+?>
+--EXPECTF--
+int(0)
+
+Fatal error: Uncaught PDOException: SQLSTATE[HY000]: General error: 8 attempt to write a readonly database in %s
+Stack trace:
+%s
+#1 {main}
+  thrown in %s