diff --git a/.travis.yml b/.travis.yml index 3f5d7438..8cd375b9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,16 +5,6 @@ sudo: false services: - rabbitmq -#install: -# - sudo apt-get update -# - sudo apt-get -qq --fix-missing install valgrind -# -# - wget -qO - http://www.rabbitmq.com/rabbitmq-signing-key-public.asc | sudo apt-key add - -# - sudo add-apt-repository 'deb http://www.rabbitmq.com/debian/ testing main' -# - sudo apt-get update -# - sudo apt-get install --only-upgrade -y rabbitmq-server -# - sudo service rabbitmq-server restart - env: global: - NO_INTERACTION=1 @@ -25,53 +15,35 @@ matrix: - php: next include: - - php: nightly - env: LIBRABBITMQ_VERSION=master - php: nightly env: LIBRABBITMQ_VERSION=master TEST_PHP_ARGS=-m - - php: 7.1 - env: LIBRABBITMQ_VERSION=master - php: 7.1 env: LIBRABBITMQ_VERSION=master TEST_PHP_ARGS=-m - php: 7.1 env: LIBRABBITMQ_VERSION=v0.8.0 TEST_PHP_ARGS=-m - - php: 7.1 - env: LIBRABBITMQ_VERSION=v0.8.0 - php: 7.1 env: LIBRABBITMQ_VERSION=v0.7.1 TEST_PHP_ARGS=-m - php: 7.1 - env: LIBRABBITMQ_VERSION=v0.7.1 + env: LIBRABBITMQ_VERSION=v0.5.2 TEST_PHP_ARGS=-m - php: 7.0 env: LIBRABBITMQ_VERSION=master TEST_PHP_ARGS=-m - - php: 7.0 - env: LIBRABBITMQ_VERSION=master - php: 7.0 env: LIBRABBITMQ_VERSION=v0.8.0 TEST_PHP_ARGS=-m - - php: 7.0 - env: LIBRABBITMQ_VERSION=v0.8.0 - php: 7.0 env: LIBRABBITMQ_VERSION=v0.7.1 TEST_PHP_ARGS=-m - php: 7.0 - env: LIBRABBITMQ_VERSION=v0.7.1 + env: LIBRABBITMQ_VERSION=v0.5.2 TEST_PHP_ARGS=-m - php: 5.6 env: LIBRABBITMQ_VERSION=master TEST_PHP_ARGS=-m - - php: 5.6 - env: LIBRABBITMQ_VERSION=master - php: 5.6 env: LIBRABBITMQ_VERSION=v0.8.0 TEST_PHP_ARGS=-m - - php: 5.6 - env: LIBRABBITMQ_VERSION=v0.8.0 - php: 5.6 env: LIBRABBITMQ_VERSION=v0.7.1 TEST_PHP_ARGS=-m - - php: 5.6 - env: LIBRABBITMQ_VERSION=v0.7.1 - php: 5.6 env: LIBRABBITMQ_VERSION=v0.5.2 TEST_PHP_ARGS=-m - - php: 5.6 - env: LIBRABBITMQ_VERSION=v0.5.2 - php: 5.5 env: LIBRABBITMQ_VERSION=master TEST_PHP_ARGS=-m diff --git a/amqp.c b/amqp.c index 8bf1272c..3b3f4913 100644 --- a/amqp.c +++ b/amqp.c @@ -20,9 +20,6 @@ | - Jonathan Tansavatdi | +----------------------------------------------------------------------+ */ - -/* $Id: amqp.c 327551 2012-09-09 03:49:34Z pdezwart $ */ - #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -45,13 +42,12 @@ #include "php_amqp.h" #include "amqp_connection.h" +#include "amqp_connection_resource.h" #include "amqp_channel.h" -#include "amqp_queue.h" -#include "amqp_exchange.h" #include "amqp_envelope.h" -#include "amqp_basic_properties.h" -#include "amqp_connection_resource.h" - +#include "amqp_exchange.h" +#include "amqp_queue.h" +#include "amqp_timestamp.h" #ifdef PHP_WIN32 # include "win32/unistd.h" @@ -59,20 +55,14 @@ # include #endif -#include "amqp_connection.h" -#include "amqp_connection_resource.h" -#include "amqp_channel.h" -#include "amqp_envelope.h" -#include "amqp_exchange.h" -#include "amqp_queue.h" - /* True global resources - no need for thread safety here */ zend_class_entry *amqp_exception_class_entry, *amqp_connection_exception_class_entry, *amqp_channel_exception_class_entry, *amqp_queue_exception_class_entry, - *amqp_exchange_exception_class_entry; + *amqp_exchange_exception_class_entry, + *amqp_value_exception_class_entry; /* {{{ amqp_functions[] * @@ -90,7 +80,7 @@ PHP_INI_BEGIN() PHP_INI_ENTRY("amqp.timeout", DEFAULT_TIMEOUT, PHP_INI_ALL, NULL) PHP_INI_ENTRY("amqp.read_timeout", DEFAULT_READ_TIMEOUT, PHP_INI_ALL, NULL) PHP_INI_ENTRY("amqp.write_timeout", DEFAULT_WRITE_TIMEOUT, PHP_INI_ALL, NULL) - PHP_INI_ENTRY("amqp.connect_timeout", DEFAULT_CONNECT_TIMEOUT, PHP_INI_ALL, NULL) + PHP_INI_ENTRY("amqp.connect_timeout", DEFAULT_CONNECT_TIMEOUT, PHP_INI_ALL, NULL) PHP_INI_ENTRY("amqp.login", DEFAULT_LOGIN, PHP_INI_ALL, NULL) PHP_INI_ENTRY("amqp.password", DEFAULT_PASSWORD, PHP_INI_ALL, NULL) PHP_INI_ENTRY("amqp.auto_ack", DEFAULT_AUTOACK, PHP_INI_ALL, NULL) @@ -126,6 +116,7 @@ static PHP_MINIT_FUNCTION(amqp) /* {{{ */ PHP_MINIT(amqp_exchange)(INIT_FUNC_ARGS_PASSTHRU); PHP_MINIT(amqp_basic_properties)(INIT_FUNC_ARGS_PASSTHRU); PHP_MINIT(amqp_envelope)(INIT_FUNC_ARGS_PASSTHRU); + PHP_MINIT(amqp_timestamp)(INIT_FUNC_ARGS_PASSTHRU); /* Class Exceptions */ INIT_CLASS_ENTRY(ce, "AMQPException", NULL); @@ -143,6 +134,9 @@ static PHP_MINIT_FUNCTION(amqp) /* {{{ */ INIT_CLASS_ENTRY(ce, "AMQPExchangeException", NULL); amqp_exchange_exception_class_entry = PHP5to7_zend_register_internal_class_ex(&ce, amqp_exception_class_entry); + INIT_CLASS_ENTRY(ce, "AMQPValueException", NULL); + amqp_value_exception_class_entry = PHP5to7_zend_register_internal_class_ex(&ce, amqp_exception_class_entry); + REGISTER_INI_ENTRIES(); REGISTER_LONG_CONSTANT("AMQP_NOPARAM", AMQP_NOPARAM, CONST_CS | CONST_PERSISTENT); @@ -329,207 +323,6 @@ void php_amqp_maybe_release_buffers_on_channel(amqp_connection_resource *connect } } -amqp_bytes_t php_amqp_long_string(char const *cstr, PHP5to7_param_str_len_type_t len) -{ - if (len < 1) { - return amqp_empty_bytes; - } - - amqp_bytes_t result; - result.len = (size_t)len; - result.bytes = (void *) cstr; - - return result; -} - -char *stringify_bytes(amqp_bytes_t bytes) -{ -/* We will need up to 4 chars per byte, plus the terminating 0 */ - char *res = emalloc(bytes.len * 4 + 1); - uint8_t *data = bytes.bytes; - char *p = res; - size_t i; - - for (i = 0; i < bytes.len; i++) { - if (data[i] >= 32 && data[i] != 127) { - *p++ = data[i]; - } else { - *p++ = '\\'; - *p++ = '0' + (data[i] >> 6); - *p++ = '0' + (data[i] >> 3 & 0x7); - *p++ = '0' + (data[i] & 0x7); - } - } - - *p = 0; - return res; -} - -void internal_convert_zval_to_amqp_table(zval *zvalArguments, amqp_table_t *arguments, char allow_int_keys TSRMLS_DC) -{ - HashTable *ht; - HashPosition pos; - - zval *value; - zval **data; - - PHP5to7_ZEND_REAL_HASH_KEY_T *real_key; - - char *key; - uint key_len; - - ulong index; - - char type[16]; - amqp_table_t *inner_table; - - ht = Z_ARRVAL_P(zvalArguments); - - /* Allocate all the memory necessary for storing the arguments */ - arguments->entries = (amqp_table_entry_t *)ecalloc((size_t)zend_hash_num_elements(ht), sizeof(amqp_table_entry_t)); - arguments->num_entries = 0; - - PHP5to7_ZEND_HASH_FOREACH_KEY_VAL(ht, index, real_key, key, key_len, data, value, pos) { - char *strKey; - char *strValue; - amqp_table_entry_t *table; - amqp_field_value_t *field; - - - /* Now pull the key */ - - if (!PHP5to7_ZEND_HASH_KEY_IS_STRING(ht, real_key, key, key_len, index, pos)) { - if (allow_int_keys) { - /* Convert to strings non-string keys */ - char str[32]; - - key_len = sprintf(str, "%lu", index); - key = str; - } else { - /* Skip things that are not strings */ - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Ignoring non-string header field '%lu'", index); - - - - PHP5to7_ZEND_HASH_FOREACH_CONTINUE; - } - } else { - PHP5to7_ZEND_HASH_KEY_MAYBE_UNPACK(real_key, key, key_len); - } - - /* Build the value */ - table = &arguments->entries[arguments->num_entries++]; - field = &table->value; - - switch (Z_TYPE_P(value)) { - PHP5to7_CASE_IS_BOOL: - field->kind = AMQP_FIELD_KIND_BOOLEAN; - field->value.boolean = (amqp_boolean_t)!PHP5to7_IS_FALSE_P(value); - break; - case IS_DOUBLE: - field->kind = AMQP_FIELD_KIND_F64; - field->value.f64 = Z_DVAL_P(value); - break; - case IS_LONG: - field->kind = AMQP_FIELD_KIND_I64; - field->value.i64 = Z_LVAL_P(value); - break; - case IS_STRING: - field->kind = AMQP_FIELD_KIND_UTF8; - - if (Z_STRLEN_P(value)) { - amqp_bytes_t bytes; - bytes.len = (size_t) Z_STRLEN_P(value); - bytes.bytes = estrndup(Z_STRVAL_P(value), (uint)Z_STRLEN_P(value)); - - field->value.bytes = bytes; - } else { - field->value.bytes = amqp_empty_bytes; - } - - break; - case IS_ARRAY: - field->kind = AMQP_FIELD_KIND_TABLE; - internal_convert_zval_to_amqp_table(value, &field->value.table, 1 TSRMLS_CC); - - break; - case IS_NULL: - field->kind = AMQP_FIELD_KIND_VOID; - break; - default: - switch(Z_TYPE_P(value)) { - case IS_OBJECT: strcpy(type, "object"); break; - case IS_RESOURCE: strcpy(type, "resource"); break; - default: strcpy(type, "unknown"); - } - - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Ignoring field '%s' due to unsupported value type (%s)", key, type); - - /* Reset entries counter back */ - arguments->num_entries --; - - PHP5to7_ZEND_HASH_FOREACH_CONTINUE; - } - - strKey = estrndup(key, key_len); - table->key = amqp_cstring_bytes(strKey); - - } PHP5to7_ZEND_HASH_FOREACH_END(); -}; - -amqp_table_t *convert_zval_to_amqp_table(zval *zvalArguments TSRMLS_DC) -{ - amqp_table_t *arguments; - /* In setArguments, we are overwriting all the existing values */ - arguments = (amqp_table_t *)emalloc(sizeof(amqp_table_t)); - - internal_convert_zval_to_amqp_table(zvalArguments, arguments, 0 TSRMLS_CC); - - return arguments; -} - - - - -void internal_php_amqp_free_amqp_table(amqp_table_t *object, char clear_root) -{ - if (!object) { - return; - } - - if (object->entries) { - int macroEntryCounter; - for (macroEntryCounter = 0; macroEntryCounter < object->num_entries; macroEntryCounter++) { - - amqp_table_entry_t *entry = &object->entries[macroEntryCounter]; - efree(entry->key.bytes); - - switch (entry->value.kind) { - case AMQP_FIELD_KIND_TABLE: - internal_php_amqp_free_amqp_table(&entry->value.value.table, 0); - break; - case AMQP_FIELD_KIND_UTF8: - if (entry->value.value.bytes.bytes) { - efree(entry->value.value.bytes.bytes); - } - break; - default: - break; - } - } - efree(object->entries); - } - - if (clear_root) { - efree(object); - } -} - -void php_amqp_free_amqp_table(amqp_table_t *object) -{ - internal_php_amqp_free_amqp_table(object, 1); -} - /* *Local variables: *tab-width: 4 diff --git a/amqp_basic_properties.c b/amqp_basic_properties.c index bec00207..43f4320d 100644 --- a/amqp_basic_properties.c +++ b/amqp_basic_properties.c @@ -29,30 +29,28 @@ #include "php_ini.h" #include "ext/standard/info.h" #include "zend_exceptions.h" - -#ifdef PHP_WIN32 -# include "win32/php_stdint.h" -# include "win32/signal.h" -#else - -# include -# include - -#endif +#include "Zend/zend_interfaces.h" #include #include #ifdef PHP_WIN32 # include "win32/unistd.h" +# include "win32/php_stdint.h" +# include "win32/signal.h" #else - +# include +# include # include +#endif +#if HAVE_INTTYPES_H +# include #endif #include "amqp_basic_properties.h" #include "php_amqp.h" +#include "amqp_timestamp.h" zend_class_entry *amqp_basic_properties_class_entry; #define this_ce amqp_basic_properties_class_entry @@ -361,7 +359,7 @@ PHP_MINIT_FUNCTION (amqp_basic_properties) { } -void parse_amqp_table(amqp_table_t *table, zval *result) { +void parse_amqp_table(amqp_table_t *table, zval *result TSRMLS_DC) { int i; zend_bool has_value = 0; @@ -378,25 +376,35 @@ void parse_amqp_table(amqp_table_t *table, zval *result) { case AMQP_FIELD_KIND_BOOLEAN: ZVAL_BOOL(PHP5to7_MAYBE_PTR(value), entry->value.value.boolean); break; - case AMQP_FIELD_KIND_I8: ZVAL_LONG(PHP5to7_MAYBE_PTR(value), entry->value.value.i8); + case AMQP_FIELD_KIND_I8: + ZVAL_LONG(PHP5to7_MAYBE_PTR(value), entry->value.value.i8); break; - case AMQP_FIELD_KIND_U8: ZVAL_LONG(PHP5to7_MAYBE_PTR(value), entry->value.value.u8); + case AMQP_FIELD_KIND_U8: + ZVAL_LONG(PHP5to7_MAYBE_PTR(value), entry->value.value.u8); break; - case AMQP_FIELD_KIND_I16: ZVAL_LONG(PHP5to7_MAYBE_PTR(value), entry->value.value.i16); + case AMQP_FIELD_KIND_I16: + ZVAL_LONG(PHP5to7_MAYBE_PTR(value), entry->value.value.i16); break; - case AMQP_FIELD_KIND_U16: ZVAL_LONG(PHP5to7_MAYBE_PTR(value), entry->value.value.u16); + case AMQP_FIELD_KIND_U16: + ZVAL_LONG(PHP5to7_MAYBE_PTR(value), entry->value.value.u16); break; - case AMQP_FIELD_KIND_I32: ZVAL_LONG(PHP5to7_MAYBE_PTR(value), entry->value.value.i32); + case AMQP_FIELD_KIND_I32: + ZVAL_LONG(PHP5to7_MAYBE_PTR(value), entry->value.value.i32); break; - case AMQP_FIELD_KIND_U32: ZVAL_LONG(PHP5to7_MAYBE_PTR(value), entry->value.value.u32); + case AMQP_FIELD_KIND_U32: + ZVAL_LONG(PHP5to7_MAYBE_PTR(value), entry->value.value.u32); break; - case AMQP_FIELD_KIND_I64: ZVAL_LONG(PHP5to7_MAYBE_PTR(value), entry->value.value.i64); + case AMQP_FIELD_KIND_I64: + ZVAL_LONG(PHP5to7_MAYBE_PTR(value), entry->value.value.i64); break; - case AMQP_FIELD_KIND_U64: ZVAL_LONG(PHP5to7_MAYBE_PTR(value), entry->value.value.i64); + case AMQP_FIELD_KIND_U64: + ZVAL_LONG(PHP5to7_MAYBE_PTR(value), entry->value.value.i64); break; - case AMQP_FIELD_KIND_F32: ZVAL_DOUBLE(PHP5to7_MAYBE_PTR(value), entry->value.value.f32); + case AMQP_FIELD_KIND_F32: + ZVAL_DOUBLE(PHP5to7_MAYBE_PTR(value), entry->value.value.f32); break; - case AMQP_FIELD_KIND_F64: ZVAL_DOUBLE(PHP5to7_MAYBE_PTR(value), entry->value.value.f64); + case AMQP_FIELD_KIND_F64: + ZVAL_DOUBLE(PHP5to7_MAYBE_PTR(value), entry->value.value.f64); break; case AMQP_FIELD_KIND_UTF8: case AMQP_FIELD_KIND_BYTES: @@ -421,7 +429,7 @@ void parse_amqp_table(amqp_table_t *table, zval *result) { parse_amqp_table( &(entry->value.value.array.entries[j].value.table), - PHP5to7_MAYBE_PTR(subtable) + PHP5to7_MAYBE_PTR(subtable) TSRMLS_CC ); add_next_index_zval(PHP5to7_MAYBE_PTR(value), PHP5to7_MAYBE_PTR(subtable)); } @@ -434,11 +442,35 @@ void parse_amqp_table(amqp_table_t *table, zval *result) { break; case AMQP_FIELD_KIND_TABLE: PHP5to7_ARRAY_INIT(value); - parse_amqp_table(&(entry->value.value.table), PHP5to7_MAYBE_PTR(value)); + parse_amqp_table(&(entry->value.value.table), PHP5to7_MAYBE_PTR(value) TSRMLS_CC); break; - case AMQP_FIELD_KIND_TIMESTAMP: ZVAL_DOUBLE(PHP5to7_MAYBE_PTR(value), entry->value.value.u64); - break; - case AMQP_FIELD_KIND_VOID: ZVAL_NULL(PHP5to7_MAYBE_PTR(value)); + + case AMQP_FIELD_KIND_TIMESTAMP: { + char timestamp_str[20]; + PHP5to7_zval_t timestamp PHP5to7_MAYBE_SET_TO_NULL; + PHP5to7_MAYBE_INIT(timestamp); + + snprintf(timestamp_str, sizeof(timestamp_str), ZEND_ULONG_FMT, entry->value.value.u64); + #if PHP_MAJOR_VERSION >= 7 + ZVAL_STRING(PHP5to7_MAYBE_PTR(timestamp), (char *)timestamp_str); + #else + ZVAL_STRING(PHP5to7_MAYBE_PTR(timestamp), (char *)timestamp_str, 0); + #endif + object_init_ex(PHP5to7_MAYBE_PTR(value), amqp_timestamp_class_entry); + + zend_call_method_with_1_params( + &value, + amqp_timestamp_class_entry, + NULL, + "__construct", + NULL, + PHP5to7_MAYBE_PTR(timestamp) + ); + break; + } + + case AMQP_FIELD_KIND_VOID: + ZVAL_NULL(PHP5to7_MAYBE_PTR(value)); break; case AMQP_FIELD_KIND_DECIMAL: /* TODO: add decimals support */ @@ -481,7 +513,7 @@ void php_amqp_basic_properties_extract(amqp_basic_properties_t *p, zval *obj TSR } if (p->_flags & AMQP_BASIC_HEADERS_FLAG) { - parse_amqp_table(&(p->headers), PHP5to7_MAYBE_PTR(headers)); + parse_amqp_table(&(p->headers), PHP5to7_MAYBE_PTR(headers) TSRMLS_CC); } zend_update_property(this_ce, obj, ZEND_STRL("headers"), PHP5to7_MAYBE_PTR(headers) TSRMLS_CC); diff --git a/amqp_basic_properties.h b/amqp_basic_properties.h index a66fa17b..a1233627 100644 --- a/amqp_basic_properties.h +++ b/amqp_basic_properties.h @@ -26,7 +26,7 @@ extern zend_class_entry *amqp_basic_properties_class_entry; -void parse_amqp_table(amqp_table_t *table, zval *result); +void parse_amqp_table(amqp_table_t *table, zval *result TSRMLS_DC); void php_amqp_basic_properties_extract(amqp_basic_properties_t *p, zval *obj TSRMLS_DC); diff --git a/amqp_channel.c b/amqp_channel.c index 3c18eb6f..d168a5a0 100644 --- a/amqp_channel.c +++ b/amqp_channel.c @@ -20,9 +20,6 @@ | - Jonathan Tansavatdi | +----------------------------------------------------------------------+ */ - -/* $Id: amqp_channel.c 318036 2011-10-11 20:30:46Z pdezwart $ */ - #ifdef HAVE_CONFIG_H #include "config.h" #endif diff --git a/amqp_channel.h b/amqp_channel.h index 4534322f..97d0a24a 100644 --- a/amqp_channel.h +++ b/amqp_channel.h @@ -20,9 +20,6 @@ | - Jonathan Tansavatdi | +----------------------------------------------------------------------+ */ - -/* $Id: amqp_channel.h 305865 2010-12-01 01:30:56Z pdezwart $ */ - extern zend_class_entry *amqp_channel_class_entry; void php_amqp_close_channel(amqp_channel_resource *channel_resource TSRMLS_DC); diff --git a/amqp_connection.h b/amqp_connection.h index 71c90f09..0b8b5559 100644 --- a/amqp_connection.h +++ b/amqp_connection.h @@ -20,9 +20,6 @@ | - Jonathan Tansavatdi | +----------------------------------------------------------------------+ */ - -/* $Id: amqp_connection.h 326660 2012-07-17 05:32:34Z pdezwart $ */ - #include "php.h" extern zend_class_entry *amqp_connection_class_entry; diff --git a/amqp_envelope.c b/amqp_envelope.c index e0922b31..cd5c342b 100644 --- a/amqp_envelope.c +++ b/amqp_envelope.c @@ -20,9 +20,6 @@ | - Jonathan Tansavatdi | +----------------------------------------------------------------------+ */ - -/* $Id: amqp_envelope.c 327551 2012-09-09 03:49:34Z pdezwart $ */ - #ifdef HAVE_CONFIG_H #include "config.h" #endif diff --git a/amqp_envelope.h b/amqp_envelope.h index 634f800e..e63a3a5f 100644 --- a/amqp_envelope.h +++ b/amqp_envelope.h @@ -20,9 +20,6 @@ | - Jonathan Tansavatdi | +----------------------------------------------------------------------+ */ - -/* $Id: amqp_envelope.h 321054 2011-12-16 01:23:28Z pdezwart $ */ - extern zend_class_entry *amqp_envelope_class_entry; void convert_amqp_envelope_to_zval(amqp_envelope_t *amqp_envelope, zval *envelope TSRMLS_DC); diff --git a/amqp_exchange.c b/amqp_exchange.c index e1524333..b0177f81 100644 --- a/amqp_exchange.c +++ b/amqp_exchange.c @@ -20,9 +20,6 @@ | - Jonathan Tansavatdi | +----------------------------------------------------------------------+ */ - -/* $Id: amqp_exchange.c 327551 2012-09-09 03:49:34Z pdezwart $ */ - #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -52,6 +49,7 @@ #include "amqp_connection.h" #include "amqp_channel.h" #include "amqp_exchange.h" +#include "amqp_type.h" zend_class_entry *amqp_exchange_class_entry; #define this_ce amqp_exchange_class_entry @@ -346,7 +344,7 @@ static PHP_METHOD(amqp_exchange_class, declareExchange) return; } - arguments = convert_zval_to_amqp_table(PHP_AMQP_READ_THIS_PROP("arguments") TSRMLS_CC); + arguments = php_amqp_type_convert_zval_to_amqp_table(PHP_AMQP_READ_THIS_PROP("arguments") TSRMLS_CC); #if AMQP_VERSION_MAJOR * 100 + AMQP_VERSION_MINOR * 10 + AMQP_VERSION_PATCH > 52 amqp_exchange_declare( @@ -374,7 +372,7 @@ static PHP_METHOD(amqp_exchange_class, declareExchange) amqp_rpc_reply_t res = amqp_get_rpc_reply(channel_resource->connection_resource->connection_state); - php_amqp_free_amqp_table(arguments); + php_amqp_type_free_amqp_table(arguments); if (PHP_AMQP_MAYBE_ERROR(res, channel_resource)) { php_amqp_zend_throw_exception_short(res, amqp_exchange_exception_class_entry TSRMLS_CC); @@ -591,7 +589,7 @@ static PHP_METHOD(amqp_exchange_class, publish) SEPARATE_ZVAL(tmp); convert_to_array(PHP5to7_MAYBE_DEREF(tmp)); - headers = convert_zval_to_amqp_table(PHP5to7_MAYBE_DEREF(tmp) TSRMLS_CC); + headers = php_amqp_type_convert_zval_to_amqp_table(PHP5to7_MAYBE_DEREF(tmp) TSRMLS_CC); props._flags |= AMQP_BASIC_HEADERS_FLAG; props.headers = *headers; @@ -616,11 +614,11 @@ static PHP_METHOD(amqp_exchange_class, publish) (AMQP_MANDATORY & flags) ? 1 : 0, /* mandatory */ (AMQP_IMMEDIATE & flags) ? 1 : 0, /* immediate */ &props, - php_amqp_long_string(msg, msg_len) /* message body */ + php_amqp_type_char_to_amqp_long(msg, msg_len) /* message body */ ); if (headers) { - php_amqp_free_amqp_table(headers); + php_amqp_type_free_amqp_table(headers); } #ifndef PHP_WIN32 @@ -673,7 +671,7 @@ static PHP_METHOD(amqp_exchange_class, bind) PHP_AMQP_VERIFY_CHANNEL_RESOURCE(channel_resource, "Could not bind to exchange."); if (zvalArguments) { - arguments = convert_zval_to_amqp_table(zvalArguments TSRMLS_CC); + arguments = php_amqp_type_convert_zval_to_amqp_table(zvalArguments TSRMLS_CC); } amqp_exchange_bind( @@ -686,7 +684,7 @@ static PHP_METHOD(amqp_exchange_class, bind) ); if (arguments) { - php_amqp_free_amqp_table(arguments); + php_amqp_type_free_amqp_table(arguments); } amqp_rpc_reply_t res = amqp_get_rpc_reply(channel_resource->connection_resource->connection_state); @@ -730,7 +728,7 @@ static PHP_METHOD(amqp_exchange_class, unbind) PHP_AMQP_VERIFY_CHANNEL_RESOURCE(channel_resource, "Could not unbind from exchange."); if (zvalArguments) { - arguments = convert_zval_to_amqp_table(zvalArguments TSRMLS_CC); + arguments = php_amqp_type_convert_zval_to_amqp_table(zvalArguments TSRMLS_CC); } amqp_exchange_unbind( @@ -743,7 +741,7 @@ static PHP_METHOD(amqp_exchange_class, unbind) ); if (arguments) { - php_amqp_free_amqp_table(arguments); + php_amqp_type_free_amqp_table(arguments); } amqp_rpc_reply_t res = amqp_get_rpc_reply(channel_resource->connection_resource->connection_state); diff --git a/amqp_exchange.h b/amqp_exchange.h index cd33ec1d..a1dbf05a 100644 --- a/amqp_exchange.h +++ b/amqp_exchange.h @@ -20,9 +20,6 @@ | - Jonathan Tansavatdi | +----------------------------------------------------------------------+ */ - -/* $Id: amqp_exchange.h 318206 2011-10-19 04:17:01Z pdezwart $ */ - extern zend_class_entry *amqp_exchange_class_entry; diff --git a/amqp_queue.c b/amqp_queue.c index 2b1dd8c5..db6bc850 100644 --- a/amqp_queue.c +++ b/amqp_queue.c @@ -20,9 +20,6 @@ | - Jonathan Tansavatdi | +----------------------------------------------------------------------+ */ - -/* $Id: amqp_queue.c 327551 2012-09-09 03:49:34Z pdezwart $ */ - #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -53,6 +50,7 @@ #include "amqp_connection.h" #include "amqp_channel.h" #include "amqp_queue.h" +#include "amqp_type.h" zend_class_entry *amqp_queue_class_entry; #define this_ce amqp_queue_class_entry @@ -315,7 +313,7 @@ static PHP_METHOD(amqp_queue_class, declareQueue) channel_resource = PHP_AMQP_GET_CHANNEL_RESOURCE(PHP_AMQP_READ_THIS_PROP("channel")); PHP_AMQP_VERIFY_CHANNEL_RESOURCE(channel_resource, "Could not declare queue."); - arguments = convert_zval_to_amqp_table(PHP_AMQP_READ_THIS_PROP("arguments") TSRMLS_CC); + arguments = php_amqp_type_convert_zval_to_amqp_table(PHP_AMQP_READ_THIS_PROP("arguments") TSRMLS_CC); amqp_queue_declare_ok_t *r = amqp_queue_declare( channel_resource->connection_resource->connection_state, @@ -328,7 +326,7 @@ static PHP_METHOD(amqp_queue_class, declareQueue) *arguments ); - php_amqp_free_amqp_table(arguments); + php_amqp_type_free_amqp_table(arguments); if (!r) { amqp_rpc_reply_t res = amqp_get_rpc_reply(channel_resource->connection_resource->connection_state); @@ -343,7 +341,7 @@ static PHP_METHOD(amqp_queue_class, declareQueue) message_count = r->message_count; /* Set the queue name, in case it is an autogenerated queue name */ - name = stringify_bytes(r->queue); + name = php_amqp_type_amqp_bytes_to_char(r->queue); zend_update_property_string(this_ce, getThis(), ZEND_STRL("name"), name TSRMLS_CC); efree(name); @@ -381,7 +379,7 @@ static PHP_METHOD(amqp_queue_class, bind) PHP_AMQP_VERIFY_CHANNEL_RESOURCE(channel_resource, "Could not bind queue."); if (zvalArguments) { - arguments = convert_zval_to_amqp_table(zvalArguments TSRMLS_CC); + arguments = php_amqp_type_convert_zval_to_amqp_table(zvalArguments TSRMLS_CC); } amqp_queue_bind( @@ -394,7 +392,7 @@ static PHP_METHOD(amqp_queue_class, bind) ); if (arguments) { - php_amqp_free_amqp_table(arguments); + php_amqp_type_free_amqp_table(arguments); } amqp_rpc_reply_t res = amqp_get_rpc_reply(channel_resource->connection_resource->connection_state); @@ -527,7 +525,7 @@ static PHP_METHOD(amqp_queue_class, consume) if (!(AMQP_JUST_CONSUME & flags)) { /* Setup the consume */ - arguments = convert_zval_to_amqp_table(PHP_AMQP_READ_THIS_PROP("arguments") TSRMLS_CC); + arguments = php_amqp_type_convert_zval_to_amqp_table(PHP_AMQP_READ_THIS_PROP("arguments") TSRMLS_CC); amqp_basic_consume_ok_t *r = amqp_basic_consume( channel_resource->connection_resource->connection_state, @@ -540,7 +538,7 @@ static PHP_METHOD(amqp_queue_class, consume) *arguments ); - php_amqp_free_amqp_table(arguments); + php_amqp_type_free_amqp_table(arguments); if (!r) { amqp_rpc_reply_t res = amqp_get_rpc_reply(channel_resource->connection_resource->connection_state); @@ -918,7 +916,7 @@ static PHP_METHOD(amqp_queue_class, unbind) PHP_AMQP_VERIFY_CHANNEL_RESOURCE(channel_resource, "Could not unbind queue."); if (zvalArguments) { - arguments = convert_zval_to_amqp_table(zvalArguments TSRMLS_CC); + arguments = php_amqp_type_convert_zval_to_amqp_table(zvalArguments TSRMLS_CC); } amqp_queue_unbind( @@ -931,7 +929,7 @@ static PHP_METHOD(amqp_queue_class, unbind) ); if (arguments) { - php_amqp_free_amqp_table(arguments); + php_amqp_type_free_amqp_table(arguments); } amqp_rpc_reply_t res = amqp_get_rpc_reply(channel_resource->connection_resource->connection_state); diff --git a/amqp_queue.h b/amqp_queue.h index 53bd8cea..a8088d01 100644 --- a/amqp_queue.h +++ b/amqp_queue.h @@ -20,9 +20,6 @@ | - Jonathan Tansavatdi | +----------------------------------------------------------------------+ */ - -/* $Id: amqp_queue.h 321959 2012-01-09 17:56:10Z pdezwart $ */ - extern zend_class_entry *amqp_queue_class_entry; diff --git a/amqp_timestamp.c b/amqp_timestamp.c new file mode 100644 index 00000000..fa183a7a --- /dev/null +++ b/amqp_timestamp.c @@ -0,0 +1,145 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2007 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Alexandre Kalendarev akalend@mail.ru Copyright (c) 2009-2010 | + | Lead: | + | - Pieter de Zwart | + | Maintainers: | + | - Brad Rodriguez | + | - Jonathan Tansavatdi | + +----------------------------------------------------------------------+ +*/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "php.h" +#include "php_ini.h" +#include "zend_exceptions.h" +#include "php_amqp.h" +#include "ext/standard/php_math.h" + +zend_class_entry *amqp_timestamp_class_entry; +#define this_ce amqp_timestamp_class_entry + +static const double AMQP_TIMESTAMP_MAX = 0xFFFFFFFFFFFFFFFF; +static const double AMQP_TIMESTAMP_MIN = 0; + +/* {{{ proto AMQPTimestamp::__construct(string $timestamp) + */ +static PHP_METHOD(amqp_timestamp_class, __construct) +{ + double timestamp; + zval *timestamp_value; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", ×tamp) == FAILURE) { + return; + } + + if (timestamp < AMQP_TIMESTAMP_MIN) { + zend_throw_exception_ex(amqp_value_exception_class_entry, 0 TSRMLS_CC, "The timestamp parameter must be greater than %0.f.", AMQP_TIMESTAMP_MIN); + return; + } + + if (timestamp > AMQP_TIMESTAMP_MAX) { + zend_throw_exception_ex(amqp_value_exception_class_entry, 0 TSRMLS_CC, "The timestamp parameter must be less than %0.f.", AMQP_TIMESTAMP_MAX); + return; + } + + { + #if PHP_MAJOR_VERSION >= 7 + zend_string *str; + str = _php_math_number_format_ex(timestamp, 0, "", 0, "", 0); + zend_update_property_str(this_ce, getThis(), ZEND_STRL("timestamp"), str); + #else + char *str; + str = _php_math_number_format_ex(timestamp, 0, "", 0, "", 0); + zend_update_property_string(this_ce, getThis(), ZEND_STRL("timestamp"), str TSRMLS_CC); + #endif + } +} +/* }}} */ + + +/* {{{ proto int AMQPTimestamp::getTimestamp() +Get timestamp */ +static PHP_METHOD(amqp_timestamp_class, getTimestamp) +{ + PHP5to7_READ_PROP_RV_PARAM_DECL; + PHP_AMQP_NOPARAMS(); + + PHP_AMQP_RETURN_THIS_PROP("timestamp"); +} +/* }}} */ + + +/* {{{ proto string AMQPTimestamp::__toString() +Return timestamp as string */ +static PHP_METHOD(amqp_timestamp_class, __toString) +{ + PHP5to7_READ_PROP_RV_PARAM_DECL; + PHP_AMQP_NOPARAMS(); + + PHP_AMQP_RETURN_THIS_PROP("timestamp"); +} +/* }}} */ + +ZEND_BEGIN_ARG_INFO_EX(arginfo_amqp_timestamp_class_construct, ZEND_SEND_BY_VAL, ZEND_RETURN_VALUE, 0) + ZEND_ARG_INFO(0, timestamp) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_amqp_timestamp_class_getTimestamp, ZEND_SEND_BY_VAL, ZEND_RETURN_VALUE, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_amqp_timestamp_class_toString, ZEND_SEND_BY_VAL, ZEND_RETURN_VALUE, 0) +ZEND_END_ARG_INFO() + +zend_function_entry amqp_timestamp_class_functions[] = { + PHP_ME(amqp_timestamp_class, __construct, arginfo_amqp_timestamp_class_construct, ZEND_ACC_PUBLIC) + PHP_ME(amqp_timestamp_class, getTimestamp, arginfo_amqp_timestamp_class_getTimestamp, ZEND_ACC_PUBLIC) + PHP_ME(amqp_timestamp_class, __toString, arginfo_amqp_timestamp_class_toString, ZEND_ACC_PUBLIC) + + {NULL, NULL, NULL} +}; + + +PHP_MINIT_FUNCTION(amqp_timestamp) +{ + zend_class_entry ce; + char min[1], max[20]; + int min_len, max_len; + + INIT_CLASS_ENTRY(ce, "AMQPTimestamp", amqp_timestamp_class_functions); + this_ce = zend_register_internal_class(&ce TSRMLS_CC); + this_ce->ce_flags = this_ce->ce_flags | PHP5to7_ZEND_ACC_FINAL_CLASS; + + zend_declare_property_null(this_ce, ZEND_STRL("timestamp"), ZEND_ACC_PRIVATE TSRMLS_CC); + + max_len = sprintf(max, "%.0f", AMQP_TIMESTAMP_MAX); + zend_declare_class_constant_stringl(this_ce, ZEND_STRL("MAX"), max, max_len TSRMLS_CC); + + min_len = sprintf(min, "%.0f", AMQP_TIMESTAMP_MIN); + zend_declare_class_constant_stringl(this_ce, ZEND_STRL("MIN"), min, min_len TSRMLS_CC); + + return SUCCESS; +} + +/* +*Local variables: +*tab-width: 4 +*c-basic-offset: 4 +*End: +*vim600: noet sw=4 ts=4 fdm=marker +*vim<6 +*/ diff --git a/amqp_timestamp.h b/amqp_timestamp.h new file mode 100644 index 00000000..5d94fc72 --- /dev/null +++ b/amqp_timestamp.h @@ -0,0 +1,36 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2007 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Alexandre Kalendarev akalend@mail.ru Copyright (c) 2009-2010 | + | Lead: | + | - Pieter de Zwart | + | Maintainers: | + | - Brad Rodriguez | + | - Jonathan Tansavatdi | + +----------------------------------------------------------------------+ +*/ +#include "php.h" + +extern zend_class_entry *amqp_timestamp_class_entry; + +PHP_MINIT_FUNCTION(amqp_timestamp); + +/* +*Local variables: +*tab-width: 4 +*c-basic-offset: 4 +*End: +*vim600: noet sw=4 ts=4 fdm=marker +*vim<600: noet sw=4 ts=4 +*/ diff --git a/amqp_type.c b/amqp_type.c new file mode 100644 index 00000000..753fee8c --- /dev/null +++ b/amqp_type.c @@ -0,0 +1,330 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2007 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Alexandre Kalendarev akalend@mail.ru Copyright (c) 2009-2010 | + | Lead: | + | - Pieter de Zwart | + | Maintainers: | + | - Brad Rodriguez | + | - Jonathan Tansavatdi | + +----------------------------------------------------------------------+ +*/ +#include +#include "Zend/zend_interfaces.h" +#include "amqp_type.h" +#include "amqp_timestamp.h" + +#ifdef PHP_WIN32 +# define strtoimax _strtoi64 +#endif + +amqp_bytes_t php_amqp_type_char_to_amqp_long(char const *cstr, PHP5to7_param_str_len_type_t len) +{ + amqp_bytes_t result; + + if (len < 1) { + return amqp_empty_bytes; + } + + result.len = (size_t)len; + result.bytes = (void *) cstr; + + return result; +} + +char *php_amqp_type_amqp_bytes_to_char(amqp_bytes_t bytes) +{ +/* We will need up to 4 chars per byte, plus the terminating 0 */ + char *res = emalloc(bytes.len * 4 + 1); + uint8_t *data = bytes.bytes; + char *p = res; + size_t i; + + for (i = 0; i < bytes.len; i++) { + if (data[i] >= 32 && data[i] != 127) { + *p++ = data[i]; + } else { + *p++ = '\\'; + *p++ = '0' + (data[i] >> 6); + *p++ = '0' + (data[i] >> 3 & 0x7); + *p++ = '0' + (data[i] & 0x7); + } + } + + *p = 0; + return res; +} + +void php_amqp_type_internal_convert_zval_array(zval *php_array, amqp_field_value_t **field, zend_bool allow_int_keys TSRMLS_DC) +{ + HashTable *ht; + HashPosition pos; + + zval *value; + zval **data; + + PHP5to7_ZEND_REAL_HASH_KEY_T *real_key; + + char *key; + uint key_len; + + ulong index; + ht = Z_ARRVAL_P(php_array); + + zend_bool is_amqp_array = 1; + + PHP5to7_ZEND_HASH_FOREACH_KEY_VAL(ht, index, real_key, key, key_len, data, value, pos) { + if (PHP5to7_ZEND_HASH_KEY_IS_STRING(ht, real_key, key, key_len, index, pos)) { + is_amqp_array = 0; + break; + } + + } PHP5to7_ZEND_HASH_FOREACH_END(); + + if (is_amqp_array) { + (*field)->kind = AMQP_FIELD_KIND_ARRAY; + php_amqp_type_internal_convert_zval_to_amqp_array(php_array, &(*field)->value.array TSRMLS_CC); + } else { + (*field)->kind = AMQP_FIELD_KIND_TABLE; + php_amqp_type_internal_convert_zval_to_amqp_table(php_array, &(*field)->value.table, allow_int_keys TSRMLS_CC); + } +} + +void php_amqp_type_internal_convert_zval_to_amqp_table(zval *php_array, amqp_table_t *amqp_table, zend_bool allow_int_keys TSRMLS_DC) +{ + HashTable *ht; + HashPosition pos; + + zval *value; + zval **data; + + PHP5to7_ZEND_REAL_HASH_KEY_T *real_key; + + char *key; + uint key_len; + + ulong index; + + + ht = Z_ARRVAL_P(php_array); + + amqp_table->entries = (amqp_table_entry_t *)ecalloc((size_t)zend_hash_num_elements(ht), sizeof(amqp_table_entry_t)); + amqp_table->num_entries = 0; + + PHP5to7_ZEND_HASH_FOREACH_KEY_VAL(ht, index, real_key, key, key_len, data, value, pos) { + char *string_key; + amqp_table_entry_t *table_entry; + amqp_field_value_t *field; + + + /* Now pull the key */ + + if (!PHP5to7_ZEND_HASH_KEY_IS_STRING(ht, real_key, key, key_len, index, pos)) { + if (allow_int_keys) { + /* Convert to strings non-string keys */ + char str[32]; + + key_len = sprintf(str, "%lu", index); + key = str; + } else { + /* Skip things that are not strings */ + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Ignoring non-string header field '%lu'", index); + + continue; + } + } else { + PHP5to7_ZEND_HASH_KEY_MAYBE_UNPACK(real_key, key, key_len); + } + + /* Build the value */ + table_entry = &amqp_table->entries[amqp_table->num_entries++]; + field = &table_entry->value; + + if (!php_amqp_type_internal_convert_php_to_amqp_field_value(value, &field, key TSRMLS_CC)) { + /* Reset entries counter back */ + amqp_table->num_entries --; + + continue; + } + + string_key = estrndup(key, key_len); + table_entry->key = amqp_cstring_bytes(string_key); + + } PHP5to7_ZEND_HASH_FOREACH_END(); +} + +void php_amqp_type_internal_convert_zval_to_amqp_array(zval *zvalArguments, amqp_array_t *arguments TSRMLS_DC) +{ + HashTable *ht; + HashPosition pos; + + zval *value; + zval **data; + + PHP5to7_ZEND_REAL_HASH_KEY_T *real_key; + + char *key; + uint key_len; + + ulong index; + + char type[16]; + + ht = Z_ARRVAL_P(zvalArguments); + + /* Allocate all the memory necessary for storing the arguments */ + arguments->entries = (amqp_field_value_t *)ecalloc((size_t)zend_hash_num_elements(ht), sizeof(amqp_field_value_t)); + arguments->num_entries = 0; + + PHP5to7_ZEND_HASH_FOREACH_KEY_VAL(ht, index, real_key, key, key_len, data, value, pos) { + amqp_field_value_t *field = &arguments->entries[arguments->num_entries++]; + + if (!php_amqp_type_internal_convert_php_to_amqp_field_value(value, &field, key TSRMLS_CC)) { + /* Reset entries counter back */ + arguments->num_entries --; + + continue; + } + } PHP5to7_ZEND_HASH_FOREACH_END(); +} + +zend_bool php_amqp_type_internal_convert_php_to_amqp_field_value(zval *value, amqp_field_value_t **fieldPtr, char *key TSRMLS_DC) +{ + zend_bool result; + char type[16]; + amqp_field_value_t *field; + + result = 1; + field = *fieldPtr; + + switch (Z_TYPE_P(value)) { + PHP5to7_CASE_IS_BOOL: + field->kind = AMQP_FIELD_KIND_BOOLEAN; + field->value.boolean = (amqp_boolean_t) !PHP5to7_IS_FALSE_P(value); + break; + case IS_DOUBLE: + field->kind = AMQP_FIELD_KIND_F64; + field->value.f64 = Z_DVAL_P(value); + break; + case IS_LONG: + field->kind = AMQP_FIELD_KIND_I64; + field->value.i64 = Z_LVAL_P(value); + break; + case IS_STRING: + field->kind = AMQP_FIELD_KIND_UTF8; + + if (Z_STRLEN_P(value)) { + amqp_bytes_t bytes; + bytes.len = (size_t) Z_STRLEN_P(value); + bytes.bytes = estrndup(Z_STRVAL_P(value), (uint) Z_STRLEN_P(value)); + + field->value.bytes = bytes; + } else { + field->value.bytes = amqp_empty_bytes; + } + + break; + case IS_ARRAY: + php_amqp_type_internal_convert_zval_array(value, &field, 1 TSRMLS_CC); + break; + case IS_NULL: + field->kind = AMQP_FIELD_KIND_VOID; + break; + case IS_OBJECT: + if (instanceof_function(Z_OBJCE_P(value), amqp_timestamp_class_entry TSRMLS_CC)) { + #if PHP_MAJOR_VERSION >= 7 + zval result; + zend_call_method_with_0_params(value, amqp_timestamp_class_entry, NULL, "gettimestamp", &result); + + field->kind = AMQP_FIELD_KIND_TIMESTAMP; + field->value.u64 = strtoimax(Z_STRVAL(result), NULL, 10); + #else + zval *result = NULL; + zend_call_method_with_0_params(&value, amqp_timestamp_class_entry, NULL, "gettimestamp", &result); + field->kind = AMQP_FIELD_KIND_TIMESTAMP; + field->value.u64 = strtoimax(Z_STRVAL_P(result), NULL, 10); + #endif + break; + } + + default: + switch(Z_TYPE_P(value)) { + case IS_OBJECT: + strcpy(type, "object"); + break; + case IS_RESOURCE: + strcpy(type, "resource"); + break; + default: + strcpy(type, "unknown"); + break; + } + + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Ignoring field '%s' due to unsupported value type (%s)", key, type); + result = 0; + break; + } + + return result; +} + +amqp_table_t *php_amqp_type_convert_zval_to_amqp_table(zval *php_array TSRMLS_DC) +{ + amqp_table_t *amqp_table; + /* In setArguments, we are overwriting all the existing values */ + amqp_table = (amqp_table_t *)emalloc(sizeof(amqp_table_t)); + + php_amqp_type_internal_convert_zval_to_amqp_table(php_array, amqp_table, 0 TSRMLS_CC); + + return amqp_table; +} + +void php_amqp_type_internal_free_amqp_table(amqp_table_t *object, zend_bool clear_root) +{ + if (!object) { + return; + } + + if (object->entries) { + int macroEntryCounter; + for (macroEntryCounter = 0; macroEntryCounter < object->num_entries; macroEntryCounter++) { + + amqp_table_entry_t *entry = &object->entries[macroEntryCounter]; + efree(entry->key.bytes); + + switch (entry->value.kind) { + case AMQP_FIELD_KIND_TABLE: + php_amqp_type_internal_free_amqp_table(&entry->value.value.table, 0); + break; + case AMQP_FIELD_KIND_UTF8: + if (entry->value.value.bytes.bytes) { + efree(entry->value.value.bytes.bytes); + } + break; + default: + break; + } + } + efree(object->entries); + } + + if (clear_root) { + efree(object); + } +} + +void php_amqp_type_free_amqp_table(amqp_table_t *object) +{ + php_amqp_type_internal_free_amqp_table(object, 1); +} diff --git a/amqp_type.h b/amqp_type.h new file mode 100644 index 00000000..90787770 --- /dev/null +++ b/amqp_type.h @@ -0,0 +1,48 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2007 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Alexandre Kalendarev akalend@mail.ru Copyright (c) 2009-2010 | + | Lead: | + | - Pieter de Zwart | + | Maintainers: | + | - Brad Rodriguez | + | - Jonathan Tansavatdi | + +----------------------------------------------------------------------+ +*/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "php.h" + +#include +#if PHP_MAJOR_VERSION >= 7 + #include "php7_support.h" +#else + #include "php5_support.h" +#endif + +PHP_MINIT_FUNCTION(amqp_type); + +char *php_amqp_type_amqp_bytes_to_char(amqp_bytes_t bytes); +amqp_bytes_t php_amqp_type_char_to_amqp_long(char const *cstr, PHP5to7_param_str_len_type_t len); + +amqp_table_t *php_amqp_type_convert_zval_to_amqp_table(zval *php_array TSRMLS_DC); +void php_amqp_type_free_amqp_table(amqp_table_t *object); + +/** Internal functions */ +zend_bool php_amqp_type_internal_convert_php_to_amqp_field_value(zval *value, amqp_field_value_t **fieldPtr, char *key TSRMLS_DC); +void php_amqp_type_internal_convert_zval_array(zval *php_array, amqp_field_value_t **field, zend_bool allow_int_keys TSRMLS_DC); +void php_amqp_type_internal_convert_zval_to_amqp_table(zval *php_array, amqp_table_t *amqp_table, zend_bool allow_int_keys TSRMLS_DC); +void php_amqp_type_internal_convert_zval_to_amqp_array(zval *php_array, amqp_array_t *amqp_array TSRMLS_DC); \ No newline at end of file diff --git a/config.m4 b/config.m4 index c285a505..797104ec 100644 --- a/config.m4 +++ b/config.m4 @@ -131,7 +131,7 @@ if test "$PHP_AMQP" != "no"; then fi PHP_SUBST(AMQP_SHARED_LIBADD) - AMQP_SOURCES="amqp.c amqp_exchange.c amqp_queue.c amqp_connection.c amqp_connection_resource.c amqp_channel.c amqp_envelope.c amqp_basic_properties.c amqp_methods_handling.c" + AMQP_SOURCES="amqp.c amqp_type.c amqp_exchange.c amqp_queue.c amqp_connection.c amqp_connection_resource.c amqp_channel.c amqp_envelope.c amqp_basic_properties.c amqp_methods_handling.c amqp_timestamp.c" PHP_NEW_EXTENSION(amqp, $AMQP_SOURCES, $ext_shared) fi diff --git a/config.w32 b/config.w32 index 2c00b041..dcee04b2 100644 --- a/config.w32 +++ b/config.w32 @@ -4,7 +4,7 @@ if (PHP_AMQP != "no") { if (CHECK_HEADER_ADD_INCLUDE("amqp.h", "CFLAGS_AMQP", PHP_PHP_BUILD + "\\include;" + PHP_AMQP) && CHECK_LIB("rabbitmq.4.lib", "amqp", PHP_PHP_BUILD + "\\lib;" + PHP_AMQP)) { // ADD_FLAG("CFLAGS_AMQP", "/D HAVE_AMQP_GETSOCKOPT"); - EXTENSION('amqp', 'amqp.c amqp_exchange.c amqp_queue.c amqp_connection.c amqp_connection_resource.c amqp_channel.c amqp_envelope.c amqp_basic_properties.c amqp_methods_handling.c'); + EXTENSION('amqp', 'amqp.c amqp_type.c amqp_exchange.c amqp_queue.c amqp_connection.c amqp_connection_resource.c amqp_channel.c amqp_envelope.c amqp_basic_properties.c amqp_methods_handling.c amqp_timestamp.c'); AC_DEFINE('HAVE_AMQP', 1); } else { WARNING("amqp not enabled; libraries and headers not found"); diff --git a/package.xml b/package.xml index 7b0c0935..5f05d06f 100644 --- a/package.xml +++ b/package.xml @@ -35,7 +35,7 @@ PHP License + + diff --git a/php5_support.h b/php5_support.h index 8f81c28b..63f25b6a 100644 --- a/php5_support.h +++ b/php5_support.h @@ -83,7 +83,6 @@ typedef zval* PHP5to7_zval_t; #define PHP5to7_ZEND_HASH_KEY_MAYBE_UNPACK(real_key, key, key_len) -#define PHP5to7_ZEND_HASH_FOREACH_CONTINUE continue #define PHP5to7_ZEND_HASH_FOREACH_END() #define Z_TRY_ADDREF_P(pz) Z_ADDREF_P(pz) @@ -104,6 +103,9 @@ typedef zend_rsrc_list_entry PHP5to7_zend_resource_le_t; #define PHP5to7_PARENT_CLASS_NAME_C(name) , (name) +#define ZEND_ULONG_FMT "%" PRIu64 +#define PHP5to7_ZEND_ACC_FINAL_CLASS ZEND_ACC_FINAL_CLASS + #endif //PHP_AMQP_PHP5_SUPPORT_H /* diff --git a/php7_support.h b/php7_support.h index b9a77349..20002d61 100644 --- a/php7_support.h +++ b/php7_support.h @@ -81,7 +81,6 @@ typedef zval PHP5to7_zval_t; (key_len) = ZSTR_LEN(real_key); \ (key) = ZSTR_VAL(real_key); -#define PHP5to7_ZEND_HASH_FOREACH_CONTINUE continue #define PHP5to7_ZEND_HASH_FOREACH_END() ZEND_HASH_FOREACH_END(); /* Resources stuff */ @@ -97,6 +96,8 @@ typedef zval PHP5to7_zend_resource_le_t; #define PHP5to7_PARENT_CLASS_NAME_C(name) +#define PHP5to7_ZEND_ACC_FINAL_CLASS ZEND_ACC_FINAL + #endif //PHP_AMQP_PHP7_SUPPORT_H /* diff --git a/php_amqp.h b/php_amqp.h index 214bfc78..e1e2e039 100644 --- a/php_amqp.h +++ b/php_amqp.h @@ -20,9 +20,6 @@ | - Jonathan Tansavatdi | +----------------------------------------------------------------------+ */ - -/* $Id: php_amqp.h 327551 2012-09-09 03:49:34Z pdezwart $ */ - #ifndef PHP_AMQP_H #define PHP_AMQP_H @@ -31,7 +28,8 @@ extern zend_class_entry *amqp_exception_class_entry, *amqp_connection_exception_class_entry, *amqp_channel_exception_class_entry, *amqp_exchange_exception_class_entry, - *amqp_queue_exception_class_entry; + *amqp_queue_exception_class_entry, + *amqp_value_exception_class_entry; typedef struct _amqp_connection_resource amqp_connection_resource; @@ -49,7 +47,7 @@ typedef struct _amqp_callback_bucket amqp_callback_bucket; #include "amqp_connection_resource.h" -#include "amqp.h" +#include extern zend_module_entry amqp_module_entry; #define phpext_amqp_ptr &amqp_module_entry @@ -96,11 +94,6 @@ extern zend_module_entry amqp_module_entry; #define PHP_AMQP_CONNECTION_RES_NAME "AMQP Connection Resource" -amqp_table_t *convert_zval_to_amqp_table(zval *zvalArguments TSRMLS_DC); -void php_amqp_free_amqp_table(amqp_table_t * table); - -char *stringify_bytes(amqp_bytes_t bytes); - struct _amqp_channel_resource { char is_connected; amqp_channel_t channel_id; @@ -376,13 +369,9 @@ int php_amqp_error_advanced(amqp_rpc_reply_t reply, char **message, amqp_connect * @deprecated */ void php_amqp_zend_throw_exception(amqp_rpc_reply_t reply, zend_class_entry *exception_ce, const char *message, PHP5to7_param_long_type_t code TSRMLS_DC); - void php_amqp_zend_throw_exception_short(amqp_rpc_reply_t reply, zend_class_entry *exception_ce TSRMLS_DC); - void php_amqp_maybe_release_buffers_on_channel(amqp_connection_resource *connection_resource, amqp_channel_resource *channel_resource); -amqp_bytes_t php_amqp_long_string(char const *cstr, PHP5to7_param_str_len_type_t len); - #endif /* PHP_AMQP_H */ diff --git a/stubs/AMQTimestamp.php b/stubs/AMQTimestamp.php new file mode 100644 index 00000000..1a9c402f --- /dev/null +++ b/stubs/AMQTimestamp.php @@ -0,0 +1,22 @@ + +--FILE-- +connect(); + +$ch = new AMQPChannel($cnn); + +$ex = new AMQPExchange($ch); +$ex->setName("exchange-" . microtime(true)); +$ex->setType(AMQP_EX_TYPE_FANOUT); +$ex->declareExchange(); + +$q = new AMQPQueue($ch); +$q->setName('queue-' . microtime(true)); +$q->declareQueue(); +$q->bind($ex->getName()); + +$headers = ['headerName' => new AMQPTimestamp(1488578462)]; + +$ex->publish('message', 'routing.key', AMQP_NOPARAM, array('headers' => $headers)); + +$message =$q->get(AMQP_AUTOACK); +var_dump($message->getHeaders()); +var_dump($headers); +echo $message->getHeaders() == $headers ? 'same' : 'differs'; +?> + + +==DONE== +--EXPECTF-- +array(1) { + ["headerName"]=> + object(AMQPTimestamp)#%d (1) { + ["timestamp":"AMQPTimestamp":private]=> + string(10) "1488578462" + } +} +array(1) { + ["headerName"]=> + object(AMQPTimestamp)#%d (1) { + ["timestamp":"AMQPTimestamp":private]=> + string(10) "1488578462" + } +} +same + +==DONE== \ No newline at end of file diff --git a/tests/amqpexchange_publish_xdeath.phpt b/tests/amqpexchange_publish_xdeath.phpt new file mode 100644 index 00000000..29a00130 --- /dev/null +++ b/tests/amqpexchange_publish_xdeath.phpt @@ -0,0 +1,155 @@ +--TEST-- +AMQPExchange publish with properties - nested header values +--SKIPIF-- + +--FILE-- +connect(); + +$ch = new AMQPChannel($cnn); + +$suffix = sha1(microtime(true)); + +$dlx = new AMQPExchange($ch); +$dlx->setName('dlx-' . $suffix); +$dlx->setType(AMQP_EX_TYPE_TOPIC); +$dlx->setFlags(AMQP_DURABLE); +$dlx->declareExchange(); + +$dq = new AMQPQueue($ch); +$dq->setName('dlx-' . $suffix); +$dq->declareQueue(); +$dq->setFlags(AMQP_DURABLE); +$dq->bind($dlx->getName(), '#'); + +$ex = new AMQPExchange($ch); +$ex->setName("exchange-" . $suffix); +$ex->setType(AMQP_EX_TYPE_FANOUT); +$ex->setFlags(AMQP_DURABLE); +$ex->declareExchange(); + +$q = new AMQPQueue($ch); +$q->setName('dlx-test-queue-' . $suffix); +$q->setFlags(AMQP_DURABLE); +$q->setArgument('x-dead-letter-exchange', $dlx->getName()); +$q->declareQueue(); +$q->bind($ex->getName()); + +$ex->publish('message'); + +function assert_xdeath(AMQPEnvelope $envelope, $exchangeName, $queueName) { + if (!$envelope->hasHeader('x-death')) { + return 'header-missing'; + } + + $originalHeader = $envelope->getHeader('x-death'); + /** + * RabbitMQ 3.5.1 handles x-death headers differently: instead of growing the table x-death + * headers indefinitely it introduces a count field indexed by queue and reason. We normalize + * the headers to match the new format and to test against that + * + * https://github.com/rabbitmq/rabbitmq-server/releases/tag/rabbitmq_v3_5_1 + * https://github.com/rabbitmq/rabbitmq-server/issues/78 + * https://github.com/rabbitmq/rabbitmq-server/pull/79 + */ + $header = []; + foreach ($originalHeader as $death) { + $index = $death['queue'] . $death['reason']; + if (!isset($header[$index])) { + $header[$index] = array_merge($death, ['count' => 1]); + } else { + $header[$index]['count'] += 1; + } + } + $header = array_values($header); + + + if (count($header) !== 1) { + return 'unexpected-number-of-headers-' . count($header) . ': ' . json_encode($header); + } + + if (!isset($header[0]['reason']) || $header[0]['reason'] !== 'rejected') { + return 'unexpected-reason: ' . json_encode($header); + } + + if (!isset($header[0]['time']) || !$header[0]['time'] instanceof AMQPTimestamp) { + return 'unexpected-time: ' . json_encode($header); + } + + if (!isset($header[0]['exchange']) || $header[0]['exchange'] !== $exchangeName) { + return 'unexpected-exchange: ' . json_encode($header); + } + + if (!isset($header[0]['queue']) || $header[0]['queue'] !== $queueName) { + return 'unexpected-queue: ' . json_encode($header); + } + + if (!isset($header[0]['routing-keys']) || $header[0]['routing-keys'] !== ['']) { + return 'unexpected-routing-keys: ' . json_encode($header); + } + + if (!isset($header[0]['count'])) { + return 'count-missing: ' . json_encode($header); + } + + return $header[0]['count']; +} + +$envelope = $q->get(); +var_dump(assert_xdeath($envelope, $ex->getName(), $q->getName())); +$q->nack($envelope->getDeliveryTag()); + +usleep(20000); + +$failed = $dq->get(); +var_dump(assert_xdeath($failed, $ex->getName(), $q->getName())); +$dq->ack($failed->getDeliveryTag()); + +$ex->publish( + $failed->getBody(), + $failed->getRoutingKey(), + AMQP_NOPARAM, + [ + 'content_type' => $failed->getContentType(), + 'content_encoding' => $failed->getContentEncoding(), + 'message_id' => $failed->getMessageId(), + 'user_id' => $failed->getUserId(), + 'app_id' => $failed->getAppId(), + 'delivery_mode' => $failed->getDeliveryMode(), + 'priority' => $failed->getPriority(), + 'timestamp' => $failed->getTimeStamp(), + 'expiration' => $failed->getExpiration(), + 'type' => $failed->getType(), + 'reply_to' => $failed->getReplyTo(), + 'headers' => $failed->getHeaders(), + 'correlation_id' => $failed->getCorrelationId(), + ] +); + +usleep(20000); + + +$envelope = $q->get(); +var_dump(assert_xdeath($envelope, $ex->getName(), $q->getName())); +$q->nack($envelope->getDeliveryTag()); + + +usleep(20000); + +$failedTwice = $dq->get(); +var_dump(assert_xdeath($failedTwice, $ex->getName(), $q->getName())); +$dq->ack($failedTwice->getDeliveryTag()); + +?> + +==DONE== +--EXPECTF-- +string(14) "header-missing" +int(1) +int(1) +int(2) + +==DONE== \ No newline at end of file diff --git a/tests/amqpqueue_nested_headers.phpt b/tests/amqpqueue_nested_headers.phpt index 9b4bac52..b24da4d5 100644 --- a/tests/amqpqueue_nested_headers.phpt +++ b/tests/amqpqueue_nested_headers.phpt @@ -74,7 +74,10 @@ array(1) { ["queue"]=> string(%d) "queue-%f" ["time"]=> - float(%d) + object(AMQPTimestamp)#%d (1) { + ["timestamp":"AMQPTimestamp":private]=> + string(10) "%s" + } ["exchange"]=> string(%d) "exchange-%f" ["routing-keys"]=> diff --git a/tests/amqptimestamp.phpt b/tests/amqptimestamp.phpt new file mode 100644 index 00000000..98358835 --- /dev/null +++ b/tests/amqptimestamp.phpt @@ -0,0 +1,55 @@ +--TEST-- +AMQPTimestamp +--SKIPIF-- +getTimestamp(), (string) $timestamp); + +$timestamp = new AMQPTimestamp(100000.1); +var_dump($timestamp->getTimestamp(), (string) $timestamp); + +new AMQPTimestamp(); + +new AMQPTimestamp("string"); + +try { + new AMQPTimestamp(AMQPTimestamp::MIN - 1); +} catch (AMQPValueException $e) { + echo $e->getMessage() . "\n"; +} + +try { + new AMQPTimestamp(INF); +} catch (AMQPValueException $e) { + echo $e->getMessage() . "\n"; +} + +var_dump((new ReflectionClass("AMQPTimestamp"))->isFinal()); + +var_dump(AMQPTimestamp::MAX); +var_dump(AMQPTimestamp::MIN); +?> + +==END== +--EXPECTF-- +string(6) "100000" +string(6) "100000" +string(6) "100000" +string(6) "100000" + +Warning: AMQPTimestamp::__construct() expects exactly 1 parameter, 0 given in %s on line %d + +Warning: AMQPTimestamp::__construct() expects parameter 1 to be %s, string given in %s on line %d +The timestamp parameter must be greater than 0. +The timestamp parameter must be less than 18446744073709551616. +bool(true) +string(20) "18446744073709551616" +string(1) "0" + +==END== \ No newline at end of file