Skip to content

Commit a8dd009

Browse files
tzmfreedomnikic
authored andcommitted
Allow specifying sqlite3 DSN (file:/) in PDO SQLite
Closes GH-6610.
1 parent cc3e03c commit a8dd009

File tree

4 files changed

+84
-0
lines changed

4 files changed

+84
-0
lines changed

UPGRADING

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,13 @@ PHP 8.1 UPGRADE NOTES
126126
echo $h, "\n";
127127
```
128128

129+
- PDO SQLite:
130+
. SQLite's "file:" DSN syntax is now supported, which allows specifying
131+
additional flags. This feature is not available if open_basedir is set.
132+
Example:
133+
134+
new PDO('sqlite:file:path/to/sqlite.db?mode=ro')
135+
129136
- Posix:
130137
. Added POSIX_RLIMIT_KQUEUES and POSIX_RLIMIT_NPTS. These rlimits are only
131138
available on FreeBSD.

ext/pdo_sqlite/sqlite_driver.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -731,6 +731,12 @@ static const struct pdo_dbh_methods sqlite_methods = {
731731

732732
static char *make_filename_safe(const char *filename)
733733
{
734+
if (*filename && strncasecmp(filename, "file:", 5) == 0) {
735+
if (PG(open_basedir) && *PG(open_basedir)) {
736+
return NULL;
737+
}
738+
return estrdup(filename);
739+
}
734740
if (*filename && memcmp(filename, ":memory:", sizeof(":memory:"))) {
735741
char *fullpath = expand_filepath(filename, NULL);
736742

@@ -803,6 +809,9 @@ static int pdo_sqlite_handle_factory(pdo_dbh_t *dbh, zval *driver_options) /* {{
803809

804810
flags = pdo_attr_lval(driver_options, PDO_SQLITE_ATTR_OPEN_FLAGS, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE);
805811

812+
if (!(PG(open_basedir) && *PG(open_basedir))) {
813+
flags |= SQLITE_OPEN_URI;
814+
}
806815
i = sqlite3_open_v2(filename, &H->db, flags, NULL);
807816

808817
efree(filename);
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
--TEST--
2+
PDO SQLite open_basedir check
3+
--SKIPIF--
4+
<?php if (!extension_loaded('pdo_sqlite')) print 'skip not loaded'; ?>
5+
--INI--
6+
open_basedir=.
7+
--FILE--
8+
<?php
9+
chdir(__DIR__);
10+
11+
try {
12+
$db = new PDO('sqlite:../not_in_open_basedir.sqlite');
13+
} catch (Exception $e) {
14+
echo $e->getMessage() . "\n";
15+
}
16+
try {
17+
$db = new PDO('sqlite:file:../not_in_open_basedir.sqlite');
18+
} catch (Exception $e) {
19+
echo $e->getMessage() . "\n";
20+
}
21+
try {
22+
$db = new PDO('sqlite:file:../not_in_open_basedir.sqlite?mode=ro');
23+
} catch (Exception $e) {
24+
echo $e->getMessage() . "\n";
25+
}
26+
27+
?>
28+
--EXPECT--
29+
open_basedir prohibits opening ../not_in_open_basedir.sqlite
30+
open_basedir prohibits opening file:../not_in_open_basedir.sqlite
31+
open_basedir prohibits opening file:../not_in_open_basedir.sqlite?mode=ro
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
--TEST--
2+
PDO_sqlite: Testing filename uri
3+
--SKIPIF--
4+
<?php if (!extension_loaded('pdo_sqlite')) print 'skip not loaded'; ?>
5+
--FILE--
6+
<?php
7+
8+
// create with default read-write|create mode
9+
$filename = "file:" . __DIR__ . DIRECTORY_SEPARATOR . "pdo_sqlite_filename_uri.db";
10+
11+
$db = new PDO('sqlite:' . $filename);
12+
13+
var_dump($db->exec('CREATE TABLE test1 (id INT);'));
14+
15+
// create with readonly mode
16+
$filename = "file:" . __DIR__ . DIRECTORY_SEPARATOR . "pdo_sqlite_filename_uri.db?mode=ro";
17+
18+
$db = new PDO('sqlite:' . $filename);
19+
20+
var_dump($db->exec('CREATE TABLE test2 (id INT);'));
21+
22+
?>
23+
--CLEAN--
24+
<?php
25+
$filename = __DIR__ . DIRECTORY_SEPARATOR . "pdo_sqlite_filename_uri.db";
26+
if (file_exists($filename)) {
27+
unlink($filename);
28+
}
29+
?>
30+
--EXPECTF--
31+
int(0)
32+
33+
Fatal error: Uncaught PDOException: SQLSTATE[HY000]: General error: 8 attempt to write a readonly database in %s
34+
Stack trace:
35+
%s
36+
#1 {main}
37+
thrown in %s

0 commit comments

Comments
 (0)