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