#ifdef HAVE_CONFIG_H #include "config.h" #endif #include "php.h" #include "php_ini.h" #include "ext/standard/info.h" #include "ext/standard/php_smart_str.h" #include "ext/standard/php_incomplete_class.h" #include "ext/standard/php_var.h" #include "ext/session/php_session.h" #include "php_msgpack.h" #include "msgpack_pack.h" #include "msgpack_unpack.h" #include "msgpack_class.h" #include "msgpack_convert.h" #include "msgpack_errors.h" #include "msgpack/version.h" ZEND_DECLARE_MODULE_GLOBALS(msgpack) static ZEND_FUNCTION(msgpack_serialize); static ZEND_FUNCTION(msgpack_unserialize); ZEND_BEGIN_ARG_INFO_EX(arginfo_msgpack_serialize, 0, 0, 1) ZEND_ARG_INFO(0, value) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_msgpack_unserialize, 0, 0, 1) ZEND_ARG_INFO(0, str) ZEND_ARG_INFO(0, object) ZEND_END_ARG_INFO() PHP_INI_BEGIN() STD_PHP_INI_BOOLEAN( "msgpack.error_display", "1", PHP_INI_ALL, OnUpdateBool, error_display, zend_msgpack_globals, msgpack_globals) STD_PHP_INI_BOOLEAN( "msgpack.php_only", "1", PHP_INI_ALL, OnUpdateBool, php_only, zend_msgpack_globals, msgpack_globals) STD_PHP_INI_BOOLEAN( "msgpack.illegal_key_insert", "0", PHP_INI_ALL, OnUpdateBool, illegal_key_insert, zend_msgpack_globals, msgpack_globals) PHP_INI_END() PS_SERIALIZER_FUNCS(msgpack); static const zend_function_entry msgpack_functions[] = { ZEND_FE(msgpack_serialize, arginfo_msgpack_serialize) ZEND_FE(msgpack_unserialize, arginfo_msgpack_unserialize) ZEND_FALIAS(msgpack_pack, msgpack_serialize, arginfo_msgpack_serialize) ZEND_FALIAS(msgpack_unpack, msgpack_unserialize, arginfo_msgpack_unserialize) {NULL, NULL, NULL} }; static void msgpack_init_globals(zend_msgpack_globals *msgpack_globals) { TSRMLS_FETCH(); if (PG(display_errors)) { msgpack_globals->error_display = 1; } else { msgpack_globals->error_display = 0; } msgpack_globals->php_only = 1; msgpack_globals->illegal_key_insert = 0; } static ZEND_MINIT_FUNCTION(msgpack) { ZEND_INIT_MODULE_GLOBALS(msgpack, msgpack_init_globals, NULL); REGISTER_INI_ENTRIES(); #if HAVE_PHP_SESSION php_session_register_serializer("msgpack", PS_SERIALIZER_ENCODE_NAME(msgpack), PS_SERIALIZER_DECODE_NAME(msgpack)); #endif msgpack_init_class(); #if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION < 1) REGISTER_LONG_CONSTANT( "MESSAGEPACK_OPT_PHPONLY", MSGPACK_CLASS_OPT_PHPONLY, CONST_CS | CONST_PERSISTENT); #endif return SUCCESS; } static ZEND_MSHUTDOWN_FUNCTION(msgpack) { UNREGISTER_INI_ENTRIES(); return SUCCESS; } static ZEND_MINFO_FUNCTION(msgpack) { php_info_print_table_start(); php_info_print_table_row(2, "MessagePack Support", "enabled"); #if HAVE_PHP_SESSION php_info_print_table_row(2, "Session Support", "enabled" ); #endif php_info_print_table_row(2, "extension Version", MSGPACK_EXTENSION_VERSION); php_info_print_table_row(2, "header Version", MSGPACK_VERSION); php_info_print_table_end(); DISPLAY_INI_ENTRIES(); } zend_module_entry msgpack_module_entry = { #if ZEND_MODULE_API_NO >= 20010901 STANDARD_MODULE_HEADER, #endif "msgpack", msgpack_functions, ZEND_MINIT(msgpack), ZEND_MSHUTDOWN(msgpack), NULL, NULL, ZEND_MINFO(msgpack), #if ZEND_MODULE_API_NO >= 20010901 MSGPACK_EXTENSION_VERSION, #endif STANDARD_MODULE_PROPERTIES }; #ifdef COMPILE_DL_MSGPACK ZEND_GET_MODULE(msgpack) #endif PS_SERIALIZER_ENCODE_FUNC(msgpack) { smart_str buf = {0}; msgpack_serialize_data_t var_hash; PHP_VAR_SERIALIZE_INIT(var_hash); #if PHP_API_VERSION < 20100412 msgpack_serialize_zval(&buf, PS(http_session_vars), &var_hash TSRMLS_CC); #else msgpack_serialize_zval(&buf, PS(http_session_vars), var_hash TSRMLS_CC); #endif if (newlen) { *newlen = buf.len; } smart_str_0(&buf); *newstr = buf.c; PHP_VAR_SERIALIZE_DESTROY(var_hash); return SUCCESS; } PS_SERIALIZER_DECODE_FUNC(msgpack) { int ret; HashTable *tmp_hash; HashPosition tmp_hash_pos; char *key_str; ulong key_long; uint key_len; zval *tmp; zval **value; size_t off = 0; msgpack_unpack_t mp; msgpack_unserialize_data_t var_hash; ALLOC_INIT_ZVAL(tmp); template_init(&mp); msgpack_unserialize_var_init(&var_hash); mp.user.retval = (zval *)tmp; mp.user.var_hash = (msgpack_unserialize_data_t *)&var_hash; ret = template_execute(&mp, (char *)val, (size_t)vallen, &off); if (ret == MSGPACK_UNPACK_EXTRA_BYTES || ret == MSGPACK_UNPACK_SUCCESS) { msgpack_unserialize_var_destroy(&var_hash, 0); tmp_hash = HASH_OF(tmp); zend_hash_internal_pointer_reset_ex(tmp_hash, &tmp_hash_pos); while (zend_hash_get_current_data_ex( tmp_hash, (void *)&value, &tmp_hash_pos) == SUCCESS) { ret = zend_hash_get_current_key_ex( tmp_hash, &key_str, &key_len, &key_long, 0, &tmp_hash_pos); switch (ret) { case HASH_KEY_IS_LONG: /* ??? */ break; case HASH_KEY_IS_STRING: php_set_session_var( key_str, key_len - 1, *value, NULL TSRMLS_CC); php_add_session_var(key_str, key_len - 1 TSRMLS_CC); break; } zend_hash_move_forward_ex(tmp_hash, &tmp_hash_pos); } } else { msgpack_unserialize_var_destroy(&var_hash, 1); } zval_ptr_dtor(&tmp); return SUCCESS; } PHP_MSGPACK_API void php_msgpack_serialize(smart_str *buf, zval *val TSRMLS_DC) { msgpack_serialize_data_t var_hash; PHP_VAR_SERIALIZE_INIT(var_hash); #if PHP_API_VERSION < 20100412 msgpack_serialize_zval(buf, val, &var_hash TSRMLS_CC); #else msgpack_serialize_zval(buf, val, var_hash TSRMLS_CC); #endif PHP_VAR_SERIALIZE_DESTROY(var_hash); } PHP_MSGPACK_API void php_msgpack_unserialize( zval *return_value, char *str, size_t str_len TSRMLS_DC) { int ret; size_t off = 0; msgpack_unpack_t mp; msgpack_unserialize_data_t var_hash; if (str_len <= 0) { RETURN_NULL(); } template_init(&mp); msgpack_unserialize_var_init(&var_hash); mp.user.retval = (zval *)return_value; mp.user.var_hash = (msgpack_unserialize_data_t *)&var_hash; ret = template_execute(&mp, str, (size_t)str_len, &off); switch (ret) { case MSGPACK_UNPACK_PARSE_ERROR: msgpack_unserialize_var_destroy(&var_hash, 1); MSGPACK_WARNING("[msgpack] (%s) Parse error", __FUNCTION__); break; case MSGPACK_UNPACK_CONTINUE: msgpack_unserialize_var_destroy(&var_hash, 1); MSGPACK_WARNING( "[msgpack] (%s) Insufficient data for unserializing", __FUNCTION__); break; case MSGPACK_UNPACK_EXTRA_BYTES: case MSGPACK_UNPACK_SUCCESS: msgpack_unserialize_var_destroy(&var_hash, 0); if (off < (size_t)str_len) { MSGPACK_WARNING("[msgpack] (%s) Extra bytes", __FUNCTION__); } break; default: msgpack_unserialize_var_destroy(&var_hash, 0); MSGPACK_WARNING("[msgpack] (%s) Unknown result", __FUNCTION__); break; } } static ZEND_FUNCTION(msgpack_serialize) { zval *parameter; smart_str buf = {0}; if (zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "z", ¶meter) == FAILURE) { return; } php_msgpack_serialize(&buf, parameter TSRMLS_CC); ZVAL_STRINGL(return_value, buf.c, buf.len, 1); smart_str_free(&buf); } static ZEND_FUNCTION(msgpack_unserialize) { char *str; int str_len; zval *object = NULL; if (zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "s|z", &str, &str_len, &object) == FAILURE) { return; } if (!str_len) { RETURN_NULL(); } if (object == NULL) { php_msgpack_unserialize(return_value, str, str_len TSRMLS_CC); } else { zval *zv; ALLOC_INIT_ZVAL(zv); php_msgpack_unserialize(zv, str, str_len TSRMLS_CC); if (msgpack_convert_template(return_value, object, &zv) != SUCCESS) { RETURN_NULL(); } } }