1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 7 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) The PHP Group |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Author: Georg Richter <georg@php.net> |
16 | Andrey Hristov <andrey@php.net> |
17 +----------------------------------------------------------------------+
18 */
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include <signal.h>
25
26 #include "php.h"
27 #include "php_ini.h"
28 #include "ext/standard/info.h"
29 #include "php_mysqli_structs.h"
30 #include "mysqli_priv.h"
31
32 #define CHECK_STATUS(value, quiet) \
33 if (!obj->ptr || ((MYSQLI_RESOURCE *)obj->ptr)->status < value ) { \
34 if (!quiet) { \
35 php_error_docref(NULL, E_WARNING, "Property access is not allowed yet"); \
36 } \
37 ZVAL_FALSE(retval); \
38 return FAILURE; \
39 } \
40
41 #define MYSQLI_GET_MYSQL(statusval) \
42 MYSQL *p; \
43 if (!obj->ptr || !(MY_MYSQL *)((MYSQLI_RESOURCE *)(obj->ptr))->ptr) { \
44 if (!quiet) { \
45 php_error_docref(NULL, E_WARNING, "Couldn't fetch %s", ZSTR_VAL(obj->zo.ce->name)); \
46 } \
47 ZVAL_FALSE(retval);\
48 return FAILURE; \
49 } else { \
50 CHECK_STATUS(statusval, quiet);\
51 p = (MYSQL *)((MY_MYSQL *)((MYSQLI_RESOURCE *)(obj->ptr))->ptr)->mysql;\
52 }
53
54 #define MYSQLI_GET_RESULT(statusval) \
55 MYSQL_RES *p; \
56 if (!obj->ptr) { \
57 if (!quiet) { \
58 php_error_docref(NULL, E_WARNING, "Couldn't fetch %s", ZSTR_VAL(obj->zo.ce->name)); \
59 } \
60 ZVAL_NULL(retval);\
61 return FAILURE; \
62 } else { \
63 CHECK_STATUS(statusval, quiet);\
64 p = (MYSQL_RES *)((MYSQLI_RESOURCE *)(obj->ptr))->ptr; \
65 }
66
67 #define MYSQLI_GET_STMT(statusval) \
68 MYSQL_STMT *p; \
69 if (!obj->ptr) { \
70 if (!quiet) { \
71 php_error_docref(NULL, E_WARNING, "Couldn't fetch %s", ZSTR_VAL(obj->zo.ce->name)); \
72 } \
73 ZVAL_NULL(retval);\
74 return FAILURE; \
75 } else { \
76 CHECK_STATUS(statusval, quiet); \
77 p = (MYSQL_STMT *)((MY_STMT *)((MYSQLI_RESOURCE *)(obj->ptr))->ptr)->stmt; \
78 }
79
80 #define MYSQLI_MAP_PROPERTY_FUNC_LONG( __func, __int_func, __get_type, __ret_type, __ret_type_sprint_mod)\
81 static int __func(mysqli_object *obj, zval *retval, zend_bool quiet) \
82 {\
83 __ret_type l;\
84 __get_type;\
85 if (!p) {\
86 ZVAL_NULL(retval);\
87 } else {\
88 l = (__ret_type)__int_func(p);\
89 if (l < ZEND_LONG_MAX) {\
90 ZVAL_LONG(retval, (zend_long) l);\
91 } else { \
92 ZVAL_NEW_STR(retval, strpprintf(0, __ret_type_sprint_mod, l)); \
93 } \
94 } \
95 return SUCCESS; \
96 }
97
98 #define MYSQLI_MAP_PROPERTY_FUNC_STRING(__func, __int_func, __get_type)\
99 static int __func(mysqli_object *obj, zval *retval, zend_bool quiet)\
100 {\
101 char *c;\
102 __get_type;\
103 if (!p) {\
104 ZVAL_NULL(retval);\
105 } else {\
106 c = (char *)__int_func(p);\
107 if (!c) {\
108 ZVAL_NULL(retval);\
109 } else {\
110 ZVAL_STRING(retval, c);\
111 }\
112 }\
113 return SUCCESS; \
114 }
115
116 /* {{{ property link_client_version_read */
link_client_version_read(mysqli_object * obj,zval * retval,zend_bool quiet)117 static int link_client_version_read(mysqli_object *obj, zval *retval, zend_bool quiet)
118 {
119 ZVAL_LONG(retval, MYSQL_VERSION_ID);
120
121 return SUCCESS;
122 }
123 /* }}} */
124
125 /* {{{ property link_client_info_read */
link_client_info_read(mysqli_object * obj,zval * retval,zend_bool quiet)126 static int link_client_info_read(mysqli_object *obj, zval *retval, zend_bool quiet)
127 {
128 CHECK_STATUS(MYSQLI_STATUS_INITIALIZED, quiet);
129 ZVAL_STRING(retval, MYSQL_SERVER_VERSION);
130
131 return SUCCESS;
132 }
133 /* }}} */
134
135 /* {{{ property link_connect_errno_read */
link_connect_errno_read(mysqli_object * obj,zval * retval,zend_bool quiet)136 static int link_connect_errno_read(mysqli_object *obj, zval *retval, zend_bool quiet)
137 {
138 ZVAL_LONG(retval, (zend_long)MyG(error_no));
139
140 return SUCCESS;
141 }
142 /* }}} */
143
144 /* {{{ property link_connect_error_read */
link_connect_error_read(mysqli_object * obj,zval * retval,zend_bool quiet)145 static int link_connect_error_read(mysqli_object *obj, zval *retval, zend_bool quiet)
146 {
147 if (MyG(error_msg)) {
148 ZVAL_STRING(retval, MyG(error_msg));
149 } else {
150 ZVAL_NULL(retval);
151 }
152
153 return SUCCESS;
154 }
155 /* }}} */
156
157 /* {{{ property link_affected_rows_read */
link_affected_rows_read(mysqli_object * obj,zval * retval,zend_bool quiet)158 static int link_affected_rows_read(mysqli_object *obj, zval *retval, zend_bool quiet)
159 {
160 MY_MYSQL *mysql;
161 my_ulonglong rc;
162
163 CHECK_STATUS(MYSQLI_STATUS_INITIALIZED, quiet);
164
165 mysql = (MY_MYSQL *)((MYSQLI_RESOURCE *)(obj->ptr))->ptr;
166
167 if (!mysql) {
168 ZVAL_NULL(retval);
169 } else {
170 CHECK_STATUS(MYSQLI_STATUS_VALID, quiet);
171
172 rc = mysql_affected_rows(mysql->mysql);
173
174 if (rc == (my_ulonglong) -1) {
175 ZVAL_LONG(retval, -1);
176 return SUCCESS;
177 }
178
179 if (rc < ZEND_LONG_MAX) {
180 ZVAL_LONG(retval, (zend_long) rc);
181 } else {
182 ZVAL_NEW_STR(retval, strpprintf(0, MYSQLI_LLU_SPEC, rc));
183 }
184 }
185
186 return SUCCESS;
187 }
188 /* }}} */
189
190 /* {{{ property link_error_list_read */
link_error_list_read(mysqli_object * obj,zval * retval,zend_bool quiet)191 static int link_error_list_read(mysqli_object *obj, zval *retval, zend_bool quiet)
192 {
193 MY_MYSQL *mysql;
194
195 CHECK_STATUS(MYSQLI_STATUS_VALID, quiet);
196
197 mysql = (MY_MYSQL *)((MYSQLI_RESOURCE *)(obj->ptr))->ptr;
198
199 if (mysql) {
200 array_init(retval);
201 #if defined(MYSQLI_USE_MYSQLND)
202 if (1) {
203 MYSQLND_ERROR_LIST_ELEMENT * message;
204 zend_llist_position pos;
205 for (message = (MYSQLND_ERROR_LIST_ELEMENT *) zend_llist_get_first_ex(&mysql->mysql->data->error_info->error_list, &pos);
206 message;
207 message = (MYSQLND_ERROR_LIST_ELEMENT *) zend_llist_get_next_ex(&mysql->mysql->data->error_info->error_list, &pos))
208 {
209 zval single_error;
210 array_init(&single_error);
211 add_assoc_long_ex(&single_error, "errno", sizeof("errno") - 1, message->error_no);
212 add_assoc_string_ex(&single_error, "sqlstate", sizeof("sqlstate") - 1, message->sqlstate);
213 add_assoc_string_ex(&single_error, "error", sizeof("error") - 1, message->error);
214 add_next_index_zval(retval, &single_error);
215 }
216 }
217 #else
218 if (mysql_errno(mysql->mysql)) {
219 zval single_error;
220 array_init(&single_error);
221 add_assoc_long_ex(&single_error, "errno", sizeof("errno") - 1, mysql_errno(mysql->mysql));
222 add_assoc_string_ex(&single_error, "sqlstate", sizeof("sqlstate") - 1, mysql_sqlstate(mysql->mysql));
223 add_assoc_string_ex(&single_error, "error", sizeof("error") - 1, mysql_error(mysql->mysql));
224 add_next_index_zval(retval, &single_error);
225 }
226 #endif
227 } else {
228 ZVAL_EMPTY_ARRAY(retval);
229 }
230
231 return SUCCESS;
232 }
233 /* }}} */
234
235 /* link properties */
MYSQLI_MAP_PROPERTY_FUNC_LONG(link_errno_read,mysql_errno,MYSQLI_GET_MYSQL (MYSQLI_STATUS_INITIALIZED),zend_ulong,ZEND_ULONG_FMT)236 MYSQLI_MAP_PROPERTY_FUNC_LONG(link_errno_read, mysql_errno, MYSQLI_GET_MYSQL(MYSQLI_STATUS_INITIALIZED), zend_ulong, ZEND_ULONG_FMT)
237 MYSQLI_MAP_PROPERTY_FUNC_STRING(link_error_read, mysql_error, MYSQLI_GET_MYSQL(MYSQLI_STATUS_INITIALIZED))
238 MYSQLI_MAP_PROPERTY_FUNC_LONG(link_field_count_read, mysql_field_count, MYSQLI_GET_MYSQL(MYSQLI_STATUS_VALID), zend_ulong, ZEND_ULONG_FMT)
239 MYSQLI_MAP_PROPERTY_FUNC_STRING(link_host_info_read, mysql_get_host_info, MYSQLI_GET_MYSQL(MYSQLI_STATUS_VALID))
240 MYSQLI_MAP_PROPERTY_FUNC_STRING(link_info_read, mysql_info, MYSQLI_GET_MYSQL(MYSQLI_STATUS_VALID))
241 MYSQLI_MAP_PROPERTY_FUNC_LONG(link_insert_id_read, mysql_insert_id, MYSQLI_GET_MYSQL(MYSQLI_STATUS_VALID), my_ulonglong, MYSQLI_LLU_SPEC)
242 MYSQLI_MAP_PROPERTY_FUNC_LONG(link_protocol_version_read, mysql_get_proto_info, MYSQLI_GET_MYSQL(MYSQLI_STATUS_VALID), zend_ulong, ZEND_ULONG_FMT)
243 MYSQLI_MAP_PROPERTY_FUNC_STRING(link_server_info_read, mysql_get_server_info, MYSQLI_GET_MYSQL(MYSQLI_STATUS_VALID))
244 MYSQLI_MAP_PROPERTY_FUNC_LONG(link_server_version_read, mysql_get_server_version, MYSQLI_GET_MYSQL(MYSQLI_STATUS_VALID), zend_ulong, ZEND_ULONG_FMT)
245 MYSQLI_MAP_PROPERTY_FUNC_STRING(link_sqlstate_read, mysql_sqlstate, MYSQLI_GET_MYSQL(MYSQLI_STATUS_VALID))
246 MYSQLI_MAP_PROPERTY_FUNC_LONG(link_thread_id_read, mysql_thread_id, MYSQLI_GET_MYSQL(MYSQLI_STATUS_VALID), zend_ulong, ZEND_ULONG_FMT)
247 MYSQLI_MAP_PROPERTY_FUNC_LONG(link_warning_count_read, mysql_warning_count, MYSQLI_GET_MYSQL(MYSQLI_STATUS_VALID), zend_ulong, ZEND_ULONG_FMT)
248
249 /* result properties */
250
251 /* {{{ property result_type_read */
252 static int result_type_read(mysqli_object *obj, zval *retval, zend_bool quiet)
253 {
254 MYSQL_RES *p;
255
256 CHECK_STATUS(MYSQLI_STATUS_VALID, quiet);
257 p = (MYSQL_RES *)((MYSQLI_RESOURCE *)(obj->ptr))->ptr;
258
259 if (!p) {
260 ZVAL_NULL(retval);
261 } else {
262 ZVAL_LONG(retval, mysqli_result_is_unbuffered(p) ? MYSQLI_USE_RESULT:MYSQLI_STORE_RESULT);
263 }
264
265 return SUCCESS;
266 }
267 /* }}} */
268
269 /* {{{ property result_lengths_read */
result_lengths_read(mysqli_object * obj,zval * retval,zend_bool quiet)270 static int result_lengths_read(mysqli_object *obj, zval *retval, zend_bool quiet)
271 {
272 MYSQL_RES *p;
273 #if defined(MYSQLI_USE_MYSQLND)
274 const size_t *ret;
275 #else
276 const zend_ulong *ret;
277 #endif
278 uint32_t field_count;
279
280 CHECK_STATUS(MYSQLI_STATUS_VALID, quiet);
281 p = (MYSQL_RES *)((MYSQLI_RESOURCE *)(obj->ptr))->ptr;
282 field_count = mysql_num_fields(p);
283 if (!p || !field_count || !(ret = mysql_fetch_lengths(p))) {
284 ZVAL_NULL(retval);
285 } else {
286 zend_ulong i;
287
288 array_init(retval);
289
290 for (i = 0; i < field_count; i++) {
291 add_index_long(retval, i, ret[i]);
292 }
293 }
294
295 return SUCCESS;
296 }
297 /* }}} */
298
MYSQLI_MAP_PROPERTY_FUNC_LONG(result_current_field_read,mysql_field_tell,MYSQLI_GET_RESULT (MYSQLI_STATUS_VALID),zend_ulong,ZEND_ULONG_FMT)299 MYSQLI_MAP_PROPERTY_FUNC_LONG(result_current_field_read, mysql_field_tell, MYSQLI_GET_RESULT(MYSQLI_STATUS_VALID), zend_ulong, ZEND_ULONG_FMT)
300 MYSQLI_MAP_PROPERTY_FUNC_LONG(result_field_count_read, mysql_num_fields, MYSQLI_GET_RESULT(MYSQLI_STATUS_VALID), zend_ulong, ZEND_ULONG_FMT)
301 MYSQLI_MAP_PROPERTY_FUNC_LONG(result_num_rows_read, mysql_num_rows, MYSQLI_GET_RESULT(MYSQLI_STATUS_VALID), my_ulonglong, MYSQLI_LLU_SPEC)
302
303 /* statement properties */
304
305 /* {{{ property stmt_id_read */
306 static int stmt_id_read(mysqli_object *obj, zval *retval, zend_bool quiet)
307 {
308 MY_STMT *p;
309
310 CHECK_STATUS(MYSQLI_STATUS_VALID, quiet);
311
312 p = (MY_STMT*)((MYSQLI_RESOURCE *)(obj->ptr))->ptr;
313
314 if (!p) {
315 ZVAL_NULL(retval);
316 } else {
317 ZVAL_LONG(retval, mysqli_stmt_get_id(p->stmt));
318 }
319
320 return SUCCESS;
321 }
322 /* }}} */
323
324 /* {{{ property stmt_affected_rows_read */
stmt_affected_rows_read(mysqli_object * obj,zval * retval,zend_bool quiet)325 static int stmt_affected_rows_read(mysqli_object *obj, zval *retval, zend_bool quiet)
326 {
327 MY_STMT *p;
328 my_ulonglong rc;
329
330 CHECK_STATUS(MYSQLI_STATUS_VALID, quiet);
331
332 p = (MY_STMT *)((MYSQLI_RESOURCE *)(obj->ptr))->ptr;
333
334 if (!p) {
335 ZVAL_NULL(retval);
336 } else {
337 rc = mysql_stmt_affected_rows(p->stmt);
338
339 if (rc == (my_ulonglong) -1) {
340 ZVAL_LONG(retval, -1);
341 return SUCCESS;
342 }
343
344 if (rc < ZEND_LONG_MAX) {
345 ZVAL_LONG(retval, (zend_long) rc);
346 } else {
347 ZVAL_NEW_STR(retval, strpprintf(0, MYSQLI_LLU_SPEC, rc));
348 }
349 }
350
351 return SUCCESS;
352 }
353 /* }}} */
354
355 /* {{{ property stmt_error_list_read */
stmt_error_list_read(mysqli_object * obj,zval * retval,zend_bool quiet)356 static int stmt_error_list_read(mysqli_object *obj, zval *retval, zend_bool quiet)
357 {
358 MY_STMT * stmt;
359
360 CHECK_STATUS(MYSQLI_STATUS_INITIALIZED, quiet);
361
362 stmt = (MY_STMT *)((MYSQLI_RESOURCE *)(obj->ptr))->ptr;
363 if (stmt && stmt->stmt) {
364 array_init(retval);
365 #if defined(MYSQLI_USE_MYSQLND)
366 if (stmt->stmt->data && stmt->stmt->data->error_info) {
367 MYSQLND_ERROR_LIST_ELEMENT * message;
368 zend_llist_position pos;
369 for (message = (MYSQLND_ERROR_LIST_ELEMENT *) zend_llist_get_first_ex(&stmt->stmt->data->error_info->error_list, &pos);
370 message;
371 message = (MYSQLND_ERROR_LIST_ELEMENT *) zend_llist_get_next_ex(&stmt->stmt->data->error_info->error_list, &pos))
372 {
373 zval single_error;
374 array_init(&single_error);
375 add_assoc_long_ex(&single_error, "errno", sizeof("errno") - 1, message->error_no);
376 add_assoc_string_ex(&single_error, "sqlstate", sizeof("sqlstate") - 1, message->sqlstate);
377 add_assoc_string_ex(&single_error, "error", sizeof("error") - 1, message->error);
378 add_next_index_zval(retval, &single_error);
379 }
380 }
381 #else
382 if (mysql_stmt_errno(stmt->stmt)) {
383 zval single_error;
384 array_init(&single_error);
385 add_assoc_long_ex(&single_error, "errno", sizeof("errno") - 1, mysql_stmt_errno(stmt->stmt));
386 add_assoc_string_ex(&single_error, "sqlstate", sizeof("sqlstate") - 1, mysql_stmt_sqlstate(stmt->stmt));
387 add_assoc_string_ex(&single_error, "error", sizeof("error") - 1, mysql_stmt_error(stmt->stmt));
388 add_next_index_zval(retval, &single_error);
389 }
390 #endif
391 } else {
392 ZVAL_EMPTY_ARRAY(retval);
393 }
394
395 return SUCCESS;
396 }
397 /* }}} */
398
399 MYSQLI_MAP_PROPERTY_FUNC_LONG(stmt_insert_id_read, mysql_stmt_insert_id, MYSQLI_GET_STMT(MYSQLI_STATUS_VALID), my_ulonglong, MYSQLI_LLU_SPEC)
400 MYSQLI_MAP_PROPERTY_FUNC_LONG(stmt_num_rows_read, mysql_stmt_num_rows, MYSQLI_GET_STMT(MYSQLI_STATUS_VALID), my_ulonglong, MYSQLI_LLU_SPEC)
401 MYSQLI_MAP_PROPERTY_FUNC_LONG(stmt_param_count_read, mysql_stmt_param_count, MYSQLI_GET_STMT(MYSQLI_STATUS_VALID), zend_ulong, ZEND_ULONG_FMT)
402 MYSQLI_MAP_PROPERTY_FUNC_LONG(stmt_field_count_read, mysql_stmt_field_count, MYSQLI_GET_STMT(MYSQLI_STATUS_VALID), zend_ulong, ZEND_ULONG_FMT)
403 MYSQLI_MAP_PROPERTY_FUNC_LONG(stmt_errno_read, mysql_stmt_errno, MYSQLI_GET_STMT(MYSQLI_STATUS_INITIALIZED), zend_ulong, ZEND_ULONG_FMT)
404 MYSQLI_MAP_PROPERTY_FUNC_STRING(stmt_error_read, mysql_stmt_error, MYSQLI_GET_STMT(MYSQLI_STATUS_INITIALIZED))
405 MYSQLI_MAP_PROPERTY_FUNC_STRING(stmt_sqlstate_read, mysql_stmt_sqlstate, MYSQLI_GET_STMT(MYSQLI_STATUS_INITIALIZED))
406
407 /* }}} */
408 const mysqli_property_entry mysqli_link_property_entries[] = {
409 {"affected_rows", sizeof("affected_rows") - 1, link_affected_rows_read, NULL},
410 {"client_info", sizeof("client_info") - 1, link_client_info_read, NULL},
411 {"client_version", sizeof("client_version") - 1, link_client_version_read, NULL},
412 {"connect_errno", sizeof("connect_errno") - 1, link_connect_errno_read, NULL},
413 {"connect_error", sizeof("connect_error") - 1, link_connect_error_read, NULL},
414 {"errno", sizeof("errno") - 1, link_errno_read, NULL},
415 {"error", sizeof("error") - 1, link_error_read, NULL},
416 {"error_list", sizeof("error_list") - 1, link_error_list_read, NULL},
417 {"field_count", sizeof("field_count") - 1, link_field_count_read, NULL},
418 {"host_info", sizeof("host_info") - 1, link_host_info_read, NULL},
419 {"info", sizeof("info") - 1, link_info_read, NULL},
420 {"insert_id", sizeof("insert_id") - 1, link_insert_id_read, NULL},
421 {"server_info", sizeof("server_info") - 1, link_server_info_read, NULL},
422 {"server_version", sizeof("server_version") - 1, link_server_version_read, NULL},
423 {"sqlstate", sizeof("sqlstate") - 1, link_sqlstate_read, NULL},
424 {"protocol_version",sizeof("protocol_version") - 1, link_protocol_version_read, NULL},
425 {"thread_id", sizeof("thread_id") - 1, link_thread_id_read, NULL},
426 {"warning_count", sizeof("warning_count") - 1, link_warning_count_read, NULL},
427 {NULL, 0, NULL, NULL}
428 };
429
430
431 const mysqli_property_entry mysqli_result_property_entries[] = {
432 {"current_field",sizeof("current_field")-1, result_current_field_read, NULL},
433 {"field_count", sizeof("field_count") - 1, result_field_count_read, NULL},
434 {"lengths", sizeof("lengths") - 1, result_lengths_read, NULL},
435 {"num_rows", sizeof("num_rows") - 1, result_num_rows_read, NULL},
436 {"type", sizeof("type") - 1, result_type_read, NULL},
437 {NULL, 0, NULL, NULL}
438 };
439
440 const mysqli_property_entry mysqli_stmt_property_entries[] = {
441 {"affected_rows", sizeof("affected_rows")-1,stmt_affected_rows_read, NULL},
442 {"insert_id", sizeof("insert_id") - 1, stmt_insert_id_read, NULL},
443 {"num_rows", sizeof("num_rows") - 1, stmt_num_rows_read, NULL},
444 {"param_count", sizeof("param_count") - 1, stmt_param_count_read, NULL},
445 {"field_count", sizeof("field_count") - 1, stmt_field_count_read, NULL},
446 {"errno", sizeof("errno") - 1, stmt_errno_read, NULL},
447 {"error", sizeof("error") - 1, stmt_error_read, NULL},
448 {"error_list", sizeof("error_list") - 1, stmt_error_list_read, NULL},
449 {"sqlstate", sizeof("sqlstate") - 1, stmt_sqlstate_read, NULL},
450 {"id", sizeof("id") - 1, stmt_id_read, NULL},
451 {NULL, 0, NULL, NULL}
452 };
453