diff --git a/ext/pdo_sqlite/config.m4 b/ext/pdo_sqlite/config.m4 index 201f9f24bf540..bd18d03e7a030 100644 --- a/ext/pdo_sqlite/config.m4 +++ b/ext/pdo_sqlite/config.m4 @@ -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]) + ]) PHP_CHECK_LIBRARY(sqlite3,sqlite3_close_v2,[ AC_DEFINE(HAVE_SQLITE3_CLOSE_V2, 1, [have sqlite3_close_v2]) ]) diff --git a/ext/pdo_sqlite/config.w32 b/ext/pdo_sqlite/config.w32 index a1dec83703152..2d63efd882f1e 100644 --- a/ext/pdo_sqlite/config.w32 +++ b/ext/pdo_sqlite/config.w32 @@ -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") + " "); EXTENSION("pdo_sqlite", "pdo_sqlite.c sqlite_driver.c sqlite_statement.c"); ADD_EXTENSION_DEP('pdo_sqlite', 'pdo'); diff --git a/ext/pdo_sqlite/pdo_sqlite.c b/ext/pdo_sqlite/pdo_sqlite.c index f91dd13982570..c11529caa0d84 100644 --- a/ext/pdo_sqlite/pdo_sqlite.c +++ b/ext/pdo_sqlite/pdo_sqlite.c @@ -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 @@ -56,7 +60,11 @@ 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 }; /* }}} */ @@ -64,9 +72,18 @@ zend_module_entry pdo_sqlite_module_entry = { 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 @@ -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; } /* }}} */ @@ -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)); } /* }}} */ diff --git a/ext/pdo_sqlite/php_pdo_sqlite.h b/ext/pdo_sqlite/php_pdo_sqlite.h index 6e5f26bf2c22c..7ab89e87117cb 100644 --- a/ext/pdo_sqlite/php_pdo_sqlite.h +++ b/ext/pdo_sqlite/php_pdo_sqlite.h @@ -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) diff --git a/ext/pdo_sqlite/sqlite_driver.c b/ext/pdo_sqlite/sqlite_driver.c index 811f43c268583..478d8bbebbd9f 100644 --- a/ext/pdo_sqlite/sqlite_driver.c +++ b/ext/pdo_sqlite/sqlite_driver.c @@ -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; @@ -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 }; diff --git a/ext/pdo_sqlite/tests/pdo_sqlite_loadextension.phpt b/ext/pdo_sqlite/tests/pdo_sqlite_loadextension.phpt new file mode 100644 index 0000000000000..7818baa69e04a --- /dev/null +++ b/ext/pdo_sqlite/tests/pdo_sqlite_loadextension.phpt @@ -0,0 +1,30 @@ +--TEST-- +PDO_sqlite: Testing sqliteLoadExtension() +--SKIPIF-- + +?> +--INI-- +open_basedir=. +pdo_sqlite.extension_dir=. +--FILE-- +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 diff --git a/ext/pdo_sqlite/tests/pdo_sqlite_loadextension_002.phpt b/ext/pdo_sqlite/tests/pdo_sqlite_loadextension_002.phpt new file mode 100644 index 0000000000000..0dc8fa9b29959 --- /dev/null +++ b/ext/pdo_sqlite/tests/pdo_sqlite_loadextension_002.phpt @@ -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-- + +--FILE-- +sqliteLoadExtension(""); +} catch (Extension $ex) { + var_dump($ex->getMessage()); +} + +?> +--EXPECTF-- +Warning: PDO::sqliteLoadExtension(): Empty string as an extension in %s on line %d diff --git a/ext/pdo_sqlite/tests/pdo_sqlite_loadextension_003.phpt b/ext/pdo_sqlite/tests/pdo_sqlite_loadextension_003.phpt new file mode 100644 index 0000000000000..a6228b87184d1 --- /dev/null +++ b/ext/pdo_sqlite/tests/pdo_sqlite_loadextension_003.phpt @@ -0,0 +1,21 @@ +--TEST-- +PDO_sqlite: Testing sqliteLoadExtension() with disabled extensions +--CREDITS-- +Jelle Lampaert +#Belgian Testfest 2009 +--SKIPIF-- + +--FILE-- +sqliteLoadExtension(""); +} catch (Extension $ex) { + var_dump($ex->getMessage()); +} + +?> +--EXPECTF-- +Warning: PDO::sqliteLoadExtension(): SQLite Extension are disabled in %s on line %d diff --git a/ext/pdo_sqlite/tests/pdo_sqlite_loadextension_004.phpt b/ext/pdo_sqlite/tests/pdo_sqlite_loadextension_004.phpt new file mode 100644 index 0000000000000..4b2c720898ae9 --- /dev/null +++ b/ext/pdo_sqlite/tests/pdo_sqlite_loadextension_004.phpt @@ -0,0 +1,18 @@ +--TEST-- +PDO_sqlite: Testing sqliteLoadExtension() with wrong parameter type +--CREDITS-- +Thijs Feryn +#TestFest PHPBelgium 2009 +--SKIPIF-- + +--FILE-- +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 +