xref: /PHP-8.4/ext/mysqli/mysqli.c (revision 857ce2c9)
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   | Authors: Georg Richter <georg@php.net>                               |
14   |          Andrey Hristov <andrey@php.net>                             |
15   |          Ulf Wendel <uw@php.net>                                     |
16   +----------------------------------------------------------------------+
17 */
18 
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
22 
23 #include <signal.h>
24 
25 #include "php.h"
26 #include "php_ini.h"
27 #include "ext/standard/info.h"
28 #include "php_mysqli.h"
29 #include "php_mysqli_structs.h"
30 #include "mysqli_priv.h"
31 #include "zend_attributes.h"
32 #include "zend_exceptions.h"
33 #include "ext/spl/spl_exceptions.h"
34 #include "zend_interfaces.h"
35 #include "zend_attributes.h"
36 #include "mysqli_arginfo.h"
37 
38 ZEND_DECLARE_MODULE_GLOBALS(mysqli)
39 static PHP_GINIT_FUNCTION(mysqli);
40 
41 #define MYSQLI_ADD_PROPERTIES(a, b) \
42 { \
43 	int i = 0; \
44 	while (b[i].pname != NULL) { \
45 		mysqli_add_property((a), (b)[i].pname, (b)[i].pname_length, \
46 							(mysqli_read_t)(b)[i].r_func, (mysqli_write_t)(b)[i].w_func); \
47 		i++; \
48 	} \
49 }
50 
51 #define ERROR_ARG_POS(arg_num) (hasThis() ? (arg_num-1) : (arg_num))
52 
53 static HashTable classes;
54 static zend_object_handlers mysqli_object_handlers;
55 static zend_object_handlers mysqli_object_driver_handlers;
56 static zend_object_handlers mysqli_object_link_handlers;
57 static zend_object_handlers mysqli_object_result_handlers;
58 static zend_object_handlers mysqli_object_stmt_handlers;
59 static zend_object_handlers mysqli_object_warning_handlers;
60 static HashTable mysqli_driver_properties;
61 static HashTable mysqli_link_properties;
62 static HashTable mysqli_result_properties;
63 static HashTable mysqli_stmt_properties;
64 static HashTable mysqli_warning_properties;
65 
66 zend_class_entry *mysqli_link_class_entry;
67 zend_class_entry *mysqli_stmt_class_entry;
68 zend_class_entry *mysqli_result_class_entry;
69 zend_class_entry *mysqli_driver_class_entry;
70 zend_class_entry *mysqli_warning_class_entry;
71 zend_class_entry *mysqli_exception_class_entry;
72 
73 
74 typedef zend_result (*mysqli_read_t)(mysqli_object *obj, zval *rv, bool quiet);
75 typedef zend_result (*mysqli_write_t)(mysqli_object *obj, zval *newval);
76 
77 typedef struct _mysqli_prop_handler {
78 	zend_string *name;
79 	mysqli_read_t read_func;
80 	mysqli_write_t write_func;
81 } mysqli_prop_handler;
82 
83 static int le_pmysqli;
84 
free_prop_handler(zval * el)85 static void free_prop_handler(zval *el) {
86 	pefree(Z_PTR_P(el), 1);
87 }
88 
89 /* Destructor for mysqli entries in free_links/used_links */
php_mysqli_dtor_p_elements(void * data)90 void php_mysqli_dtor_p_elements(void *data)
91 {
92 	MYSQL *mysql = (MYSQL *)data;
93 	mysqli_close(mysql, MYSQLI_CLOSE_IMPLICIT);
94 }
95 
96 
ZEND_RSRC_DTOR_FUNC(php_mysqli_dtor)97 ZEND_RSRC_DTOR_FUNC(php_mysqli_dtor)
98 {
99 	if (res->ptr) {
100 		mysqli_plist_entry *plist = (mysqli_plist_entry *)res->ptr;
101 		zend_ptr_stack_clean(&plist->free_links, php_mysqli_dtor_p_elements, 0);
102 		zend_ptr_stack_destroy(&plist->free_links);
103 		free(plist);
104 	}
105 }
106 
107 
php_le_pmysqli(void)108 int php_le_pmysqli(void)
109 {
110 	return le_pmysqli;
111 }
112 
113 /* {{{ php_clear_stmt_bind */
php_clear_stmt_bind(MY_STMT * stmt)114 void php_clear_stmt_bind(MY_STMT *stmt)
115 {
116 	if (stmt->stmt) {
117 		if (mysqli_stmt_close(stmt->stmt, true)) {
118 			php_error_docref(NULL, E_WARNING, "Error occurred while closing statement");
119 			return;
120 		}
121 	}
122 
123 	/*
124 	  mysqlnd keeps track of the binding and has freed its
125 	  structures in stmt_close() above
126 	*/
127 	if (stmt->query) {
128 		efree(stmt->query);
129 	}
130 	efree(stmt);
131 }
132 /* }}} */
133 
134 /* {{{ php_clear_mysql */
php_clear_mysql(MY_MYSQL * mysql)135 void php_clear_mysql(MY_MYSQL *mysql) {
136 	if (mysql->hash_key) {
137 		zend_string_release_ex(mysql->hash_key, 0);
138 		mysql->hash_key = NULL;
139 	}
140 	if (!Z_ISUNDEF(mysql->li_read)) {
141 		zval_ptr_dtor(&(mysql->li_read));
142 		ZVAL_UNDEF(&mysql->li_read);
143 	}
144 }
145 /* }}} */
146 
147 /* {{{ mysqli_objects_free_storage */
mysqli_objects_free_storage(zend_object * object)148 static void mysqli_objects_free_storage(zend_object	*object)
149 {
150 	mysqli_object 	*intern = php_mysqli_fetch_object(object);
151 	MYSQLI_RESOURCE	*my_res = (MYSQLI_RESOURCE *)intern->ptr;
152 
153 	if (my_res) {
154 		efree(my_res);
155 	}
156 	zend_object_std_dtor(&intern->zo);
157 }
158 /* }}} */
159 
160 /* mysqli_link_free_storage partly doubles the work of PHP_FUNCTION(mysqli_close) */
161 
162 /* {{{ mysqli_link_free_storage */
mysqli_link_free_storage(zend_object * object)163 static void mysqli_link_free_storage(zend_object *object)
164 {
165 	mysqli_object 	*intern = php_mysqli_fetch_object(object);
166 	MYSQLI_RESOURCE	*my_res = (MYSQLI_RESOURCE *)intern->ptr;
167 
168 	if (my_res && my_res->ptr) {
169 		MY_MYSQL *mysql = (MY_MYSQL *)my_res->ptr;
170 		if (mysql->mysql) {
171 			php_mysqli_close(mysql, MYSQLI_CLOSE_EXPLICIT, my_res->status);
172 		}
173 		php_clear_mysql(mysql);
174 		efree(mysql);
175 		my_res->status = MYSQLI_STATUS_UNKNOWN;
176 	}
177 	mysqli_objects_free_storage(object);
178 }
179 /* }}} */
180 
181 /* {{{ mysql_driver_free_storage */
mysqli_driver_free_storage(zend_object * object)182 static void mysqli_driver_free_storage(zend_object *object)
183 {
184 	mysqli_objects_free_storage(object);
185 }
186 /* }}} */
187 
188 /* {{{ mysqli_stmt_free_storage */
mysqli_stmt_free_storage(zend_object * object)189 static void mysqli_stmt_free_storage(zend_object *object)
190 {
191 	mysqli_object 	*intern = php_mysqli_fetch_object(object);
192 	MYSQLI_RESOURCE	*my_res = (MYSQLI_RESOURCE *)intern->ptr;
193 
194 	if (my_res && my_res->ptr) {
195 		MY_STMT *stmt = (MY_STMT *)my_res->ptr;
196 		php_clear_stmt_bind(stmt);
197 	}
198 	mysqli_objects_free_storage(object);
199 }
200 /* }}} */
201 
202 /* {{{ mysqli_result_free_storage */
mysqli_result_free_storage(zend_object * object)203 static void mysqli_result_free_storage(zend_object *object)
204 {
205 	mysqli_object 	*intern = php_mysqli_fetch_object(object);
206 	MYSQLI_RESOURCE	*my_res = (MYSQLI_RESOURCE *)intern->ptr;
207 
208 	if (my_res && my_res->ptr) {
209 		mysql_free_result(my_res->ptr);
210 	}
211 	mysqli_objects_free_storage(object);
212 }
213 /* }}} */
214 
215 /* {{{ mysqli_warning_free_storage */
mysqli_warning_free_storage(zend_object * object)216 static void mysqli_warning_free_storage(zend_object *object)
217 {
218 	mysqli_object 	*intern = php_mysqli_fetch_object(object);
219 	MYSQLI_RESOURCE	*my_res = (MYSQLI_RESOURCE *)intern->ptr;
220 
221 	if (my_res && my_res->ptr) {
222 		php_clear_warnings((MYSQLI_WARNING *)my_res->info);
223 		my_res->ptr = NULL;
224 	}
225 	mysqli_objects_free_storage(object);
226 }
227 /* }}} */
228 
229 /* {{{ mysqli_read_na */
mysqli_read_na(mysqli_object * obj,zval * retval,bool quiet)230 static zend_result mysqli_read_na(mysqli_object *obj, zval *retval, bool quiet)
231 {
232 	if (!quiet) {
233 		zend_throw_error(NULL, "Cannot read property");
234 	}
235 
236 	return FAILURE;
237 }
238 /* }}} */
239 
240 /* {{{ mysqli_read_property */
mysqli_read_property(zend_object * object,zend_string * name,int type,void ** cache_slot,zval * rv)241 zval *mysqli_read_property(zend_object *object, zend_string *name, int type, void **cache_slot, zval *rv)
242 {
243 	mysqli_object *obj = php_mysqli_fetch_object(object);
244 	if (obj->prop_handler) {
245 		mysqli_prop_handler *hnd = zend_hash_find_ptr(obj->prop_handler, name);
246 		if (hnd) {
247 			if (hnd->read_func(obj, rv, type == BP_VAR_IS) == SUCCESS) {
248 				return rv;
249 			} else {
250 				return &EG(uninitialized_zval);
251 			}
252 		}
253 	}
254 
255 	return zend_std_read_property(object, name, type, cache_slot, rv);
256 }
257 /* }}} */
258 
259 /* {{{ mysqli_write_property */
mysqli_write_property(zend_object * object,zend_string * name,zval * value,void ** cache_slot)260 zval *mysqli_write_property(zend_object *object, zend_string *name, zval *value, void **cache_slot)
261 {
262 	mysqli_object *obj = php_mysqli_fetch_object(object);
263 	if (obj->prop_handler) {
264 		const mysqli_prop_handler *hnd = zend_hash_find_ptr(obj->prop_handler, name);
265 		if (hnd) {
266 			if (!hnd->write_func) {
267 				zend_throw_error(NULL, "Cannot write read-only property %s::$%s",
268 					ZSTR_VAL(object->ce->name), ZSTR_VAL(name));
269 				return &EG(error_zval);
270 			}
271 
272 			zend_property_info *prop = zend_get_property_info(object->ce, name, /* silent */ true);
273 			if (prop && ZEND_TYPE_IS_SET(prop->type)) {
274 				zval tmp;
275 				ZVAL_COPY(&tmp, value);
276 				if (!zend_verify_property_type(prop, &tmp,
277 							ZEND_CALL_USES_STRICT_TYPES(EG(current_execute_data)))) {
278 					zval_ptr_dtor(&tmp);
279 					return &EG(error_zval);
280 				}
281 				hnd->write_func(obj, &tmp);
282 				zval_ptr_dtor(&tmp);
283 			} else {
284 				hnd->write_func(obj, value);
285 			}
286 			return value;
287 		}
288 	}
289 	return zend_std_write_property(object, name, value, cache_slot);
290 }
291 /* }}} */
292 
293 /* {{{ void mysqli_add_property(HashTable *h, char *pname, mysqli_read_t r_func, mysqli_write_t w_func) */
mysqli_add_property(HashTable * h,const char * pname,size_t pname_len,mysqli_read_t r_func,mysqli_write_t w_func)294 void mysqli_add_property(HashTable *h, const char *pname, size_t pname_len, mysqli_read_t r_func, mysqli_write_t w_func) {
295 	mysqli_prop_handler	p;
296 
297 	p.name = zend_string_init_interned(pname, pname_len, 1);
298 	p.read_func = (r_func) ? r_func : mysqli_read_na;
299 	p.write_func = w_func;
300 	zend_hash_add_mem(h, p.name, &p, sizeof(mysqli_prop_handler));
301 	zend_string_release_ex(p.name, 1);
302 }
303 /* }}} */
304 
mysqli_object_has_property(zend_object * object,zend_string * name,int has_set_exists,void ** cache_slot)305 static int mysqli_object_has_property(zend_object *object, zend_string *name, int has_set_exists, void **cache_slot) /* {{{ */
306 {
307 	mysqli_object *obj = php_mysqli_fetch_object(object);
308 	mysqli_prop_handler	*p;
309 	bool has_property = false;
310 
311 	if ((p = zend_hash_find_ptr(obj->prop_handler, name)) != NULL) {
312 		switch (has_set_exists) {
313 			case ZEND_PROPERTY_EXISTS:
314 				has_property = true;
315 				break;
316 			case ZEND_PROPERTY_NOT_EMPTY: {
317 				zval rv;
318 				zval *value = mysqli_read_property(object, name, BP_VAR_IS, cache_slot, &rv);
319 				if (value != &EG(uninitialized_zval)) {
320 					convert_to_boolean(value);
321 					has_property = Z_TYPE_P(value) == IS_TRUE;
322 				}
323 				break;
324 			}
325 			case ZEND_PROPERTY_ISSET: {
326 				zval rv;
327 				zval *value = mysqli_read_property(object, name, BP_VAR_IS, cache_slot, &rv);
328 				if (value != &EG(uninitialized_zval)) {
329 					has_property = Z_TYPE_P(value) != IS_NULL;
330 					zval_ptr_dtor(value);
331 				}
332 				break;
333 			}
334 			EMPTY_SWITCH_DEFAULT_CASE();
335 		}
336 	} else {
337 		has_property = zend_std_has_property(object, name, has_set_exists, cache_slot);
338 	}
339 
340 	return has_property;
341 } /* }}} */
342 
mysqli_object_get_debug_info(zend_object * object,int * is_temp)343 HashTable *mysqli_object_get_debug_info(zend_object *object, int *is_temp)
344 {
345 	mysqli_object *obj = php_mysqli_fetch_object(object);
346 	HashTable *retval, *props = obj->prop_handler;
347 	mysqli_prop_handler *entry;
348 
349 	retval = zend_new_array(zend_hash_num_elements(props) + 1);
350 
351 	ZEND_HASH_MAP_FOREACH_PTR(props, entry) {
352 		zval rv;
353 		zval *value;
354 
355 		value = mysqli_read_property(object, entry->name, BP_VAR_IS, 0, &rv);
356 		if (value != &EG(uninitialized_zval)) {
357 			zend_hash_add(retval, entry->name, value);
358 		}
359 	} ZEND_HASH_FOREACH_END();
360 
361 	*is_temp = 1;
362 	return retval;
363 }
364 
365 /* {{{ mysqli_objects_new */
mysqli_objects_new(zend_class_entry * class_type)366 PHP_MYSQLI_EXPORT(zend_object *) mysqli_objects_new(zend_class_entry *class_type)
367 {
368 	mysqli_object *intern;
369 	zend_class_entry *mysqli_base_class;
370 	zend_object_handlers *handlers;
371 
372 	intern = zend_object_alloc(sizeof(mysqli_object), class_type);
373 
374 	mysqli_base_class = class_type;
375 	while (mysqli_base_class->type != ZEND_INTERNAL_CLASS &&
376 		   mysqli_base_class->parent != NULL) {
377 		mysqli_base_class = mysqli_base_class->parent;
378 	}
379 	intern->prop_handler = zend_hash_find_ptr(&classes, mysqli_base_class->name);
380 
381 	zend_object_std_init(&intern->zo, class_type);
382 	object_properties_init(&intern->zo, class_type);
383 
384 	/* link object */
385 	if (instanceof_function(class_type, mysqli_link_class_entry)) {
386 		handlers = &mysqli_object_link_handlers;
387 	} else if (instanceof_function(class_type, mysqli_driver_class_entry)) { /* driver object */
388 		handlers = &mysqli_object_driver_handlers;
389 	} else if (instanceof_function(class_type, mysqli_stmt_class_entry)) { /* stmt object */
390 		handlers = &mysqli_object_stmt_handlers;
391 	} else if (instanceof_function(class_type, mysqli_result_class_entry)) { /* result object */
392 		handlers = &mysqli_object_result_handlers;
393 	} else if (instanceof_function(class_type, mysqli_warning_class_entry)) { /* warning object */
394 		handlers = &mysqli_object_warning_handlers;
395 	} else {
396 		handlers = &mysqli_object_handlers;
397 	}
398 
399 	intern->zo.handlers = handlers;
400 
401 	return &intern->zo;
402 }
403 /* }}} */
404 
405 #include "ext/mysqlnd/mysqlnd_reverse_api.h"
mysqli_convert_zv_to_mysqlnd(zval * zv)406 static MYSQLND *mysqli_convert_zv_to_mysqlnd(zval * zv)
407 {
408 	if (Z_TYPE_P(zv) == IS_OBJECT && instanceof_function(Z_OBJCE_P(zv), mysqli_link_class_entry)) {
409 		MY_MYSQL *mysql;
410 		MYSQLI_RESOURCE  *my_res;
411 		mysqli_object *intern = Z_MYSQLI_P(zv);
412 		if (!(my_res = (MYSQLI_RESOURCE *)intern->ptr)) {
413 			/* We know that we have a mysqli object, so this failure should be emitted */
414 			zend_throw_error(NULL, "%s object is already closed", ZSTR_VAL(intern->zo.ce->name));
415 			return NULL;
416 		}
417 		mysql = (MY_MYSQL *)(my_res->ptr);
418 		return mysql ? mysql->mysql : NULL;
419 	}
420 	return NULL;
421 }
422 
423 static const MYSQLND_REVERSE_API mysqli_reverse_api = {
424 	&mysqli_module_entry,
425 	mysqli_convert_zv_to_mysqlnd
426 };
427 
428 /* {{{ PHP_INI_BEGIN */
429 PHP_INI_BEGIN()
430 	STD_PHP_INI_ENTRY_EX("mysqli.max_links",			"-1",	PHP_INI_SYSTEM,		OnUpdateLong,		max_links,			zend_mysqli_globals,		mysqli_globals, display_link_numbers)
431 	STD_PHP_INI_ENTRY_EX("mysqli.max_persistent",		"-1",	PHP_INI_SYSTEM,		OnUpdateLong,		max_persistent,		zend_mysqli_globals,		mysqli_globals,	display_link_numbers)
432 	STD_PHP_INI_BOOLEAN("mysqli.allow_persistent",		"1",	PHP_INI_SYSTEM,		OnUpdateBool,		allow_persistent,	zend_mysqli_globals,		mysqli_globals)
433 	STD_PHP_INI_BOOLEAN("mysqli.rollback_on_cached_plink",	"0",PHP_INI_SYSTEM,		OnUpdateBool,		rollback_on_cached_plink,	zend_mysqli_globals,		mysqli_globals)
434 	STD_PHP_INI_ENTRY("mysqli.default_host",			NULL,	PHP_INI_ALL,		OnUpdateString,		default_host,		zend_mysqli_globals,		mysqli_globals)
435 	STD_PHP_INI_ENTRY("mysqli.default_user",			NULL,	PHP_INI_ALL,		OnUpdateString,		default_user,		zend_mysqli_globals,		mysqli_globals)
436 	STD_PHP_INI_ENTRY("mysqli.default_pw",				NULL,	PHP_INI_ALL,		OnUpdateString,		default_pw,			zend_mysqli_globals,		mysqli_globals)
437 	STD_PHP_INI_ENTRY("mysqli.default_port",			"3306",	PHP_INI_ALL,		OnUpdateLong,		default_port,		zend_mysqli_globals,		mysqli_globals)
438 #ifdef PHP_MYSQL_UNIX_SOCK_ADDR
439 	STD_PHP_INI_ENTRY("mysqli.default_socket",			MYSQL_UNIX_ADDR,PHP_INI_ALL,OnUpdateStringUnempty,	default_socket,	zend_mysqli_globals,		mysqli_globals)
440 #else
441 	STD_PHP_INI_ENTRY("mysqli.default_socket",			NULL,	PHP_INI_ALL,		OnUpdateStringUnempty,	default_socket,	zend_mysqli_globals,		mysqli_globals)
442 #endif
443 	STD_PHP_INI_BOOLEAN("mysqli.allow_local_infile",	"0",	PHP_INI_SYSTEM,		OnUpdateBool,		allow_local_infile,	zend_mysqli_globals,		mysqli_globals)
444 	STD_PHP_INI_ENTRY("mysqli.local_infile_directory",	NULL,	PHP_INI_SYSTEM,		OnUpdateString,		local_infile_directory,	zend_mysqli_globals,	mysqli_globals)
PHP_INI_END()445 PHP_INI_END()
446 /* }}} */
447 
448 /* {{{ PHP_GINIT_FUNCTION */
449 static PHP_GINIT_FUNCTION(mysqli)
450 {
451 #if defined(COMPILE_DL_MYSQLI) && defined(ZTS)
452 	ZEND_TSRMLS_CACHE_UPDATE();
453 #endif
454 	mysqli_globals->num_links = 0;
455 	mysqli_globals->max_links = -1;
456 	mysqli_globals->num_active_persistent = 0;
457 	mysqli_globals->num_inactive_persistent = 0;
458 	mysqli_globals->max_persistent = -1;
459 	mysqli_globals->allow_persistent = 1;
460 	mysqli_globals->default_port = 0;
461 	mysqli_globals->default_host = NULL;
462 	mysqli_globals->default_user = NULL;
463 	mysqli_globals->default_pw = NULL;
464 	mysqli_globals->default_socket = NULL;
465 	mysqli_globals->report_mode = MYSQLI_REPORT_ERROR|MYSQLI_REPORT_STRICT;;
466 	mysqli_globals->allow_local_infile = 0;
467 	mysqli_globals->local_infile_directory = NULL;
468 	mysqli_globals->rollback_on_cached_plink = false;
469 }
470 /* }}} */
471 
472 /* {{{ PHP_MINIT_FUNCTION */
PHP_MINIT_FUNCTION(mysqli)473 PHP_MINIT_FUNCTION(mysqli)
474 {
475 	REGISTER_INI_ENTRIES();
476 
477 	memcpy(&mysqli_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
478 	mysqli_object_handlers.offset = XtOffsetOf(mysqli_object, zo);
479 	mysqli_object_handlers.free_obj = mysqli_objects_free_storage;
480 	mysqli_object_handlers.clone_obj = NULL;
481 	mysqli_object_handlers.read_property = mysqli_read_property;
482 	mysqli_object_handlers.write_property = mysqli_write_property;
483 	mysqli_object_handlers.has_property = mysqli_object_has_property;
484 	mysqli_object_handlers.get_debug_info = mysqli_object_get_debug_info;
485 	memcpy(&mysqli_object_driver_handlers, &mysqli_object_handlers, sizeof(zend_object_handlers));
486 	mysqli_object_driver_handlers.free_obj = mysqli_driver_free_storage;
487 	memcpy(&mysqli_object_link_handlers, &mysqli_object_handlers, sizeof(zend_object_handlers));
488 	mysqli_object_link_handlers.free_obj = mysqli_link_free_storage;
489 	memcpy(&mysqli_object_result_handlers, &mysqli_object_handlers, sizeof(zend_object_handlers));
490 	mysqli_object_result_handlers.free_obj = mysqli_result_free_storage;
491 	memcpy(&mysqli_object_stmt_handlers, &mysqli_object_handlers, sizeof(zend_object_handlers));
492 	mysqli_object_stmt_handlers.free_obj = mysqli_stmt_free_storage;
493 	memcpy(&mysqli_object_warning_handlers, &mysqli_object_handlers, sizeof(zend_object_handlers));
494 	mysqli_object_warning_handlers.free_obj = mysqli_warning_free_storage;
495 
496 	zend_hash_init(&classes, 0, NULL, NULL, 1);
497 
498 	/* persistent connections */
499 	le_pmysqli = zend_register_list_destructors_ex(NULL, php_mysqli_dtor,
500 		"MySqli persistent connection", module_number);
501 
502 	mysqli_exception_class_entry = register_class_mysqli_sql_exception(spl_ce_RuntimeException);
503 
504 	mysqli_driver_class_entry = register_class_mysqli_driver();
505 	mysqli_driver_class_entry->create_object = mysqli_objects_new;
506 	zend_hash_init(&mysqli_driver_properties, 0, NULL, free_prop_handler, 1);
507 	MYSQLI_ADD_PROPERTIES(&mysqli_driver_properties, mysqli_driver_property_entries);
508 	zend_hash_add_ptr(&classes, mysqli_driver_class_entry->name, &mysqli_driver_properties);
509 
510 	mysqli_link_class_entry = register_class_mysqli();
511 	mysqli_link_class_entry->create_object = mysqli_objects_new;
512 	zend_hash_init(&mysqli_link_properties, 0, NULL, free_prop_handler, 1);
513 	MYSQLI_ADD_PROPERTIES(&mysqli_link_properties, mysqli_link_property_entries);
514 	zend_hash_add_ptr(&classes, mysqli_link_class_entry->name, &mysqli_link_properties);
515 
516 	mysqli_warning_class_entry = register_class_mysqli_warning();
517 	mysqli_warning_class_entry->create_object = mysqli_objects_new;
518 	zend_hash_init(&mysqli_warning_properties, 0, NULL, free_prop_handler, 1);
519 	MYSQLI_ADD_PROPERTIES(&mysqli_warning_properties, mysqli_warning_property_entries);
520 	zend_hash_add_ptr(&classes, mysqli_warning_class_entry->name, &mysqli_warning_properties);
521 
522 	mysqli_result_class_entry = register_class_mysqli_result(zend_ce_aggregate);
523 	mysqli_result_class_entry->create_object = mysqli_objects_new;
524 	mysqli_result_class_entry->get_iterator = php_mysqli_result_get_iterator;
525 	zend_hash_init(&mysqli_result_properties, 0, NULL, free_prop_handler, 1);
526 	MYSQLI_ADD_PROPERTIES(&mysqli_result_properties, mysqli_result_property_entries);
527 	zend_hash_add_ptr(&classes, mysqli_result_class_entry->name, &mysqli_result_properties);
528 
529 	mysqli_stmt_class_entry = register_class_mysqli_stmt();
530 	mysqli_stmt_class_entry->create_object = mysqli_objects_new;
531 	zend_hash_init(&mysqli_stmt_properties, 0, NULL, free_prop_handler, 1);
532 	MYSQLI_ADD_PROPERTIES(&mysqli_stmt_properties, mysqli_stmt_property_entries);
533 	zend_hash_add_ptr(&classes, mysqli_stmt_class_entry->name, &mysqli_stmt_properties);
534 
535 	register_mysqli_symbols(module_number);
536 
537 	mysqlnd_reverse_api_register_api(&mysqli_reverse_api);
538 
539 	return SUCCESS;
540 }
541 /* }}} */
542 
543 /* {{{ PHP_MSHUTDOWN_FUNCTION */
PHP_MSHUTDOWN_FUNCTION(mysqli)544 PHP_MSHUTDOWN_FUNCTION(mysqli)
545 {
546 	zend_hash_destroy(&mysqli_driver_properties);
547 	zend_hash_destroy(&mysqli_result_properties);
548 	zend_hash_destroy(&mysqli_stmt_properties);
549 	zend_hash_destroy(&mysqli_warning_properties);
550 	zend_hash_destroy(&mysqli_link_properties);
551 	zend_hash_destroy(&classes);
552 
553 	UNREGISTER_INI_ENTRIES();
554 	return SUCCESS;
555 }
556 /* }}} */
557 
558 /* {{{ PHP_RINIT_FUNCTION */
PHP_RINIT_FUNCTION(mysqli)559 PHP_RINIT_FUNCTION(mysqli)
560 {
561 	MyG(error_msg) = NULL;
562 	MyG(error_no) = 0;
563 	MyG(report_mode) = MYSQLI_REPORT_ERROR|MYSQLI_REPORT_STRICT;
564 
565 	return SUCCESS;
566 }
567 /* }}} */
568 
569 
570 /* {{{ PHP_RSHUTDOWN_FUNCTION */
PHP_RSHUTDOWN_FUNCTION(mysqli)571 PHP_RSHUTDOWN_FUNCTION(mysqli)
572 {
573 	/* check persistent connections, move used to free */
574 
575 	if (MyG(error_msg)) {
576 		efree(MyG(error_msg));
577 	}
578 
579 	return SUCCESS;
580 }
581 /* }}} */
582 
583 
584 /* {{{ PHP_MINFO_FUNCTION */
PHP_MINFO_FUNCTION(mysqli)585 PHP_MINFO_FUNCTION(mysqli)
586 {
587 	char buf[32];
588 
589 	php_info_print_table_start();
590 	php_info_print_table_row(2, "MysqlI Support", "enabled");
591 	php_info_print_table_row(2, "Client API library version", mysql_get_client_info());
592 	snprintf(buf, sizeof(buf), ZEND_LONG_FMT, MyG(num_active_persistent));
593 	php_info_print_table_row(2, "Active Persistent Links", buf);
594 	snprintf(buf, sizeof(buf), ZEND_LONG_FMT, MyG(num_inactive_persistent));
595 	php_info_print_table_row(2, "Inactive Persistent Links", buf);
596 	snprintf(buf, sizeof(buf), ZEND_LONG_FMT, MyG(num_links));
597 	php_info_print_table_row(2, "Active Links", buf);
598 	php_info_print_table_end();
599 
600 	DISPLAY_INI_ENTRIES();
601 }
602 /* }}} */
603 
604 
605 /* Dependencies */
606 static const  zend_module_dep mysqli_deps[] = {
607 	ZEND_MOD_REQUIRED("spl")
608 	ZEND_MOD_REQUIRED("mysqlnd")
609 	ZEND_MOD_END
610 };
611 
612 /* {{{ mysqli_module_entry */
613 zend_module_entry mysqli_module_entry = {
614 	STANDARD_MODULE_HEADER_EX, NULL,
615 	mysqli_deps,
616 	"mysqli",
617 	ext_functions,
618 	PHP_MINIT(mysqli),
619 	PHP_MSHUTDOWN(mysqli),
620 	PHP_RINIT(mysqli),
621 	PHP_RSHUTDOWN(mysqli),
622 	PHP_MINFO(mysqli),
623 	PHP_MYSQLI_VERSION,
624 	PHP_MODULE_GLOBALS(mysqli),
625 	PHP_GINIT(mysqli),
626 	NULL,
627 	NULL,
628 	STANDARD_MODULE_PROPERTIES_EX
629 };
630 /* }}} */
631 
632 #ifdef COMPILE_DL_MYSQLI
633 #ifdef ZTS
634 ZEND_TSRMLS_CACHE_DEFINE()
635 #endif
ZEND_GET_MODULE(mysqli)636 ZEND_GET_MODULE(mysqli)
637 #endif
638 
639 
640 PHP_METHOD(mysqli_stmt, __construct)
641 {
642 	MY_MYSQL			*mysql;
643 	zval				*mysql_link;
644 	MY_STMT				*stmt;
645 	MYSQLI_RESOURCE		*mysqli_resource;
646 	char				*statement = NULL;
647 	size_t					statement_len;
648 
649 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|s!", &mysql_link, mysqli_link_class_entry, &statement, &statement_len) == FAILURE) {
650 		RETURN_THROWS();
651 	}
652 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
653 
654 	stmt = (MY_STMT *) ecalloc(1, sizeof(MY_STMT));
655 
656 	if (!(stmt->stmt = mysql_stmt_init(mysql->mysql))) {
657 		efree(stmt);
658 		RETURN_FALSE;
659 	}
660 
661 	mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE));
662 	mysqli_resource->ptr = (void *)stmt;
663 	mysqli_resource->status = MYSQLI_STATUS_INITIALIZED;
664 
665 	MYSQLI_REGISTER_RESOURCE_EX(mysqli_resource, getThis());
666 
667 	if (statement) {
668 		if(mysql_stmt_prepare(stmt->stmt, statement, statement_len)) {
669 			MYSQLI_REPORT_STMT_ERROR(stmt->stmt);
670 			RETURN_FALSE;
671 		}
672 		mysqli_resource->status = MYSQLI_STATUS_VALID;
673 	}
674 }
675 
PHP_METHOD(mysqli_result,__construct)676 PHP_METHOD(mysqli_result, __construct)
677 {
678 	MY_MYSQL			*mysql;
679 	MYSQL_RES			*result = NULL;
680 	zval				*mysql_link;
681 	MYSQLI_RESOURCE		*mysqli_resource;
682 	zend_long				resmode = MYSQLI_STORE_RESULT;
683 
684 	if (zend_parse_parameters(ZEND_NUM_ARGS(), "O|l", &mysql_link, mysqli_link_class_entry, &resmode) == FAILURE) {
685 		RETURN_THROWS();
686 	}
687 
688 	MYSQLI_FETCH_RESOURCE_CONN(mysql, mysql_link, MYSQLI_STATUS_VALID);
689 
690 	switch (resmode) {
691 		case MYSQLI_STORE_RESULT:
692 			result = mysql_store_result(mysql->mysql);
693 			break;
694 		case MYSQLI_USE_RESULT:
695 			result = mysql_use_result(mysql->mysql);
696 			break;
697 		default:
698 			zend_argument_value_error(2, "must be either MYSQLI_STORE_RESULT or MYSQLI_USE_RESULT");
699 			RETURN_THROWS();
700 	}
701 
702 	if (!result) {
703 		MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql);
704 		RETURN_FALSE;
705 	}
706 	if (MyG(report_mode) & MYSQLI_REPORT_INDEX) {
707 		php_mysqli_report_index("from previous query", mysqli_server_status(mysql->mysql));
708 	}
709 
710 	mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE));
711 	mysqli_resource->ptr = (void *)result;
712 	mysqli_resource->status = MYSQLI_STATUS_VALID;
713 
714 	MYSQLI_REGISTER_RESOURCE_EX(mysqli_resource, getThis());
715 }
716 
PHP_METHOD(mysqli_result,getIterator)717 PHP_METHOD(mysqli_result, getIterator)
718 {
719 	if (zend_parse_parameters_none() == FAILURE) {
720 		RETURN_THROWS();
721 	}
722 
723 	zend_create_internal_iterator_zval(return_value, ZEND_THIS);
724 }
725 
726 /* {{{ php_mysqli_fetch_into_hash_aux */
php_mysqli_fetch_into_hash_aux(zval * return_value,MYSQL_RES * result,zend_long fetchtype)727 void php_mysqli_fetch_into_hash_aux(zval *return_value, MYSQL_RES * result, zend_long fetchtype)
728 {
729 	mysqlnd_fetch_into(result, ((fetchtype & MYSQLI_NUM)? MYSQLND_FETCH_NUM:0) | ((fetchtype & MYSQLI_ASSOC)? MYSQLND_FETCH_ASSOC:0), return_value);
730 	/* TODO: We don't have access to the connection object at this point, so we use low-level
731 	 * mysqlnd APIs to access the error information. We should try to pass through the connection
732 	 * object instead. */
733 	if (MyG(report_mode) & MYSQLI_REPORT_ERROR && result->conn) {
734 		MYSQLND_CONN_DATA *conn = result->conn;
735 		unsigned error_no = conn->m->get_error_no(conn);
736 		if (error_no) {
737 			php_mysqli_report_error(
738 				conn->m->get_sqlstate(conn), error_no, conn->m->get_error_str(conn));
739 		}
740 	}
741 }
742 /* }}} */
743 
744 /* TODO Split this up */
745 /* {{{ php_mysqli_fetch_into_hash */
php_mysqli_fetch_into_hash(INTERNAL_FUNCTION_PARAMETERS,int override_flags,int into_object)746 void php_mysqli_fetch_into_hash(INTERNAL_FUNCTION_PARAMETERS, int override_flags, int into_object)
747 {
748 	MYSQL_RES		*result;
749 	zval			*mysql_result;
750 	zend_long			fetchtype;
751 	HashTable			*ctor_params = NULL;
752 	zend_class_entry *ce = NULL;
753 
754 	if (into_object) {
755 		if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O|Ch", &mysql_result, mysqli_result_class_entry, &ce, &ctor_params) == FAILURE) {
756 			RETURN_THROWS();
757 		}
758 		if (ce == NULL) {
759 			ce = zend_standard_class_def;
760 		}
761 		if (UNEXPECTED(ce->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_TRAIT|ZEND_ACC_IMPLICIT_ABSTRACT_CLASS|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS))) {
762 			zend_throw_error(NULL, "Class %s cannot be instantiated", ZSTR_VAL(ce->name));
763 			RETURN_THROWS();
764 		}
765 		fetchtype = MYSQLI_ASSOC;
766 	} else {
767 		if (override_flags) {
768 			if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O", &mysql_result, mysqli_result_class_entry) == FAILURE) {
769 				RETURN_THROWS();
770 			}
771 			fetchtype = override_flags;
772 		} else {
773 			fetchtype = MYSQLI_BOTH;
774 			if (zend_parse_method_parameters(ZEND_NUM_ARGS(), getThis(), "O|l", &mysql_result, mysqli_result_class_entry, &fetchtype) == FAILURE) {
775 				RETURN_THROWS();
776 			}
777 		}
778 	}
779 	MYSQLI_FETCH_RESOURCE(result, MYSQL_RES *, mysql_result, "mysqli_result", MYSQLI_STATUS_VALID);
780 
781 	if (fetchtype < MYSQLI_ASSOC || fetchtype > MYSQLI_BOTH) {
782 		zend_argument_value_error(ERROR_ARG_POS(2), "must be one of MYSQLI_NUM, MYSQLI_ASSOC, or MYSQLI_BOTH");
783 		RETURN_THROWS();
784 	}
785 
786 	php_mysqli_fetch_into_hash_aux(return_value, result, fetchtype);
787 
788 	if (into_object && Z_TYPE_P(return_value) == IS_ARRAY) {
789 		zval dataset;
790 
791 		ZVAL_COPY_VALUE(&dataset, return_value);
792 
793 		object_init_ex(return_value, ce);
794 		HashTable *prop_table = zend_symtable_to_proptable(Z_ARR(dataset));
795 		zval_ptr_dtor(&dataset);
796 		if (!ce->default_properties_count && !ce->__set) {
797 			Z_OBJ_P(return_value)->properties = prop_table;
798 		} else {
799 			zend_merge_properties(return_value, prop_table);
800 			zend_array_release(prop_table);
801 		}
802 
803 		if (ce->constructor) {
804 			zend_call_known_function(ce->constructor, Z_OBJ_P(return_value), Z_OBJCE_P(return_value),
805 				/* retval */ NULL, /* argc */ 0, /* params */ NULL, ctor_params);
806 		} else if (ctor_params && zend_hash_num_elements(ctor_params) > 0) {
807 			zend_argument_value_error(ERROR_ARG_POS(3),
808 				"must be empty when the specified class (%s) does not have a constructor",
809 				ZSTR_VAL(ce->name)
810 			);
811 		}
812 	}
813 }
814 /* }}} */
815