xref: /php-src/ext/pdo_sqlite/pdo_sqlite.c (revision d6a0b3af)
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 "pdo/php_pdo.h"
26 #include "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(PdoSqlite,createFunction)64 PHP_METHOD(PdoSqlite, 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(PdoSqlite,loadExtension)71 PHP_METHOD(PdoSqlite, 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_value_error(1, "cannot be empty");
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(PdoSqlite,openBlob)287 PHP_METHOD(PdoSqlite, 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;
339 	zval zargs[2];
340 	zval retval;
341 	struct pdo_sqlite_collation *collation = (struct pdo_sqlite_collation*) context;
342 
343 	collation->fc.fci.size = sizeof(collation->fc.fci);
344 	ZVAL_COPY_VALUE(&collation->fc.fci.function_name, &collation->callback);
345 	collation->fc.fci.object = NULL;
346 	collation->fc.fci.retval = &retval;
347 
348 	// Prepare the arguments.
349 	ZVAL_STRINGL(&zargs[0], (char *) string1, string1_len);
350 	ZVAL_STRINGL(&zargs[1], (char *) string2, string2_len);
351 	collation->fc.fci.param_count = 2;
352 	collation->fc.fci.params = zargs;
353 
354 	if ((ret = zend_call_function(&collation->fc.fci, &collation->fc.fcc)) == FAILURE) {
355 		php_error_docref(NULL, E_WARNING, "An error occurred while invoking the callback");
356 	} else if (!Z_ISUNDEF(retval)) {
357 		if (Z_TYPE(retval) != IS_LONG) {
358 			zend_string *func_name = get_active_function_or_method_name();
359 			zend_type_error("%s(): Return value of the callback must be of type int, %s returned",
360 				ZSTR_VAL(func_name), zend_zval_value_name(&retval));
361 			zend_string_release(func_name);
362 			return FAILURE;
363 		}
364 		ret = 0;
365 		if (Z_LVAL(retval) > 0) {
366 			ret = 1;
367 		} else if (Z_LVAL(retval) < 0) {
368 			ret = -1;
369 		}
370 		zval_ptr_dtor(&retval);
371 	}
372 
373 	zval_ptr_dtor(&zargs[0]);
374 	zval_ptr_dtor(&zargs[1]);
375 
376 	return ret;
377 }
378 
PHP_METHOD(PdoSqlite,createAggregate)379 PHP_METHOD(PdoSqlite, createAggregate)
380 {
381 	pdo_sqlite_create_aggregate_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU);
382 }
383 
PHP_METHOD(PdoSqlite,createCollation)384 PHP_METHOD(PdoSqlite, createCollation)
385 {
386 	pdo_sqlite_create_collation_internal(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_sqlite_collation_callback);
387 }
388 
389 /* {{{ PHP_MINIT_FUNCTION */
PHP_MINIT_FUNCTION(pdo_sqlite)390 PHP_MINIT_FUNCTION(pdo_sqlite)
391 {
392 #ifdef SQLITE_DETERMINISTIC
393 	REGISTER_PDO_CLASS_CONST_LONG("SQLITE_DETERMINISTIC", (zend_long)SQLITE_DETERMINISTIC);
394 #endif
395 
396 	REGISTER_PDO_CLASS_CONST_LONG("SQLITE_ATTR_OPEN_FLAGS", (zend_long)PDO_SQLITE_ATTR_OPEN_FLAGS);
397 	REGISTER_PDO_CLASS_CONST_LONG("SQLITE_OPEN_READONLY", (zend_long)SQLITE_OPEN_READONLY);
398 	REGISTER_PDO_CLASS_CONST_LONG("SQLITE_OPEN_READWRITE", (zend_long)SQLITE_OPEN_READWRITE);
399 	REGISTER_PDO_CLASS_CONST_LONG("SQLITE_OPEN_CREATE", (zend_long)SQLITE_OPEN_CREATE);
400 	REGISTER_PDO_CLASS_CONST_LONG("SQLITE_ATTR_READONLY_STATEMENT", (zend_long)PDO_SQLITE_ATTR_READONLY_STATEMENT);
401 	REGISTER_PDO_CLASS_CONST_LONG("SQLITE_ATTR_EXTENDED_RESULT_CODES", (zend_long)PDO_SQLITE_ATTR_EXTENDED_RESULT_CODES);
402 
403 	pdosqlite_ce = register_class_PdoSqlite(pdo_dbh_ce);
404 	pdosqlite_ce->create_object = pdo_dbh_new;
405 
406 	if (php_pdo_register_driver(&pdo_sqlite_driver) == FAILURE) {
407 		return FAILURE;
408 	}
409 
410 	return php_pdo_register_driver_specific_ce(&pdo_sqlite_driver, pdosqlite_ce);
411 }
412 /* }}} */
413 
414 /* {{{ PHP_MSHUTDOWN_FUNCTION */
PHP_MSHUTDOWN_FUNCTION(pdo_sqlite)415 PHP_MSHUTDOWN_FUNCTION(pdo_sqlite)
416 {
417 	php_pdo_unregister_driver(&pdo_sqlite_driver);
418 	return SUCCESS;
419 }
420 /* }}} */
421 
422 /* {{{ PHP_MINFO_FUNCTION */
PHP_MINFO_FUNCTION(pdo_sqlite)423 PHP_MINFO_FUNCTION(pdo_sqlite)
424 {
425 	php_info_print_table_start();
426 	php_info_print_table_row(2, "PDO Driver for SQLite 3.x", "enabled");
427 	php_info_print_table_row(2, "SQLite Library", sqlite3_libversion());
428 	php_info_print_table_end();
429 }
430 /* }}} */
431