xref: /PHP-8.4/ext/pdo_sqlite/pdo_sqlite.c (revision 5853cdb7)
1 /*
2   +----------------------------------------------------------------------+
3   | Copyright (c) The PHP Group                                          |
4   +----------------------------------------------------------------------+
5   | This source file is subject to version 3.01 of the PHP license,      |
6   | that is bundled with this package in the file LICENSE, and is        |
7   | available through the world-wide-web at the following url:           |
8   | https://www.php.net/license/3_01.txt                                 |
9   | If you did not receive a copy of the PHP license and are unable to   |
10   | obtain it through the world-wide-web, please send a note to          |
11   | license@php.net so we can mail you a copy immediately.               |
12   +----------------------------------------------------------------------+
13   | Author: Wez Furlong <wez@php.net>                                    |
14   +----------------------------------------------------------------------+
15 */
16 
17 #ifdef HAVE_CONFIG_H
18 #include <config.h>
19 #endif
20 
21 #include "php.h"
22 #include "php_ini.h"
23 #include "ext/standard/info.h"
24 #include "SAPI.h"
25 #include "ext/pdo/php_pdo.h"
26 #include "ext/pdo/php_pdo_driver.h"
27 #include "php_pdo_sqlite.h"
28 #include "php_pdo_sqlite_int.h"
29 #include "zend_exceptions.h"
30 #include "pdo_sqlite_arginfo.h"
31 
32 static zend_class_entry *pdosqlite_ce;
33 
34 /* {{{ pdo_sqlite_deps */
35 static const zend_module_dep pdo_sqlite_deps[] = {
36 	ZEND_MOD_REQUIRED("pdo")
37 	ZEND_MOD_END
38 };
39 /* }}} */
40 
41 /* {{{ pdo_sqlite_module_entry */
42 zend_module_entry pdo_sqlite_module_entry = {
43 	STANDARD_MODULE_HEADER_EX, NULL,
44 	pdo_sqlite_deps,
45 	"pdo_sqlite",
46 	NULL,
47 	PHP_MINIT(pdo_sqlite),
48 	PHP_MSHUTDOWN(pdo_sqlite),
49 	NULL,
50 	NULL,
51 	PHP_MINFO(pdo_sqlite),
52 	PHP_PDO_SQLITE_VERSION,
53 	STANDARD_MODULE_PROPERTIES
54 };
55 /* }}} */
56 
57 #if defined(COMPILE_DL_PDO_SQLITE) || defined(COMPILE_DL_PDO_SQLITE_EXTERNAL)
58 ZEND_GET_MODULE(pdo_sqlite)
59 #endif
60 
61 /* proto bool PdoSqlite::createFunction(string $function_name, callable $callback, int $num_args = -1, int $flags = 0)
62     Creates a function that can be used in a query
63 */
PHP_METHOD(Pdo_Sqlite,createFunction)64 PHP_METHOD(Pdo_Sqlite, createFunction)
65 {
66 	pdo_sqlite_create_function_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU);
67 }
68 
69 #ifndef PDO_SQLITE_OMIT_LOAD_EXTENSION
70 /* Attempts to load an SQLite extension library. */
PHP_METHOD(Pdo_Sqlite,loadExtension)71 PHP_METHOD(Pdo_Sqlite, loadExtension)
72 {
73 	char *extension, *errtext = NULL;
74 	char fullpath[MAXPATHLEN];
75 	size_t extension_len;
76 
77 	pdo_dbh_t *dbh;
78 	pdo_sqlite_db_handle *db_handle;
79 
80 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "p", &extension, &extension_len) == FAILURE) {
81 		RETURN_THROWS();
82 	}
83 
84 	if (extension_len == 0) {
85 		zend_argument_must_not_be_empty_error(1);
86 		RETURN_THROWS();
87 	}
88 
89 	dbh = Z_PDO_DBH_P(ZEND_THIS);
90 	PDO_CONSTRUCT_CHECK;
91 
92 	db_handle = (pdo_sqlite_db_handle *)dbh->driver_data;
93 
94 #ifdef ZTS
95 	if ((strncmp(sapi_module.name, "cgi", 3) != 0) &&
96 		(strcmp(sapi_module.name, "cli") != 0) &&
97 		(strncmp(sapi_module.name, "embed", 5) != 0)
98 	) {
99 		zend_throw_exception_ex(php_pdo_get_exception(), 0, "Not supported in multithreaded Web servers");
100 		RETURN_THROWS();
101 	}
102 #endif
103 
104 	if (!VCWD_REALPATH(extension, fullpath)) {
105 		zend_throw_exception_ex(php_pdo_get_exception(), 0, "Unable to load extension \"%s\"", extension);
106 		RETURN_THROWS();
107 	}
108 
109 	sqlite3 *sqlite_handle;
110 	sqlite_handle = db_handle->db;
111 
112 	/* This only enables extension loading for the C api, not for SQL */
113 	sqlite3_db_config(sqlite_handle, SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, 1, NULL);
114 
115 	if (sqlite3_load_extension(sqlite_handle, fullpath, 0, &errtext) != SQLITE_OK) {
116 		zend_throw_exception_ex(php_pdo_get_exception(), 0, "Unable to load extension \"%s\"", errtext);
117 		sqlite3_free(errtext);
118 		sqlite3_db_config(sqlite_handle, SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, 0, NULL);
119 		RETURN_THROWS();
120 	}
121 
122 	/* We disable extension loading for a vague feeling of safety. This is probably not necessary
123 	as extensions can only be loaded through C code, not through SQL, and if someone can get
124 	some C code to run on the server, they can do anything.*/
125 	sqlite3_db_config(sqlite_handle, SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION, 0, NULL);
126 }
127 #endif
128 
129 typedef struct {
130 	sqlite3_blob *blob;
131 	size_t		 position;
132 	size_t       size;
133 	int          flags;
134 } php_stream_pdosqlite3_data;
135 
php_pdosqlite3_stream_write(php_stream * stream,const char * buf,size_t count)136 static ssize_t php_pdosqlite3_stream_write(php_stream *stream, const char *buf, size_t count)
137 {
138 	php_stream_pdosqlite3_data *sqlite3_stream = (php_stream_pdosqlite3_data *) stream->abstract;
139 
140 	if (sqlite3_stream->flags & SQLITE_OPEN_READONLY) {
141 		php_error_docref(NULL, E_WARNING, "Can't write to blob stream: is open as read only");
142 		return -1;
143 	}
144 
145 	if (sqlite3_stream->position + count > sqlite3_stream->size) {
146 		php_error_docref(NULL, E_WARNING, "It is not possible to increase the size of a BLOB");
147 		return -1;
148 	}
149 
150 	if (sqlite3_blob_write(sqlite3_stream->blob, buf, count, sqlite3_stream->position) != SQLITE_OK) {
151 		return -1;
152 	}
153 
154 	if (sqlite3_stream->position + count >= sqlite3_stream->size) {
155 		stream->eof = 1;
156 		sqlite3_stream->position = sqlite3_stream->size;
157 	}
158 	else {
159 		sqlite3_stream->position += count;
160 	}
161 
162 	return count;
163 }
164 
php_pdosqlite3_stream_read(php_stream * stream,char * buf,size_t count)165 static ssize_t php_pdosqlite3_stream_read(php_stream *stream, char *buf, size_t count)
166 {
167 	php_stream_pdosqlite3_data *sqlite3_stream = (php_stream_pdosqlite3_data *) stream->abstract;
168 
169 	if (sqlite3_stream->position + count >= sqlite3_stream->size) {
170 		count = sqlite3_stream->size - sqlite3_stream->position;
171 		stream->eof = 1;
172 	}
173 	if (count) {
174 		if (sqlite3_blob_read(sqlite3_stream->blob, buf, count, sqlite3_stream->position) != SQLITE_OK) {
175 			return -1;
176 		}
177 		sqlite3_stream->position += count;
178 	}
179 	return count;
180 }
181 
php_pdosqlite3_stream_close(php_stream * stream,int close_handle)182 static int php_pdosqlite3_stream_close(php_stream *stream, int close_handle)
183 {
184 	php_stream_pdosqlite3_data *sqlite3_stream = (php_stream_pdosqlite3_data *) stream->abstract;
185 
186 	if (sqlite3_blob_close(sqlite3_stream->blob) != SQLITE_OK) {
187 		/* Error occurred, but it still closed */
188 	}
189 
190 	efree(sqlite3_stream);
191 
192 	return 0;
193 }
194 
php_pdosqlite3_stream_flush(php_stream * stream)195 static int php_pdosqlite3_stream_flush(php_stream *stream)
196 {
197 	/* do nothing */
198 	return 0;
199 }
200 
php_pdosqlite3_stream_seek(php_stream * stream,zend_off_t offset,int whence,zend_off_t * newoffs)201 static int php_pdosqlite3_stream_seek(php_stream *stream, zend_off_t offset, int whence, zend_off_t *newoffs)
202 {
203 	php_stream_pdosqlite3_data *sqlite3_stream = (php_stream_pdosqlite3_data *) stream->abstract;
204 
205 	switch(whence) {
206 		case SEEK_CUR:
207 			if (offset < 0) {
208 				if (sqlite3_stream->position < (size_t)(-offset)) {
209 					sqlite3_stream->position = 0;
210 					*newoffs = -1;
211 					return -1;
212 				} else {
213 					sqlite3_stream->position = sqlite3_stream->position + offset;
214 					*newoffs = sqlite3_stream->position;
215 					stream->eof = 0;
216 					return 0;
217 				}
218 			} else {
219 				if (sqlite3_stream->position + (size_t)(offset) > sqlite3_stream->size) {
220 					sqlite3_stream->position = sqlite3_stream->size;
221 					*newoffs = -1;
222 					return -1;
223 				} else {
224 					sqlite3_stream->position = sqlite3_stream->position + offset;
225 					*newoffs = sqlite3_stream->position;
226 					stream->eof = 0;
227 					return 0;
228 				}
229 			}
230 		case SEEK_SET:
231 			if (sqlite3_stream->size < (size_t)(offset)) {
232 				sqlite3_stream->position = sqlite3_stream->size;
233 				*newoffs = -1;
234 				return -1;
235 			} else {
236 				sqlite3_stream->position = offset;
237 				*newoffs = sqlite3_stream->position;
238 				stream->eof = 0;
239 				return 0;
240 			}
241 		case SEEK_END:
242 			if (offset > 0) {
243 				sqlite3_stream->position = sqlite3_stream->size;
244 				*newoffs = -1;
245 				return -1;
246 			} else if (sqlite3_stream->size < (size_t)(-offset)) {
247 				sqlite3_stream->position = 0;
248 				*newoffs = -1;
249 				return -1;
250 			} else {
251 				sqlite3_stream->position = sqlite3_stream->size + offset;
252 				*newoffs = sqlite3_stream->position;
253 				stream->eof = 0;
254 				return 0;
255 			}
256 		default:
257 			*newoffs = sqlite3_stream->position;
258 			return -1;
259 	}
260 }
261 
php_pdosqlite3_stream_cast(php_stream * stream,int castas,void ** ret)262 static int php_pdosqlite3_stream_cast(php_stream *stream, int castas, void **ret)
263 {
264 	return FAILURE;
265 }
266 
php_pdosqlite3_stream_stat(php_stream * stream,php_stream_statbuf * ssb)267 static int php_pdosqlite3_stream_stat(php_stream *stream, php_stream_statbuf *ssb)
268 {
269 	php_stream_pdosqlite3_data *sqlite3_stream = (php_stream_pdosqlite3_data *) stream->abstract;
270 	ssb->sb.st_size = sqlite3_stream->size;
271 	return 0;
272 }
273 
274 static const php_stream_ops php_stream_pdosqlite3_ops = {
275 		php_pdosqlite3_stream_write,
276 		php_pdosqlite3_stream_read,
277 		php_pdosqlite3_stream_close,
278 		php_pdosqlite3_stream_flush,
279 		"PDOSQLite",
280 		php_pdosqlite3_stream_seek,
281 		php_pdosqlite3_stream_cast,
282 		php_pdosqlite3_stream_stat,
283 		NULL
284 };
285 
286 /* Open a blob as a stream which we can read / write to. */
PHP_METHOD(Pdo_Sqlite,openBlob)287 PHP_METHOD(Pdo_Sqlite, openBlob)
288 {
289 	char *table, *column, *dbname = "main", *mode = "rb";
290 	size_t table_len, column_len, dbname_len;
291 	zend_long rowid, flags = SQLITE_OPEN_READONLY, sqlite_flags = 0;
292 	sqlite3_blob *blob = NULL;
293 	php_stream_pdosqlite3_data *sqlite3_stream;
294 	php_stream *stream;
295 
296 	pdo_dbh_t *dbh;
297 	pdo_sqlite_db_handle *db_handle;
298 
299 	dbh = Z_PDO_DBH_P(ZEND_THIS);
300 	PDO_CONSTRUCT_CHECK;
301 	db_handle = (pdo_sqlite_db_handle *)dbh->driver_data;
302 
303 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "ppl|pl", &table, &table_len, &column, &column_len, &rowid, &dbname, &dbname_len, &flags) == FAILURE) {
304 		RETURN_THROWS();
305 	}
306 
307 	sqlite3 *sqlite_handle;
308 	sqlite_handle = db_handle->db;
309 	sqlite_flags = (flags & SQLITE_OPEN_READWRITE) ? 1 : 0;
310 
311 	if (sqlite3_blob_open(sqlite_handle, dbname, table, column, rowid, sqlite_flags, &blob) != SQLITE_OK) {
312 		zend_error(E_WARNING, "Unable to open blob: %s", sqlite3_errmsg(sqlite_handle));
313 		RETURN_FALSE;
314 	}
315 
316 	sqlite3_stream = emalloc(sizeof(php_stream_pdosqlite3_data));
317 	sqlite3_stream->blob = blob;
318 	sqlite3_stream->flags = flags;
319 	sqlite3_stream->position = 0;
320 	sqlite3_stream->size = sqlite3_blob_bytes(blob);
321 
322 	if (sqlite_flags != 0) {
323 		mode = "r+b";
324 	}
325 
326 	stream = php_stream_alloc(&php_stream_pdosqlite3_ops, sqlite3_stream, 0, mode);
327 
328 	if (stream) {
329 		php_stream_to_zval(stream, return_value);
330 	} else {
331 		RETURN_FALSE;
332 	}
333 }
334 
php_sqlite_collation_callback(void * context,int string1_len,const void * string1,int string2_len,const void * string2)335 static int php_sqlite_collation_callback(void *context, int string1_len, const void *string1,
336 	int string2_len, const void *string2)
337 {
338 	int ret = 0;
339 	zval zargs[2];
340 	zval retval;
341 	struct pdo_sqlite_collation *collation = (struct pdo_sqlite_collation*) context;
342 
343 	// Prepare the arguments.
344 	ZVAL_STRINGL(&zargs[0], (char *) string1, string1_len);
345 	ZVAL_STRINGL(&zargs[1], (char *) string2, string2_len);
346 
347 	zend_call_known_fcc(&collation->callback, &retval, /* argc */ 2, zargs, /* named_params */ NULL);
348 
349 	if (!Z_ISUNDEF(retval)) {
350 		if (Z_TYPE(retval) != IS_LONG) {
351 			zend_string *func_name = get_active_function_or_method_name();
352 			zend_type_error("%s(): Return value of the callback must be of type int, %s returned",
353 				ZSTR_VAL(func_name), zend_zval_value_name(&retval));
354 			zend_string_release(func_name);
355 			return FAILURE;
356 		}
357 		if (Z_LVAL(retval) > 0) {
358 			ret = 1;
359 		} else if (Z_LVAL(retval) < 0) {
360 			ret = -1;
361 		}
362 		zval_ptr_dtor(&retval);
363 	}
364 
365 	zval_ptr_dtor(&zargs[0]);
366 	zval_ptr_dtor(&zargs[1]);
367 
368 	return ret;
369 }
370 
PHP_METHOD(Pdo_Sqlite,createAggregate)371 PHP_METHOD(Pdo_Sqlite, createAggregate)
372 {
373 	pdo_sqlite_create_aggregate_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU);
374 }
375 
PHP_METHOD(Pdo_Sqlite,createCollation)376 PHP_METHOD(Pdo_Sqlite, createCollation)
377 {
378 	pdo_sqlite_create_collation_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_sqlite_collation_callback);
379 }
380 
381 /* {{{ PHP_MINIT_FUNCTION */
PHP_MINIT_FUNCTION(pdo_sqlite)382 PHP_MINIT_FUNCTION(pdo_sqlite)
383 {
384 #ifdef SQLITE_DETERMINISTIC
385 	REGISTER_PDO_CLASS_CONST_LONG("SQLITE_DETERMINISTIC", (zend_long)SQLITE_DETERMINISTIC);
386 #endif
387 
388 	REGISTER_PDO_CLASS_CONST_LONG("SQLITE_ATTR_OPEN_FLAGS", (zend_long)PDO_SQLITE_ATTR_OPEN_FLAGS);
389 	REGISTER_PDO_CLASS_CONST_LONG("SQLITE_OPEN_READONLY", (zend_long)SQLITE_OPEN_READONLY);
390 	REGISTER_PDO_CLASS_CONST_LONG("SQLITE_OPEN_READWRITE", (zend_long)SQLITE_OPEN_READWRITE);
391 	REGISTER_PDO_CLASS_CONST_LONG("SQLITE_OPEN_CREATE", (zend_long)SQLITE_OPEN_CREATE);
392 	REGISTER_PDO_CLASS_CONST_LONG("SQLITE_ATTR_READONLY_STATEMENT", (zend_long)PDO_SQLITE_ATTR_READONLY_STATEMENT);
393 	REGISTER_PDO_CLASS_CONST_LONG("SQLITE_ATTR_EXTENDED_RESULT_CODES", (zend_long)PDO_SQLITE_ATTR_EXTENDED_RESULT_CODES);
394 
395 	pdosqlite_ce = register_class_Pdo_Sqlite(pdo_dbh_ce);
396 	pdosqlite_ce->create_object = pdo_dbh_new;
397 
398 	if (php_pdo_register_driver(&pdo_sqlite_driver) == FAILURE) {
399 		return FAILURE;
400 	}
401 
402 	return php_pdo_register_driver_specific_ce(&pdo_sqlite_driver, pdosqlite_ce);
403 }
404 /* }}} */
405 
406 /* {{{ PHP_MSHUTDOWN_FUNCTION */
PHP_MSHUTDOWN_FUNCTION(pdo_sqlite)407 PHP_MSHUTDOWN_FUNCTION(pdo_sqlite)
408 {
409 	php_pdo_unregister_driver(&pdo_sqlite_driver);
410 	return SUCCESS;
411 }
412 /* }}} */
413 
414 /* {{{ PHP_MINFO_FUNCTION */
PHP_MINFO_FUNCTION(pdo_sqlite)415 PHP_MINFO_FUNCTION(pdo_sqlite)
416 {
417 	php_info_print_table_start();
418 	php_info_print_table_row(2, "PDO Driver for SQLite 3.x", "enabled");
419 	php_info_print_table_row(2, "SQLite Library", sqlite3_libversion());
420 	php_info_print_table_end();
421 }
422 /* }}} */
423