Skip to content

Implemented request #64810 (impossible to load extension via pdo_sqlite) #3368

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions ext/pdo_sqlite/config.m4
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ if test "$PHP_PDO_SQLITE" != "no"; then
PHP_CHECK_LIBRARY(sqlite3,sqlite3_key,[
AC_DEFINE(HAVE_SQLITE3_KEY,1, [have commercial sqlite3 with crypto support])
])
PHP_CHECK_LIBRARY(sqlite3,sqlite3_load_extension,
[],
[AC_DEFINE(SQLITE_OMIT_LOAD_EXTENSION, 1, [have sqlite3 with extension support])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit odd, we'd usually go for a positive define instead. HAVE_SQLITE3_LOAD_EXTENSION would be typical.

])
PHP_CHECK_LIBRARY(sqlite3,sqlite3_close_v2,[
AC_DEFINE(HAVE_SQLITE3_CLOSE_V2, 1, [have sqlite3_close_v2])
])
Expand Down
1 change: 1 addition & 0 deletions ext/pdo_sqlite/config.w32
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ ARG_WITH("pdo-sqlite", "for pdo_sqlite support", "no");

if (PHP_PDO_SQLITE != "no") {
if (SETUP_SQLITE3("pdo_sqlite", PHP_PDO_SQLITE, PHP_PDO_SQLITE_SHARED)) {
ADD_FLAG('CFLAGS_PDO_SQLITE', "/D SQLITE_THREADSAFE=" + (PHP_ZTS == "yes" ? "1" : "0") + " ");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure I understand the purpose of this change. As we no longer bundle libsqlite3 nowadays, does this even have an effect?

EXTENSION("pdo_sqlite", "pdo_sqlite.c sqlite_driver.c sqlite_statement.c");

ADD_EXTENSION_DEP('pdo_sqlite', 'pdo');
Expand Down
33 changes: 32 additions & 1 deletion ext/pdo_sqlite/pdo_sqlite.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@
#include "php_pdo_sqlite_int.h"
#include "zend_exceptions.h"

ZEND_DECLARE_MODULE_GLOBALS(pdo_sqlite)

static PHP_GINIT_FUNCTION(pdo_sqlite);

/* {{{ pdo_sqlite_functions[] */
static const zend_function_entry pdo_sqlite_functions[] = {
PHP_FE_END
Expand Down Expand Up @@ -56,17 +60,30 @@ zend_module_entry pdo_sqlite_module_entry = {
NULL,
PHP_MINFO(pdo_sqlite),
PHP_PDO_SQLITE_VERSION,
STANDARD_MODULE_PROPERTIES
PHP_MODULE_GLOBALS(pdo_sqlite),
PHP_GINIT(pdo_sqlite),
NULL,
NULL,
STANDARD_MODULE_PROPERTIES_EX
};
/* }}} */

#if defined(COMPILE_DL_PDO_SQLITE) || defined(COMPILE_DL_PDO_SQLITE_EXTERNAL)
ZEND_GET_MODULE(pdo_sqlite)
#endif

/* {{{ PHP_INI
*/
PHP_INI_BEGIN()
STD_PHP_INI_ENTRY("pdo_sqlite.extension_dir", NULL, PHP_INI_SYSTEM, OnUpdateString, extension_dir, zend_pdo_sqlite_globals, pdo_sqlite_globals)
PHP_INI_END()
/* }}} */

/* {{{ PHP_MINIT_FUNCTION */
PHP_MINIT_FUNCTION(pdo_sqlite)
{
REGISTER_INI_ENTRIES();

#ifdef SQLITE_DETERMINISTIC
REGISTER_PDO_CLASS_CONST_LONG("SQLITE_DETERMINISTIC", (zend_long)SQLITE_DETERMINISTIC);
#endif
Expand All @@ -85,6 +102,7 @@ PHP_MINIT_FUNCTION(pdo_sqlite)
PHP_MSHUTDOWN_FUNCTION(pdo_sqlite)
{
php_pdo_unregister_driver(&pdo_sqlite_driver);
UNREGISTER_INI_ENTRIES();
return SUCCESS;
}
/* }}} */
Expand All @@ -97,6 +115,19 @@ PHP_MINFO_FUNCTION(pdo_sqlite)
php_info_print_table_header(2, "PDO Driver for SQLite 3.x", "enabled");
php_info_print_table_row(2, "SQLite Library", sqlite3_libversion());
php_info_print_table_end();

DISPLAY_INI_ENTRIES();
}
/* }}} */

/* {{{ PHP_GINIT_FUNCTION
*/
static PHP_GINIT_FUNCTION(pdo_sqlite)
{
#if defined(COMPILE_DL_PDO_SQLITE) && defined(ZTS)
ZEND_TSRMLS_CACHE_UPDATE();
#endif
memset(pdo_sqlite_globals, 0, sizeof(*pdo_sqlite_globals));
}
/* }}} */

Expand Down
7 changes: 4 additions & 3 deletions ext/pdo_sqlite/php_pdo_sqlite.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,12 @@ PHP_MINFO_FUNCTION(pdo_sqlite);
Declare any global variables you may need between the BEGIN
and END macros here:

*/
ZEND_BEGIN_MODULE_GLOBALS(pdo_sqlite)
long global_value;
char *global_string;
char *extension_dir;
ZEND_END_MODULE_GLOBALS(pdo_sqlite)
*/

ZEND_EXTERN_MODULE_GLOBALS(pdo_sqlite)

#ifdef ZTS
#define PDO_SQLITE_G(v) TSRMG(pdo_sqlite_globals_id, zend_pdo_sqlite_globals *, v)
Expand Down
87 changes: 87 additions & 0 deletions ext/pdo_sqlite/sqlite_driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@
#include "php_pdo_sqlite_int.h"
#include "zend_exceptions.h"

#include "main/SAPI.h"
#include "SAPI.h"

//ZEND_DECLARE_MODULE_GLOBALS(pdo_sqlite)

int _pdo_sqlite_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, const char *file, int line) /* {{{ */
{
pdo_sqlite_db_handle *H = (pdo_sqlite_db_handle *)dbh->driver_data;
Expand Down Expand Up @@ -692,10 +697,92 @@ static PHP_METHOD(SQLite, sqliteCreateCollation)
}
/* }}} */

#ifndef SQLITE_OMIT_LOAD_EXTENSION
/* {{{ bool SQLite::sqliteLoadExtension(string name, mixed callback)
Registers a collation with the sqlite db handle */
static PHP_METHOD(SQLite, sqliteLoadExtension)
{
char *extension, *lib_path, *extension_dir, *errtext = NULL;
char fullpath[MAXPATHLEN];
size_t extension_len, extension_dir_len;
pdo_dbh_t *dbh;
pdo_sqlite_db_handle *H;

ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_STRING(extension, extension_len)
ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);

dbh = Z_PDO_DBH_P(getThis());
PDO_CONSTRUCT_CHECK;

#ifdef ZTS
if ((strncmp(sapi_module.name, "cgi", 3) != 0) &&
(strcmp(sapi_module.name, "cli") != 0) &&
(strncmp(sapi_module.name, "embed", 5) != 0)
) {
php_error_docref(NULL, E_WARNING, "Not supported in multithreaded Web servers");
RETURN_FALSE;
}
#endif


H = (pdo_sqlite_db_handle *)dbh->driver_data;

if (!PDO_SQLITE_G(extension_dir)) {
php_error_docref(NULL, E_WARNING, "SQLite Extension are disabled");
RETURN_FALSE;
}

if (extension_len == 0) {
php_error_docref(NULL, E_WARNING, "Empty string as an extension");
RETURN_FALSE;
}

extension_dir = PDO_SQLITE_G(extension_dir);
extension_dir_len = strlen(PDO_SQLITE_G(extension_dir));

if (IS_SLASH(extension_dir[extension_dir_len-1])) {
spprintf(&lib_path, 0, "%s%s", extension_dir, extension);
} else {
spprintf(&lib_path, 0, "%s%c%s", extension_dir, DEFAULT_SLASH, extension);
}

if (!VCWD_REALPATH(lib_path, fullpath)) {
php_error_docref(NULL, E_WARNING, "Unable to load extension at '%s'", lib_path);
efree(lib_path);
RETURN_FALSE;
}

efree(lib_path);

if (strncmp(fullpath, extension_dir, extension_dir_len) != 0) {
php_error_docref(NULL, E_WARNING, "Unable to open extensions outside the defined directory");
RETURN_FALSE;
}

/* Extension loading should only be enabled for when we attempt to load */
sqlite3_enable_load_extension(H->db, 1);
if (sqlite3_load_extension(H->db, fullpath, 0, &errtext) != SQLITE_OK) {
php_error_docref(NULL, E_WARNING, "%s", errtext);
sqlite3_free(errtext);
sqlite3_enable_load_extension(H->db, 0);
RETURN_FALSE;
}
sqlite3_enable_load_extension(H->db, 0);

RETURN_TRUE;
}
/* }}} */
#endif


static const zend_function_entry dbh_methods[] = {
PHP_ME(SQLite, sqliteCreateFunction, NULL, ZEND_ACC_PUBLIC)
PHP_ME(SQLite, sqliteCreateAggregate, NULL, ZEND_ACC_PUBLIC)
PHP_ME(SQLite, sqliteCreateCollation, NULL, ZEND_ACC_PUBLIC)
#ifndef SQLITE_OMIT_LOAD_EXTENSION
PHP_ME(SQLite, sqliteLoadExtension, NULL, ZEND_ACC_PUBLIC)
#endif
PHP_FE_END
};

Expand Down
30 changes: 30 additions & 0 deletions ext/pdo_sqlite/tests/pdo_sqlite_loadextension.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
--TEST--
PDO_sqlite: Testing sqliteLoadExtension()
--SKIPIF--
<?php
<?php if (!extension_loaded('pdo_sqlite')) print 'skip not loaded'; ?>
?>
--INI--
open_basedir=.
pdo_sqlite.extension_dir=.
--FILE--
<?php

$db = new pdo('sqlite::memory:');

$directory = __DIR__;

touch($directory . '/myext.txt');

try {
$db->sqliteLoadExtension('myext.txt');
} catch (Extension $ex) {
var_dump($ex->getMessage());
}
unlink($directory . '/myext.txt');

echo "Done\n";
?>
--EXPECTF--
Warning: PDO::sqliteLoadExtension(): Unable to load extension at '.%emyext.txt' in %s on line %d
Done
23 changes: 23 additions & 0 deletions ext/pdo_sqlite/tests/pdo_sqlite_loadextension_002.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
--TEST--
PDO_sqlite: Testing sqliteLoadExtension() with empty extension test
--CREDITS--
Jelle Lampaert
#Belgian Testfest 2009
--INI--
pdo_sqlite.extension_dir=/tmp
--SKIPIF--
<?php if (!extension_loaded('pdo_sqlite')) print 'skip not loaded'; ?>
--FILE--
<?php

$db = new pdo('sqlite::memory:');

try {
$db->sqliteLoadExtension("");
} catch (Extension $ex) {
var_dump($ex->getMessage());
}

?>
--EXPECTF--
Warning: PDO::sqliteLoadExtension(): Empty string as an extension in %s on line %d
21 changes: 21 additions & 0 deletions ext/pdo_sqlite/tests/pdo_sqlite_loadextension_003.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
--TEST--
PDO_sqlite: Testing sqliteLoadExtension() with disabled extensions
--CREDITS--
Jelle Lampaert
#Belgian Testfest 2009
--SKIPIF--
<?php if (!extension_loaded('pdo_sqlite')) print 'skip not loaded'; ?>
--FILE--
<?php

$db = new pdo('sqlite::memory:');

try {
$db->sqliteLoadExtension("");
} catch (Extension $ex) {
var_dump($ex->getMessage());
}

?>
--EXPECTF--
Warning: PDO::sqliteLoadExtension(): SQLite Extension are disabled in %s on line %d
18 changes: 18 additions & 0 deletions ext/pdo_sqlite/tests/pdo_sqlite_loadextension_004.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
--TEST--
PDO_sqlite: Testing sqliteLoadExtension() with wrong parameter type
--CREDITS--
Thijs Feryn <[email protected]>
#TestFest PHPBelgium 2009
--SKIPIF--
<?php if (!extension_loaded('pdo_sqlite')) print 'skip not loaded'; ?>
--FILE--
<?php
$db = new pdo('sqlite::memory:');
var_dump($db->sqliteLoadExtension(array()));
echo "Done\n";
?>
--EXPECTF--
Warning: PDO::sqliteLoadExtension() expects parameter 1 to be string, array given in %s on line %d
bool(false)
Done