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