diff options
Diffstat (limited to 'ext')
68 files changed, 3877 insertions, 1033 deletions
diff --git a/ext/curl/interface.c b/ext/curl/interface.c index 4b6e5e27dc..80618674a3 100644 --- a/ext/curl/interface.c +++ b/ext/curl/interface.c @@ -1792,7 +1792,7 @@ static void alloc_curl_handle(php_curl **ch) zend_llist_init(&(*ch)->to_free->str, sizeof(char *), (llist_dtor_func_t) curl_free_string, 0); zend_llist_init(&(*ch)->to_free->slist, sizeof(struct curl_slist), (llist_dtor_func_t) curl_free_slist, 0); zend_llist_init(&(*ch)->to_free->post, sizeof(struct HttpPost), (llist_dtor_func_t) curl_free_post, 0); - (*ch)->safe_upload = 0; /* for now, for BC reason we allow unsafe API */ + (*ch)->safe_upload = 1; /* for now, for BC reason we allow unsafe API */ } /* }}} */ diff --git a/ext/gd/gd.c b/ext/gd/gd.c index 7fef56ed74..7da8a62a39 100644 --- a/ext/gd/gd.c +++ b/ext/gd/gd.c @@ -82,6 +82,10 @@ static void php_free_ps_enc(zend_rsrc_list_entry *rsrc TSRMLS_DC); # endif #endif +#if defined(HAVE_GD_XPM) && defined(HAVE_GD_BUNDLED) +# include "X11/xpm.h" +#endif + #ifndef M_PI #define M_PI 3.14159265358979323846 #endif @@ -92,6 +96,10 @@ static void php_imagettftext_common(INTERNAL_FUNCTION_PARAMETERS, int, int); #include "gd_ctx.c" +/* as it is not really public, duplicate declaration here to avoid + pointless warnings */ +int overflow2(int a, int b); + /* Section Filters Declarations */ /* IMPORTANT NOTE FOR NEW FILTER * Do not forget to update: @@ -2082,7 +2090,7 @@ PHP_FUNCTION(imagerotate) ZEND_FETCH_RESOURCE(im_src, gdImagePtr, &SIM, -1, "Image", le_gd); - im_dst = gdImageRotateInterpolated(im_src, (float)degrees, color); + im_dst = gdImageRotateInterpolated(im_src, (const float)degrees, color); if (im_dst != NULL) { ZEND_REGISTER_RESOURCE(return_value, im_dst, le_gd); @@ -5175,8 +5183,6 @@ PHP_FUNCTION(imageaffine) pRect = NULL; } - - //int gdTransformAffineGetImage(gdImagePtr *dst, const gdImagePtr src, gdRectPtr src_area, const double affine[6]); if (gdTransformAffineGetImage(&dst, src, pRect, affine) != GD_TRUE) { RETURN_FALSE; } diff --git a/ext/gd/libgd/gd.h b/ext/gd/libgd/gd.h index 72515108d6..20156b97b5 100644 --- a/ext/gd/libgd/gd.h +++ b/ext/gd/libgd/gd.h @@ -849,8 +849,7 @@ gdImagePtr gdImageRotateNearestNeighbour(gdImagePtr src, const float degrees, co gdImagePtr gdImageRotateBilinear(gdImagePtr src, const float degrees, const int bgColor); gdImagePtr gdImageRotateBicubicFixed(gdImagePtr src, const float degrees, const int bgColor); gdImagePtr gdImageRotateGeneric(gdImagePtr src, const float degrees, const int bgColor); - - +gdImagePtr gdImageRotateInterpolated(const gdImagePtr src, const float angle, int bgcolor); typedef enum { GD_AFFINE_TRANSLATE = 0, diff --git a/ext/gd/libgd/gd_interpolation.c b/ext/gd/libgd/gd_interpolation.c index e3247a78c1..b6e7c69201 100644 --- a/ext/gd/libgd/gd_interpolation.c +++ b/ext/gd/libgd/gd_interpolation.c @@ -1,4 +1,5 @@ /* + * The two pass scaling function is based on: * Filtered Image Rescaling * Based on Gems III * - Schumacher general filtered image rescaling @@ -13,6 +14,7 @@ * * Initial sources code is avaibable in the Gems Source Code Packages: * http://www.acm.org/pubs/tog/GraphicsGems/GGemsIII.tar.gz + * */ /* @@ -816,10 +818,6 @@ int getPixelInterpolated(gdImagePtr im, const double x, const double y, const in return -1; } - /* Default to full alpha */ - if (bgColor == -1) { - } - if (im->interpolation_id == GD_WEIGHTED4) { return getPixelInterpolateWeight(im, x, y, bgColor); } @@ -1708,6 +1706,7 @@ gdImagePtr gdImageRotateNearestNeighbour(gdImagePtr src, const float degrees, co gdImagePtr gdImageRotateGeneric(gdImagePtr src, const float degrees, const int bgColor) { float _angle = ((float) (-degrees / 180.0f) * (float)M_PI); + const int angle_rounded = (int)floor(degrees * 100); const int src_w = gdImageSX(src); const int src_h = gdImageSY(src); const unsigned int new_width = (unsigned int)(abs((int)(src_w * cos(_angle))) + abs((int)(src_h * sin(_angle))) + 0.5f); @@ -1730,6 +1729,10 @@ gdImagePtr gdImageRotateGeneric(gdImagePtr src, const float degrees, const int b : 0; + if (bgColor < 0) { + return NULL; + } + dst = gdImageCreateTrueColor(new_width, new_height); if (!dst) { return NULL; diff --git a/ext/gmp/gmp.c b/ext/gmp/gmp.c index c9da09b230..6b3dadf405 100644 --- a/ext/gmp/gmp.c +++ b/ext/gmp/gmp.c @@ -24,6 +24,7 @@ #include "php_ini.h" #include "php_gmp.h" #include "ext/standard/info.h" +#include "zend_exceptions.h" #if HAVE_GMP @@ -34,9 +35,6 @@ #include "ext/standard/php_lcg.h" #define GMP_ABS(x) ((x) >= 0 ? (x) : -(x)) -/* True global resources - no need for thread safety here */ -static int le_gmp; - /* {{{ arginfo */ ZEND_BEGIN_ARG_INFO_EX(arginfo_gmp_init, 0, 0, 1) ZEND_ARG_INFO(0, number) @@ -308,9 +306,18 @@ zend_module_entry gmp_module_entry = { ZEND_GET_MODULE(gmp) #endif -static void _php_gmpnum_free(zend_rsrc_list_entry *rsrc TSRMLS_DC); +zend_class_entry *gmp_ce; +static zend_object_handlers gmp_object_handlers; + +typedef struct _gmp_object { + zend_object std; + mpz_t num; +} gmp_object; -#define GMP_RESOURCE_NAME "GMP integer" +typedef struct _gmp_temp { + mpz_t num; + zend_bool is_used; +} gmp_temp_t; #define GMP_ROUND_ZERO 0 #define GMP_ROUND_PLUSINF 1 @@ -324,6 +331,123 @@ static void _php_gmpnum_free(zend_rsrc_list_entry *rsrc TSRMLS_DC); # define MAX_BASE 36 #endif +#define IS_GMP(zval) \ + (Z_TYPE_P(zval) == IS_OBJECT && instanceof_function(Z_OBJCE_P(zval), gmp_ce TSRMLS_CC)) + +#define GET_GMP_FROM_ZVAL(zval) \ + (((gmp_object *) zend_object_store_get_object((zval) TSRMLS_CC))->num) + +/* The FETCH_GMP_ZVAL_* family of macros is used to fetch a gmp number + * (mpz_ptr) from a zval. If the zval is not a GMP instance, then we + * try to convert the value to a temporary gmp number using convert_to_gmp. + * This temporary number is stored in the temp argument, which is of type + * gmp_temp_t. This temporary value needs to be freed lateron using the + * FREE_GMP_TEMP macro. + * + * If the conversion to a gmp number fails, the macros return false. + * The _DEP / _DEP_DEP variants additionally free the temporary values + * passed in the last / last two arguments. + * + * If one zval can sometimes be fetched as a long you have to set the + * is_used member of the corresponding gmp_temp_t value to 0, otherwise + * the FREE_GMP_TEMP and *_DEP macros will not work properly. + * + * The three FETCH_GMP_ZVAL_* macros below are mostly copy & paste code + * as I couldn't find a way to combine them. + */ + +#define FREE_GMP_TEMP(temp) \ + if (temp.is_used) { \ + mpz_clear(temp.num); \ + } + +#define FETCH_GMP_ZVAL_DEP_DEP(gmpnumber, zval, temp, dep1, dep2) \ +if (IS_GMP(zval)) { \ + gmpnumber = GET_GMP_FROM_ZVAL(zval); \ + temp.is_used = 0; \ +} else { \ + mpz_init(temp.num); \ + if (convert_to_gmp(temp.num, zval, 0 TSRMLS_CC) == FAILURE) { \ + mpz_clear(temp.num); \ + FREE_GMP_TEMP(dep1); \ + FREE_GMP_TEMP(dep2); \ + RETURN_FALSE; \ + } \ + temp.is_used = 1; \ + gmpnumber = temp.num; \ +} + +#define FETCH_GMP_ZVAL_DEP(gmpnumber, zval, temp, dep) \ +if (IS_GMP(zval)) { \ + gmpnumber = GET_GMP_FROM_ZVAL(zval); \ + temp.is_used = 0; \ +} else { \ + mpz_init(temp.num); \ + if (convert_to_gmp(temp.num, zval, 0 TSRMLS_CC) == FAILURE) { \ + mpz_clear(temp.num); \ + FREE_GMP_TEMP(dep); \ + RETURN_FALSE; \ + } \ + temp.is_used = 1; \ + gmpnumber = temp.num; \ +} + +#define FETCH_GMP_ZVAL(gmpnumber, zval, temp) \ +if (IS_GMP(zval)) { \ + gmpnumber = GET_GMP_FROM_ZVAL(zval); \ + temp.is_used = 0; \ +} else { \ + mpz_init(temp.num); \ + if (convert_to_gmp(temp.num, zval, 0 TSRMLS_CC) == FAILURE) { \ + mpz_clear(temp.num); \ + RETURN_FALSE; \ + } \ + temp.is_used = 1; \ + gmpnumber = temp.num; \ +} + +#define INIT_GMP_RETVAL(gmpnumber) \ + gmp_create_ex(return_value, &gmpnumber TSRMLS_CC) + +static void gmp_strval(zval *result, mpz_t gmpnum, long base); +static int convert_to_gmp(mpz_t gmpnumber, zval *val, int base TSRMLS_DC); +static void gmp_cmp(zval *return_value, zval *a_arg, zval *b_arg TSRMLS_DC); + +/* + * The gmp_*_op functions provide an implementation for several common types + * of GMP functions. The gmp_zval_(unary|binary)_*_op functions have to be manually + * passed zvals to work on, whereas the gmp_(unary|binary)_*_op macros already + * include parameter parsing. + */ +typedef void (*gmp_unary_op_t)(mpz_ptr, mpz_srcptr); +typedef int (*gmp_unary_opl_t)(mpz_srcptr); + +typedef void (*gmp_unary_ui_op_t)(mpz_ptr, unsigned long); + +typedef void (*gmp_binary_op_t)(mpz_ptr, mpz_srcptr, mpz_srcptr); +typedef int (*gmp_binary_opl_t)(mpz_srcptr, mpz_srcptr); + +typedef void (*gmp_binary_ui_op_t)(mpz_ptr, mpz_srcptr, unsigned long); +typedef void (*gmp_binary_op2_t)(mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr); +typedef void (*gmp_binary_ui_op2_t)(mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long); + +static inline void gmp_zval_binary_ui_op(zval *return_value, zval *a_arg, zval *b_arg, gmp_binary_op_t gmp_op, gmp_binary_ui_op_t gmp_ui_op, int check_b_zero TSRMLS_DC); +static inline void gmp_zval_binary_ui_op2(zval *return_value, zval *a_arg, zval *b_arg, gmp_binary_op2_t gmp_op, gmp_binary_ui_op2_t gmp_ui_op, int check_b_zero TSRMLS_DC); +static inline void gmp_zval_unary_op(zval *return_value, zval *a_arg, gmp_unary_op_t gmp_op TSRMLS_DC); +static inline void gmp_zval_unary_ui_op(zval *return_value, zval *a_arg, gmp_unary_ui_op_t gmp_op TSRMLS_DC); + +/* Binary operations */ +#define gmp_binary_ui_op(op, uop) _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op, uop, 0) +#define gmp_binary_op(op) _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op, NULL, 0) +#define gmp_binary_opl(op) _gmp_binary_opl(INTERNAL_FUNCTION_PARAM_PASSTHRU, op) +#define gmp_binary_ui_op_no_zero(op, uop) \ + _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op, uop, 1) + +/* Unary operations */ +#define gmp_unary_op(op) _gmp_unary_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op) +#define gmp_unary_opl(op) _gmp_unary_opl(INTERNAL_FUNCTION_PARAM_PASSTHRU, op) +#define gmp_unary_ui_op(op) _gmp_unary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op) + /* {{{ gmp_emalloc */ static void *gmp_emalloc(size_t size) @@ -348,6 +472,245 @@ static void gmp_efree(void *ptr, size_t size) } /* }}} */ +static inline long gmp_get_long(zval *zv) /* {{{ */ +{ + if (Z_TYPE_P(zv) == IS_LONG) { + return Z_LVAL_P(zv); + } else { + zval tmp_zv; + MAKE_COPY_ZVAL(&zv, &tmp_zv); + convert_to_long(&tmp_zv); + return Z_LVAL(tmp_zv); + } +} +/* }}} */ + +static void gmp_free_object_storage(gmp_object *intern TSRMLS_DC) /* {{{ */ +{ + mpz_clear(intern->num); + + zend_object_std_dtor(&intern->std TSRMLS_CC); + efree(intern); +} +/* }}} */ + +static inline zend_object_value gmp_create_object_ex(zend_class_entry *ce, mpz_ptr *gmpnum_target TSRMLS_DC) /* {{{ */ +{ + zend_object_value retval; + gmp_object *intern = emalloc(sizeof(gmp_object)); + + zend_object_std_init(&intern->std, ce TSRMLS_CC); + object_properties_init(&intern->std, ce); + + mpz_init(intern->num); + *gmpnum_target = intern->num; + + retval.handle = zend_objects_store_put( + intern, (zend_objects_store_dtor_t) zend_objects_destroy_object, + (zend_objects_free_object_storage_t) gmp_free_object_storage, + NULL TSRMLS_CC + ); + retval.handlers = &gmp_object_handlers; + + return retval; +} +/* }}} */ + +static zend_object_value gmp_create_object(zend_class_entry *ce TSRMLS_DC) /* {{{ */ +{ + mpz_ptr gmpnum_dummy; + return gmp_create_object_ex(ce, &gmpnum_dummy TSRMLS_CC); +} +/* }}} */ + +static inline void gmp_create_ex(zval *target, mpz_ptr *gmpnum_target TSRMLS_DC) /* {{{ */ +{ + Z_TYPE_P(target) = IS_OBJECT; + Z_OBJVAL_P(target) = gmp_create_object_ex(gmp_ce, gmpnum_target TSRMLS_CC); +} +/* }}} */ + +static zval *gmp_create(mpz_ptr *gmpnum_target TSRMLS_DC) /* {{{ */ +{ + zval *obj; + MAKE_STD_ZVAL(obj); + gmp_create_ex(obj, gmpnum_target TSRMLS_CC); + return obj; +} +/* }}} */ + +static int gmp_cast_object(zval *readobj, zval *writeobj, int type TSRMLS_DC) /* {{{ */ +{ + mpz_ptr gmpnum; + switch (type) { + case IS_STRING: + gmpnum = GET_GMP_FROM_ZVAL(readobj); + INIT_PZVAL(writeobj); + gmp_strval(writeobj, gmpnum, 10); + return SUCCESS; + case IS_LONG: + gmpnum = GET_GMP_FROM_ZVAL(readobj); + INIT_PZVAL(writeobj); + ZVAL_LONG(writeobj, mpz_get_si(gmpnum)); + return SUCCESS; + case IS_DOUBLE: + gmpnum = GET_GMP_FROM_ZVAL(readobj); + INIT_PZVAL(writeobj); + ZVAL_DOUBLE(writeobj, mpz_get_d(gmpnum)); + return SUCCESS; + default: + return FAILURE; + } +} +/* }}} */ + +static HashTable *gmp_get_properties(zval *obj TSRMLS_DC) /* {{{ */ +{ + HashTable *ht = zend_std_get_properties(obj TSRMLS_CC); + mpz_ptr gmpnum = GET_GMP_FROM_ZVAL(obj); + zval *zv; + + MAKE_STD_ZVAL(zv); + gmp_strval(zv, gmpnum, 10); + zend_hash_update(ht, "num", sizeof("num"), &zv, sizeof(zval *), NULL); + + return ht; +} +/* }}} */ + +static zend_object_value gmp_clone_obj(zval *obj TSRMLS_DC) /* {{{ */ +{ + gmp_object *old_object = zend_object_store_get_object(obj TSRMLS_CC); + zend_object_value new_object_val = gmp_create_object(Z_OBJCE_P(obj) TSRMLS_CC); + gmp_object *new_object = zend_object_store_get_object_by_handle( + new_object_val.handle TSRMLS_CC + ); + + zend_objects_clone_members( + &new_object->std, new_object_val, + &old_object->std, Z_OBJ_HANDLE_P(obj) TSRMLS_CC + ); + + mpz_set(new_object->num, old_object->num); + + return new_object_val; +} +/* }}} */ + +static void shift_operator_helper(gmp_binary_ui_op_t op, zval *return_value, zval *op1, zval *op2 TSRMLS_DC) { + zval op2_copy; + if (Z_TYPE_P(op2) != IS_LONG) { + op2_copy = *op2; + zval_copy_ctor(&op2_copy); + convert_to_long(&op2_copy); + op2 = &op2_copy; + } + + if (Z_LVAL_P(op2) < 0) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Shift cannot be negative"); + RETVAL_FALSE; + } else { + mpz_ptr gmpnum_op, gmpnum_result; + gmp_temp_t temp; + + FETCH_GMP_ZVAL(gmpnum_op, op1, temp); + INIT_GMP_RETVAL(gmpnum_result); + op(gmpnum_result, gmpnum_op, (unsigned long) Z_LVAL_P(op2)); + FREE_GMP_TEMP(temp); + } +} + +#define DO_BINARY_UI_OP_EX(op, uop, check_b_zero) \ + gmp_zval_binary_ui_op( \ + result, op1, op2, op, (gmp_binary_ui_op_t) uop, \ + check_b_zero TSRMLS_CC \ + ); \ + return SUCCESS; + +#define DO_BINARY_UI_OP(op) DO_BINARY_UI_OP_EX(op, op ## _ui, 0) +#define DO_BINARY_OP(op) DO_BINARY_UI_OP_EX(op, NULL, 0) + +#define DO_UNARY_OP(op) \ + gmp_zval_unary_op(result, op1, op TSRMLS_CC); \ + return SUCCESS; + +static int gmp_do_operation(zend_uchar opcode, zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */ +{ + switch (opcode) { + case ZEND_ADD: + DO_BINARY_UI_OP(mpz_add); + case ZEND_SUB: + DO_BINARY_UI_OP(mpz_sub); + case ZEND_MUL: + DO_BINARY_UI_OP(mpz_mul); + case ZEND_DIV: + DO_BINARY_UI_OP_EX(mpz_tdiv_q, mpz_tdiv_q_ui, 1); + case ZEND_MOD: + DO_BINARY_UI_OP_EX(mpz_mod, mpz_mod_ui, 1); + case ZEND_SL: + shift_operator_helper(mpz_mul_2exp, result, op1, op2 TSRMLS_CC); + return SUCCESS; + case ZEND_SR: + shift_operator_helper(mpz_fdiv_q_2exp, result, op1, op2 TSRMLS_CC); + return SUCCESS; + case ZEND_BW_OR: + DO_BINARY_OP(mpz_ior); + case ZEND_BW_AND: + DO_BINARY_OP(mpz_and); + case ZEND_BW_XOR: + DO_BINARY_OP(mpz_xor); + case ZEND_BW_NOT: + DO_UNARY_OP(mpz_com); + + default: + return FAILURE; + } +} +/* }}} */ + +static int gmp_compare(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{{ */ +{ + gmp_cmp(result, op1, op2 TSRMLS_CC); + if (Z_TYPE_P(result) == IS_BOOL) { + ZVAL_LONG(result, 1); + } + return SUCCESS; +} +/* }}} */ + +PHP_METHOD(GMP, __wakeup) /* {{{ */ +{ + HashTable *props; + zval **num_zv; + + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + props = zend_std_get_properties(getThis() TSRMLS_CC); + if (zend_hash_find(props, "num", sizeof("num"), (void **) &num_zv) == SUCCESS + && Z_TYPE_PP(num_zv) == IS_STRING && Z_STRLEN_PP(num_zv) > 0 + ) { + mpz_ptr gmpnumber = GET_GMP_FROM_ZVAL(getThis()); + if (convert_to_gmp(gmpnumber, *num_zv, 10 TSRMLS_CC) == SUCCESS) { + return; + } + } + + zend_throw_exception( + NULL, "Invalid serialization data", 0 TSRMLS_CC + ); +} +/* }}} */ + +ZEND_BEGIN_ARG_INFO_EX(arginfo_wakeup, 0, 0, 0) +ZEND_END_ARG_INFO() + +const zend_function_entry gmp_methods[] = { + PHP_ME(GMP, __wakeup, arginfo_wakeup, ZEND_ACC_PUBLIC) + PHP_FE_END +}; + /* {{{ ZEND_GINIT_FUNCTION */ static ZEND_GINIT_FUNCTION(gmp) @@ -358,9 +721,20 @@ static ZEND_GINIT_FUNCTION(gmp) /* {{{ ZEND_MINIT_FUNCTION */ -ZEND_MODULE_STARTUP_D(gmp) +ZEND_MINIT_FUNCTION(gmp) { - le_gmp = zend_register_list_destructors_ex(_php_gmpnum_free, NULL, GMP_RESOURCE_NAME, module_number); + zend_class_entry tmp_ce; + INIT_CLASS_ENTRY(tmp_ce, "GMP", gmp_methods); /* No methods on the class for now */ + gmp_ce = zend_register_internal_class(&tmp_ce TSRMLS_CC); + gmp_ce->create_object = gmp_create_object; + + memcpy(&gmp_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); + gmp_object_handlers.cast_object = gmp_cast_object; + gmp_object_handlers.get_properties = gmp_get_properties; + gmp_object_handlers.clone_obj = gmp_clone_obj; + gmp_object_handlers.do_operation = gmp_do_operation; + gmp_object_handlers.compare = gmp_compare; + REGISTER_LONG_CONSTANT("GMP_ROUND_ZERO", GMP_ROUND_ZERO, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("GMP_ROUND_PLUSINF", GMP_ROUND_PLUSINF, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("GMP_ROUND_MINUSINF", GMP_ROUND_MINUSINF, CONST_CS | CONST_PERSISTENT); @@ -403,246 +777,211 @@ ZEND_MODULE_INFO_D(gmp) } /* }}} */ -/* Fetch zval to be GMP number. - Initially, zval can be also number or string */ -#define FETCH_GMP_ZVAL(gmpnumber, zval, tmp_resource) \ -if (Z_TYPE_PP(zval) == IS_RESOURCE) { \ - ZEND_FETCH_RESOURCE(gmpnumber, mpz_t *, zval, -1, GMP_RESOURCE_NAME, le_gmp); \ - tmp_resource = 0; \ -} else { \ - if (convert_to_gmp(&gmpnumber, zval, 0 TSRMLS_CC) == FAILURE) { \ - RETURN_FALSE; \ - } \ - tmp_resource = ZEND_REGISTER_RESOURCE(NULL, gmpnumber, le_gmp); \ -} - -#define FREE_GMP_TEMP(tmp_resource) \ - if(tmp_resource) { \ - zend_list_delete(tmp_resource); \ - } - - -/* create a new initialized GMP number */ -#define INIT_GMP_NUM(gmpnumber) { gmpnumber=emalloc(sizeof(mpz_t)); mpz_init(*gmpnumber); } -#define FREE_GMP_NUM(gmpnumber) { mpz_clear(*gmpnumber); efree(gmpnumber); } /* {{{ convert_to_gmp * Convert zval to be gmp number */ -static int convert_to_gmp(mpz_t * *gmpnumber, zval **val, int base TSRMLS_DC) +static int convert_to_gmp(mpz_t gmpnumber, zval *val, int base TSRMLS_DC) { - int ret = 0; - int skip_lead = 0; - - *gmpnumber = emalloc(sizeof(mpz_t)); - - switch (Z_TYPE_PP(val)) { + switch (Z_TYPE_P(val)) { case IS_LONG: case IS_BOOL: - case IS_CONSTANT: - { - convert_to_long_ex(val); - mpz_init_set_si(**gmpnumber, Z_LVAL_PP(val)); - } - break; - case IS_STRING: - { - char *numstr = Z_STRVAL_PP(val); - - if (Z_STRLEN_PP(val) > 2) { - if (numstr[0] == '0') { - if (numstr[1] == 'x' || numstr[1] == 'X') { - base = 16; - skip_lead = 1; - } else if (base != 16 && (numstr[1] == 'b' || numstr[1] == 'B')) { - base = 2; - skip_lead = 1; - } + case IS_CONSTANT: { + mpz_set_si(gmpnumber, gmp_get_long(val)); + return SUCCESS; + } + case IS_STRING: { + char *numstr = Z_STRVAL_P(val); + int skip_lead = 0; + + if (Z_STRLEN_P(val) > 2) { + if (numstr[0] == '0') { + if (numstr[1] == 'x' || numstr[1] == 'X') { + base = 16; + skip_lead = 1; + } else if (base != 16 && (numstr[1] == 'b' || numstr[1] == 'B')) { + base = 2; + skip_lead = 1; } } - ret = mpz_init_set_str(**gmpnumber, (skip_lead ? &numstr[2] : numstr), base); } - break; - default: - php_error_docref(NULL TSRMLS_CC, E_WARNING,"Unable to convert variable to GMP - wrong type"); - efree(*gmpnumber); - return FAILURE; - } - if (ret) { - FREE_GMP_NUM(*gmpnumber); + return mpz_set_str(gmpnumber, (skip_lead ? &numstr[2] : numstr), base); + } + default: + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to convert variable to GMP - wrong type"); return FAILURE; } - - return SUCCESS; } /* }}} */ -/* {{{ typedefs - */ -typedef void (*gmp_unary_op_t)(mpz_ptr, mpz_srcptr); -typedef int (*gmp_unary_opl_t)(mpz_srcptr); +static void gmp_strval(zval *result, mpz_t gmpnum, long base) /* {{{ */ +{ + int num_len; + char *out_string; -typedef void (*gmp_unary_ui_op_t)(mpz_ptr, unsigned long); + num_len = mpz_sizeinbase(gmpnum, abs(base)); + if (mpz_sgn(gmpnum) < 0) { + num_len++; + } -typedef void (*gmp_binary_op_t)(mpz_ptr, mpz_srcptr, mpz_srcptr); -typedef int (*gmp_binary_opl_t)(mpz_srcptr, mpz_srcptr); + out_string = emalloc(num_len + 1); + mpz_get_str(out_string, base, gmpnum); + + /* + * From GMP documentation for mpz_sizeinbase(): + * The returned value will be exact or 1 too big. If base is a power of + * 2, the returned value will always be exact. + * + * So let's check to see if we already have a \0 byte... + */ + + if (out_string[num_len - 1] == '\0') { + num_len--; + } else { + out_string[num_len] = '\0'; + } -typedef unsigned long (*gmp_binary_ui_op_t)(mpz_ptr, mpz_srcptr, unsigned long); -typedef void (*gmp_binary_op2_t)(mpz_ptr, mpz_ptr, mpz_srcptr, mpz_srcptr); -typedef unsigned long (*gmp_binary_ui_op2_t)(mpz_ptr, mpz_ptr, mpz_srcptr, unsigned long); + ZVAL_STRINGL(result, out_string, num_len, 0); +} /* }}} */ -#define gmp_zval_binary_ui_op(r, a, b, o, u) gmp_zval_binary_ui_op_ex(r, a, b, o, u, 0, 0, 0 TSRMLS_CC) -#define gmp_zval_binary_ui_op2(r, a, b, o, u) gmp_zval_binary_ui_op2_ex(r, a, b, o, u, 0, 0, 0 TSRMLS_CC) +static void gmp_cmp(zval *return_value, zval *a_arg, zval *b_arg TSRMLS_DC) /* {{{ */ +{ + mpz_ptr gmpnum_a, gmpnum_b; + gmp_temp_t temp_a, temp_b; + zend_bool use_si = 0; + long res; -#define gmp_binary_ui_op(op, uop) _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op, uop) -#define gmp_binary_op(op) _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op, NULL) -#define gmp_binary_opl(op) _gmp_binary_opl(INTERNAL_FUNCTION_PARAM_PASSTHRU, op) + FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); -/* Unary operations */ -#define gmp_unary_op(op) _gmp_unary_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op) -#define gmp_unary_opl(op) _gmp_unary_opl(INTERNAL_FUNCTION_PARAM_PASSTHRU, op) -#define gmp_unary_ui_op(op) _gmp_unary_ui_op(INTERNAL_FUNCTION_PARAM_PASSTHRU, op) + if (Z_TYPE_P(b_arg) == IS_LONG) { + use_si = 1; + temp_b.is_used = 0; + } else { + FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a); + } + + if (use_si) { + res = mpz_cmp_si(gmpnum_a, Z_LVAL_P(b_arg)); + } else { + res = mpz_cmp(gmpnum_a, gmpnum_b); + } + + FREE_GMP_TEMP(temp_a); + FREE_GMP_TEMP(temp_b); + + RETURN_LONG(res); +} +/* }}} */ -/* {{{ gmp_zval_binary_ui_op_ex +/* {{{ gmp_zval_binary_ui_op Execute GMP binary operation. - May return GMP resource or long if operation allows this */ -static inline void gmp_zval_binary_ui_op_ex(zval *return_value, zval **a_arg, zval **b_arg, gmp_binary_op_t gmp_op, gmp_binary_ui_op_t gmp_ui_op, int allow_ui_return, int check_b_zero, int use_sign TSRMLS_DC) +static inline void gmp_zval_binary_ui_op(zval *return_value, zval *a_arg, zval *b_arg, gmp_binary_op_t gmp_op, gmp_binary_ui_op_t gmp_ui_op, int check_b_zero TSRMLS_DC) { - mpz_t *gmpnum_a, *gmpnum_b, *gmpnum_result; - unsigned long long_result = 0; + mpz_ptr gmpnum_a, gmpnum_b, gmpnum_result; int use_ui = 0; - int arga_tmp = 0, argb_tmp = 0; + gmp_temp_t temp_a, temp_b; - FETCH_GMP_ZVAL(gmpnum_a, a_arg, arga_tmp); + FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); - if (gmp_ui_op && Z_TYPE_PP(b_arg) == IS_LONG && Z_LVAL_PP(b_arg) >= 0) { + if (gmp_ui_op && Z_TYPE_P(b_arg) == IS_LONG && Z_LVAL_P(b_arg) >= 0) { use_ui = 1; + temp_b.is_used = 0; } else { - FETCH_GMP_ZVAL(gmpnum_b, b_arg, argb_tmp); + FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a); } - if(check_b_zero) { + if (check_b_zero) { int b_is_zero = 0; - if(use_ui) { - b_is_zero = (Z_LVAL_PP(b_arg) == 0); + if (use_ui) { + b_is_zero = (Z_LVAL_P(b_arg) == 0); } else { - b_is_zero = !mpz_cmp_ui(*gmpnum_b, 0); + b_is_zero = !mpz_cmp_ui(gmpnum_b, 0); } - if(b_is_zero) { + if (b_is_zero) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Zero operand not allowed"); - FREE_GMP_TEMP(arga_tmp); - FREE_GMP_TEMP(argb_tmp); + FREE_GMP_TEMP(temp_a); + FREE_GMP_TEMP(temp_b); RETURN_FALSE; } } - INIT_GMP_NUM(gmpnum_result); + INIT_GMP_RETVAL(gmpnum_result); - if (use_ui && gmp_ui_op) { - if (allow_ui_return) { - long_result = gmp_ui_op(*gmpnum_result, *gmpnum_a, (unsigned long)Z_LVAL_PP(b_arg)); - if (use_sign && mpz_sgn(*gmpnum_a) == -1) { - long_result = -long_result; - } - } else { - gmp_ui_op(*gmpnum_result, *gmpnum_a, (unsigned long)Z_LVAL_PP(b_arg)); - } + if (use_ui) { + gmp_ui_op(gmpnum_result, gmpnum_a, (unsigned long) Z_LVAL_P(b_arg)); } else { - gmp_op(*gmpnum_result, *gmpnum_a, *gmpnum_b); + gmp_op(gmpnum_result, gmpnum_a, gmpnum_b); } - FREE_GMP_TEMP(arga_tmp); - FREE_GMP_TEMP(argb_tmp); - - if (use_ui && allow_ui_return) { - FREE_GMP_NUM(gmpnum_result); - RETURN_LONG((long)long_result); - } else { - ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp); - } + FREE_GMP_TEMP(temp_a); + FREE_GMP_TEMP(temp_b); } /* }}} */ -/* {{{ gmp_zval_binary_ui_op2_ex +/* {{{ gmp_zval_binary_ui_op2 Execute GMP binary operation which returns 2 values. - May return GMP resources or longs if operation allows this. */ -static inline void gmp_zval_binary_ui_op2_ex(zval *return_value, zval **a_arg, zval **b_arg, gmp_binary_op2_t gmp_op, gmp_binary_ui_op2_t gmp_ui_op, int allow_ui_return, int check_b_zero TSRMLS_DC) +static inline void gmp_zval_binary_ui_op2(zval *return_value, zval *a_arg, zval *b_arg, gmp_binary_op2_t gmp_op, gmp_binary_ui_op2_t gmp_ui_op, int check_b_zero TSRMLS_DC) { - mpz_t *gmpnum_a, *gmpnum_b, *gmpnum_result1, *gmpnum_result2; - zval r; + mpz_ptr gmpnum_a, gmpnum_b, gmpnum_result1, gmpnum_result2; int use_ui = 0; - unsigned long long_result = 0; - int arga_tmp = 0, argb_tmp = 0; + gmp_temp_t temp_a, temp_b; - FETCH_GMP_ZVAL(gmpnum_a, a_arg, arga_tmp); + FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); - if (gmp_ui_op && Z_TYPE_PP(b_arg) == IS_LONG && Z_LVAL_PP(b_arg) >= 0) { + if (gmp_ui_op && Z_TYPE_P(b_arg) == IS_LONG && Z_LVAL_P(b_arg) >= 0) { /* use _ui function */ use_ui = 1; + temp_b.is_used = 0; } else { - FETCH_GMP_ZVAL(gmpnum_b, b_arg, argb_tmp); + FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a); } - if(check_b_zero) { + if (check_b_zero) { int b_is_zero = 0; - if(use_ui) { - b_is_zero = (Z_LVAL_PP(b_arg) == 0); + if (use_ui) { + b_is_zero = (Z_LVAL_P(b_arg) == 0); } else { - b_is_zero = !mpz_cmp_ui(*gmpnum_b, 0); + b_is_zero = !mpz_cmp_ui(gmpnum_b, 0); } - if(b_is_zero) { + if (b_is_zero) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Zero operand not allowed"); - FREE_GMP_TEMP(arga_tmp); - FREE_GMP_TEMP(argb_tmp); + FREE_GMP_TEMP(temp_a); + FREE_GMP_TEMP(temp_b); RETURN_FALSE; } } - INIT_GMP_NUM(gmpnum_result1); - INIT_GMP_NUM(gmpnum_result2); + array_init(return_value); + add_index_zval(return_value, 0, gmp_create(&gmpnum_result1 TSRMLS_CC)); + add_index_zval(return_value, 1, gmp_create(&gmpnum_result2 TSRMLS_CC)); - if (use_ui && gmp_ui_op) { - if (allow_ui_return) { - long_result = gmp_ui_op(*gmpnum_result1, *gmpnum_result2, *gmpnum_a, (unsigned long)Z_LVAL_PP(b_arg)); - } else { - gmp_ui_op(*gmpnum_result1, *gmpnum_result2, *gmpnum_a, (unsigned long)Z_LVAL_PP(b_arg)); - } + if (use_ui) { + gmp_ui_op(gmpnum_result1, gmpnum_result2, gmpnum_a, (unsigned long) Z_LVAL_P(b_arg)); } else { - gmp_op(*gmpnum_result1, *gmpnum_result2, *gmpnum_a, *gmpnum_b); + gmp_op(gmpnum_result1, gmpnum_result2, gmpnum_a, gmpnum_b); } - FREE_GMP_TEMP(arga_tmp); - FREE_GMP_TEMP(argb_tmp); - - array_init(return_value); - ZEND_REGISTER_RESOURCE(&r, gmpnum_result1, le_gmp); - add_index_resource(return_value, 0, Z_LVAL(r)); - if (use_ui && allow_ui_return) { - mpz_clear(*gmpnum_result2); - add_index_long(return_value, 1, long_result); - } else { - ZEND_REGISTER_RESOURCE(&r, gmpnum_result2, le_gmp); - add_index_resource(return_value, 1, Z_LVAL(r)); - } + FREE_GMP_TEMP(temp_a); + FREE_GMP_TEMP(temp_b); } /* }}} */ /* {{{ _gmp_binary_ui_op */ -static inline void _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAMETERS, gmp_binary_op_t gmp_op, gmp_binary_ui_op_t gmp_ui_op) +static inline void _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAMETERS, gmp_binary_op_t gmp_op, gmp_binary_ui_op_t gmp_ui_op, int check_b_zero) { - zval **a_arg, **b_arg; + zval *a_arg, *b_arg; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){ + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &a_arg, &b_arg) == FAILURE){ return; } - gmp_zval_binary_ui_op(return_value, a_arg, b_arg, gmp_op, gmp_ui_op); + gmp_zval_binary_ui_op(return_value, a_arg, b_arg, gmp_op, gmp_ui_op, check_b_zero TSRMLS_CC); } /* }}} */ @@ -650,33 +989,28 @@ static inline void _gmp_binary_ui_op(INTERNAL_FUNCTION_PARAMETERS, gmp_binary_op /* {{{ gmp_zval_unary_op */ -static inline void gmp_zval_unary_op(zval *return_value, zval **a_arg, gmp_unary_op_t gmp_op TSRMLS_DC) +static inline void gmp_zval_unary_op(zval *return_value, zval *a_arg, gmp_unary_op_t gmp_op TSRMLS_DC) { - mpz_t *gmpnum_a, *gmpnum_result; - int temp_a; + mpz_ptr gmpnum_a, gmpnum_result; + gmp_temp_t temp_a; FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); - INIT_GMP_NUM(gmpnum_result); - gmp_op(*gmpnum_result, *gmpnum_a); + INIT_GMP_RETVAL(gmpnum_result); + gmp_op(gmpnum_result, gmpnum_a); FREE_GMP_TEMP(temp_a); - ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp); } /* }}} */ /* {{{ gmp_zval_unary_ui_op */ -static inline void gmp_zval_unary_ui_op(zval *return_value, zval **a_arg, gmp_unary_ui_op_t gmp_op TSRMLS_DC) +static inline void gmp_zval_unary_ui_op(zval *return_value, zval *a_arg, gmp_unary_ui_op_t gmp_op TSRMLS_DC) { - mpz_t *gmpnum_result; - - convert_to_long_ex(a_arg); + mpz_ptr gmpnum_result; - INIT_GMP_NUM(gmpnum_result); - gmp_op(*gmpnum_result, Z_LVAL_PP(a_arg)); - - ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp); + INIT_GMP_RETVAL(gmpnum_result); + gmp_op(gmpnum_result, gmp_get_long(a_arg)); } /* }}} */ @@ -685,9 +1019,9 @@ static inline void gmp_zval_unary_ui_op(zval *return_value, zval **a_arg, gmp_un */ static inline void _gmp_unary_ui_op(INTERNAL_FUNCTION_PARAMETERS, gmp_unary_ui_op_t gmp_op) { - zval **a_arg; + zval *a_arg; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){ + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &a_arg) == FAILURE){ return; } @@ -699,9 +1033,9 @@ static inline void _gmp_unary_ui_op(INTERNAL_FUNCTION_PARAMETERS, gmp_unary_ui_o */ static inline void _gmp_unary_op(INTERNAL_FUNCTION_PARAMETERS, gmp_unary_op_t gmp_op) { - zval **a_arg; + zval *a_arg; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){ + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &a_arg) == FAILURE){ return; } @@ -713,16 +1047,16 @@ static inline void _gmp_unary_op(INTERNAL_FUNCTION_PARAMETERS, gmp_unary_op_t gm */ static inline void _gmp_unary_opl(INTERNAL_FUNCTION_PARAMETERS, gmp_unary_opl_t gmp_op) { - zval **a_arg; - mpz_t *gmpnum_a; - int temp_a; + zval *a_arg; + mpz_ptr gmpnum_a; + gmp_temp_t temp_a; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){ + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &a_arg) == FAILURE){ return; } FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); - RETVAL_LONG(gmp_op(*gmpnum_a)); + RETVAL_LONG(gmp_op(gmpnum_a)); FREE_GMP_TEMP(temp_a); } /* }}} */ @@ -731,33 +1065,33 @@ static inline void _gmp_unary_opl(INTERNAL_FUNCTION_PARAMETERS, gmp_unary_opl_t */ static inline void _gmp_binary_opl(INTERNAL_FUNCTION_PARAMETERS, gmp_binary_opl_t gmp_op) { - zval **a_arg, **b_arg; - mpz_t *gmpnum_a, *gmpnum_b; - int temp_a, temp_b; + zval *a_arg, *b_arg; + mpz_ptr gmpnum_a, gmpnum_b; + gmp_temp_t temp_a, temp_b; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){ + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &a_arg, &b_arg) == FAILURE){ return; } FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); - FETCH_GMP_ZVAL(gmpnum_b, b_arg, temp_b); + FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a); - RETVAL_LONG(gmp_op(*gmpnum_a, *gmpnum_b)); + RETVAL_LONG(gmp_op(gmpnum_a, gmpnum_b)); FREE_GMP_TEMP(temp_a); FREE_GMP_TEMP(temp_b); } /* }}} */ -/* {{{ proto resource gmp_init(mixed number [, int base]) +/* {{{ proto GMP gmp_init(mixed number [, int base]) Initializes GMP number */ ZEND_FUNCTION(gmp_init) { - zval **number_arg; - mpz_t * gmpnumber; - long base=0; + zval *number_arg; + mpz_ptr gmpnumber; + long base = 0; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|l", &number_arg, &base) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|l", &number_arg, &base) == FAILURE) { return; } @@ -766,48 +1100,42 @@ ZEND_FUNCTION(gmp_init) RETURN_FALSE; } - if (convert_to_gmp(&gmpnumber, number_arg, base TSRMLS_CC) == FAILURE) { + INIT_GMP_RETVAL(gmpnumber); + if (convert_to_gmp(gmpnumber, number_arg, base TSRMLS_CC) == FAILURE) { + zval_dtor(return_value); RETURN_FALSE; } - - /* Write your own code here to handle argument number. */ - ZEND_REGISTER_RESOURCE(return_value, gmpnumber, le_gmp); } /* }}} */ -/* {{{ proto int gmp_intval(resource gmpnumber) +/* {{{ proto int gmp_intval(mixed gmpnumber) Gets signed long value of GMP number */ ZEND_FUNCTION(gmp_intval) { - zval **gmpnumber_arg; - mpz_t * gmpnum; + zval *gmpnumber_arg; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &gmpnumber_arg) == FAILURE){ + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &gmpnumber_arg) == FAILURE){ return; } - if (Z_TYPE_PP(gmpnumber_arg) == IS_RESOURCE) { - ZEND_FETCH_RESOURCE(gmpnum, mpz_t *, gmpnumber_arg, -1, GMP_RESOURCE_NAME, le_gmp); - RETVAL_LONG(mpz_get_si(*gmpnum)); + if (IS_GMP(gmpnumber_arg)) { + RETVAL_LONG(mpz_get_si(GET_GMP_FROM_ZVAL(gmpnumber_arg))); } else { - convert_to_long_ex(gmpnumber_arg); - RETVAL_LONG(Z_LVAL_PP(gmpnumber_arg)); + RETVAL_LONG(gmp_get_long(gmpnumber_arg)); } } /* }}} */ -/* {{{ proto string gmp_strval(resource gmpnumber [, int base]) +/* {{{ proto string gmp_strval(mixed gmpnumber [, int base]) Gets string representation of GMP number */ ZEND_FUNCTION(gmp_strval) { - zval **gmpnumber_arg; - int num_len; + zval *gmpnumber_arg; long base = 10; - mpz_t * gmpnum; - char *out_string; - int temp_a; + mpz_ptr gmpnum; + gmp_temp_t temp_a; - if( zend_parse_parameters( ZEND_NUM_ARGS() TSRMLS_CC, "Z|l", &gmpnumber_arg, &base ) == FAILURE ) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|l", &gmpnumber_arg, &base) == FAILURE) { return; } @@ -825,162 +1153,138 @@ ZEND_FUNCTION(gmp_strval) FETCH_GMP_ZVAL(gmpnum, gmpnumber_arg, temp_a); - num_len = mpz_sizeinbase(*gmpnum, abs(base)); - out_string = emalloc(num_len+2); - if (mpz_sgn(*gmpnum) < 0) { - num_len++; - } - mpz_get_str(out_string, base, *gmpnum); - - FREE_GMP_TEMP(temp_a); - - /* - From GMP documentation for mpz_sizeinbase(): - The returned value will be exact or 1 too big. If base is a power of - 2, the returned value will always be exact. - - So let's check to see if we already have a \0 byte... - */ + gmp_strval(return_value, gmpnum, base); - if (out_string[num_len-1] == '\0') { - num_len--; - } else { - out_string[num_len] = '\0'; - } - RETVAL_STRINGL(out_string, num_len, 0); + FREE_GMP_TEMP(temp_a); } /* }}} */ -/* {{{ proto resource gmp_add(resource a, resource b) +/* {{{ proto GMP gmp_add(mixed a, mixed b) Add a and b */ ZEND_FUNCTION(gmp_add) { - gmp_binary_ui_op(mpz_add, (gmp_binary_ui_op_t)mpz_add_ui); + gmp_binary_ui_op(mpz_add, mpz_add_ui); } /* }}} */ -/* {{{ proto resource gmp_sub(resource a, resource b) +/* {{{ proto GMP gmp_sub(mixed a, mixed b) Subtract b from a */ ZEND_FUNCTION(gmp_sub) { - gmp_binary_ui_op(mpz_sub, (gmp_binary_ui_op_t)mpz_sub_ui); + gmp_binary_ui_op(mpz_sub, mpz_sub_ui); } /* }}} */ -/* {{{ proto resource gmp_mul(resource a, resource b) +/* {{{ proto GMP gmp_mul(mixed a, mixed b) Multiply a and b */ ZEND_FUNCTION(gmp_mul) { - gmp_binary_ui_op(mpz_mul, (gmp_binary_ui_op_t)mpz_mul_ui); + gmp_binary_ui_op(mpz_mul, mpz_mul_ui); } /* }}} */ -/* {{{ proto array gmp_div_qr(resource a, resource b [, int round]) +/* {{{ proto array gmp_div_qr(mixed a, mixed b [, int round]) Divide a by b, returns quotient and reminder */ ZEND_FUNCTION(gmp_div_qr) { - zval **a_arg, **b_arg; + zval *a_arg, *b_arg; long round = GMP_ROUND_ZERO; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ|l", &a_arg, &b_arg, &round) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz|l", &a_arg, &b_arg, &round) == FAILURE) { return; } switch (round) { case GMP_ROUND_ZERO: - gmp_zval_binary_ui_op2_ex(return_value, a_arg, b_arg, mpz_tdiv_qr, (gmp_binary_ui_op2_t)mpz_tdiv_qr_ui, 0, 1 TSRMLS_CC); + gmp_zval_binary_ui_op2(return_value, a_arg, b_arg, mpz_tdiv_qr, (gmp_binary_ui_op2_t) mpz_tdiv_qr_ui, 1 TSRMLS_CC); break; case GMP_ROUND_PLUSINF: - gmp_zval_binary_ui_op2_ex(return_value, a_arg, b_arg, mpz_cdiv_qr, (gmp_binary_ui_op2_t)mpz_cdiv_qr_ui, 0, 1 TSRMLS_CC); + gmp_zval_binary_ui_op2(return_value, a_arg, b_arg, mpz_cdiv_qr, (gmp_binary_ui_op2_t) mpz_cdiv_qr_ui, 1 TSRMLS_CC); break; case GMP_ROUND_MINUSINF: - gmp_zval_binary_ui_op2_ex(return_value, a_arg, b_arg, mpz_fdiv_qr, (gmp_binary_ui_op2_t)mpz_fdiv_qr_ui, 0, 1 TSRMLS_CC); + gmp_zval_binary_ui_op2(return_value, a_arg, b_arg, mpz_fdiv_qr, (gmp_binary_ui_op2_t) mpz_fdiv_qr_ui, 1 TSRMLS_CC); break; + default: + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid rounding mode"); + RETURN_FALSE; } - } /* }}} */ -/* {{{ proto resource gmp_div_r(resource a, resource b [, int round]) +/* {{{ proto GMP gmp_div_r(mixed a, mixed b [, int round]) Divide a by b, returns reminder only */ ZEND_FUNCTION(gmp_div_r) { - zval **a_arg, **b_arg; + zval *a_arg, *b_arg; long round = GMP_ROUND_ZERO; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ|l", &a_arg, &b_arg, &round) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz|l", &a_arg, &b_arg, &round) == FAILURE) { return; } switch (round) { case GMP_ROUND_ZERO: - gmp_zval_binary_ui_op_ex(return_value, a_arg, b_arg, mpz_tdiv_r, (gmp_binary_ui_op_t)mpz_tdiv_r_ui, 1, 1, 1 TSRMLS_CC); + gmp_zval_binary_ui_op(return_value, a_arg, b_arg, mpz_tdiv_r, (gmp_binary_ui_op_t) mpz_tdiv_r_ui, 1 TSRMLS_CC); break; case GMP_ROUND_PLUSINF: - gmp_zval_binary_ui_op_ex(return_value, a_arg, b_arg, mpz_cdiv_r, (gmp_binary_ui_op_t)mpz_cdiv_r_ui, 1, 1, 1 TSRMLS_CC); + gmp_zval_binary_ui_op(return_value, a_arg, b_arg, mpz_cdiv_r, (gmp_binary_ui_op_t) mpz_cdiv_r_ui, 1 TSRMLS_CC); break; case GMP_ROUND_MINUSINF: - gmp_zval_binary_ui_op_ex(return_value, a_arg, b_arg, mpz_fdiv_r, (gmp_binary_ui_op_t)mpz_fdiv_r_ui, 1, 1, 1 TSRMLS_CC); + gmp_zval_binary_ui_op(return_value, a_arg, b_arg, mpz_fdiv_r, (gmp_binary_ui_op_t) mpz_fdiv_r_ui, 1 TSRMLS_CC); break; + default: + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid rounding mode"); + RETURN_FALSE; } } /* }}} */ -/* {{{ proto resource gmp_div_q(resource a, resource b [, int round]) +/* {{{ proto GMP gmp_div_q(mixed a, mixed b [, int round]) Divide a by b, returns quotient only */ ZEND_FUNCTION(gmp_div_q) { - zval **a_arg, **b_arg; + zval *a_arg, *b_arg; long round = GMP_ROUND_ZERO; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ|l", &a_arg, &b_arg, &round) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz|l", &a_arg, &b_arg, &round) == FAILURE) { return; } switch (round) { case GMP_ROUND_ZERO: - gmp_zval_binary_ui_op_ex(return_value, a_arg, b_arg, mpz_tdiv_q, (gmp_binary_ui_op_t)mpz_tdiv_q_ui, 0, 1, 1 TSRMLS_CC); + gmp_zval_binary_ui_op(return_value, a_arg, b_arg, mpz_tdiv_q, (gmp_binary_ui_op_t) mpz_tdiv_q_ui, 1 TSRMLS_CC); break; case GMP_ROUND_PLUSINF: - gmp_zval_binary_ui_op_ex(return_value, a_arg, b_arg, mpz_cdiv_q, (gmp_binary_ui_op_t)mpz_cdiv_q_ui, 0, 1, 1 TSRMLS_CC); + gmp_zval_binary_ui_op(return_value, a_arg, b_arg, mpz_cdiv_q, (gmp_binary_ui_op_t) mpz_cdiv_q_ui, 1 TSRMLS_CC); break; case GMP_ROUND_MINUSINF: - gmp_zval_binary_ui_op_ex(return_value, a_arg, b_arg, mpz_fdiv_q, (gmp_binary_ui_op_t)mpz_fdiv_q_ui, 0, 1, 1 TSRMLS_CC); + gmp_zval_binary_ui_op(return_value, a_arg, b_arg, mpz_fdiv_q, (gmp_binary_ui_op_t) mpz_fdiv_q_ui, 1 TSRMLS_CC); break; + default: + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid rounding mode"); + RETURN_FALSE; } } /* }}} */ -/* {{{ proto resource gmp_mod(resource a, resource b) +/* {{{ proto GMP gmp_mod(mixed a, mixed b) Computes a modulo b */ ZEND_FUNCTION(gmp_mod) { - zval **a_arg, **b_arg; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){ - return; - } - - gmp_zval_binary_ui_op_ex(return_value, a_arg, b_arg, mpz_mod, (gmp_binary_ui_op_t)mpz_mod_ui, 1, 1, 0 TSRMLS_CC); + gmp_binary_ui_op_no_zero(mpz_mod, (gmp_binary_ui_op_t) mpz_mod_ui); } /* }}} */ -/* {{{ proto resource gmp_divexact(resource a, resource b) +/* {{{ proto GMP gmp_divexact(mixed a, mixed b) Divide a by b using exact division algorithm */ ZEND_FUNCTION(gmp_divexact) { - zval **a_arg, **b_arg; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){ - return; - } - - gmp_zval_binary_ui_op_ex(return_value, a_arg, b_arg, mpz_divexact, NULL, 0, 1, 1 TSRMLS_CC); + gmp_binary_ui_op_no_zero(mpz_divexact, NULL); } /* }}} */ -/* {{{ proto resource gmp_neg(resource a) +/* {{{ proto GMP gmp_neg(mixed a) Negates a number */ ZEND_FUNCTION(gmp_neg) { @@ -988,7 +1292,7 @@ ZEND_FUNCTION(gmp_neg) } /* }}} */ -/* {{{ proto resource gmp_abs(resource a) +/* {{{ proto GMP gmp_abs(mixed a) Calculates absolute value */ ZEND_FUNCTION(gmp_abs) { @@ -996,99 +1300,92 @@ ZEND_FUNCTION(gmp_abs) } /* }}} */ -/* {{{ proto resource gmp_fact(int a) +/* {{{ proto GMP gmp_fact(int a) Calculates factorial function */ ZEND_FUNCTION(gmp_fact) { - zval **a_arg; - mpz_t *gmpnum_tmp; - int temp_a; + zval *a_arg; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){ + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &a_arg) == FAILURE){ return; } - if (Z_TYPE_PP(a_arg) == IS_RESOURCE) { - FETCH_GMP_ZVAL(gmpnum_tmp, a_arg, temp_a); /* no need to free this since it's IS_RESOURCE */ - if (mpz_sgn(*gmpnum_tmp) < 0) { + if (IS_GMP(a_arg)) { + mpz_ptr gmpnum_tmp = GET_GMP_FROM_ZVAL(a_arg); + if (mpz_sgn(gmpnum_tmp) < 0) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Number has to be greater than or equal to 0"); RETURN_FALSE; } } else { - convert_to_long_ex(a_arg); - if (Z_LVAL_PP(a_arg) < 0) { + if (gmp_get_long(a_arg) < 0) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Number has to be greater than or equal to 0"); RETURN_FALSE; } } - + gmp_zval_unary_ui_op(return_value, a_arg, mpz_fac_ui TSRMLS_CC); } /* }}} */ -/* {{{ proto resource gmp_pow(resource base, int exp) +/* {{{ proto GMP gmp_pow(mixed base, int exp) Raise base to power exp */ ZEND_FUNCTION(gmp_pow) { - zval **base_arg; - mpz_t *gmpnum_result, *gmpnum_base; - int use_ui = 0; - int temp_base; + zval *base_arg; + mpz_ptr gmpnum_result, gmpnum_base; + gmp_temp_t temp_base; long exp; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zl", &base_arg, &exp) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zl", &base_arg, &exp) == FAILURE) { return; } - if (Z_TYPE_PP(base_arg) == IS_LONG && Z_LVAL_PP(base_arg) >= 0) { - use_ui = 1; - } else { - FETCH_GMP_ZVAL(gmpnum_base, base_arg, temp_base); - } - if (exp < 0) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Negative exponent not supported"); RETURN_FALSE; } - INIT_GMP_NUM(gmpnum_result); - if (use_ui) { - mpz_ui_pow_ui(*gmpnum_result, Z_LVAL_PP(base_arg), exp); + INIT_GMP_RETVAL(gmpnum_result); + if (Z_TYPE_P(base_arg) == IS_LONG && Z_LVAL_P(base_arg) >= 0) { + mpz_ui_pow_ui(gmpnum_result, Z_LVAL_P(base_arg), exp); } else { - mpz_pow_ui(*gmpnum_result, *gmpnum_base, exp); + FETCH_GMP_ZVAL(gmpnum_base, base_arg, temp_base); + mpz_pow_ui(gmpnum_result, gmpnum_base, exp); FREE_GMP_TEMP(temp_base); } - ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp); } /* }}} */ -/* {{{ proto resource gmp_powm(resource base, resource exp, resource mod) +/* {{{ proto GMP gmp_powm(mixed base, mixed exp, mixed mod) Raise base to power exp and take result modulo mod */ ZEND_FUNCTION(gmp_powm) { - zval **base_arg, **exp_arg, **mod_arg; - mpz_t *gmpnum_base, *gmpnum_exp, *gmpnum_mod, *gmpnum_result; + zval *base_arg, *exp_arg, *mod_arg; + mpz_ptr gmpnum_base, gmpnum_exp, gmpnum_mod, gmpnum_result; int use_ui = 0; - int temp_base, temp_exp, temp_mod; + gmp_temp_t temp_base, temp_exp, temp_mod; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZZ", &base_arg, &exp_arg, &mod_arg) == FAILURE){ + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zzz", &base_arg, &exp_arg, &mod_arg) == FAILURE){ return; } FETCH_GMP_ZVAL(gmpnum_base, base_arg, temp_base); - if (Z_TYPE_PP(exp_arg) == IS_LONG && Z_LVAL_PP(exp_arg) >= 0) { + if (Z_TYPE_P(exp_arg) == IS_LONG && Z_LVAL_P(exp_arg) >= 0) { use_ui = 1; + temp_exp.is_used = 0; } else { - FETCH_GMP_ZVAL(gmpnum_exp, exp_arg, temp_exp); - if (mpz_sgn(*gmpnum_exp) < 0) { - php_error_docref(NULL TSRMLS_CC, E_WARNING,"Second parameter cannot be less than 0"); + FETCH_GMP_ZVAL_DEP(gmpnum_exp, exp_arg, temp_exp, temp_base); + if (mpz_sgn(gmpnum_exp) < 0) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Second parameter cannot be less than 0"); + FREE_GMP_TEMP(temp_base); + FREE_GMP_TEMP(temp_exp); RETURN_FALSE; } } - FETCH_GMP_ZVAL(gmpnum_mod, mod_arg, temp_mod); + FETCH_GMP_ZVAL_DEP_DEP(gmpnum_mod, mod_arg, temp_mod, temp_exp, temp_base); - if (!mpz_cmp_ui(*gmpnum_mod, 0)) { + if (!mpz_cmp_ui(gmpnum_mod, 0)) { FREE_GMP_TEMP(temp_base); if (use_ui) { FREE_GMP_TEMP(temp_exp); @@ -1097,202 +1394,175 @@ ZEND_FUNCTION(gmp_powm) RETURN_FALSE; } - INIT_GMP_NUM(gmpnum_result); + INIT_GMP_RETVAL(gmpnum_result); if (use_ui) { - mpz_powm_ui(*gmpnum_result, *gmpnum_base, (unsigned long)Z_LVAL_PP(exp_arg), *gmpnum_mod); + mpz_powm_ui(gmpnum_result, gmpnum_base, (unsigned long) Z_LVAL_P(exp_arg), gmpnum_mod); } else { - mpz_powm(*gmpnum_result, *gmpnum_base, *gmpnum_exp, *gmpnum_mod); + mpz_powm(gmpnum_result, gmpnum_base, gmpnum_exp, gmpnum_mod); FREE_GMP_TEMP(temp_exp); } FREE_GMP_TEMP(temp_base); FREE_GMP_TEMP(temp_mod); - - ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp); - } /* }}} */ -/* {{{ proto resource gmp_sqrt(resource a) +/* {{{ proto GMP gmp_sqrt(mixed a) Takes integer part of square root of a */ ZEND_FUNCTION(gmp_sqrt) { - zval **a_arg; - mpz_t *gmpnum_a, *gmpnum_result; - int temp_a; + zval *a_arg; + mpz_ptr gmpnum_a, gmpnum_result; + gmp_temp_t temp_a; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){ + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &a_arg) == FAILURE){ return; } FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); - if (mpz_sgn(*gmpnum_a) < 0) { + if (mpz_sgn(gmpnum_a) < 0) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Number has to be greater than or equal to 0"); FREE_GMP_TEMP(temp_a); RETURN_FALSE; } - - INIT_GMP_NUM(gmpnum_result); - mpz_sqrt(*gmpnum_result, *gmpnum_a); - FREE_GMP_TEMP(temp_a); - ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp); + INIT_GMP_RETVAL(gmpnum_result); + mpz_sqrt(gmpnum_result, gmpnum_a); + FREE_GMP_TEMP(temp_a); } /* }}} */ -/* {{{ proto array gmp_sqrtrem(resource a) +/* {{{ proto array gmp_sqrtrem(mixed a) Square root with remainder */ ZEND_FUNCTION(gmp_sqrtrem) { - zval **a_arg; - mpz_t *gmpnum_a, *gmpnum_result1, *gmpnum_result2; - zval r; - int temp_a; + zval *a_arg; + mpz_ptr gmpnum_a, gmpnum_result1, gmpnum_result2; + gmp_temp_t temp_a; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){ + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &a_arg) == FAILURE){ return; } FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); - - if (mpz_sgn(*gmpnum_a) < 0) { - php_error_docref(NULL TSRMLS_CC, E_WARNING,"Number has to be greater than or equal to 0"); + + if (mpz_sgn(gmpnum_a) < 0) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Number has to be greater than or equal to 0"); + FREE_GMP_TEMP(temp_a); RETURN_FALSE; } - INIT_GMP_NUM(gmpnum_result1); - INIT_GMP_NUM(gmpnum_result2); + array_init(return_value); + add_index_zval(return_value, 0, gmp_create(&gmpnum_result1 TSRMLS_CC)); + add_index_zval(return_value, 1, gmp_create(&gmpnum_result2 TSRMLS_CC)); - mpz_sqrtrem(*gmpnum_result1, *gmpnum_result2, *gmpnum_a); + mpz_sqrtrem(gmpnum_result1, gmpnum_result2, gmpnum_a); FREE_GMP_TEMP(temp_a); - - array_init(return_value); - ZEND_REGISTER_RESOURCE(&r, gmpnum_result1, le_gmp); - add_index_resource(return_value, 0, Z_LVAL(r)); - ZEND_REGISTER_RESOURCE(&r, gmpnum_result2, le_gmp); - add_index_resource(return_value, 1, Z_LVAL(r)); } /* }}} */ -/* {{{ proto bool gmp_perfect_square(resource a) +/* {{{ proto bool gmp_perfect_square(mixed a) Checks if a is an exact square */ ZEND_FUNCTION(gmp_perfect_square) { - zval **a_arg; - mpz_t *gmpnum_a; - int temp_a; + zval *a_arg; + mpz_ptr gmpnum_a; + gmp_temp_t temp_a; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){ + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &a_arg) == FAILURE){ return; } FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); - RETVAL_BOOL((mpz_perfect_square_p(*gmpnum_a)!=0)); + RETVAL_BOOL((mpz_perfect_square_p(gmpnum_a) != 0)); FREE_GMP_TEMP(temp_a); } /* }}} */ -/* {{{ proto int gmp_prob_prime(resource a[, int reps]) +/* {{{ proto int gmp_prob_prime(mixed a[, int reps]) Checks if a is "probably prime" */ ZEND_FUNCTION(gmp_prob_prime) { - zval **gmpnumber_arg; - mpz_t *gmpnum_a; + zval *gmpnumber_arg; + mpz_ptr gmpnum_a; long reps = 10; - int temp_a; + gmp_temp_t temp_a; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z|l", &gmpnumber_arg, &reps) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|l", &gmpnumber_arg, &reps) == FAILURE) { return; } FETCH_GMP_ZVAL(gmpnum_a, gmpnumber_arg, temp_a); - RETVAL_LONG(mpz_probab_prime_p(*gmpnum_a, reps)); + RETVAL_LONG(mpz_probab_prime_p(gmpnum_a, reps)); FREE_GMP_TEMP(temp_a); } /* }}} */ -/* {{{ proto resource gmp_gcd(resource a, resource b) +/* {{{ proto GMP gmp_gcd(mixed a, mixed b) Computes greatest common denominator (gcd) of a and b */ ZEND_FUNCTION(gmp_gcd) { - zval **a_arg, **b_arg; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){ - return; - } - - gmp_zval_binary_ui_op_ex(return_value, a_arg, b_arg, mpz_gcd, (gmp_binary_ui_op_t)mpz_gcd_ui, 0, 0, 1 TSRMLS_CC); + gmp_binary_ui_op(mpz_gcd, (gmp_binary_ui_op_t) mpz_gcd_ui); } /* }}} */ -/* {{{ proto array gmp_gcdext(resource a, resource b) +/* {{{ proto array gmp_gcdext(mixed a, mixed b) Computes G, S, and T, such that AS + BT = G = `gcd' (A, B) */ ZEND_FUNCTION(gmp_gcdext) { - zval **a_arg, **b_arg; - mpz_t *gmpnum_a, *gmpnum_b, *gmpnum_t, *gmpnum_s, *gmpnum_g; - zval r; - int temp_a, temp_b; + zval *a_arg, *b_arg; + mpz_ptr gmpnum_a, gmpnum_b, gmpnum_t, gmpnum_s, gmpnum_g; + gmp_temp_t temp_a, temp_b; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){ + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &a_arg, &b_arg) == FAILURE){ return; } FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); - FETCH_GMP_ZVAL(gmpnum_b, b_arg, temp_b); + FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a); - INIT_GMP_NUM(gmpnum_g); - INIT_GMP_NUM(gmpnum_s); - INIT_GMP_NUM(gmpnum_t); + array_init(return_value); + add_assoc_zval(return_value, "g", gmp_create(&gmpnum_g TSRMLS_CC)); + add_assoc_zval(return_value, "s", gmp_create(&gmpnum_s TSRMLS_CC)); + add_assoc_zval(return_value, "t", gmp_create(&gmpnum_t TSRMLS_CC)); - mpz_gcdext(*gmpnum_g, *gmpnum_s, *gmpnum_t, *gmpnum_a, *gmpnum_b); + mpz_gcdext(gmpnum_g, gmpnum_s, gmpnum_t, gmpnum_a, gmpnum_b); FREE_GMP_TEMP(temp_a); FREE_GMP_TEMP(temp_b); - - array_init(return_value); - - ZEND_REGISTER_RESOURCE(&r, gmpnum_g, le_gmp); - add_assoc_resource(return_value, "g", Z_LVAL(r)); - ZEND_REGISTER_RESOURCE(&r, gmpnum_s, le_gmp); - add_assoc_resource(return_value, "s", Z_LVAL(r)); - ZEND_REGISTER_RESOURCE(&r, gmpnum_t, le_gmp); - add_assoc_resource(return_value, "t", Z_LVAL(r)); } /* }}} */ -/* {{{ proto resource gmp_invert(resource a, resource b) +/* {{{ proto GMP gmp_invert(mixed a, mixed b) Computes the inverse of a modulo b */ ZEND_FUNCTION(gmp_invert) { - zval **a_arg, **b_arg; - mpz_t *gmpnum_a, *gmpnum_b, *gmpnum_result; - int temp_a, temp_b; + zval *a_arg, *b_arg; + mpz_ptr gmpnum_a, gmpnum_b, gmpnum_result; + gmp_temp_t temp_a, temp_b; int res; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){ + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &a_arg, &b_arg) == FAILURE){ return; } FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); - FETCH_GMP_ZVAL(gmpnum_b, b_arg, temp_b); + FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a); - INIT_GMP_NUM(gmpnum_result); - res=mpz_invert(*gmpnum_result, *gmpnum_a, *gmpnum_b); + INIT_GMP_RETVAL(gmpnum_result); + res = mpz_invert(gmpnum_result, gmpnum_a, gmpnum_b); FREE_GMP_TEMP(temp_a); FREE_GMP_TEMP(temp_b); - if (res) { - ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp); - } else { - FREE_GMP_NUM(gmpnum_result); + if (!res) { + zval_dtor(return_value); RETURN_FALSE; } } /* }}} */ -/* {{{ proto int gmp_jacobi(resource a, resource b) +/* {{{ proto int gmp_jacobi(mixed a, mixed b) Computes Jacobi symbol */ ZEND_FUNCTION(gmp_jacobi) { @@ -1300,7 +1570,7 @@ ZEND_FUNCTION(gmp_jacobi) } /* }}} */ -/* {{{ proto int gmp_legendre(resource a, resource b) +/* {{{ proto int gmp_legendre(mixed a, mixed b) Computes Legendre symbol */ ZEND_FUNCTION(gmp_legendre) { @@ -1308,69 +1578,51 @@ ZEND_FUNCTION(gmp_legendre) } /* }}} */ -/* {{{ proto int gmp_cmp(resource a, resource b) +/* {{{ proto int gmp_cmp(mixed a, mixed b) Compares two numbers */ ZEND_FUNCTION(gmp_cmp) { - zval **a_arg, **b_arg; - mpz_t *gmpnum_a, *gmpnum_b; - int use_si = 0, res; - int temp_a, temp_b; + zval *a_arg, *b_arg; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){ + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &a_arg, &b_arg) == FAILURE){ return; } - FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); - - if (Z_TYPE_PP(b_arg) == IS_LONG) { - use_si = 1; - } else { - FETCH_GMP_ZVAL(gmpnum_b, b_arg, temp_b); - } - - if (use_si) { - res = mpz_cmp_si(*gmpnum_a, Z_LVAL_PP(b_arg)); - } else { - res = mpz_cmp(*gmpnum_a, *gmpnum_b); - } - FREE_GMP_TEMP(temp_a); - - RETURN_LONG(res); + gmp_cmp(return_value, a_arg, b_arg TSRMLS_CC); } /* }}} */ -/* {{{ proto int gmp_sign(resource a) +/* {{{ proto int gmp_sign(mixed a) Gets the sign of the number */ ZEND_FUNCTION(gmp_sign) { - zval **a_arg; - mpz_t *gmpnum_a; - int temp_a; + zval *a_arg; + mpz_ptr gmpnum_a; + gmp_temp_t temp_a; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){ + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &a_arg) == FAILURE){ return; } FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); - RETVAL_LONG(mpz_sgn(*gmpnum_a)); + RETVAL_LONG(mpz_sgn(gmpnum_a)); FREE_GMP_TEMP(temp_a); } /* }}} */ -/* {{{ proto resource gmp_random([int limiter]) +/* {{{ proto GMP gmp_random([int limiter]) Gets random number */ ZEND_FUNCTION(gmp_random) { long limiter = 20; - mpz_t *gmpnum_result; + mpz_ptr gmpnum_result; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &limiter) == FAILURE) { return; } - INIT_GMP_NUM(gmpnum_result); + INIT_GMP_RETVAL(gmpnum_result); if (!GMPG(rand_initialized)) { /* Initialize */ @@ -1382,15 +1634,14 @@ ZEND_FUNCTION(gmp_random) GMPG(rand_initialized) = 1; } #ifdef GMP_LIMB_BITS - mpz_urandomb(*gmpnum_result, GMPG(rand_state), GMP_ABS (limiter) * GMP_LIMB_BITS); + mpz_urandomb(gmpnum_result, GMPG(rand_state), GMP_ABS (limiter) * GMP_LIMB_BITS); #else - mpz_urandomb(*gmpnum_result, GMPG(rand_state), GMP_ABS (limiter) * __GMP_BITS_PER_MP_LIMB); + mpz_urandomb(gmpnum_result, GMPG(rand_state), GMP_ABS (limiter) * __GMP_BITS_PER_MP_LIMB); #endif - ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp); } /* }}} */ -/* {{{ proto resource gmp_and(resource a, resource b) +/* {{{ proto GMP gmp_and(mixed a, mixed b) Calculates logical AND of a and b */ ZEND_FUNCTION(gmp_and) { @@ -1398,7 +1649,7 @@ ZEND_FUNCTION(gmp_and) } /* }}} */ -/* {{{ proto resource gmp_or(resource a, resource b) +/* {{{ proto GMP gmp_or(mixed a, mixed b) Calculates logical OR of a and b */ ZEND_FUNCTION(gmp_or) { @@ -1406,7 +1657,7 @@ ZEND_FUNCTION(gmp_or) } /* }}} */ -/* {{{ proto resource gmp_com(resource a) +/* {{{ proto GMP gmp_com(mixed a) Calculates one's complement of a */ ZEND_FUNCTION(gmp_com) { @@ -1414,7 +1665,7 @@ ZEND_FUNCTION(gmp_com) } /* }}} */ -/* {{{ proto resource gmp_nextprime(resource a) +/* {{{ proto GMP gmp_nextprime(mixed a) Finds next prime of a */ ZEND_FUNCTION(gmp_nextprime) { @@ -1422,21 +1673,22 @@ ZEND_FUNCTION(gmp_nextprime) } /* }}} */ -/* {{{ proto resource gmp_xor(resource a, resource b) +/* {{{ proto GMP gmp_xor(mixed a, mixed b) Calculates logical exclusive OR of a and b */ ZEND_FUNCTION(gmp_xor) { - /* use formula: a^b = (a|b)&^(a&b) */ - zval **a_arg, **b_arg; + gmp_binary_op(mpz_xor); + /* use formula: a^b = (a|b)&~(a&b) */ + /*zval **a_arg, **b_arg; mpz_t *gmpnum_a, *gmpnum_b, *gmpnum_result, *gmpnum_t; - int temp_a, temp_b; + gmp_temp_t temp_a, temp_b; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){ return; } FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); - FETCH_GMP_ZVAL(gmpnum_b, b_arg, temp_b); + FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a); INIT_GMP_NUM(gmpnum_result); INIT_GMP_NUM(gmpnum_t); @@ -1451,183 +1703,169 @@ ZEND_FUNCTION(gmp_xor) FREE_GMP_TEMP(temp_a); FREE_GMP_TEMP(temp_b); - ZEND_REGISTER_RESOURCE(return_value, gmpnum_result, le_gmp); + RETVAL_GMP(gmpnum_result);*/ } /* }}} */ -/* {{{ proto void gmp_setbit(resource &a, int index[, bool set_clear]) +/* {{{ proto void gmp_setbit(GMP &a, int index[, bool set_clear]) Sets or clear bit in a */ ZEND_FUNCTION(gmp_setbit) { - zval **a_arg; + zval *a_arg; long index; zend_bool set = 1; - mpz_t *gmpnum_a; + mpz_ptr gmpnum_a; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zl|b", &a_arg, &index, &set) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Ol|b", &a_arg, gmp_ce, &index, &set) == FAILURE) { return; } - ZEND_FETCH_RESOURCE(gmpnum_a, mpz_t *, a_arg, -1, GMP_RESOURCE_NAME, le_gmp); - if (index < 0) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Index must be greater than or equal to zero"); return; } + gmpnum_a = GET_GMP_FROM_ZVAL(a_arg); + if (set) { - mpz_setbit(*gmpnum_a, index); + mpz_setbit(gmpnum_a, index); } else { - mpz_clrbit(*gmpnum_a, index); + mpz_clrbit(gmpnum_a, index); } } /* }}} */ -/* {{{ proto void gmp_clrbit(resource &a, int index) +/* {{{ proto void gmp_clrbit(GMP &a, int index) Clears bit in a */ ZEND_FUNCTION(gmp_clrbit) { - zval **a_arg; + zval *a_arg; long index; - mpz_t *gmpnum_a; + mpz_ptr gmpnum_a; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zl", &a_arg, &index) == FAILURE){ + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Ol", &a_arg, gmp_ce, &index) == FAILURE){ return; } - ZEND_FETCH_RESOURCE(gmpnum_a, mpz_t *, a_arg, -1, GMP_RESOURCE_NAME, le_gmp); - if (index < 0) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Index must be greater than or equal to zero"); return; } - mpz_clrbit(*gmpnum_a, index); + gmpnum_a = GET_GMP_FROM_ZVAL(a_arg); + mpz_clrbit(gmpnum_a, index); } /* }}} */ -/* {{{ proto bool gmp_testbit(resource a, int index) +/* {{{ proto bool gmp_testbit(mixed a, int index) Tests if bit is set in a */ ZEND_FUNCTION(gmp_testbit) { - zval **a_arg; + zval *a_arg; long index; - mpz_t *gmpnum_a; + mpz_ptr gmpnum_a; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zl", &a_arg, &index) == FAILURE){ + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zl", &a_arg, &index) == FAILURE){ return; } - ZEND_FETCH_RESOURCE(gmpnum_a, mpz_t *, a_arg, -1, GMP_RESOURCE_NAME, le_gmp); - if (index < 0) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Index must be greater than or equal to zero"); RETURN_FALSE; } - if (mpz_tstbit(*gmpnum_a, index)) { - RETURN_TRUE; - } - RETURN_FALSE; + gmpnum_a = GET_GMP_FROM_ZVAL(a_arg); + RETURN_BOOL(mpz_tstbit(gmpnum_a, index)); } /* }}} */ -/* {{{ proto int gmp_popcount(resource a) +/* {{{ proto int gmp_popcount(mixed a) Calculates the population count of a */ ZEND_FUNCTION(gmp_popcount) { - zval **a_arg; - mpz_t *gmpnum_a; - int temp_a; + zval *a_arg; + mpz_ptr gmpnum_a; + gmp_temp_t temp_a; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &a_arg) == FAILURE){ + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &a_arg) == FAILURE){ return; } FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); - RETVAL_LONG(mpz_popcount(*gmpnum_a)); + RETVAL_LONG(mpz_popcount(gmpnum_a)); FREE_GMP_TEMP(temp_a); } /* }}} */ -/* {{{ proto int gmp_hamdist(resource a, resource b) +/* {{{ proto int gmp_hamdist(mixed a, mixed b) Calculates hamming distance between a and b */ ZEND_FUNCTION(gmp_hamdist) { - zval **a_arg, **b_arg; - mpz_t *gmpnum_a, *gmpnum_b; - int temp_a, temp_b; + zval *a_arg, *b_arg; + mpz_ptr gmpnum_a, gmpnum_b; + gmp_temp_t temp_a, temp_b; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ZZ", &a_arg, &b_arg) == FAILURE){ + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &a_arg, &b_arg) == FAILURE){ return; } FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); - FETCH_GMP_ZVAL(gmpnum_b, b_arg, temp_b); + FETCH_GMP_ZVAL_DEP(gmpnum_b, b_arg, temp_b, temp_a); - RETVAL_LONG(mpz_hamdist(*gmpnum_a, *gmpnum_b)); + RETVAL_LONG(mpz_hamdist(gmpnum_a, gmpnum_b)); FREE_GMP_TEMP(temp_a); FREE_GMP_TEMP(temp_b); } /* }}} */ -/* {{{ proto int gmp_scan0(resource a, int start) +/* {{{ proto int gmp_scan0(mixed a, int start) Finds first zero bit */ ZEND_FUNCTION(gmp_scan0) { - zval **a_arg; - mpz_t *gmpnum_a; - int temp_a; + zval *a_arg; + mpz_ptr gmpnum_a; + gmp_temp_t temp_a; long start; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zl", &a_arg, &start) == FAILURE){ + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zl", &a_arg, &start) == FAILURE){ return; } - FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); - if (start < 0) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Starting index must be greater than or equal to zero"); RETURN_FALSE; } - RETVAL_LONG(mpz_scan0(*gmpnum_a, start)); + FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); + + RETVAL_LONG(mpz_scan0(gmpnum_a, start)); FREE_GMP_TEMP(temp_a); } /* }}} */ -/* {{{ proto int gmp_scan1(resource a, int start) +/* {{{ proto int gmp_scan1(mixed a, int start) Finds first non-zero bit */ ZEND_FUNCTION(gmp_scan1) { - zval **a_arg; - mpz_t *gmpnum_a; - int temp_a; + zval *a_arg; + mpz_ptr gmpnum_a; + gmp_temp_t temp_a; long start; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zl", &a_arg, &start) == FAILURE){ + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zl", &a_arg, &start) == FAILURE){ return; } - FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); if (start < 0) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Starting index must be greater than or equal to zero"); RETURN_FALSE; } - RETVAL_LONG(mpz_scan1(*gmpnum_a, start)); - FREE_GMP_TEMP(temp_a); -} -/* }}} */ - -/* {{{ _php_gmpnum_free - */ -static void _php_gmpnum_free(zend_rsrc_list_entry *rsrc TSRMLS_DC) -{ - mpz_t *gmpnum = (mpz_t *)rsrc->ptr; + FETCH_GMP_ZVAL(gmpnum_a, a_arg, temp_a); - FREE_GMP_NUM(gmpnum); + RETVAL_LONG(mpz_scan1(gmpnum_a, start)); + FREE_GMP_TEMP(temp_a); } /* }}} */ diff --git a/ext/gmp/tests/004.phpt b/ext/gmp/tests/004.phpt index a0fa1cd133..088dd08fd8 100644 --- a/ext/gmp/tests/004.phpt +++ b/ext/gmp/tests/004.phpt @@ -38,8 +38,6 @@ int(2342344) Notice: Object of class stdClass could not be converted to int in %s on line %d int(1) int(0) - -Warning: gmp_intval(): supplied resource is not a valid GMP integer resource in %s on line %d -bool(false) +int(%d) int(12345678) Done diff --git a/ext/gmp/tests/005.phpt b/ext/gmp/tests/005.phpt index 7907ffbf53..4ae0cb750a 100644 --- a/ext/gmp/tests/005.phpt +++ b/ext/gmp/tests/005.phpt @@ -47,7 +47,7 @@ bool(false) Warning: gmp_strval() expects parameter 2 to be long, string given in %s on line %d NULL -Warning: gmp_strval(): supplied resource is not a valid GMP integer resource in %s on line %d +Warning: gmp_strval(): Unable to convert variable to GMP - wrong type in %s on line %d bool(false) string(7) "9765456" diff --git a/ext/gmp/tests/006.phpt b/ext/gmp/tests/006.phpt index dedbcd0472..740760631d 100644 --- a/ext/gmp/tests/006.phpt +++ b/ext/gmp/tests/006.phpt @@ -35,9 +35,15 @@ NULL Warning: gmp_sub(): Unable to convert variable to GMP - wrong type in %s on line %d bool(false) -resource(%d) of type (GMP integer) +object(GMP)#%d (1) { + ["num"]=> + string(2) "-1" +} string(2) "-1" -resource(%d) of type (GMP integer) +object(GMP)#%d (1) { + ["num"]=> + string(5) "10001" +} string(5) "10001" Warning: gmp_sub(): Unable to convert variable to GMP - wrong type in %s on line %d diff --git a/ext/gmp/tests/007.phpt b/ext/gmp/tests/007.phpt index 4d4a993a17..e391c121f8 100644 --- a/ext/gmp/tests/007.phpt +++ b/ext/gmp/tests/007.phpt @@ -8,34 +8,16 @@ gmp_div_qr() tests var_dump(gmp_div_qr()); var_dump(gmp_div_qr("")); -var_dump($r = gmp_div_qr(0,1)); -var_dump(gmp_strval($r[0])); -var_dump(gmp_strval($r[1])); -var_dump($r = gmp_div_qr(1,0)); -var_dump($r = gmp_div_qr(12653,23482734)); -var_dump(gmp_strval($r[0])); -var_dump(gmp_strval($r[1])); -var_dump($r = gmp_div_qr(12653,23482734, 10)); -var_dump(gmp_strval($r[0])); -var_dump(gmp_strval($r[1])); -var_dump($r = gmp_div_qr(1123123,123)); -var_dump(gmp_strval($r[0])); -var_dump(gmp_strval($r[1])); -var_dump($r = gmp_div_qr(1123123,123, 1)); -var_dump(gmp_strval($r[0])); -var_dump(gmp_strval($r[1])); -var_dump($r = gmp_div_qr(1123123,123, 2)); -var_dump(gmp_strval($r[0])); -var_dump(gmp_strval($r[1])); -var_dump($r = gmp_div_qr(1123123,123, GMP_ROUND_ZERO)); -var_dump(gmp_strval($r[0])); -var_dump(gmp_strval($r[1])); -var_dump($r = gmp_div_qr(1123123,123, GMP_ROUND_PLUSINF)); -var_dump(gmp_strval($r[0])); -var_dump(gmp_strval($r[1])); -var_dump($r = gmp_div_qr(1123123,123, GMP_ROUND_MINUSINF)); -var_dump(gmp_strval($r[0])); -var_dump(gmp_strval($r[1])); +var_dump(gmp_div_qr(0,1)); +var_dump(gmp_div_qr(1,0)); +var_dump(gmp_div_qr(12653,23482734)); +var_dump(gmp_div_qr(12653,23482734, 10)); +var_dump(gmp_div_qr(1123123,123)); +var_dump(gmp_div_qr(1123123,123, 1)); +var_dump(gmp_div_qr(1123123,123, 2)); +var_dump(gmp_div_qr(1123123,123, GMP_ROUND_ZERO)); +var_dump(gmp_div_qr(1123123,123, GMP_ROUND_PLUSINF)); +var_dump(gmp_div_qr(1123123,123, GMP_ROUND_MINUSINF)); $fp = fopen(__FILE__, 'r'); @@ -52,80 +34,108 @@ Warning: gmp_div_qr() expects at least 2 parameters, 1 given in %s on line %d NULL array(2) { [0]=> - resource(%d) of type (GMP integer) + object(GMP)#%d (1) { + ["num"]=> + string(1) "0" + } [1]=> - resource(%d) of type (GMP integer) + object(GMP)#%d (1) { + ["num"]=> + string(1) "0" + } } -string(1) "0" -string(1) "0" Warning: gmp_div_qr(): Zero operand not allowed in %s on line %d bool(false) array(2) { [0]=> - resource(%d) of type (GMP integer) + object(GMP)#%d (1) { + ["num"]=> + string(1) "0" + } [1]=> - resource(%d) of type (GMP integer) + object(GMP)#%d (1) { + ["num"]=> + string(5) "12653" + } } -string(1) "0" -string(5) "12653" -NULL - -Warning: gmp_strval(): Unable to convert variable to GMP - wrong type in %s on line %d -bool(false) -Warning: gmp_strval(): Unable to convert variable to GMP - wrong type in %s on line %d +Warning: gmp_div_qr(): Invalid rounding mode in %s on line %d bool(false) array(2) { [0]=> - resource(%d) of type (GMP integer) + object(GMP)#%d (1) { + ["num"]=> + string(4) "9131" + } [1]=> - resource(%d) of type (GMP integer) + object(GMP)#%d (1) { + ["num"]=> + string(2) "10" + } } -string(4) "9131" -string(2) "10" array(2) { [0]=> - resource(%d) of type (GMP integer) + object(GMP)#%d (1) { + ["num"]=> + string(4) "9132" + } [1]=> - resource(%d) of type (GMP integer) + object(GMP)#%d (1) { + ["num"]=> + string(4) "-113" + } } -string(4) "9132" -string(4) "-113" array(2) { [0]=> - resource(%d) of type (GMP integer) + object(GMP)#%d (1) { + ["num"]=> + string(4) "9131" + } [1]=> - resource(%d) of type (GMP integer) + object(GMP)#%d (1) { + ["num"]=> + string(2) "10" + } } -string(4) "9131" -string(2) "10" array(2) { [0]=> - resource(%d) of type (GMP integer) + object(GMP)#%d (1) { + ["num"]=> + string(4) "9131" + } [1]=> - resource(%d) of type (GMP integer) + object(GMP)#%d (1) { + ["num"]=> + string(2) "10" + } } -string(4) "9131" -string(2) "10" array(2) { [0]=> - resource(%d) of type (GMP integer) + object(GMP)#%d (1) { + ["num"]=> + string(4) "9132" + } [1]=> - resource(%d) of type (GMP integer) + object(GMP)#%d (1) { + ["num"]=> + string(4) "-113" + } } -string(4) "9132" -string(4) "-113" array(2) { [0]=> - resource(%d) of type (GMP integer) + object(GMP)#%d (1) { + ["num"]=> + string(4) "9131" + } [1]=> - resource(%d) of type (GMP integer) + object(GMP)#%d (1) { + ["num"]=> + string(2) "10" + } } -string(4) "9131" -string(2) "10" -Warning: gmp_div_qr(): supplied resource is not a valid GMP integer resource in %s on line %d +Warning: gmp_div_qr(): Unable to convert variable to GMP - wrong type in %s on line %d bool(false) Warning: gmp_div_qr(): Unable to convert variable to GMP - wrong type in %s on line %d diff --git a/ext/gmp/tests/008.phpt b/ext/gmp/tests/008.phpt index 4e44ec10bf..c1874c86f9 100644 --- a/ext/gmp/tests/008.phpt +++ b/ext/gmp/tests/008.phpt @@ -9,24 +9,15 @@ var_dump(gmp_div_r()); var_dump(gmp_div_r("")); var_dump($r = gmp_div_r(0,1)); -var_dump(gmp_strval($r)); var_dump($r = gmp_div_r(1,0)); var_dump($r = gmp_div_r(12653,23482734)); -var_dump(gmp_strval($r)); var_dump($r = gmp_div_r(12653,23482734, 10)); -var_dump(gmp_strval($r)); var_dump($r = gmp_div_r(1123123,123)); -var_dump(gmp_strval($r)); var_dump($r = gmp_div_r(1123123,123, 1)); -var_dump(gmp_strval($r)); var_dump($r = gmp_div_r(1123123,123, 2)); -var_dump(gmp_strval($r)); var_dump($r = gmp_div_r(1123123,123, GMP_ROUND_ZERO)); -var_dump(gmp_strval($r)); var_dump($r = gmp_div_r(1123123,123, GMP_ROUND_PLUSINF)); -var_dump(gmp_strval($r)); var_dump($r = gmp_div_r(1123123,123, GMP_ROUND_MINUSINF)); -var_dump(gmp_strval($r)); $fp = fopen(__FILE__, 'r'); @@ -41,31 +32,46 @@ NULL Warning: gmp_div_r() expects at least 2 parameters, 1 given in %s on line %d NULL -int(0) -string(1) "0" +object(GMP)#%d (1) { + ["num"]=> + string(1) "0" +} Warning: gmp_div_r(): Zero operand not allowed in %s on line %d bool(false) -int(12653) -string(5) "12653" -NULL +object(GMP)#%d (1) { + ["num"]=> + string(5) "12653" +} -Warning: gmp_strval(): Unable to convert variable to GMP - wrong type in %s on line %d +Warning: gmp_div_r(): Invalid rounding mode in %s on line %d bool(false) -int(10) -string(2) "10" -int(113) -string(3) "113" -int(10) -string(2) "10" -int(10) -string(2) "10" -int(113) -string(3) "113" -int(10) -string(2) "10" +object(GMP)#%d (1) { + ["num"]=> + string(2) "10" +} +object(GMP)#%d (1) { + ["num"]=> + string(4) "-113" +} +object(GMP)#%d (1) { + ["num"]=> + string(2) "10" +} +object(GMP)#%d (1) { + ["num"]=> + string(2) "10" +} +object(GMP)#%d (1) { + ["num"]=> + string(4) "-113" +} +object(GMP)#%d (1) { + ["num"]=> + string(2) "10" +} -Warning: gmp_div_r(): supplied resource is not a valid GMP integer resource in %s on line %d +Warning: gmp_div_r(): Unable to convert variable to GMP - wrong type in %s on line %d bool(false) Warning: gmp_div_r(): Unable to convert variable to GMP - wrong type in %s on line %d diff --git a/ext/gmp/tests/009.phpt b/ext/gmp/tests/009.phpt index 745a4ef638..3b75a48e18 100644 --- a/ext/gmp/tests/009.phpt +++ b/ext/gmp/tests/009.phpt @@ -8,25 +8,16 @@ gmp_div_q() tests var_dump(gmp_div_q()); var_dump(gmp_div_q("")); -var_dump($r = gmp_div_q(0,1)); -var_dump(gmp_strval($r)); -var_dump($r = gmp_div_q(1,0)); -var_dump($r = gmp_div_q(12653,23482734)); -var_dump(gmp_strval($r)); -var_dump($r = gmp_div_q(12653,23482734, 10)); -var_dump(gmp_strval($r)); -var_dump($r = gmp_div_q(1123123,123)); -var_dump(gmp_strval($r)); -var_dump($r = gmp_div_q(1123123,123, 1)); -var_dump(gmp_strval($r)); -var_dump($r = gmp_div_q(1123123,123, 2)); -var_dump(gmp_strval($r)); -var_dump($r = gmp_div_q(1123123,123, GMP_ROUND_ZERO)); -var_dump(gmp_strval($r)); -var_dump($r = gmp_div_q(1123123,123, GMP_ROUND_PLUSINF)); -var_dump(gmp_strval($r)); -var_dump($r = gmp_div_q(1123123,123, GMP_ROUND_MINUSINF)); -var_dump(gmp_strval($r)); +var_dump(gmp_div_q(0,1)); +var_dump(gmp_div_q(1,0)); +var_dump(gmp_div_q(12653,23482734)); +var_dump(gmp_div_q(12653,23482734, 10)); +var_dump(gmp_div_q(1123123,123)); +var_dump(gmp_div_q(1123123,123, 1)); +var_dump(gmp_div_q(1123123,123, 2)); +var_dump(gmp_div_q(1123123,123, GMP_ROUND_ZERO)); +var_dump(gmp_div_q(1123123,123, GMP_ROUND_PLUSINF)); +var_dump(gmp_div_q(1123123,123, GMP_ROUND_MINUSINF)); $fp = fopen(__FILE__, 'r'); @@ -41,31 +32,46 @@ NULL Warning: gmp_div_q() expects at least 2 parameters, 1 given in %s on line %d NULL -resource(%d) of type (GMP integer) -string(1) "0" +object(GMP)#%d (1) { + ["num"]=> + string(1) "0" +} Warning: gmp_div_q(): Zero operand not allowed in %s on line %d bool(false) -resource(%d) of type (GMP integer) -string(1) "0" -NULL +object(GMP)#%d (1) { + ["num"]=> + string(1) "0" +} -Warning: gmp_strval(): Unable to convert variable to GMP - wrong type in %s on line %d +Warning: gmp_div_q(): Invalid rounding mode %s on line %d bool(false) -resource(%d) of type (GMP integer) -string(4) "9131" -resource(%d) of type (GMP integer) -string(4) "9132" -resource(%d) of type (GMP integer) -string(4) "9131" -resource(%d) of type (GMP integer) -string(4) "9131" -resource(%d) of type (GMP integer) -string(4) "9132" -resource(%d) of type (GMP integer) -string(4) "9131" +object(GMP)#%d (1) { + ["num"]=> + string(4) "9131" +} +object(GMP)#%d (1) { + ["num"]=> + string(4) "9132" +} +object(GMP)#%d (1) { + ["num"]=> + string(4) "9131" +} +object(GMP)#%d (1) { + ["num"]=> + string(4) "9131" +} +object(GMP)#%d (1) { + ["num"]=> + string(4) "9132" +} +object(GMP)#%d (1) { + ["num"]=> + string(4) "9131" +} -Warning: gmp_div_q(): supplied resource is not a valid GMP integer resource in %s on line %d +Warning: gmp_div_q(): Unable to convert variable to GMP - wrong type in %s on line %d bool(false) Warning: gmp_div_q(): Unable to convert variable to GMP - wrong type in %s on line %d diff --git a/ext/gmp/tests/010.phpt b/ext/gmp/tests/010.phpt index 293a2a0bf2..e3f85ec44f 100644 --- a/ext/gmp/tests/010.phpt +++ b/ext/gmp/tests/010.phpt @@ -28,13 +28,22 @@ NULL Warning: gmp_mod() expects exactly 2 parameters, 1 given in %s on line %d NULL bool(false) -int(0) -resource(%d) of type (GMP integer) +object(GMP)#%d (1) { + ["num"]=> + string(1) "0" +} +object(GMP)#%d (1) { + ["num"]=> + string(1) "0" +} Warning: gmp_mod(): Zero operand not allowed in %s on line %d bool(false) Warning: gmp_mod(): Unable to convert variable to GMP - wrong type in %s on line %d bool(false) -resource(%d) of type (GMP integer) +object(GMP)#%d (1) { + ["num"]=> + string(5) "31161" +} Done diff --git a/ext/gmp/tests/014.phpt b/ext/gmp/tests/014.phpt index 40e10c6fbe..6afccaf936 100644 --- a/ext/gmp/tests/014.phpt +++ b/ext/gmp/tests/014.phpt @@ -43,7 +43,7 @@ string(19) "2432902008176640000" string(65) "30414093201713378043612608166064768844377641568960512000000000000" string(7) "3628800" string(1) "1" -string(11) "87178291200" +string(9) "479001600" Warning: gmp_fact(): Number has to be greater than or equal to 0 in %s on line %d string(1) "0" @@ -53,6 +53,9 @@ NULL Warning: gmp_fact() expects exactly 1 parameter, 2 given in %s on line %d NULL -resource(%d) of type (GMP integer) +object(GMP)#%d (1) { + ["num"]=> + string(1) "1" +} string(1) "1" Done diff --git a/ext/gmp/tests/016.phpt b/ext/gmp/tests/016.phpt index 44360865ca..8a0b34458f 100644 --- a/ext/gmp/tests/016.phpt +++ b/ext/gmp/tests/016.phpt @@ -69,5 +69,8 @@ NULL Warning: gmp_powm(): Second parameter cannot be less than 0 in %s on line %d bool(false) -resource(%d) of type (GMP integer) +object(GMP)#%d (1) { + ["num"]=> + string(1) "1" +} Done diff --git a/ext/gmp/tests/033.phpt b/ext/gmp/tests/033.phpt index 38ff5be5bf..99848959d5 100644 --- a/ext/gmp/tests/033.phpt +++ b/ext/gmp/tests/033.phpt @@ -52,13 +52,13 @@ string(12) "100008388608" string(12) "100000000000" string(12) "100000000008" -Warning: gmp_setbit(): supplied argument is not a valid GMP integer resource in %s on line %d +Warning: gmp_setbit() expects parameter 1 to be GMP, string given in %s on line %d Warning: gmp_setbit() expects at least 2 parameters, 1 given in %s on line %d Warning: gmp_setbit() expects at most 3 parameters, 4 given in %s on line %d -Warning: gmp_setbit() expects parameter 2 to be long, array given in %s on line %d +Warning: gmp_setbit() expects parameter 1 to be GMP, string given in %s on line %d -Warning: gmp_setbit() expects parameter 2 to be long, array given in %s on line %d +Warning: gmp_setbit() expects parameter 1 to be GMP, array given in %s on line %d Done diff --git a/ext/gmp/tests/034.phpt b/ext/gmp/tests/034.phpt index 6011029905..079d5d669f 100644 --- a/ext/gmp/tests/034.phpt +++ b/ext/gmp/tests/034.phpt @@ -46,7 +46,7 @@ string(7) "1000000" string(7) "1000000" string(30) "238462734628347239571822592658" -Warning: gmp_clrbit(): supplied argument is not a valid GMP integer resource in %s on line %d +Warning: gmp_clrbit() expects parameter 1 to be GMP, array given in %s on line %d Warning: gmp_clrbit() expects exactly 2 parameters, 3 given in %s on line %d diff --git a/ext/gmp/tests/040.phpt b/ext/gmp/tests/040.phpt index 3af18cce59..9cc497edc6 100644 --- a/ext/gmp/tests/040.phpt +++ b/ext/gmp/tests/040.phpt @@ -18,7 +18,10 @@ var_dump(gmp_strval(gmp_init("993247326237679187178",3))); echo "Done\n"; ?> --EXPECTF-- -resource(%d) of type (GMP integer) +object(GMP)#%d (1) { + ["num"]=> + string(8) "98765678" +} string(8) "98765678" Warning: gmp_init() expects at least 1 parameter, 0 given in %s on line %d diff --git a/ext/gmp/tests/cast.phpt b/ext/gmp/tests/cast.phpt new file mode 100644 index 0000000000..eb1832c4dd --- /dev/null +++ b/ext/gmp/tests/cast.phpt @@ -0,0 +1,22 @@ +--TEST-- +GMP casting using casting operators +--SKIPIF-- +<?php if (!extension_loaded("gmp")) print "skip"; ?> +--FILE-- +<?php + +$n = gmp_init(42); +echo $n, "\n"; +var_dump((string) $n); +var_dump((int) $n); +var_dump((float) $n); +var_dump((bool) $n); + +?> +--EXPECTF-- +42 +string(2) "42" +int(42) +float(42) + +Catchable fatal error: Object of class GMP could not be converted to boolean in %s on line %d diff --git a/ext/gmp/tests/clone.phpt b/ext/gmp/tests/clone.phpt new file mode 100644 index 0000000000..56b5ca3dfe --- /dev/null +++ b/ext/gmp/tests/clone.phpt @@ -0,0 +1,22 @@ +--TEST-- +Cloning GMP instances +--SKIPIF-- +<?php if (!extension_loaded("gmp")) print "skip"; ?> +--FILE-- +<?php + +$a = gmp_init(3); +$b = clone $a; +gmp_clrbit($a, 0); +var_dump($a, $b); // $b should be unaffected + +?> +--EXPECTF-- +object(GMP)#1 (1) { + ["num"]=> + string(1) "2" +} +object(GMP)#2 (1) { + ["num"]=> + string(1) "3" +} diff --git a/ext/gmp/tests/comparison.phpt b/ext/gmp/tests/comparison.phpt new file mode 100644 index 0000000000..1f3a423267 --- /dev/null +++ b/ext/gmp/tests/comparison.phpt @@ -0,0 +1,37 @@ +--TEST-- +Overloaded GMP comparison in sort() etc +--SKIPIF-- +<?php if (!extension_loaded("gmp")) print "skip"; ?> +--FILE-- +<?php + +$arr = [gmp_init(0), -3, gmp_init(2), 1]; +sort($arr); +var_dump($arr); + +var_dump(min(gmp_init(3), 4)); +var_dump(max(gmp_init(3), 4)); + +?> +--EXPECT-- +array(4) { + [0]=> + int(-3) + [1]=> + object(GMP)#1 (1) { + ["num"]=> + string(1) "0" + } + [2]=> + int(1) + [3]=> + object(GMP)#2 (1) { + ["num"]=> + string(1) "2" + } +} +object(GMP)#3 (1) { + ["num"]=> + string(1) "3" +} +int(4) diff --git a/ext/gmp/tests/overloading.phpt b/ext/gmp/tests/overloading.phpt new file mode 100644 index 0000000000..18e0bb2aa9 --- /dev/null +++ b/ext/gmp/tests/overloading.phpt @@ -0,0 +1,259 @@ +--TEST-- +GMP operator overloading +--SKIPIF-- +<?php if (!extension_loaded("gmp")) print "skip"; ?> +--FILE-- +<?php + +$a = gmp_init(42); +$b = gmp_init(17); + +var_dump($a + $b); +var_dump($a + 17); +var_dump(42 + $b); + +var_dump($a - $b); +var_dump($a - 17); +var_dump(42 - $b); + +var_dump($a / $b); +var_dump($a / 17); +var_dump(42 / $b); +var_dump($a / 0); + +var_dump($a % $b); +var_dump($a % 17); +var_dump(42 % $b); +var_dump($a % 0); + +// sl, sr + +var_dump($a | $b); +var_dump($a | 17); +var_dump(42 | $b); + +var_dump($a & $b); +var_dump($a & 17); +var_dump(42 & $b); + +var_dump($a ^ $b); +var_dump($a ^ 17); +var_dump(42 ^ $b); + +var_dump($a << $b); +var_dump($a << 17); +var_dump(42 << $b); + +var_dump($a >> 2); +var_dump(-$a >> 2); + +var_dump(~$a); +var_dump(-$a); +var_dump(+$a); + +var_dump($a == $b); +var_dump($a != $b); +var_dump($a < $b); +var_dump($a <= $b); +var_dump($a > $b); +var_dump($a >= $b); + +var_dump($a == $a); +var_dump($a != $a); + +var_dump($a == 42); +var_dump($a != 42); +var_dump($a < 42); +var_dump($a <= 42); +var_dump($a > 42); +var_dump($a >= 42); + +var_dump($a == new stdClass); + +$a += 1; +var_dump($a); +$a -= 1; +var_dump($a); + +var_dump(++$a); +var_dump($a++); +var_dump($a); + +var_dump(--$a); +var_dump($a--); +var_dump($a); + +?> +--EXPECTF-- +object(GMP)#%d (1) { + ["num"]=> + string(2) "59" +} +object(GMP)#%d (1) { + ["num"]=> + string(2) "59" +} +object(GMP)#%d (1) { + ["num"]=> + string(2) "59" +} +object(GMP)#%d (1) { + ["num"]=> + string(2) "25" +} +object(GMP)#%d (1) { + ["num"]=> + string(2) "25" +} +object(GMP)#%d (1) { + ["num"]=> + string(2) "25" +} +object(GMP)#%d (1) { + ["num"]=> + string(1) "2" +} +object(GMP)#%d (1) { + ["num"]=> + string(1) "2" +} +object(GMP)#%d (1) { + ["num"]=> + string(1) "2" +} + +Warning: main(): Zero operand not allowed in %s on line %d +bool(false) +object(GMP)#%d (1) { + ["num"]=> + string(1) "8" +} +object(GMP)#%d (1) { + ["num"]=> + string(1) "8" +} +object(GMP)#%d (1) { + ["num"]=> + string(1) "8" +} + +Warning: main(): Zero operand not allowed in %s on line %d +bool(false) +object(GMP)#%d (1) { + ["num"]=> + string(2) "59" +} +object(GMP)#%d (1) { + ["num"]=> + string(2) "59" +} +object(GMP)#%d (1) { + ["num"]=> + string(2) "59" +} +object(GMP)#%d (1) { + ["num"]=> + string(1) "0" +} +object(GMP)#%d (1) { + ["num"]=> + string(1) "0" +} +object(GMP)#%d (1) { + ["num"]=> + string(1) "0" +} +object(GMP)#%d (1) { + ["num"]=> + string(2) "59" +} +object(GMP)#%d (1) { + ["num"]=> + string(2) "59" +} +object(GMP)#%d (1) { + ["num"]=> + string(2) "59" +} +object(GMP)#%d (1) { + ["num"]=> + string(7) "5505024" +} +object(GMP)#%d (1) { + ["num"]=> + string(7) "5505024" +} +object(GMP)#%d (1) { + ["num"]=> + string(7) "5505024" +} +object(GMP)#%d (1) { + ["num"]=> + string(2) "10" +} +object(GMP)#%d (1) { + ["num"]=> + string(3) "-11" +} +object(GMP)#%d (1) { + ["num"]=> + string(3) "-43" +} +object(GMP)#%d (1) { + ["num"]=> + string(3) "-42" +} +object(GMP)#%d (1) { + ["num"]=> + string(2) "42" +} +bool(false) +bool(true) +bool(false) +bool(false) +bool(true) +bool(true) +bool(true) +bool(false) +bool(true) +bool(false) +bool(false) +bool(true) +bool(false) +bool(true) + +Warning: main(): Unable to convert variable to GMP - wrong type in %s on line %d +bool(false) +object(GMP)#%d (1) { + ["num"]=> + string(2) "43" +} +object(GMP)#%d (1) { + ["num"]=> + string(2) "42" +} +object(GMP)#%d (1) { + ["num"]=> + string(2) "43" +} +object(GMP)#%d (1) { + ["num"]=> + string(2) "43" +} +object(GMP)#%d (1) { + ["num"]=> + string(2) "44" +} +object(GMP)#%d (1) { + ["num"]=> + string(2) "43" +} +object(GMP)#%d (1) { + ["num"]=> + string(2) "43" +} +object(GMP)#%d (1) { + ["num"]=> + string(2) "42" +} + diff --git a/ext/gmp/tests/serialize.phpt b/ext/gmp/tests/serialize.phpt new file mode 100644 index 0000000000..26716b659c --- /dev/null +++ b/ext/gmp/tests/serialize.phpt @@ -0,0 +1,22 @@ +--TEST-- +GMP serialization and unserialization +--SKIPIF-- +<?php if (!extension_loaded("gmp")) print "skip"; ?> +--FILE-- +<?php + +var_dump($n = gmp_init(42)); +var_dump($s = serialize($n)); +var_dump(unserialize($s)); + +?> +--EXPECTF-- +object(GMP)#%d (1) { + ["num"]=> + string(2) "42" +} +string(33) "O:3:"GMP":1:{s:3:"num";s:2:"42";}" +object(GMP)#%d (1) { + ["num"]=> + string(2) "42" +} diff --git a/ext/hash/tests/hash_file_basic.phpt b/ext/hash/tests/hash_file_basic.phpt index 9851c14b91..b16927d20e 100644 --- a/ext/hash/tests/hash_file_basic.phpt +++ b/ext/hash/tests/hash_file_basic.phpt @@ -15,7 +15,7 @@ Felix De Vliegher <felix.devliegher@gmail.com> echo "*** Testing hash_file() : basic functionality ***\n"; // Set up file -$filename = 'hash_file_example.txt'; +$filename = 'hash_file_basic_example.txt'; file_put_contents( $filename, 'The quick brown fox jumped over the lazy dog.' ); var_dump( hash_file( 'md5', $filename ) ); @@ -30,7 +30,7 @@ var_dump( base64_encode( hash_file( 'md5', $filename, true ) ) ); --CLEAN-- <?php -$filename = 'hash_file_example.txt'; +$filename = 'hash_file_basic_example.txt'; unlink( $filename ); ?> diff --git a/ext/hash/tests/hash_file_error.phpt b/ext/hash/tests/hash_file_error.phpt index 326fbd51a5..e1380301c2 100644 --- a/ext/hash/tests/hash_file_error.phpt +++ b/ext/hash/tests/hash_file_error.phpt @@ -15,7 +15,7 @@ Felix De Vliegher <felix.devliegher@gmail.com> echo "*** Testing hash_file() : error conditions ***\n"; // Set up file -$filename = 'hash_file_example.txt'; +$filename = 'hash_file_error_example.txt'; file_put_contents( $filename, 'The quick brown fox jumped over the lazy dog.' ); @@ -38,7 +38,7 @@ var_dump( hash_file( 'md5', $filename, false, $extra_arg ) ); --CLEAN-- <?php -$filename = 'hash_file_example.txt'; +$filename = 'hash_file_error_example.txt'; unlink( $filename ); ?> diff --git a/ext/mbstring/libmbfl/filters/mbfilter_utf8.c b/ext/mbstring/libmbfl/filters/mbfilter_utf8.c index fcee610533..5539700343 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_utf8.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_utf8.c @@ -79,7 +79,7 @@ const struct mbfl_convert_vtbl vtbl_utf8_wchar = { mbfl_filt_conv_common_ctor, mbfl_filt_conv_common_dtor, mbfl_filt_conv_utf8_wchar, - mbfl_filt_conv_common_flush + mbfl_filt_conv_utf8_wchar_flush }; const struct mbfl_convert_vtbl vtbl_wchar_utf8 = { @@ -93,6 +93,17 @@ const struct mbfl_convert_vtbl vtbl_wchar_utf8 = { #define CK(statement) do { if ((statement) < 0) return (-1); } while (0) +int mbfl_filt_put_invalid_char(int c, mbfl_convert_filter *filter) +{ + int w; + w = c & MBFL_WCSGROUP_MASK; + w |= MBFL_WCSGROUP_THROUGH; + filter->status = 0; + filter->cache = 0; + CK((*filter->output_function)(w, filter->data)); +} + + /* * UTF-8 => wchar */ @@ -100,111 +111,104 @@ int mbfl_filt_conv_utf8_wchar(int c, mbfl_convert_filter *filter) { int s, c1, w = 0, flag = 0; - if (c < 0x80) { - if (filter->status != 0) { - w = (filter->cache & MBFL_WCSGROUP_MASK) | MBFL_WCSGROUP_THROUGH; - CK((*filter->output_function)(w, filter->data)); - filter->status = 0; - filter->cache = 0; - } - if (c >= 0) { +retry: + switch (filter->status & 0xff) { + case 0x00: + if (c < 0x80) { CK((*filter->output_function)(c, filter->data)); + } else if (c >= 0xc2 && c <= 0xdf) { /* 2byte code first char: 0xc2-0xdf */ + filter->status = 0x10; + filter->cache = c & 0x1f; + } else if (c >= 0xe0 && c <= 0xef) { /* 3byte code first char: 0xe0-0xef */ + filter->status = 0x20; + filter->cache = c & 0xf; + } else if (c >= 0xf0 && c <= 0xf4) { /* 3byte code first char: 0xf0-0xf4 */ + filter->status = 0x30; + filter->cache = c & 0x7; + } else { + mbfl_filt_put_invalid_char(c, filter); } - } else if (c < 0xc0) { - int status = filter->status & 0xff; - switch (status) { - case 0x10: /* 2byte code 2nd char: 0x80-0xbf */ - case 0x21: /* 3byte code 3rd char: 0x80-0xbf */ - case 0x32: /* 4byte code 4th char: 0x80-0xbf */ - filter->status = 0; - s = filter->cache | (c & 0x3f); + break; + case 0x10: /* 2byte code 2nd char: 0x80-0xbf */ + case 0x21: /* 3byte code 3rd char: 0x80-0xbf */ + case 0x32: /* 4byte code 4th char: 0x80-0xbf */ + filter->status = 0; + if (c >= 0x80 && c <= 0xbf) { + s = (filter->cache<<6) | (c & 0x3f); filter->cache = 0; - if ((status == 0x10 && s >= 0x80) || - (status == 0x21 && s >= 0x800 && (s < 0xd800 || s > 0xdfff)) || - (status == 0x32 && s >= 0x10000 && s < 0x110000)) { - CK((*filter->output_function)(s, filter->data)); - } else { - w = s & MBFL_WCSGROUP_MASK; - flag = 1; - } - break; - case 0x20: /* 3byte code 2nd char: 0:0xa0-0xbf,D:0x80-9F,1-C,E-F:0x80-0x9f */ - s = filter->cache | ((c & 0x3f) << 6); - c1 = (s >> 12) & 0xf; - if ((c1 == 0x0 && c >= 0xa0) || - (c1 == 0xd && c < 0xa0) || - (c1 > 0x0 && c1 != 0xd)) { - filter->cache = s; - filter->status++; - } else { - w = s & MBFL_WCSGROUP_MASK; - flag = 1; - } - break; - case 0x31: /* 4byte code 3rd char: 0x80-0xbf */ - filter->cache |= ((c & 0x3f) << 6); - filter->status++; - break; - case 0x30: /* 4byte code 2nd char: 0:0x90-0xbf,1-3:0x80-0xbf,4:0x80-0x8f */ - s = filter->cache | ((c & 0x3f) << 12); - c1 = (s >> 18) & 0x7; - if ((c1 == 0x0 && c >= 0x90) || - (c1 > 0x0 && c1 < 0x4) || - (c1 == 0x4 && c < 0x90)) { - filter->cache = s; - filter->status++; - } else { - w = s & MBFL_WCSGROUP_MASK; - flag = 1; - } - break; - default: - w = c & MBFL_WCSGROUP_MASK; - flag = 1; - break; + CK((*filter->output_function)(s, filter->data)); + } else { + mbfl_filt_put_invalid_char(filter->cache, filter); + goto retry; } - } else if (c < 0xc2) { /* invalid: 0xc0,0xc1 */ - w = c & MBFL_WCSGROUP_MASK; - flag = 1; - } else if (c < 0xe0) { /* 2byte code first char: 0xc2-0xdf */ - if (filter->status == 0x0) { - filter->status = 0x10; - filter->cache = (c & 0x1f) << 6; + break; + case 0x20: /* 3byte code 2nd char: 0:0xa0-0xbf,D:0x80-9F,1-C,E-F:0x80-0x9f */ + s = (filter->cache<<6) | (c & 0x3f); + c1 = filter->cache & 0xf; + + if ((c >= 0x80 && c <= 0xbf) && + ((c1 == 0x0 && c >= 0xa0) || + (c1 == 0xd && c < 0xa0) || + (c1 > 0x0 && c1 != 0xd))) { + filter->cache = s; + filter->status++; } else { - w = c & MBFL_WCSGROUP_MASK; - flag = 1; + mbfl_filt_put_invalid_char(filter->cache, filter); + goto retry; } - } else if (c < 0xf0) { /* 3byte code first char: 0xe0-0xef */ - if (filter->status == 0x0) { - filter->status = 0x20; - filter->cache = (c & 0xf) << 12; + break; + case 0x30: /* 4byte code 2nd char: 0:0x90-0xbf,1-3:0x80-0xbf,4:0x80-0x8f */ + s = (filter->cache<<6) | (c & 0x3f); + c1 = filter->cache & 0x7; + + if ((c >= 0x80 && c <= 0xbf) && + ((c1 == 0x0 && c >= 0x90) || + (c1 == 0x4 && c < 0x90) || + (c1 > 0x0 && c1 != 0x4))) { + filter->cache = s; + filter->status++; } else { - w = c & MBFL_WCSGROUP_MASK; - flag = 1; + mbfl_filt_put_invalid_char(filter->cache, filter); + goto retry; } - } else if (c < 0xf5) { /* 4byte code first char: 0xf0-0xf4 */ - if (filter->status == 0x0) { - filter->status = 0x30; - filter->cache = (c & 0x7) << 18; + break; + case 0x31: /* 4byte code 3rd char: 0x80-0xbf */ + if (c >= 0x80 && c <= 0xbf) { + filter->cache = (filter->cache<<6) | (c & 0x3f); + filter->status++; } else { - w = c & MBFL_WCSGROUP_MASK; - flag = 1; + mbfl_filt_put_invalid_char(filter->cache, filter); + goto retry; } - } else { - w = c & MBFL_WCSGROUP_MASK; - flag = 1; - } - - if (flag) { - w |= MBFL_WCSGROUP_THROUGH; - CK((*filter->output_function)(w, filter->data)); + break; + default: filter->status = 0; - filter->cache = 0; + break; } return c; } +int mbfl_filt_conv_utf8_wchar_flush(mbfl_convert_filter *filter) +{ + int status, cache; + + status = filter->status; + cache = filter->cache; + + filter->status = 0; + filter->cache = 0; + + if (status != 0) { + mbfl_filt_put_invalid_char(cache, filter); + } + + if (filter->flush_function != NULL) { + (*filter->flush_function)(filter->data); + } + return 0; +} + /* * wchar => UTF-8 */ diff --git a/ext/mbstring/libmbfl/filters/mbfilter_utf8.h b/ext/mbstring/libmbfl/filters/mbfilter_utf8.h index 07bf655022..970ace6462 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_utf8.h +++ b/ext/mbstring/libmbfl/filters/mbfilter_utf8.h @@ -37,5 +37,6 @@ extern const struct mbfl_convert_vtbl vtbl_wchar_utf8; int mbfl_filt_conv_utf8_wchar(int c, mbfl_convert_filter *filter); int mbfl_filt_conv_wchar_utf8(int c, mbfl_convert_filter *filter); +int mbfl_filt_conv_utf8_wchar_flush(mbfl_convert_filter *filter); #endif /* MBFL_MBFILTER_UTF8_H */ diff --git a/ext/mbstring/libmbfl/filters/mbfilter_utf8_mobile.c b/ext/mbstring/libmbfl/filters/mbfilter_utf8_mobile.c index 62feca40b6..f9b643c17d 100644 --- a/ext/mbstring/libmbfl/filters/mbfilter_utf8_mobile.c +++ b/ext/mbstring/libmbfl/filters/mbfilter_utf8_mobile.c @@ -37,6 +37,7 @@ #include "mbfilter_sjis_mobile.h" extern int mbfl_filt_ident_utf8(int c, mbfl_identify_filter *filter); +extern int mbfl_filt_conv_utf8_wchar_flush(mbfl_convert_filter *filter); extern const unsigned char mblen_table_utf8[]; @@ -115,7 +116,7 @@ const struct mbfl_convert_vtbl vtbl_utf8_docomo_wchar = { mbfl_filt_conv_common_ctor, mbfl_filt_conv_common_dtor, mbfl_filt_conv_utf8_mobile_wchar, - mbfl_filt_conv_common_flush + mbfl_filt_conv_utf8_wchar_flush }; const struct mbfl_convert_vtbl vtbl_wchar_utf8_docomo = { @@ -133,7 +134,7 @@ const struct mbfl_convert_vtbl vtbl_utf8_kddi_a_wchar = { mbfl_filt_conv_common_ctor, mbfl_filt_conv_common_dtor, mbfl_filt_conv_utf8_mobile_wchar, - mbfl_filt_conv_common_flush + mbfl_filt_conv_utf8_wchar_flush }; const struct mbfl_convert_vtbl vtbl_wchar_utf8_kddi_a = { @@ -151,7 +152,7 @@ const struct mbfl_convert_vtbl vtbl_utf8_kddi_b_wchar = { mbfl_filt_conv_common_ctor, mbfl_filt_conv_common_dtor, mbfl_filt_conv_utf8_mobile_wchar, - mbfl_filt_conv_common_flush + mbfl_filt_conv_utf8_wchar_flush }; const struct mbfl_convert_vtbl vtbl_wchar_utf8_kddi_b = { @@ -169,7 +170,7 @@ const struct mbfl_convert_vtbl vtbl_utf8_sb_wchar = { mbfl_filt_conv_common_ctor, mbfl_filt_conv_common_dtor, mbfl_filt_conv_utf8_mobile_wchar, - mbfl_filt_conv_common_flush + mbfl_filt_conv_utf8_wchar_flush }; const struct mbfl_convert_vtbl vtbl_wchar_utf8_sb = { @@ -191,119 +192,97 @@ int mbfl_filt_conv_utf8_mobile_wchar(int c, mbfl_convert_filter *filter) int s, w = 0, flag = 0; int s1 = 0, c1 = 0, snd = 0; - if (c < 0x80) { - if (c >= 0) { +retry: + switch (filter->status & 0xff) { + case 0x00: + if (c < 0x80) { CK((*filter->output_function)(c, filter->data)); + } else if (c >= 0xc2 && c <= 0xdf) { /* 2byte code first char: 0xc2-0xdf */ + filter->status = 0x10; + filter->cache = c & 0x1f; + } else if (c >= 0xe0 && c <= 0xef) { /* 3byte code first char: 0xe0-0xef */ + filter->status = 0x20; + filter->cache = c & 0xf; + } else if (c >= 0xf0 && c <= 0xf4) { /* 3byte code first char: 0xf0-0xf4 */ + filter->status = 0x30; + filter->cache = c & 0x7; + } else { + mbfl_filt_put_invalid_char(c, filter); } + break; + case 0x10: /* 2byte code 2nd char: 0x80-0xbf */ + case 0x21: /* 3byte code 3rd char: 0x80-0xbf */ + case 0x32: /* 4byte code 4th char: 0x80-0xbf */ filter->status = 0; - } else if (c < 0xc0) { - int status = filter->status & 0xff; - switch (status) { - case 0x10: /* 2byte code 2nd char: 0x80-0xbf */ - case 0x21: /* 3byte code 3rd char: 0x80-0xbf */ - case 0x32: /* 4byte code 4th char: 0x80-0xbf */ - filter->status = 0; - s = filter->cache | (c & 0x3f); + if (c >= 0x80 && c <= 0xbf) { + s = (filter->cache<<6) | (c & 0x3f); filter->cache = 0; - if ((status == 0x10 && s >= 0x80) || - (status == 0x21 && s >= 0x800 && (s < 0xd800 || s > 0xdfff)) || - (status == 0x32 && s >= 0x10000 && s < 0x110000)) { - - if (filter->from->no_encoding == mbfl_no_encoding_utf8_docomo && - mbfilter_conv_r_map_tbl(s, &s1, mbfl_docomo2uni_pua, 4) > 0) { - s = mbfilter_sjis_emoji_docomo2unicode(s1, &snd); - } else if (filter->from->no_encoding == mbfl_no_encoding_utf8_kddi_a && - mbfilter_conv_r_map_tbl(s, &s1, mbfl_kddi2uni_pua, 7) > 0) { - s = mbfilter_sjis_emoji_kddi2unicode(s1, &snd); - } else if (filter->from->no_encoding == mbfl_no_encoding_utf8_kddi_b && - mbfilter_conv_r_map_tbl(s, &s1, mbfl_kddi2uni_pua_b, 8) > 0) { - s = mbfilter_sjis_emoji_kddi2unicode(s1, &snd); - } else if (filter->from->no_encoding == mbfl_no_encoding_utf8_sb && - mbfilter_conv_r_map_tbl(s, &s1, mbfl_sb2uni_pua, 6) > 0) { - s = mbfilter_sjis_emoji_sb2unicode(s1, &snd); - } - - if (snd > 0) { - CK((*filter->output_function)(snd, filter->data)); - } - CK((*filter->output_function)(s, filter->data)); - } else { - w = s & MBFL_WCSGROUP_MASK; - flag = 1; - } - break; - case 0x20: /* 3byte code 2nd char: 0:0xa0-0xbf,D:0x80-9F,1-C,E-F:0x80-0x9f */ - s = filter->cache | ((c & 0x3f) << 6); - c1 = (s >> 12) & 0xf; - if ((c1 == 0x0 && c >= 0xa0) || - (c1 == 0xd && c < 0xa0) || - (c1 > 0x0 && c1 != 0xd)) { - filter->cache = s; - filter->status++; - } else { - w = s & MBFL_WCSGROUP_MASK; - flag = 1; + + if (filter->from->no_encoding == mbfl_no_encoding_utf8_docomo && + mbfilter_conv_r_map_tbl(s, &s1, mbfl_docomo2uni_pua, 4) > 0) { + s = mbfilter_sjis_emoji_docomo2unicode(s1, &snd); + } else if (filter->from->no_encoding == mbfl_no_encoding_utf8_kddi_a && + mbfilter_conv_r_map_tbl(s, &s1, mbfl_kddi2uni_pua, 7) > 0) { + s = mbfilter_sjis_emoji_kddi2unicode(s1, &snd); + } else if (filter->from->no_encoding == mbfl_no_encoding_utf8_kddi_b && + mbfilter_conv_r_map_tbl(s, &s1, mbfl_kddi2uni_pua_b, 8) > 0) { + s = mbfilter_sjis_emoji_kddi2unicode(s1, &snd); + } else if (filter->from->no_encoding == mbfl_no_encoding_utf8_sb && + mbfilter_conv_r_map_tbl(s, &s1, mbfl_sb2uni_pua, 6) > 0) { + s = mbfilter_sjis_emoji_sb2unicode(s1, &snd); } - break; - case 0x31: /* 4byte code 3rd char: 0x80-0xbf */ - filter->cache |= ((c & 0x3f) << 6); - filter->status++; - break; - case 0x30: /* 4byte code 2nd char: 0:0x90-0xbf,1-3:0x80-0xbf,4:0x80-0x8f */ - s = filter->cache | ((c & 0x3f) << 12); - c1 = (s >> 18) & 0x7; - if ((c1 == 0x0 && c >= 0x90) || - (c1 > 0x0 && c1 < 0x4) || - (c1 == 0x4 && c < 0x90)) { - filter->cache = s; - filter->status++; - } else { - w = s & MBFL_WCSGROUP_MASK; - flag = 1; + + if (snd > 0) { + CK((*filter->output_function)(snd, filter->data)); } - break; - default: - w = c & MBFL_WCSGROUP_MASK; - flag = 1; - break; + CK((*filter->output_function)(s, filter->data)); + } else { + mbfl_filt_put_invalid_char(filter->cache, filter); + goto retry; } - } else if (c < 0xc2) { /* invalid: 0xc0,0xc1 */ - w = c & MBFL_WCSGROUP_MASK; - flag = 1; - } else if (c < 0xe0) { /* 2byte code first char: 0xc2-0xdf */ - if (filter->status == 0x0) { - filter->status = 0x10; - filter->cache = (c & 0x1f) << 6; + break; + case 0x20: /* 3byte code 2nd char: 0:0xa0-0xbf,D:0x80-9F,1-C,E-F:0x80-0x9f */ + s = (filter->cache<<6) | (c & 0x3f); + c1 = filter->cache & 0xf; + + if ((c >= 0x80 && c <= 0xbf) && + ((c1 == 0x0 && c >= 0xa0) || + (c1 == 0xd && c < 0xa0) || + (c1 > 0x0 && c1 != 0xd))) { + filter->cache = s; + filter->status++; } else { - w = c & MBFL_WCSGROUP_MASK; - flag = 1; + mbfl_filt_put_invalid_char(filter->cache, filter); + goto retry; } - } else if (c < 0xf0) { /* 3byte code first char: 0xe0-0xef */ - if (filter->status == 0x0) { - filter->status = 0x20; - filter->cache = (c & 0xf) << 12; + break; + case 0x30: /* 4byte code 2nd char: 0:0x90-0xbf,1-3:0x80-0xbf,4:0x80-0x8f */ + s = (filter->cache<<6) | (c & 0x3f); + c1 = filter->cache & 0x7; + + if ((c >= 0x80 && c <= 0xbf) && + ((c1 == 0x0 && c >= 0x90) || + (c1 == 0x4 && c < 0x90) || + (c1 > 0x0 && c1 != 0x4))) { + filter->cache = s; + filter->status++; } else { - w = c & MBFL_WCSGROUP_MASK; - flag = 1; + mbfl_filt_put_invalid_char(filter->cache, filter); + goto retry; } - } else if (c < 0xf5) { /* 4byte code first char: 0xf0-0xf4 */ - if (filter->status == 0x0) { - filter->status = 0x30; - filter->cache = (c & 0x7) << 18; + break; + case 0x31: /* 4byte code 3rd char: 0x80-0xbf */ + if (c >= 0x80 && c <= 0xbf) { + filter->cache = (filter->cache<<6) | (c & 0x3f); + filter->status++; } else { - w = c & MBFL_WCSGROUP_MASK; - flag = 1; + mbfl_filt_put_invalid_char(filter->cache, filter); + goto retry; } - } else { - w = c & MBFL_WCSGROUP_MASK; - flag = 1; - } - - if (flag) { - w |= MBFL_WCSGROUP_THROUGH; - CK((*filter->output_function)(w, filter->data)); + break; + default: filter->status = 0; - filter->cache = 0; + break; } return c; diff --git a/ext/mbstring/tests/bug65045.phpt b/ext/mbstring/tests/bug65045.phpt new file mode 100644 index 0000000000..03a090ded2 --- /dev/null +++ b/ext/mbstring/tests/bug65045.phpt @@ -0,0 +1,29 @@ +--TEST-- +Bug #65045: mb_convert_encoding breaks well-formed character +--SKIPIF-- +<?php extension_loaded('mbstring') or die('skip mbstring not available'); ?> +--FILE-- +<?php + +//declare(encoding = 'UTF-8'); +mb_internal_encoding('UTF-8'); + +$str = "\xF0\xA4\xAD". "\xF0\xA4\xAD\xA2"."\xF0\xA4\xAD\xA2"; +$expected = "\xEF\xBF\xBD"."\xF0\xA4\xAD\xA2"."\xF0\xA4\xAD\xA2"; + +$str2 = "\xF0\xA4\xAD\xA2"."\xF0\xA4\xAD\xA2"."\xF0\xA4\xAD"; +$expected2 = "\xF0\xA4\xAD\xA2"."\xF0\xA4\xAD\xA2"."\xEF\xBF\xBD"; + +mb_substitute_character(0xFFFD); +var_dump( + $expected === htmlspecialchars_decode(htmlspecialchars($str, ENT_SUBSTITUTE, 'UTF-8')), + $expected2 === htmlspecialchars_decode(htmlspecialchars($str2, ENT_SUBSTITUTE, 'UTF-8')), + $expected === mb_convert_encoding($str, 'UTF-8', 'UTF-8'), + $expected2 === mb_convert_encoding($str2, 'UTF-8', 'UTF-8') +); + +--EXPECT-- +bool(true) +bool(true) +bool(true) +bool(true)
\ No newline at end of file diff --git a/ext/opcache/Optimizer/compact_literals.c b/ext/opcache/Optimizer/compact_literals.c new file mode 100644 index 0000000000..b29241344c --- /dev/null +++ b/ext/opcache/Optimizer/compact_literals.c @@ -0,0 +1,481 @@ +/* pass 11 + * - compact literals table + */ +#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO + +#define DEBUG_COMPACT_LITERALS 0 + +#define LITERAL_VALUE 0x0100 +#define LITERAL_FUNC 0x0200 +#define LITERAL_CLASS 0x0300 +#define LITERAL_CONST 0x0400 +#define LITERAL_CLASS_CONST 0x0500 +#define LITERAL_STATIC_METHOD 0x0600 +#define LITERAL_STATIC_PROPERTY 0x0700 +#define LITERAL_METHOD 0x0800 +#define LITERAL_PROPERTY 0x0900 + +#define LITERAL_EX_CLASS 0x4000 +#define LITERAL_EX_OBJ 0x2000 +#define LITERAL_MAY_MERGE 0x1000 +#define LITERAL_KIND_MASK 0x0f00 +#define LITERAL_NUM_RELATED_MASK 0x000f +#define LITERAL_NUM_SLOTS_MASK 0x00f0 +#define LITERAL_NUM_SLOTS_SHIFT 4 + +#define LITERAL_NUM_RELATED(info) (info & LITERAL_NUM_RELATED_MASK) +#define LITERAL_NUM_SLOTS(info) ((info & LITERAL_NUM_SLOTS_MASK) >> LITERAL_NUM_SLOTS_SHIFT) + +typedef struct _literal_info { + zend_uint flags; /* bitmask (see defines above) */ + union { + int num; /* variable number or class name literal number */ + } u; +} literal_info; + +#define LITERAL_FLAGS(kind, slots, related) \ + ((kind) | ((slots) << LITERAL_NUM_SLOTS_SHIFT) | (related)) + +#define LITERAL_INFO(n, kind, merge, slots, related) do { \ + info[n].flags = (((merge) ? LITERAL_MAY_MERGE : 0) | LITERAL_FLAGS(kind, slots, related)); \ + } while (0) + +#define LITERAL_INFO_CLASS(n, kind, merge, slots, related, _num) do { \ + info[n].flags = (LITERAL_EX_CLASS | ((merge) ? LITERAL_MAY_MERGE : 0) | LITERAL_FLAGS(kind, slots, related)); \ + info[n].u.num = (_num); \ + } while (0) + +#define LITERAL_INFO_OBJ(n, kind, merge, slots, related, _num) do { \ + info[n].flags = (LITERAL_EX_OBJ | ((merge) ? LITERAL_MAY_MERGE : 0) | LITERAL_FLAGS(kind, slots, related)); \ + info[n].u.num = (_num); \ + } while (0) + +static void optimizer_literal_obj_info(literal_info *info, + zend_uchar op_type, + znode_op op, + int constant, + zend_uint kind, + zend_uint slots, + zend_uint related, + zend_op_array *op_array) +{ + /* For now we merge only $this object properties and methods. + * In general it's also possible to do it for any CV variable as well, + * but it would require complex dataflow and/or type analysis. + */ + if (Z_TYPE(op_array->literals[constant].constant) == IS_STRING && + op_type == IS_UNUSED) { + LITERAL_INFO_OBJ(constant, kind, 1, slots, related, op_array->this_var); + } else { + LITERAL_INFO(constant, kind, 0, slots, related); + } +} + +static void optimizer_literal_class_info(literal_info *info, + zend_uchar op_type, + znode_op op, + int constant, + zend_uint kind, + zend_uint slots, + zend_uint related, + zend_op_array *op_array) +{ + if (op_type == IS_CONST) { + LITERAL_INFO_CLASS(constant, kind, 1, slots, related, op.constant); + } else { + LITERAL_INFO(constant, kind, 0, slots, related); + } +} + +static void optimizer_compact_literals(zend_op_array *op_array TSRMLS_DC) +{ + zend_op *opline, *end; + int i, j, n, *pos, *map, cache_slots; + ulong h; + literal_info *info; + int l_null = -1; + int l_false = -1; + int l_true = -1; + HashTable hash; + char *key; + int key_len; + + if (op_array->last_literal) { + info = (literal_info*)ecalloc(op_array->last_literal, sizeof(literal_info)); + + /* Mark literals of specific types */ + opline = op_array->opcodes; + end = opline + op_array->last; + while (opline < end) { + switch (opline->opcode) { + case ZEND_DO_FCALL: + LITERAL_INFO(opline->op1.constant, LITERAL_FUNC, 1, 1, 1); + break; + case ZEND_INIT_FCALL_BY_NAME: + if (ZEND_OP2_TYPE(opline) == IS_CONST) { + LITERAL_INFO(opline->op2.constant, LITERAL_FUNC, 1, 1, 2); + } + break; + case ZEND_INIT_NS_FCALL_BY_NAME: + LITERAL_INFO(opline->op2.constant, LITERAL_FUNC, 1, 1, 3); + break; + case ZEND_INIT_METHOD_CALL: + if (ZEND_OP2_TYPE(opline) == IS_CONST) { + optimizer_literal_obj_info( + info, + opline->op1_type, + opline->op1, + opline->op2.constant, + LITERAL_METHOD, 2, 2, + op_array); + } + break; + case ZEND_INIT_STATIC_METHOD_CALL: + if (ZEND_OP1_TYPE(opline) == IS_CONST) { + LITERAL_INFO(opline->op1.constant, LITERAL_CLASS, 1, 1, 2); + } + if (ZEND_OP2_TYPE(opline) == IS_CONST) { + optimizer_literal_class_info( + info, + opline->op1_type, + opline->op1, + opline->op2.constant, + LITERAL_STATIC_METHOD, (ZEND_OP1_TYPE(opline) == IS_CONST) ? 1 : 2, 2, + op_array); + } + break; + case ZEND_CATCH: + LITERAL_INFO(opline->op1.constant, LITERAL_CLASS, 1, 1, 2); + break; + case ZEND_FETCH_CONSTANT: + if (ZEND_OP1_TYPE(opline) == IS_UNUSED) { + if ((opline->extended_value & (IS_CONSTANT_IN_NAMESPACE|IS_CONSTANT_UNQUALIFIED)) == (IS_CONSTANT_IN_NAMESPACE|IS_CONSTANT_UNQUALIFIED)) { + LITERAL_INFO(opline->op2.constant, LITERAL_CONST, 1, 1, 5); + } else { + LITERAL_INFO(opline->op2.constant, LITERAL_CONST, 1, 1, 3); + } + } else { + if (ZEND_OP1_TYPE(opline) == IS_CONST) { + LITERAL_INFO(opline->op1.constant, LITERAL_CLASS, 1, 1, 2); + } + optimizer_literal_class_info( + info, + opline->op1_type, + opline->op1, + opline->op2.constant, + LITERAL_CLASS_CONST, (ZEND_OP1_TYPE(opline) == IS_CONST) ? 1 : 2, 1, + op_array); + } + break; + case ZEND_FETCH_R: + case ZEND_FETCH_W: + case ZEND_FETCH_RW: + case ZEND_FETCH_IS: + case ZEND_FETCH_UNSET: + case ZEND_FETCH_FUNC_ARG: + case ZEND_UNSET_VAR: + case ZEND_ISSET_ISEMPTY_VAR: + if (ZEND_OP2_TYPE(opline) == IS_UNUSED) { + if (ZEND_OP1_TYPE(opline) == IS_CONST) { + LITERAL_INFO(opline->op1.constant, LITERAL_VALUE, 1, 0, 1); + } + } else { + if (ZEND_OP2_TYPE(opline) == IS_CONST) { + LITERAL_INFO(opline->op2.constant, LITERAL_CLASS, 1, 1, 2); + } + if (ZEND_OP1_TYPE(opline) == IS_CONST) { + optimizer_literal_class_info( + info, + opline->op2_type, + opline->op2, + opline->op1.constant, + LITERAL_STATIC_PROPERTY, 2, 1, + op_array); + } + } + break; + case ZEND_FETCH_CLASS: + case ZEND_ADD_INTERFACE: + case ZEND_ADD_TRAIT: + if (ZEND_OP2_TYPE(opline) == IS_CONST) { + LITERAL_INFO(opline->op2.constant, LITERAL_CLASS, 1, 1, 2); + } + break; + case ZEND_ASSIGN_OBJ: + case ZEND_FETCH_OBJ_R: + case ZEND_FETCH_OBJ_W: + case ZEND_FETCH_OBJ_RW: + case ZEND_FETCH_OBJ_IS: + case ZEND_FETCH_OBJ_UNSET: + case ZEND_FETCH_OBJ_FUNC_ARG: + case ZEND_UNSET_OBJ: + case ZEND_PRE_INC_OBJ: + case ZEND_PRE_DEC_OBJ: + case ZEND_POST_INC_OBJ: + case ZEND_POST_DEC_OBJ: + case ZEND_ISSET_ISEMPTY_PROP_OBJ: + if (ZEND_OP2_TYPE(opline) == IS_CONST) { + optimizer_literal_obj_info( + info, + opline->op1_type, + opline->op1, + opline->op2.constant, + LITERAL_PROPERTY, 2, 1, + op_array); + } + break; + case ZEND_ASSIGN_ADD: + case ZEND_ASSIGN_SUB: + case ZEND_ASSIGN_MUL: + case ZEND_ASSIGN_DIV: + case ZEND_ASSIGN_MOD: + case ZEND_ASSIGN_SL: + case ZEND_ASSIGN_SR: + case ZEND_ASSIGN_CONCAT: + case ZEND_ASSIGN_BW_OR: + case ZEND_ASSIGN_BW_AND: + case ZEND_ASSIGN_BW_XOR: + if (ZEND_OP2_TYPE(opline) == IS_CONST) { + if (opline->extended_value == ZEND_ASSIGN_OBJ) { + optimizer_literal_obj_info( + info, + opline->op1_type, + opline->op1, + opline->op2.constant, + LITERAL_PROPERTY, 2, 1, + op_array); + } else { + LITERAL_INFO(opline->op2.constant, LITERAL_VALUE, 1, 0, 1); + } + } + break; + default: + if (ZEND_OP1_TYPE(opline) == IS_CONST) { + LITERAL_INFO(opline->op1.constant, LITERAL_VALUE, 1, 0, 1); + } + if (ZEND_OP2_TYPE(opline) == IS_CONST) { + LITERAL_INFO(opline->op2.constant, LITERAL_VALUE, 1, 0, 1); + } + break; + } + opline++; + } + +#if DEBUG_COMPACT_LITERALS + { + int i, use_copy; + fprintf(stderr, "File %s func %s\n", op_array->filename, + op_array->function_name? op_array->function_name : "main"); + fprintf(stderr, "Literlas table size %d\n", op_array->last_literal); + + for (i = 0; i < op_array->last_literal; i++) { + zval zv = op_array->literals[i].constant; + zend_make_printable_zval(&op_array->literals[i].constant, &zv, &use_copy); + fprintf(stderr, "Literal %d, val (%d):%s\n", i, Z_STRLEN(zv), Z_STRVAL(zv)); + if (use_copy) { + zval_dtor(&zv); + } + } + fflush(stderr); + } +#endif + + /* Merge equal constants */ + j = 0; cache_slots = 0; + zend_hash_init(&hash, 16, NULL, NULL, 0); + map = (int*)ecalloc(op_array->last_literal, sizeof(int)); + for (i = 0; i < op_array->last_literal; i++) { + if (!info[i].flags) { + /* unsed literal */ + zval_dtor(&op_array->literals[i].constant); + continue; + } + switch (Z_TYPE(op_array->literals[i].constant)) { + case IS_NULL: + if (l_null < 0) { + l_null = j; + if (i != j) { + op_array->literals[j] = op_array->literals[i]; + info[j] = info[i]; + } + j++; + } + map[i] = l_null; + break; + case IS_BOOL: + if (Z_LVAL(op_array->literals[i].constant)) { + if (l_true < 0) { + l_true = j; + if (i != j) { + op_array->literals[j] = op_array->literals[i]; + info[j] = info[i]; + } + j++; + } + map[i] = l_true; + } else { + if (l_false < 0) { + l_false = j; + if (i != j) { + op_array->literals[j] = op_array->literals[i]; + info[j] = info[i]; + } + j++; + } + map[i] = l_false; + } + break; + case IS_LONG: + if (zend_hash_index_find(&hash, Z_LVAL(op_array->literals[i].constant), (void**)&pos) == SUCCESS) { + map[i] = *pos; + } else { + map[i] = j; + zend_hash_index_update(&hash, Z_LVAL(op_array->literals[i].constant), (void**)&j, sizeof(int), NULL); + if (i != j) { + op_array->literals[j] = op_array->literals[i]; + info[j] = info[i]; + } + j++; + } + break; + case IS_DOUBLE: + if (zend_hash_find(&hash, (char*)&Z_DVAL(op_array->literals[i].constant), sizeof(double), (void**)&pos) == SUCCESS) { + map[i] = *pos; + } else { + map[i] = j; + zend_hash_add(&hash, (char*)&Z_DVAL(op_array->literals[i].constant), sizeof(double), (void**)&j, sizeof(int), NULL); + if (i != j) { + op_array->literals[j] = op_array->literals[i]; + info[j] = info[i]; + } + j++; + } + break; + case IS_STRING: + case IS_CONSTANT: + if (info[i].flags & LITERAL_MAY_MERGE) { + if (info[i].flags & LITERAL_EX_OBJ) { + key_len = MAX_LENGTH_OF_LONG + sizeof("->") + Z_STRLEN(op_array->literals[i].constant); + key = emalloc(key_len); + key_len = snprintf(key, key_len-1, "%d->%s", info[i].u.num, Z_STRVAL(op_array->literals[i].constant)); + } else if (info[i].flags & LITERAL_EX_CLASS) { + zval *class_name = &op_array->literals[(info[i].u.num < i) ? map[info[i].u.num] : info[i].u.num].constant; + key_len = Z_STRLEN_P(class_name) + sizeof("::") + Z_STRLEN(op_array->literals[i].constant); + key = emalloc(key_len); + memcpy(key, Z_STRVAL_P(class_name), Z_STRLEN_P(class_name)); + memcpy(key + Z_STRLEN_P(class_name), "::", sizeof("::") - 1); + memcpy(key + Z_STRLEN_P(class_name) + sizeof("::") - 1, + Z_STRVAL(op_array->literals[i].constant), + Z_STRLEN(op_array->literals[i].constant) + 1); + } else { + key = Z_STRVAL(op_array->literals[i].constant); + key_len = Z_STRLEN(op_array->literals[i].constant)+1; + } + h = zend_hash_func(key, key_len); + h += info[i].flags; + } + if ((info[i].flags & LITERAL_MAY_MERGE) && + zend_hash_quick_find(&hash, key, key_len, h, (void**)&pos) == SUCCESS && + Z_TYPE(op_array->literals[i].constant) == Z_TYPE(op_array->literals[*pos].constant) && + info[i].flags == info[*pos].flags) { + + if (info[i].flags & (LITERAL_EX_OBJ|LITERAL_EX_CLASS)) { + efree(key); + } + map[i] = *pos; + zval_dtor(&op_array->literals[i].constant); + n = LITERAL_NUM_RELATED(info[i].flags); + while (n > 1) { + i++; + zval_dtor(&op_array->literals[i].constant); + n--; + } + } else { + map[i] = j; + if (info[i].flags & LITERAL_MAY_MERGE) { + zend_hash_quick_add(&hash, key, key_len, h, (void**)&j, sizeof(int), NULL); + if (info[i].flags & (LITERAL_EX_OBJ|LITERAL_EX_CLASS)) { + efree(key); + } + } + if (i != j) { + op_array->literals[j] = op_array->literals[i]; + info[j] = info[i]; + } + if (!op_array->literals[j].hash_value) { + if (IS_INTERNED(Z_STRVAL(op_array->literals[j].constant))) { + op_array->literals[j].hash_value = INTERNED_HASH(Z_STRVAL(op_array->literals[j].constant)); + } else { + op_array->literals[j].hash_value = zend_hash_func(Z_STRVAL(op_array->literals[j].constant), Z_STRLEN(op_array->literals[j].constant)+1); + } + } + if (LITERAL_NUM_SLOTS(info[i].flags)) { + op_array->literals[j].cache_slot = cache_slots; + cache_slots += LITERAL_NUM_SLOTS(info[i].flags); + } + j++; + n = LITERAL_NUM_RELATED(info[i].flags); + while (n > 1) { + i++; + if (i != j) op_array->literals[j] = op_array->literals[i]; + if (!op_array->literals[j].hash_value) { + if (IS_INTERNED(Z_STRVAL(op_array->literals[j].constant))) { + op_array->literals[j].hash_value = INTERNED_HASH(Z_STRVAL(op_array->literals[j].constant)); + } else { + op_array->literals[j].hash_value = zend_hash_func(Z_STRVAL(op_array->literals[j].constant), Z_STRLEN(op_array->literals[j].constant)+1); + } + } + j++; + n--; + } + } + break; + default: + /* don't merge other types */ + map[i] = j; + if (i != j) { + op_array->literals[j] = op_array->literals[i]; + info[j] = info[i]; + } + j++; + break; + } + } + zend_hash_destroy(&hash); + op_array->last_literal = j; + op_array->last_cache_slot = cache_slots; + + /* Update opcodes to use new literals table */ + opline = op_array->opcodes; + end = opline + op_array->last; + while (opline < end) { + if (ZEND_OP1_TYPE(opline) == IS_CONST) { + opline->op1.constant = map[opline->op1.constant]; + } + if (ZEND_OP2_TYPE(opline) == IS_CONST) { + opline->op2.constant = map[opline->op2.constant]; + } + opline++; + } + efree(map); + efree(info); + +#if DEBUG_COMPACT_LITERALS + { + int i, use_copy; + fprintf(stderr, "Optimized literlas table size %d\n", op_array->last_literal); + + for (i = 0; i < op_array->last_literal; i++) { + zval zv = op_array->literals[i].constant; + zend_make_printable_zval(&op_array->literals[i].constant, &zv, &use_copy); + fprintf(stderr, "Literal %d, val (%d):%s\n", i, Z_STRLEN(zv), Z_STRVAL(zv)); + if (use_copy) { + zval_dtor(&zv); + } + } + fflush(stderr); + } +#endif + } +} +#endif diff --git a/ext/opcache/Optimizer/optimize_func_calls.c b/ext/opcache/Optimizer/optimize_func_calls.c new file mode 100644 index 0000000000..98bfc1e99e --- /dev/null +++ b/ext/opcache/Optimizer/optimize_func_calls.c @@ -0,0 +1,138 @@ +/* pass 4 + * - optimize INIT_FCALL_BY_NAME to DO_FCALL + */ +#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO + +typedef struct _optimizer_call_info { + zend_function *func; + zend_op *opline; +} optimizer_call_info; + +static void optimize_func_calls(zend_op_array *op_array, zend_persistent_script *script TSRMLS_DC) { + zend_op *opline = op_array->opcodes; + zend_op *end = opline + op_array->last; + int call = 0; +#if ZEND_EXTENSION_API_NO > PHP_5_4_X_API_NO + optimizer_call_info *call_stack = ecalloc(op_array->nested_calls + 1, sizeof(optimizer_call_info)); +#else + int stack_size = 4; + optimizer_call_info *call_stack = ecalloc(stack_size, sizeof(optimizer_call_info)); +#endif + + while (opline < end) { + switch (opline->opcode) { + case ZEND_INIT_FCALL_BY_NAME: + case ZEND_INIT_NS_FCALL_BY_NAME: + if (ZEND_OP2_TYPE(opline) == IS_CONST) { + zend_function *func; + zval *function_name = &op_array->literals[opline->op2.constant + 1].constant; + if ((zend_hash_quick_find(&script->function_table, + Z_STRVAL_P(function_name), Z_STRLEN_P(function_name) + 1, + Z_HASH_P(function_name), (void **)&func) == SUCCESS)) { + call_stack[call].func = func; + } + } + /* break missing intentionally */ + case ZEND_NEW: + case ZEND_INIT_METHOD_CALL: + case ZEND_INIT_STATIC_METHOD_CALL: + call_stack[call].opline = opline; + call++; +#if ZEND_EXTENSION_API_NO < PHP_5_5_X_API_NO + if (call == stack_size) { + stack_size += 4; + call_stack = erealloc(call_stack, sizeof(optimizer_call_info) * stack_size); + memset(call_stack + 4, 0, 4 * sizeof(optimizer_call_info)); + } +#endif + break; + case ZEND_DO_FCALL_BY_NAME: + call--; + if (call_stack[call].func && call_stack[call].opline) { + zend_op *fcall = call_stack[call].opline; + + opline->opcode = ZEND_DO_FCALL; + ZEND_OP1_TYPE(opline) = IS_CONST; + opline->op1.constant = fcall->op2.constant + 1; + op_array->literals[fcall->op2.constant + 1].cache_slot = op_array->literals[fcall->op2.constant].cache_slot; + literal_dtor(&ZEND_OP2_LITERAL(fcall)); + if (fcall->opcode == ZEND_INIT_NS_FCALL_BY_NAME) { + literal_dtor(&op_array->literals[fcall->op2.constant + 2].constant); + } + MAKE_NOP(fcall); + } else if (opline->extended_value == 0 && + call_stack[call].opline && + call_stack[call].opline->opcode == ZEND_INIT_FCALL_BY_NAME && + ZEND_OP2_TYPE(call_stack[call].opline) == IS_CONST) { + + zend_op *fcall = call_stack[call].opline; + + opline->opcode = ZEND_DO_FCALL; + ZEND_OP1_TYPE(opline) = IS_CONST; + opline->op1.constant = fcall->op2.constant + 1; + op_array->literals[fcall->op2.constant + 1].cache_slot = op_array->literals[fcall->op2.constant].cache_slot; + literal_dtor(&ZEND_OP2_LITERAL(fcall)); + MAKE_NOP(fcall); + } + call_stack[call].func = NULL; + call_stack[call].opline = NULL; + break; + case ZEND_FETCH_FUNC_ARG: + case ZEND_FETCH_OBJ_FUNC_ARG: + case ZEND_FETCH_DIM_FUNC_ARG: + if (call_stack[call - 1].func) { + if (ARG_SHOULD_BE_SENT_BY_REF(call_stack[call - 1].func, (opline->extended_value & ZEND_FETCH_ARG_MASK))) { + opline->extended_value = 0; + opline->opcode -= 9; + } else { + opline->extended_value = 0; + opline->opcode -= 12; + } + } + break; + case ZEND_SEND_VAL: + if (opline->extended_value == ZEND_DO_FCALL_BY_NAME && call_stack[call - 1].func) { + if (ARG_MUST_BE_SENT_BY_REF(call_stack[call - 1].func, opline->op2.num)) { + /* We won't convert it into_DO_FCALL to emit error at run-time */ + call_stack[call - 1].opline = NULL; + } else { + opline->extended_value = ZEND_DO_FCALL; + } + } + break; + case ZEND_SEND_VAR: + if (opline->extended_value == ZEND_DO_FCALL_BY_NAME && call_stack[call - 1].func) { + if (ARG_SHOULD_BE_SENT_BY_REF(call_stack[call - 1].func, opline->op2.num)) { + opline->opcode = ZEND_SEND_REF; + } + opline->extended_value = ZEND_DO_FCALL; + } + break; + case ZEND_SEND_VAR_NO_REF: + if (!(opline->extended_value & ZEND_ARG_COMPILE_TIME_BOUND) && call_stack[call - 1].func) { + if (ARG_SHOULD_BE_SENT_BY_REF(call_stack[call - 1].func, opline->op2.num)) { + opline->extended_value |= ZEND_ARG_COMPILE_TIME_BOUND | ZEND_ARG_SEND_BY_REF; + } else if (opline->extended_value) { + opline->extended_value |= ZEND_ARG_COMPILE_TIME_BOUND; + } else { + opline->opcode = ZEND_SEND_VAR; + opline->extended_value = ZEND_DO_FCALL; + } + } + break; + case ZEND_SEND_REF: + if (opline->extended_value == ZEND_DO_FCALL_BY_NAME && call_stack[call - 1].func) { + /* We won't handle run-time pass by reference */ + call_stack[call - 1].opline = NULL; + } + break; + + default: + break; + } + opline++; + } + + efree(call_stack); +} +#endif diff --git a/ext/opcache/Optimizer/pass1_5.c b/ext/opcache/Optimizer/pass1_5.c index dc9e7319a9..ec5a786577 100644 --- a/ext/opcache/Optimizer/pass1_5.c +++ b/ext/opcache/Optimizer/pass1_5.c @@ -3,13 +3,13 @@ * - perform compile-time evaluation of constant binary and unary operations * - optimize series of ADD_STRING and/or ADD_CHAR * - convert CAST(IS_BOOL,x) into BOOL(x) - * - convert INTI_FCALL_BY_NAME, DO_FCALL_BY_NAME into DO_FCALL */ if (ZEND_OPTIMIZER_PASS_1 & OPTIMIZATION_LEVEL) { int i = 0; zend_op *opline = op_array->opcodes; zend_op *end = opline + op_array->last; + zend_bool collect_constants = (op_array == &script->main_op_array); while (opline < end) { switch (opline->opcode) { @@ -357,7 +357,9 @@ if (ZEND_OPTIMIZER_PASS_1 & OPTIMIZATION_LEVEL) { zval c; if (!zend_get_persistent_constant(Z_STRVAL(ZEND_OP2_LITERAL(opline)), Z_STRLEN(ZEND_OP2_LITERAL(opline)), &c, 1 TSRMLS_CC)) { - break; + if (!*constants || !zend_optimizer_get_collected_constant(*constants, &ZEND_OP2_LITERAL(opline), &c)) { + break; + } } literal_dtor(&ZEND_OP2_LITERAL(opline)); ZEND_OP1_TYPE(opline) = IS_CONST; @@ -371,22 +373,70 @@ if (ZEND_OPTIMIZER_PASS_1 & OPTIMIZATION_LEVEL) { } break; - case ZEND_INIT_FCALL_BY_NAME: - if (opline->extended_value == 0 /* not method */ && - ZEND_OP1_TYPE(opline) == IS_UNUSED && - ZEND_OP2_TYPE(opline) == IS_CONST) { - if ((opline + 1)->opcode == ZEND_DO_FCALL_BY_NAME && - (opline + 1)->extended_value == 0) { - (opline + 1)->opcode = ZEND_DO_FCALL; - COPY_NODE((opline + 1)->op1, opline->op2); - zend_str_tolower(Z_STRVAL(ZEND_OP1_LITERAL(opline + 1)), Z_STRLEN(ZEND_OP1_LITERAL(opline + 1))); + case ZEND_DO_FCALL: + /* define("name", scalar); */ + if (collect_constants && + opline->extended_value == 2 && + ZEND_OP1_TYPE(opline) == IS_CONST && + Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING && + Z_STRLEN(ZEND_OP1_LITERAL(opline)) == sizeof("define")-1 && + zend_binary_strcasecmp(Z_STRVAL(ZEND_OP1_LITERAL(opline)), Z_STRLEN(ZEND_OP1_LITERAL(opline)), "define", sizeof("define")-1) == 0 && + (opline-1)->opcode == ZEND_SEND_VAL && + ZEND_OP1_TYPE(opline-1) == IS_CONST && + (Z_TYPE(ZEND_OP1_LITERAL(opline-1)) <= IS_BOOL || + Z_TYPE(ZEND_OP1_LITERAL(opline-1)) == IS_STRING) && + (opline-2)->opcode == ZEND_SEND_VAL && + ZEND_OP1_TYPE(opline-2) == IS_CONST && + Z_TYPE(ZEND_OP1_LITERAL(opline-2)) == IS_STRING) { + zend_optimizer_collect_constant(constants, &ZEND_OP1_LITERAL(opline-2), &ZEND_OP1_LITERAL(opline-1)); + } + break; +#if ZEND_EXTENSION_API_NO > PHP_5_2_X_API_NO + case ZEND_DECLARE_CONST: + if (collect_constants && + Z_TYPE(ZEND_OP1_LITERAL(opline)) == IS_STRING && + (Z_TYPE(ZEND_OP2_LITERAL(opline)) <= IS_BOOL || + Z_TYPE(ZEND_OP2_LITERAL(opline)) == IS_STRING)) { + zend_optimizer_collect_constant(constants, &ZEND_OP1_LITERAL(opline), &ZEND_OP2_LITERAL(opline)); + } + break; +#endif + + case ZEND_RETURN: #if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO - Z_HASH_P(&ZEND_OP1_LITERAL(opline + 1)) = zend_hash_func(Z_STRVAL(ZEND_OP1_LITERAL(opline + 1)), Z_STRLEN(ZEND_OP1_LITERAL(opline + 1)) + 1); - op_array->literals[(opline + 1)->op1.constant].cache_slot = op_array->last_cache_slot++; + case ZEND_RETURN_BY_REF: #endif - MAKE_NOP(opline); - } - } +#if ZEND_EXTENSION_API_NO > PHP_5_4_X_API_NO + case ZEND_GENERATOR_RETURN: +#endif + case ZEND_EXIT: + case ZEND_THROW: + case ZEND_CATCH: + case ZEND_BRK: + case ZEND_CONT: +#if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO + case ZEND_GOTO: +#endif +#if ZEND_EXTENSION_API_NO > PHP_5_4_X_API_NO + case ZEND_FAST_CALL: + case ZEND_FAST_RET: +#endif + case ZEND_JMP: + case ZEND_JMPZNZ: + case ZEND_JMPZ: + case ZEND_JMPNZ: + case ZEND_JMPZ_EX: + case ZEND_JMPNZ_EX: + case ZEND_FE_RESET: + case ZEND_FE_FETCH: + case ZEND_NEW: +#if ZEND_EXTENSION_API_NO >= PHP_5_3_X_API_NO + case ZEND_JMP_SET: +#endif +#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO + case ZEND_JMP_SET_VAR: +#endif + collect_constants = 0; break; } opline++; diff --git a/ext/opcache/Optimizer/zend_optimizer.c b/ext/opcache/Optimizer/zend_optimizer.c index a6450ab5c4..f3fbabcf81 100644 --- a/ext/opcache/Optimizer/zend_optimizer.c +++ b/ext/opcache/Optimizer/zend_optimizer.c @@ -24,19 +24,47 @@ #include "zend_API.h"
#include "zend_constants.h"
#include "zend_execute.h"
+#include "zend_vm.h"
#define OPTIMIZATION_LEVEL \
ZCG(accel_directives).optimization_level
+static void zend_optimizer_zval_dtor_wrapper(zval *zvalue)
+{
+ zval_dtor(zvalue);
+}
+
+static void zend_optimizer_collect_constant(HashTable **constants, zval *name, zval* value)
+{
+ zval val;
+
+ if (!*constants) {
+ *constants = emalloc(sizeof(HashTable));
+ zend_hash_init(*constants, 16, NULL, (void (*)(void *))zend_optimizer_zval_dtor_wrapper, 0);
+ }
+ val = *value;
+ zval_copy_ctor(&val);
+ zend_hash_add(*constants, Z_STRVAL_P(name), Z_STRLEN_P(name)+1, (void**)&val, sizeof(zval), NULL);
+}
+
+static int zend_optimizer_get_collected_constant(HashTable *constants, zval *name, zval* value)
+{
+ zval *val;
+
+ if (zend_hash_find(constants, Z_STRVAL_P(name), Z_STRLEN_P(name)+1, (void**)&val) == SUCCESS) {
+ *value = *val;
+ zval_copy_ctor(value);
+ return 1;
+ }
+ return 0;
+}
+
#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
int zend_optimizer_add_literal(zend_op_array *op_array, const zval *zv TSRMLS_DC)
{
int i = op_array->last_literal;
op_array->last_literal++;
- if (i >= CG(context).literals_size) {
- CG(context).literals_size += 16; /* FIXME */
- op_array->literals = (zend_literal*)erealloc(op_array->literals, CG(context).literals_size * sizeof(zend_literal));
- }
+ op_array->literals = (zend_literal*)erealloc(op_array->literals, op_array->last_literal * sizeof(zend_literal));
op_array->literals[i].constant = *zv;
op_array->literals[i].hash_value = 0;
op_array->literals[i].cache_slot = -1;
@@ -84,8 +112,12 @@ int zend_optimizer_add_literal(zend_op_array *op_array, const zval *zv TSRMLS_DC #include "Optimizer/nop_removal.c"
#include "Optimizer/block_pass.c"
#include "Optimizer/optimize_temp_vars_5.c"
+#include "Optimizer/compact_literals.c"
+#include "Optimizer/optimize_func_calls.c"
-void zend_optimizer(zend_op_array *op_array TSRMLS_DC)
+static void zend_optimize(zend_op_array *op_array,
+ zend_persistent_script *script,
+ HashTable **constants TSRMLS_DC)
{
if (op_array->type == ZEND_EVAL_CODE ||
(op_array->fn_flags & ZEND_ACC_INTERACTIVE)) {
@@ -97,7 +129,6 @@ void zend_optimizer(zend_op_array *op_array TSRMLS_DC) * - perform compile-time evaluation of constant binary and unary operations
* - optimize series of ADD_STRING and/or ADD_CHAR
* - convert CAST(IS_BOOL,x) into BOOL(x)
- * - convert INTI_FCALL_BY_NAME + DO_FCALL_BY_NAME into DO_FCALL
*/
#include "Optimizer/pass1_5.c"
@@ -115,12 +146,21 @@ void zend_optimizer(zend_op_array *op_array TSRMLS_DC) */
#include "Optimizer/pass3.c"
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ /* pass 4:
+ * - INIT_FCALL_BY_NAME -> DO_FCALL
+ */
+ if (ZEND_OPTIMIZER_PASS_4 & OPTIMIZATION_LEVEL) {
+ optimize_func_calls(op_array, script TSRMLS_CC);
+ }
+#endif
+
/* pass 5:
* - CFG optimization
*/
#include "Optimizer/pass5.c"
- /* pass 9:
+ /* pass 9:
* - Optimize temp variables usage
*/
#include "Optimizer/pass9.c"
@@ -129,4 +169,143 @@ void zend_optimizer(zend_op_array *op_array TSRMLS_DC) * - remove NOPs
*/
#include "Optimizer/pass10.c"
+
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ /* pass 11:
+ * - Compact literals table
+ */
+ if (ZEND_OPTIMIZER_PASS_11 & OPTIMIZATION_LEVEL) {
+ optimizer_compact_literals(op_array TSRMLS_CC);
+ }
+#endif
+}
+
+static void zend_accel_optimize(zend_op_array *op_array,
+ zend_persistent_script *script,
+ HashTable **constants TSRMLS_DC)
+{
+ zend_op *opline, *end;
+
+ /* Revert pass_two() */
+ opline = op_array->opcodes;
+ end = opline + op_array->last;
+ while (opline < end) {
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ if (opline->op1_type == IS_CONST) {
+ opline->op1.constant = opline->op1.literal - op_array->literals;
+ }
+ if (opline->op2_type == IS_CONST) {
+ opline->op2.constant = opline->op2.literal - op_array->literals;
+ }
+#endif
+ switch (opline->opcode) {
+ case ZEND_JMP:
+#if ZEND_EXTENSION_API_NO > PHP_5_2_X_API_NO
+ case ZEND_GOTO:
+#endif
+#if ZEND_EXTENSION_API_NO > PHP_5_4_X_API_NO
+ case ZEND_FAST_CALL:
+#endif
+ ZEND_OP1(opline).opline_num = ZEND_OP1(opline).jmp_addr - op_array->opcodes;
+ break;
+ case ZEND_JMPZ:
+ case ZEND_JMPNZ:
+ case ZEND_JMPZ_EX:
+ case ZEND_JMPNZ_EX:
+#if ZEND_EXTENSION_API_NO > PHP_5_2_X_API_NO
+ case ZEND_JMP_SET:
+#endif
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ case ZEND_JMP_SET_VAR:
+#endif
+ ZEND_OP2(opline).opline_num = ZEND_OP2(opline).jmp_addr - op_array->opcodes;
+ break;
+ }
+ opline++;
+ }
+
+ /* Do actual optimizations */
+ zend_optimize(op_array, script, constants TSRMLS_CC);
+
+ /* Redo pass_two() */
+ opline = op_array->opcodes;
+ end = opline + op_array->last;
+ while (opline < end) {
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ if (opline->op1_type == IS_CONST) {
+ opline->op1.zv = &op_array->literals[opline->op1.constant].constant;
+ }
+ if (opline->op2_type == IS_CONST) {
+ opline->op2.zv = &op_array->literals[opline->op2.constant].constant;
+ }
+#endif
+ switch (opline->opcode) {
+ case ZEND_JMP:
+#if ZEND_EXTENSION_API_NO > PHP_5_2_X_API_NO
+ case ZEND_GOTO:
+#endif
+#if ZEND_EXTENSION_API_NO > PHP_5_4_X_API_NO
+ case ZEND_FAST_CALL:
+#endif
+ ZEND_OP1(opline).jmp_addr = &op_array->opcodes[ZEND_OP1(opline).opline_num];
+ break;
+ case ZEND_JMPZ:
+ case ZEND_JMPNZ:
+ case ZEND_JMPZ_EX:
+ case ZEND_JMPNZ_EX:
+#if ZEND_EXTENSION_API_NO > PHP_5_2_X_API_NO
+ case ZEND_JMP_SET:
+#endif
+#if ZEND_EXTENSION_API_NO > PHP_5_3_X_API_NO
+ case ZEND_JMP_SET_VAR:
+#endif
+ ZEND_OP2(opline).jmp_addr = &op_array->opcodes[ZEND_OP2(opline).opline_num];
+ break;
+ }
+ ZEND_VM_SET_OPCODE_HANDLER(opline);
+ opline++;
+ }
+}
+
+int zend_accel_script_optimize(zend_persistent_script *script TSRMLS_DC)
+{
+ Bucket *p, *q;
+ HashTable *constants = NULL;
+
+ zend_accel_optimize(&script->main_op_array, script, &constants TSRMLS_CC);
+
+ p = script->function_table.pListHead;
+ while (p) {
+ zend_op_array *op_array = (zend_op_array*)p->pData;
+ zend_accel_optimize(op_array, script, &constants TSRMLS_CC);
+ p = p->pListNext;
+ }
+
+ p = script->class_table.pListHead;
+ while (p) {
+ zend_class_entry *ce = (zend_class_entry*)p->pDataPtr;
+ q = ce->function_table.pListHead;
+ while (q) {
+ zend_op_array *op_array = (zend_op_array*)q->pData;
+ if (op_array->scope == ce) {
+ zend_accel_optimize(op_array, script, &constants TSRMLS_CC);
+ } else if (op_array->type == ZEND_USER_FUNCTION) {
+ zend_op_array *orig_op_array;
+ if (zend_hash_find(&op_array->scope->function_table, q->arKey, q->nKeyLength, (void**)&orig_op_array) == SUCCESS) {
+ HashTable *ht = op_array->static_variables;
+ *op_array = *orig_op_array;
+ op_array->static_variables = ht;
+ }
+ }
+ q = q->pListNext;
+ }
+ p = p->pListNext;
+ }
+
+ if (constants) {
+ zend_hash_destroy(constants);
+ efree(constants);
+ }
+
+ return 1;
}
diff --git a/ext/opcache/Optimizer/zend_optimizer.h b/ext/opcache/Optimizer/zend_optimizer.h index 98275a20aa..5a3d715ac9 100644 --- a/ext/opcache/Optimizer/zend_optimizer.h +++ b/ext/opcache/Optimizer/zend_optimizer.h @@ -28,14 +28,14 @@ #define ZEND_OPTIMIZER_PASS_1 (1<<0) /* CSE, STRING construction */
#define ZEND_OPTIMIZER_PASS_2 (1<<1) /* Constant conversion and jumps */
#define ZEND_OPTIMIZER_PASS_3 (1<<2) /* ++, +=, series of jumps */
-#define ZEND_OPTIMIZER_PASS_4 (1<<3)
+#define ZEND_OPTIMIZER_PASS_4 (1<<3) /* INIT_FCALL_BY_NAME -> DO_FCALL */
#define ZEND_OPTIMIZER_PASS_5 (1<<4) /* CFG based optimization */
#define ZEND_OPTIMIZER_PASS_6 (1<<5)
#define ZEND_OPTIMIZER_PASS_7 (1<<6)
#define ZEND_OPTIMIZER_PASS_8 (1<<7)
#define ZEND_OPTIMIZER_PASS_9 (1<<8) /* TMP VAR usage */
#define ZEND_OPTIMIZER_PASS_10 (1<<9) /* NOP removal */
-#define ZEND_OPTIMIZER_PASS_11 (1<<10)
+#define ZEND_OPTIMIZER_PASS_11 (1<<10) /* Merge equal constants */
#define ZEND_OPTIMIZER_PASS_12 (1<<11)
#define ZEND_OPTIMIZER_PASS_13 (1<<12)
#define ZEND_OPTIMIZER_PASS_14 (1<<13)
@@ -44,6 +44,4 @@ #define DEFAULT_OPTIMIZATION_LEVEL "0xFFFFFFFF"
-void zend_optimizer(zend_op_array *op_array TSRMLS_DC);
-
#endif
diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c index efd902f431..38b2028cfa 100644 --- a/ext/opcache/ZendAccelerator.c +++ b/ext/opcache/ZendAccelerator.c @@ -1126,6 +1126,10 @@ static zend_persistent_script *cache_script_in_shared_memory(zend_persistent_scr return new_persistent_script; } + if (!zend_accel_script_optimize(new_persistent_script TSRMLS_CC)) { + return new_persistent_script; + } + if (!compact_persistent_script(new_persistent_script)) { return new_persistent_script; } @@ -2744,19 +2748,6 @@ void accelerator_shm_read_unlock(TSRMLS_D) } } -static void accel_op_array_handler(zend_op_array *op_array) -{ - TSRMLS_FETCH(); - - if (ZCG(enabled) && - accel_startup_ok && - ZCSG(accelerator_enabled) && - !ZSMMG(memory_exhausted) && - !ZCSG(restart_pending)) { - zend_optimizer(op_array TSRMLS_CC); - } -} - ZEND_EXT_API zend_extension zend_extension_entry = { ACCELERATOR_PRODUCT_NAME, /* name */ ACCELERATOR_VERSION, /* version */ @@ -2768,7 +2759,7 @@ ZEND_EXT_API zend_extension zend_extension_entry = { accel_activate, /* per-script activation */ accel_deactivate, /* per-script deactivation */ NULL, /* message handler */ - accel_op_array_handler, /* op_array handler */ + NULL, /* op_array handler */ NULL, /* extended statement handler */ NULL, /* extended fcall begin handler */ NULL, /* extended fcall end handler */ diff --git a/ext/opcache/ZendAccelerator.h b/ext/opcache/ZendAccelerator.h index 733e544e11..06a2cf7f4a 100644 --- a/ext/opcache/ZendAccelerator.h +++ b/ext/opcache/ZendAccelerator.h @@ -319,6 +319,7 @@ extern char *zps_api_failure_reason; void zend_accel_schedule_restart(zend_accel_restart_reason reason TSRMLS_DC); void zend_accel_schedule_restart_if_necessary(zend_accel_restart_reason reason TSRMLS_DC); int zend_accel_invalidate(const char *filename, int filename_len, zend_bool force TSRMLS_DC); +int zend_accel_script_optimize(zend_persistent_script *persistent_script TSRMLS_DC); int accelerator_shm_read_lock(TSRMLS_D); void accelerator_shm_read_unlock(TSRMLS_D); diff --git a/ext/opcache/tests/compact_literals.phpt b/ext/opcache/tests/compact_literals.phpt new file mode 100644 index 0000000000..a691b912e3 --- /dev/null +++ b/ext/opcache/tests/compact_literals.phpt @@ -0,0 +1,215 @@ +--TEST-- +Test with compact literals +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.optimization_level=-1 +--SKIPIF-- +<?php require_once('skipif.inc'); ?> +--FILE-- +<?php + +echo "array key hash" . ":" . PHP_EOL; +$array = array( + "1" => "one", + "2" => "two", + "one" => 1, + "two" => 2, +); + +unset($array["one"]); +unset($array["2"]); + +print_r($array); + +echo "funcion define" . ":" . PHP_EOL; +if (!function_exists("dummy")) { + function dummy() { + var_dump(__FUNCTION__); + } +} + +dummy(); + +$dummy = function () { var_dump("lambda" . "dummy"); }; +$dummy(); + +if (!class_exists("A")) { + class A { + public static $name = "A"; + public static function say($n = "name") { + var_dump(static::$name); + } + } +} + +class B extends A { + public static $name = "B"; +} + +if (!class_exists("C")) { + class C extends B { + public static $name = "C"; + } +} + +A::say(); +B::Say(); +A::say(); +B::say(); +C::say(); + +function get_eol_define() { + define("MY_EOL", PHP_EOL); +} +get_eol_define(); +define("EOL", MY_EOL); + +echo "constants define" . ":" . EOL; + +echo "define " . "TEST" . EOL; +define("TEST", "TEST"); + +class E { + public static $E="EP"; + const E="E"; + const TEST="NULL"; +} + +class F { + const F="F"; + public static $E="FEP"; + const E="FE"; + const TEST="FALSE"; + public static $F = "FP"; +} + +var_dump(TEST); //"TEST" +var_dump(E::E); //"E" +var_dump(F::E); //"FE" +var_dump(F::F); //"F" +var_dump(E::TEST); //"NULL" +var_dump(F::TEST); //"FALSE" +var_dump(E::$E); //"EP" +var_dumP(F::$F); //"FP" +var_dumP(F::$E); //"FEP" + +echo "propertes and methods" . EOL; + +class CH { + const H = "H"; + public function h() { + var_dump(self::H); + } +} + +class CI { + const H = "I"; + public function h() { + var_dump(self::H); + } +} + +function change(&$obj) { + $obj = new CH; +} + +function geti() { + return new CI; +} + +$h = new CH; + +echo "-->H" . PHP_EOL; +$h->H(); +var_dump($h::H); +var_dump(CH::H); + +$h->H(); +var_dump($h::H); +var_dump(CH::H); + +echo "-->I" . PHP_EOL; +$h = new CI; +$h->H(); +var_dump($h::H); +var_dump(CI::H); +$h->H(); +var_dump($h::H); +var_dump(CI::H); + +echo "-->H" . PHP_EOL; +change($h); + +$h->H(); +var_dump($h::H); +var_dump(CH::H); + +$h->H(); +var_dump($h::H); +var_dump(CH::H); + +echo "-->I" . PHP_EOL; +$h = geti(); +$h->H(); +var_dump($h::H); +var_dump(CI::H); +$h->H(); +var_dump($h::H); +var_dump(CI::H); +?> +--EXPECT-- +array key hash: +Array +( + [1] => one + [two] => 2 +) +funcion define: +string(5) "dummy" +string(11) "lambdadummy" +string(1) "A" +string(1) "B" +string(1) "A" +string(1) "B" +string(1) "C" +constants define: +define TEST +string(4) "TEST" +string(1) "E" +string(2) "FE" +string(1) "F" +string(4) "NULL" +string(5) "FALSE" +string(2) "EP" +string(2) "FP" +string(3) "FEP" +propertes and methods +-->H +string(1) "H" +string(1) "H" +string(1) "H" +string(1) "H" +string(1) "H" +string(1) "H" +-->I +string(1) "I" +string(1) "I" +string(1) "I" +string(1) "I" +string(1) "I" +string(1) "I" +-->H +string(1) "H" +string(1) "H" +string(1) "H" +string(1) "H" +string(1) "H" +string(1) "H" +-->I +string(1) "I" +string(1) "I" +string(1) "I" +string(1) "I" +string(1) "I" +string(1) "I" diff --git a/ext/opcache/tests/optimize_func_calls.phpt b/ext/opcache/tests/optimize_func_calls.phpt new file mode 100644 index 0000000000..b3bc8da6a9 --- /dev/null +++ b/ext/opcache/tests/optimize_func_calls.phpt @@ -0,0 +1,130 @@ +--TEST-- +Test with optimization of function calls +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.optimization_level=-1 +--SKIPIF-- +<?php require_once('skipif.inc'); ?> +--FILE-- +<?php + +class A { + public $obj; + public function test($a) { + } +} + +function a(&$b) { + $b = "changed"; + return "done"; +} + +$a = "a"; +$b = "b"; +$c = "c"; +$f = "a"; + +/* + * INIT_FCALL_BY_NAME + * SEND_VAR + * DO_FCALL + * DO_FCALL_BY_NAME + */ +foo(a($a)); +var_dump($a); +$a = "a"; + +/* + * INIT_FCALL_BY_NAME + * INIT_FCALL_BY_NAME -- un-optimizable + * DO_FCALL_BY_NAME -- un-optimizable + * DO_FCALL_BY_NAME + */ +foo($f($a)); +var_dump($a); + +/* + * INIT_FCALL_BY_NAME + * ZEND_NEW + * DO_FCALL_BY_NAME + * DO_FCALL_BY_NAME + */ +foo(new A()); + +/* + * INIT_FCALL_BY_NAME + * FETCH_OBJ_FUNC_ARG + * ZEND_SEND_VAR + * DO_FCALL_BY_NAME + */ +foo((new A)->obj); +$obj = new A; +ref($obj->obj); +var_dump($obj->obj); + +ref(retarray()[0]); + +$a = "a"; +foo(a($a), $a, ref($b, $c), $obj); +var_dump($a); +var_dump($b); + +/* + * INIT_FCALL_BY_NAME + * SEND_VAL + * DO_FCALL_BY_NAME + */ +ref("xxx"); + +function retarray() { + return array("retarray"); +} + +function foo($a) { + print_r(func_get_args()); +} + +function ref(&$b) { + $b = "changed"; + return "ref"; +} +--EXPECTF-- +Array +( + [0] => done +) +string(7) "changed" +Array +( + [0] => done +) +string(7) "changed" +Array +( + [0] => A Object + ( + [obj] => + ) + +) +Array +( + [0] => +) +string(7) "changed" +Array +( + [0] => done + [1] => changed + [2] => ref + [3] => A Object + ( + [obj] => changed + ) + +) +string(7) "changed" +string(7) "changed" + +Fatal error: Cannot pass parameter 1 by reference in %soptimize_func_calls.php on line %d diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c index c939c01b2b..68f3aaf19b 100644 --- a/ext/openssl/openssl.c +++ b/ext/openssl/openssl.c @@ -391,11 +391,35 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_random_pseudo_bytes, 0, 0, 1) ZEND_ARG_INFO(0, length) ZEND_ARG_INFO(1, result_is_strong) ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_openssl_spki_new, 0, 0, 2) + ZEND_ARG_INFO(0, privkey) + ZEND_ARG_INFO(0, challenge) + ZEND_ARG_INFO(0, algo) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_openssl_spki_verify, 0) + ZEND_ARG_INFO(0, spki) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_openssl_spki_export, 0) + ZEND_ARG_INFO(0, spki) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_openssl_spki_export_challenge, 0) + ZEND_ARG_INFO(0, spki) +ZEND_END_ARG_INFO() /* }}} */ /* {{{ openssl_functions[] */ const zend_function_entry openssl_functions[] = { +/* spki functions */ + PHP_FE(openssl_spki_new, arginfo_openssl_spki_new) + PHP_FE(openssl_spki_verify, arginfo_openssl_spki_verify) + PHP_FE(openssl_spki_export, arginfo_openssl_spki_export) + PHP_FE(openssl_spki_export_challenge, arginfo_openssl_spki_export_challenge) + /* public/private key functions */ PHP_FE(openssl_pkey_free, arginfo_openssl_pkey_free) PHP_FE(openssl_pkey_new, arginfo_openssl_pkey_new) @@ -790,6 +814,7 @@ static int add_oid_section(struct php_x509_request * req TSRMLS_DC) /* {{{ */ static const EVP_CIPHER * php_openssl_get_evp_cipher_from_algo(long algo); +int openssl_spki_cleanup(const char *src, char *dest); static int php_openssl_parse_config(struct php_x509_request * req, zval * optional_args TSRMLS_DC) /* {{{ */ { @@ -1334,6 +1359,280 @@ PHP_FUNCTION(openssl_x509_export_to_file) } /* }}} */ +/* {{{ proto string openssl_spki_new(mixed zpkey, string challenge [, mixed method]) + Creates new private key (or uses existing) and creates a new spki cert + outputting results to var */ +PHP_FUNCTION(openssl_spki_new) +{ + int challenge_len; + char * challenge = NULL, * spkstr = NULL, * s = NULL; + long keyresource = -1; + const char *spkac = "SPKAC="; + long algo = OPENSSL_ALGO_MD5; + + zval *method = NULL; + zval * zpkey = NULL; + EVP_PKEY * pkey = NULL; + NETSCAPE_SPKI *spki=NULL; + const EVP_MD *mdtype; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|z", &zpkey, &challenge, &challenge_len, &method) == FAILURE) { + return; + } + RETVAL_FALSE; + + pkey = php_openssl_evp_from_zval(&zpkey, 0, challenge, 1, &keyresource TSRMLS_CC); + + if (pkey == NULL) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to use supplied private key"); + goto cleanup; + } + + if (method != NULL) { + if (Z_TYPE_P(method) == IS_LONG) { + algo = Z_LVAL_P(method); + } else { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Algorithm must be of supported type"); + goto cleanup; + } + } + mdtype = php_openssl_get_evp_md_from_algo(algo); + + if (!mdtype) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown signature algorithm"); + goto cleanup; + } + + if ((spki = NETSCAPE_SPKI_new()) == NULL) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to create new SPKAC"); + goto cleanup; + } + + if (challenge) { + ASN1_STRING_set(spki->spkac->challenge, challenge, challenge_len); + } + + if (!NETSCAPE_SPKI_set_pubkey(spki, pkey)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to embed public key"); + goto cleanup; + } + + if (!NETSCAPE_SPKI_sign(spki, pkey, mdtype)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to sign with specified algorithm"); + goto cleanup; + } + + spkstr = NETSCAPE_SPKI_b64_encode(spki); + if (!spkstr){ + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to encode SPKAC"); + goto cleanup; + } + + s = emalloc(strlen(spkac) + strlen(spkstr) + 1); + sprintf(s, "%s%s", spkac, spkstr); + + RETVAL_STRINGL(s, strlen(s), 0); + goto cleanup; + +cleanup: + + if (keyresource == -1 && spki != NULL) { + NETSCAPE_SPKI_free(spki); + } + if (keyresource == -1 && pkey != NULL) { + EVP_PKEY_free(pkey); + } + if (keyresource == -1 && spkstr != NULL) { + efree(spkstr); + } + + if (strlen(s) <= 0) { + RETVAL_FALSE; + } + + if (keyresource == -1 && s != NULL) { + efree(s); + } +} +/* }}} */ + +/* {{{ proto bool openssl_spki_verify(string spki) + Verifies spki returns boolean */ +PHP_FUNCTION(openssl_spki_verify) +{ + int spkstr_len, i = 0; + char *spkstr = NULL, * spkstr_cleaned = NULL; + + EVP_PKEY *pkey = NULL; + NETSCAPE_SPKI *spki = NULL; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &spkstr, &spkstr_len) == FAILURE) { + return; + } + RETVAL_FALSE; + + if (spkstr == NULL) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to use supplied SPKAC"); + goto cleanup; + } + + spkstr_cleaned = emalloc(spkstr_len + 1); + openssl_spki_cleanup(spkstr, spkstr_cleaned); + + if (strlen(spkstr_cleaned)<=0) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid SPKAC"); + goto cleanup; + } + + spki = NETSCAPE_SPKI_b64_decode(spkstr_cleaned, strlen(spkstr_cleaned)); + if (spki == NULL) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to decode supplied SPKAC"); + goto cleanup; + } + + pkey = X509_PUBKEY_get(spki->spkac->pubkey); + if (pkey == NULL) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to aquire signed public key"); + goto cleanup; + } + + i = NETSCAPE_SPKI_verify(spki, pkey); + goto cleanup; + +cleanup: + if (spki != NULL) { + NETSCAPE_SPKI_free(spki); + } + if (pkey != NULL) { + EVP_PKEY_free(pkey); + } + if (spkstr_cleaned != NULL) { + efree(spkstr_cleaned); + } + + if (i > 0) { + RETVAL_TRUE; + } +} +/* }}} */ + +/* {{{ proto string openssl_spki_export(string spki) + Exports public key from existing spki to var */ +PHP_FUNCTION(openssl_spki_export) +{ + int spkstr_len; + char *spkstr = NULL, * spkstr_cleaned = NULL, * s = NULL; + + EVP_PKEY *pkey = NULL; + NETSCAPE_SPKI *spki = NULL; + BIO *out = BIO_new(BIO_s_mem()); + BUF_MEM *bio_buf; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &spkstr, &spkstr_len) == FAILURE) { + return; + } + RETVAL_FALSE; + + if (spkstr == NULL) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to use supplied SPKAC"); + goto cleanup; + } + + spkstr_cleaned = emalloc(spkstr_len + 1); + openssl_spki_cleanup(spkstr, spkstr_cleaned); + + spki = NETSCAPE_SPKI_b64_decode(spkstr_cleaned, strlen(spkstr_cleaned)); + if (spki == NULL) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to decode supplied SPKAC"); + goto cleanup; + } + + pkey = X509_PUBKEY_get(spki->spkac->pubkey); + if (pkey == NULL) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to aquire signed public key"); + goto cleanup; + } + + out = BIO_new_fp(stdout, BIO_NOCLOSE); + PEM_write_bio_PUBKEY(out, pkey); + goto cleanup; + +cleanup: + + if (spki != NULL) { + NETSCAPE_SPKI_free(spki); + } + if (out != NULL) { + BIO_free_all(out); + } + if (pkey != NULL) { + EVP_PKEY_free(pkey); + } + if (spkstr_cleaned != NULL) { + efree(spkstr_cleaned); + } + if (s != NULL) { + efree(s); + } +} +/* }}} */ + +/* {{{ proto string openssl_spki_export_challenge(string spki) + Exports spkac challenge from existing spki to var */ +PHP_FUNCTION(openssl_spki_export_challenge) +{ + int spkstr_len; + char *spkstr = NULL, * spkstr_cleaned = NULL; + + NETSCAPE_SPKI *spki = NULL; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &spkstr, &spkstr_len) == FAILURE) { + return; + } + RETVAL_FALSE; + + if (spkstr == NULL) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to use supplied SPKAC"); + goto cleanup; + } + + spkstr_cleaned = emalloc(spkstr_len + 1); + openssl_spki_cleanup(spkstr, spkstr_cleaned); + + spki = NETSCAPE_SPKI_b64_decode(spkstr_cleaned, strlen(spkstr_cleaned)); + if (spki == NULL) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to decode SPKAC"); + goto cleanup; + } + + RETVAL_STRING(ASN1_STRING_data(spki->spkac->challenge), 1); + goto cleanup; + +cleanup: + if (spkstr_cleaned != NULL) { + efree(spkstr_cleaned); + } +} +/* }}} */ + +/* {{{ strip line endings from spkac */ +int openssl_spki_cleanup(const char *src, char *dest) +{ + int removed=0; + + while (*src) { + if (*src!='\n'&&*src!='\r') { + *dest++=*src; + } else { + ++removed; + } + ++src; + } + *dest=0; + return removed; +} +/* }}} */ + /* {{{ proto bool openssl_x509_export(mixed x509, string &out [, bool notext = true]) Exports a CERT to file or a var */ PHP_FUNCTION(openssl_x509_export) diff --git a/ext/openssl/php_openssl.h b/ext/openssl/php_openssl.h index e6b064a277..8483bbf762 100644 --- a/ext/openssl/php_openssl.h +++ b/ext/openssl/php_openssl.h @@ -79,6 +79,11 @@ PHP_FUNCTION(openssl_csr_export_to_file); PHP_FUNCTION(openssl_csr_sign); PHP_FUNCTION(openssl_csr_get_subject); PHP_FUNCTION(openssl_csr_get_public_key); + +PHP_FUNCTION(openssl_spki_new); +PHP_FUNCTION(openssl_spki_verify); +PHP_FUNCTION(openssl_spki_export); +PHP_FUNCTION(openssl_spki_export_challenge); #else #define phpext_openssl_ptr NULL diff --git a/ext/openssl/tests/openssl_spki_export.phpt b/ext/openssl/tests/openssl_spki_export.phpt new file mode 100644 index 0000000000..59332f70a5 --- /dev/null +++ b/ext/openssl/tests/openssl_spki_export.phpt @@ -0,0 +1,62 @@ +--TEST-- +Testing openssl_spki_export() +Creates SPKAC for all available key sizes & signature algorithms and exports public key +--SKIPIF-- +<?php +if (!extension_loaded("openssl")) die("skip"); +if (!@openssl_pkey_new()) die("skip cannot create private key"); +?> +--FILE-- +<?php + +/* array of private key sizes to test */ +$ksize = array('1024'=>1024, + '2048'=>2048, + '4096'=>4096); + +/* array of available hashings to test */ +$algo = array('md4'=>OPENSSL_ALGO_MD4, + 'md5'=>OPENSSL_ALGO_MD5, + 'sha1'=>OPENSSL_ALGO_SHA1, + 'sha224'=>OPENSSL_ALGO_SHA224, + 'sha256'=>OPENSSL_ALGO_SHA256, + 'sha384'=>OPENSSL_ALGO_SHA384, + 'sha512'=>OPENSSL_ALGO_SHA512, + 'rmd160'=>OPENSSL_ALGO_RMD160); + +/* loop over key sizes for test */ +foreach($ksize as $k => $v) { + + /* generate new private key of specified size to use for tests */ + $pkey = openssl_pkey_new(array('digest_alg' => 'sha512', + 'private_key_type' => OPENSSL_KEYTYPE_RSA, + 'private_key_bits' => $v)); + openssl_pkey_export($pkey, $pass); + + /* loop to create and verify results */ + foreach($algo as $key => $value) { + $spkac = openssl_spki_new($pkey, _uuid(), $value); + echo openssl_spki_export(preg_replace('/SPKAC=/', '', $spkac)); + } + openssl_free_key($pkey); +} + +/* generate a random challenge */ +function _uuid() +{ + return sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x', mt_rand(0, 0xffff), + mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0x0fff) | 0x4000, + mt_rand(0, 0x3fff) | 0x8000, mt_rand(0, 0xffff), + mt_rand(0, 0xffff), mt_rand(0, 0xffff)); +} + +?> +--EXPECTREGEX-- +\-\-\-\-\-BEGIN PUBLIC KEY\-\-\-\-\-.*\-\-\-\-\-END PUBLIC KEY\-\-\-\-\- +\-\-\-\-\-BEGIN PUBLIC KEY\-\-\-\-\-.*\-\-\-\-\-END PUBLIC KEY\-\-\-\-\- +\-\-\-\-\-BEGIN PUBLIC KEY\-\-\-\-\-.*\-\-\-\-\-END PUBLIC KEY\-\-\-\-\- +\-\-\-\-\-BEGIN PUBLIC KEY\-\-\-\-\-.*\-\-\-\-\-END PUBLIC KEY\-\-\-\-\- +\-\-\-\-\-BEGIN PUBLIC KEY\-\-\-\-\-.*\-\-\-\-\-END PUBLIC KEY\-\-\-\-\- +\-\-\-\-\-BEGIN PUBLIC KEY\-\-\-\-\-.*\-\-\-\-\-END PUBLIC KEY\-\-\-\-\- +\-\-\-\-\-BEGIN PUBLIC KEY\-\-\-\-\-.*\-\-\-\-\-END PUBLIC KEY\-\-\-\-\- +\-\-\-\-\-BEGIN PUBLIC KEY\-\-\-\-\-.*\-\-\-\-\-END PUBLIC KEY\-\-\-\-\- diff --git a/ext/openssl/tests/openssl_spki_export_challenge.phpt b/ext/openssl/tests/openssl_spki_export_challenge.phpt new file mode 100644 index 0000000000..71ef62edd5 --- /dev/null +++ b/ext/openssl/tests/openssl_spki_export_challenge.phpt @@ -0,0 +1,105 @@ +--TEST-- +Testing openssl_spki_export_challenge() +Creates SPKAC for all available key sizes & signature algorithms and exports challenge +--INI-- +error_reporting=0 +--SKIPIF-- +<?php +if (!extension_loaded("openssl")) die("skip"); +if (!@openssl_pkey_new()) die("skip cannot create private key"); +?> +--FILE-- +<?php + +/* array of private key sizes to test */ +$ksize = array('1024'=>1024, + '2048'=>2048, + '4096'=>4096); + +/* array of available hashings to test */ +$algo = array('md4'=>OPENSSL_ALGO_MD4, + 'md5'=>OPENSSL_ALGO_MD5, + 'sha1'=>OPENSSL_ALGO_SHA1, + 'sha224'=>OPENSSL_ALGO_SHA224, + 'sha256'=>OPENSSL_ALGO_SHA256, + 'sha384'=>OPENSSL_ALGO_SHA384, + 'sha512'=>OPENSSL_ALGO_SHA512, + 'rmd160'=>OPENSSL_ALGO_RMD160); + +/* loop over key sizes for test */ +foreach($ksize as $k => $v) { + + /* generate new private key of specified size to use for tests */ + $pkey = openssl_pkey_new(array('digest_alg' => 'sha512', + 'private_key_type' => OPENSSL_KEYTYPE_RSA, + 'private_key_bits' => $v)); + openssl_pkey_export($pkey, $pass); + + /* loop to create and verify results */ + foreach($algo as $key => $value) { + $spkac = openssl_spki_new($pkey, _uuid(), $value); + var_dump(openssl_spki_export_challenge(preg_replace('/SPKAC=/', '', $spkac))); + var_dump(openssl_spki_export_challenge($spkac.'Make it fail')); + } + openssl_free_key($pkey); +} + +/* generate a random challenge */ +function _uuid() +{ + return sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x', mt_rand(0, 0xffff), + mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0x0fff) | 0x4000, + mt_rand(0, 0x3fff) | 0x8000, mt_rand(0, 0xffff), + mt_rand(0, 0xffff), mt_rand(0, 0xffff)); +} + +?> +--EXPECTREGEX-- +string\(36\) \"[0-9a-f]{8}\-([0-9a-f]{4}\-){3}[0-9a-f]{12}\" +bool\(false\) +string\(36\) \"[0-9a-f]{8}\-([0-9a-f]{4}\-){3}[0-9a-f]{12}\" +bool\(false\) +string\(36\) \"[0-9a-f]{8}\-([0-9a-f]{4}\-){3}[0-9a-f]{12}\" +bool\(false\) +string\(36\) \"[0-9a-f]{8}\-([0-9a-f]{4}\-){3}[0-9a-f]{12}\" +bool\(false\) +string\(36\) \"[0-9a-f]{8}\-([0-9a-f]{4}\-){3}[0-9a-f]{12}\" +bool\(false\) +string\(36\) \"[0-9a-f]{8}\-([0-9a-f]{4}\-){3}[0-9a-f]{12}\" +bool\(false\) +string\(36\) \"[0-9a-f]{8}\-([0-9a-f]{4}\-){3}[0-9a-f]{12}\" +bool\(false\) +string\(36\) \"[0-9a-f]{8}\-([0-9a-f]{4}\-){3}[0-9a-f]{12}\" +bool\(false\) +string\(36\) \"[0-9a-f]{8}\-([0-9a-f]{4}\-){3}[0-9a-f]{12}\" +bool\(false\) +string\(36\) \"[0-9a-f]{8}\-([0-9a-f]{4}\-){3}[0-9a-f]{12}\" +bool\(false\) +string\(36\) \"[0-9a-f]{8}\-([0-9a-f]{4}\-){3}[0-9a-f]{12}\" +bool\(false\) +string\(36\) \"[0-9a-f]{8}\-([0-9a-f]{4}\-){3}[0-9a-f]{12}\" +bool\(false\) +string\(36\) \"[0-9a-f]{8}\-([0-9a-f]{4}\-){3}[0-9a-f]{12}\" +bool\(false\) +string\(36\) \"[0-9a-f]{8}\-([0-9a-f]{4}\-){3}[0-9a-f]{12}\" +bool\(false\) +string\(36\) \"[0-9a-f]{8}\-([0-9a-f]{4}\-){3}[0-9a-f]{12}\" +bool\(false\) +string\(36\) \"[0-9a-f]{8}\-([0-9a-f]{4}\-){3}[0-9a-f]{12}\" +bool\(false\) +string\(36\) \"[0-9a-f]{8}\-([0-9a-f]{4}\-){3}[0-9a-f]{12}\" +bool\(false\) +string\(36\) \"[0-9a-f]{8}\-([0-9a-f]{4}\-){3}[0-9a-f]{12}\" +bool\(false\) +string\(36\) \"[0-9a-f]{8}\-([0-9a-f]{4}\-){3}[0-9a-f]{12}\" +bool\(false\) +string\(36\) \"[0-9a-f]{8}\-([0-9a-f]{4}\-){3}[0-9a-f]{12}\" +bool\(false\) +string\(36\) \"[0-9a-f]{8}\-([0-9a-f]{4}\-){3}[0-9a-f]{12}\" +bool\(false\) +string\(36\) \"[0-9a-f]{8}\-([0-9a-f]{4}\-){3}[0-9a-f]{12}\" +bool\(false\) +string\(36\) \"[0-9a-f]{8}\-([0-9a-f]{4}\-){3}[0-9a-f]{12}\" +bool\(false\) +string\(36\) \"[0-9a-f]{8}\-([0-9a-f]{4}\-){3}[0-9a-f]{12}\" +bool\(false\) diff --git a/ext/openssl/tests/openssl_spki_new.phpt b/ext/openssl/tests/openssl_spki_new.phpt new file mode 100644 index 0000000000..e40f9bf28e --- /dev/null +++ b/ext/openssl/tests/openssl_spki_new.phpt @@ -0,0 +1,77 @@ +--TEST-- +Testing openssl_spki_new() +Tests SPKAC for all available private key sizes & hashing algorithms +--SKIPIF-- +<?php +if (!extension_loaded("openssl")) die("skip"); +if (!@openssl_pkey_new()) die("skip cannot create private key"); +?> +--FILE-- +<?php + +/* array of private key sizes to test */ +$ksize = array('1024'=>1024, + '2048'=>2048, + '4096'=>4096); + +/* array of available hashings to test */ +$algo = array('md4'=>OPENSSL_ALGO_MD4, + 'md5'=>OPENSSL_ALGO_MD5, + 'sha1'=>OPENSSL_ALGO_SHA1, + 'sha224'=>OPENSSL_ALGO_SHA224, + 'sha256'=>OPENSSL_ALGO_SHA256, + 'sha384'=>OPENSSL_ALGO_SHA384, + 'sha512'=>OPENSSL_ALGO_SHA512, + 'rmd160'=>OPENSSL_ALGO_RMD160); + +/* loop over key sizes for test */ +foreach($ksize as $k => $v) { + + /* generate new private key of specified size to use for tests */ + $pkey = openssl_pkey_new(array('digest_alg' => 'sha512', + 'private_key_type' => OPENSSL_KEYTYPE_RSA, + 'private_key_bits' => $v)); + openssl_pkey_export($pkey, $pass); + + /* loop to create and verify results */ + foreach($algo as $key => $value) { + var_dump(openssl_spki_new($pkey, _uuid(), $value)); + } + openssl_free_key($pkey); +} + +/* generate a random challenge */ +function _uuid() +{ + return sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x', mt_rand(0, 0xffff), + mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0x0fff) | 0x4000, + mt_rand(0, 0x3fff) | 0x8000, mt_rand(0, 0xffff), + mt_rand(0, 0xffff), mt_rand(0, 0xffff)); +} + +?> +--EXPECTF-- +string(478) "%s" +string(478) "%s" +string(478) "%s" +string(478) "%s" +string(478) "%s" +string(478) "%s" +string(478) "%s" +string(474) "%s" +string(830) "%s" +string(830) "%s" +string(830) "%s" +string(830) "%s" +string(830) "%s" +string(830) "%s" +string(830) "%s" +string(826) "%s" +string(1510) "%s" +string(1510) "%s" +string(1510) "%s" +string(1510) "%s" +string(1510) "%s" +string(1510) "%s" +string(1510) "%s" +string(1506) "%s" diff --git a/ext/openssl/tests/openssl_spki_verify.phpt b/ext/openssl/tests/openssl_spki_verify.phpt new file mode 100644 index 0000000000..1ee573fd3f --- /dev/null +++ b/ext/openssl/tests/openssl_spki_verify.phpt @@ -0,0 +1,105 @@ +--TEST-- +Testing openssl_spki_verify() +Creates SPKAC for all available key sizes & signature algorithms and tests for valid signature +--INI-- +error_reporting=0 +--SKIPIF-- +<?php +if (!extension_loaded("openssl")) die("skip"); +if (!@openssl_pkey_new()) die("skip cannot create private key"); +?> +--FILE-- +<?php + +/* array of private key sizes to test */ +$ksize = array('1024'=>1024, + '2048'=>2048, + '4096'=>4096); + +/* array of available hashings to test */ +$algo = array('md4'=>OPENSSL_ALGO_MD4, + 'md5'=>OPENSSL_ALGO_MD5, + 'sha1'=>OPENSSL_ALGO_SHA1, + 'sha224'=>OPENSSL_ALGO_SHA224, + 'sha256'=>OPENSSL_ALGO_SHA256, + 'sha384'=>OPENSSL_ALGO_SHA384, + 'sha512'=>OPENSSL_ALGO_SHA512, + 'rmd160'=>OPENSSL_ALGO_RMD160); + +/* loop over key sizes for test */ +foreach($ksize as $k => $v) { + + /* generate new private key of specified size to use for tests */ + $pkey = openssl_pkey_new(array('digest_alg' => 'sha512', + 'private_key_type' => OPENSSL_KEYTYPE_RSA, + 'private_key_bits' => $v)); + openssl_pkey_export($pkey, $pass); + + /* loop to create and verify results */ + foreach($algo as $key => $value) { + $spkac = openssl_spki_new($pkey, _uuid(), $value); + var_dump(openssl_spki_verify(preg_replace('/SPKAC=/', '', $spkac))); + var_dump(openssl_spki_verify($spkac.'Make it fail')); + } + openssl_free_key($pkey); +} + +/* generate a random challenge */ +function _uuid() +{ + return sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x', mt_rand(0, 0xffff), + mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0x0fff) | 0x4000, + mt_rand(0, 0x3fff) | 0x8000, mt_rand(0, 0xffff), + mt_rand(0, 0xffff), mt_rand(0, 0xffff)); +} + +?> +--EXPECT-- +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +bool(false)
\ No newline at end of file diff --git a/ext/pdo/Makefile.frag b/ext/pdo/Makefile.frag index 5ba5f80840..dc25c9f70b 100644 --- a/ext/pdo/Makefile.frag +++ b/ext/pdo/Makefile.frag @@ -2,7 +2,8 @@ phpincludedir=$(prefix)/include/php PDO_HEADER_FILES= \ php_pdo.h \ - php_pdo_driver.h + php_pdo_driver.h \ + php_pdo_error.h $(srcdir)/pdo_sql_parser.c: $(srcdir)/pdo_sql_parser.re diff --git a/ext/pdo/pdo_dbh.c b/ext/pdo/pdo_dbh.c index 25db6842f6..833c608f66 100644 --- a/ext/pdo/pdo_dbh.c +++ b/ext/pdo/pdo_dbh.c @@ -101,7 +101,7 @@ void pdo_raise_impl_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, const char *sqlstate } /* }}} */ -void pdo_handle_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */ +PDO_API void pdo_handle_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */ { pdo_error_type *pdo_err = &dbh->error_code; const char *msg = "<<Unknown>>"; diff --git a/ext/pdo/php_pdo_error.h b/ext/pdo/php_pdo_error.h new file mode 100644 index 0000000000..387436af8f --- /dev/null +++ b/ext/pdo/php_pdo_error.h @@ -0,0 +1,47 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 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: Wez Furlong <wez@php.net> | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#ifndef PHP_PDO_ERROR_H +#define PHP_PDO_ERROR_H + +#include "php_pdo_driver.h" + +PDO_API void pdo_handle_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt TSRMLS_DC); + +#define PDO_DBH_CLEAR_ERR() do { \ + strlcpy(dbh->error_code, PDO_ERR_NONE, sizeof(PDO_ERR_NONE)); \ + if (dbh->query_stmt) { \ + dbh->query_stmt = NULL; \ + zend_objects_store_del_ref(&dbh->query_stmt_zval TSRMLS_CC); \ + } \ +} while (0) +#define PDO_STMT_CLEAR_ERR() strcpy(stmt->error_code, PDO_ERR_NONE) +#define PDO_HANDLE_DBH_ERR() if (strcmp(dbh->error_code, PDO_ERR_NONE)) { pdo_handle_error(dbh, NULL TSRMLS_CC); } +#define PDO_HANDLE_STMT_ERR() if (strcmp(stmt->error_code, PDO_ERR_NONE)) { pdo_handle_error(stmt->dbh, stmt TSRMLS_CC); } + +#endif /* PHP_PDO_ERROR_H */ +/* + * 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/ext/pdo/php_pdo_int.h b/ext/pdo/php_pdo_int.h index 91d0bf0412..59dbaf9b01 100644 --- a/ext/pdo/php_pdo_int.h +++ b/ext/pdo/php_pdo_int.h @@ -23,6 +23,8 @@ /* Stuff private to the PDO extension and not for consumption by PDO drivers * */ +#include "php_pdo_error.h" + extern HashTable pdo_driver_hash; extern zend_class_entry *pdo_exception_ce; PDO_API zend_class_entry *php_pdo_get_exception_base(int root TSRMLS_DC); @@ -55,19 +57,6 @@ zend_object_iterator *php_pdo_dbstmt_iter_get(zend_class_entry *ce, zval *object extern pdo_driver_t *pdo_find_driver(const char *name, int namelen); -extern void pdo_handle_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt TSRMLS_DC); - -#define PDO_DBH_CLEAR_ERR() do { \ - strlcpy(dbh->error_code, PDO_ERR_NONE, sizeof(PDO_ERR_NONE)); \ - if (dbh->query_stmt) { \ - dbh->query_stmt = NULL; \ - zend_objects_store_del_ref(&dbh->query_stmt_zval TSRMLS_CC); \ - } \ -} while (0) -#define PDO_STMT_CLEAR_ERR() strcpy(stmt->error_code, PDO_ERR_NONE) -#define PDO_HANDLE_DBH_ERR() if (strcmp(dbh->error_code, PDO_ERR_NONE)) { pdo_handle_error(dbh, NULL TSRMLS_CC); } -#define PDO_HANDLE_STMT_ERR() if (strcmp(stmt->error_code, PDO_ERR_NONE)) { pdo_handle_error(stmt->dbh, stmt TSRMLS_CC); } - int pdo_sqlstate_init_error_table(void); void pdo_sqlstate_fini_error_table(void); const char *pdo_sqlstate_state_to_description(char *state); diff --git a/ext/pdo_pgsql/pgsql_driver.c b/ext/pdo_pgsql/pgsql_driver.c index 252bfff25b..80abb4b7c8 100644 --- a/ext/pdo_pgsql/pgsql_driver.c +++ b/ext/pdo_pgsql/pgsql_driver.c @@ -27,8 +27,10 @@ #include "php.h" #include "php_ini.h" #include "ext/standard/info.h" +#include "main/php_network.h" #include "pdo/php_pdo.h" #include "pdo/php_pdo_driver.h" +#include "pdo/php_pdo_error.h" #include "ext/standard/file.h" #undef PACKAGE_BUGREPORT @@ -60,7 +62,7 @@ static char * _pdo_pgsql_trim_message(const char *message, int persistent) return tmp; } -int _pdo_pgsql_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, int errcode, const char *sqlstate, const char *file, int line TSRMLS_DC) /* {{{ */ +int _pdo_pgsql_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, int errcode, const char *sqlstate, const char *msg, const char *file, int line TSRMLS_DC) /* {{{ */ { pdo_pgsql_db_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data; pdo_error_type *pdo_err = stmt ? &stmt->error_code : &dbh->error_code; @@ -83,7 +85,10 @@ int _pdo_pgsql_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, int errcode, const char * strcpy(*pdo_err, sqlstate); } - if (errmsg) { + if (msg) { + einfo->errmsg = estrdup(msg); + } + else if (errmsg) { einfo->errmsg = _pdo_pgsql_trim_message(errmsg, dbh->is_persistent); } @@ -91,7 +96,7 @@ int _pdo_pgsql_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, int errcode, const char * zend_throw_exception_ex(php_pdo_get_exception(), einfo->errcode TSRMLS_CC, "SQLSTATE[%s] [%d] %s", *pdo_err, einfo->errcode, einfo->errmsg); } - + return errcode; } /* }}} */ @@ -315,7 +320,7 @@ static int pgsql_handle_quoter(pdo_dbh_t *dbh, const char *unquoted, int unquote case PDO_PARAM_LOB: /* escapedlen returned by PQescapeBytea() accounts for trailing 0 */ #ifdef HAVE_PQESCAPE_BYTEA_CONN - escaped = PQescapeByteaConn(H->server, unquoted, unquotedlen, &tmp_len); + escaped = PQescapeByteaConn(H->server, (unsigned char *)unquoted, unquotedlen, &tmp_len); #else escaped = PQescapeBytea(unquoted, unquotedlen, &tmp_len); #endif @@ -535,11 +540,13 @@ static PHP_METHOD(PDO, pgsqlCopyFromArray) dbh = zend_object_store_get_object(getThis() TSRMLS_CC); PDO_CONSTRUCT_CHECK; + PDO_DBH_CLEAR_ERR(); + /* using pre-9.0 syntax as PDO_pgsql is 7.4+ compatible */ if (pg_fields) { - spprintf(&query, 0, "COPY %s (%s) FROM STDIN DELIMITERS E'%c' WITH NULL AS E'%s'", table_name, pg_fields, (pg_delim_len ? *pg_delim : '\t'), (pg_null_as_len ? pg_null_as : "\\\\N")); + spprintf(&query, 0, "COPY %s (%s) FROM STDIN WITH DELIMITER E'%c' NULL AS E'%s'", table_name, pg_fields, (pg_delim_len ? *pg_delim : '\t'), (pg_null_as_len ? pg_null_as : "\\\\N")); } else { - spprintf(&query, 0, "COPY %s FROM STDIN DELIMITERS E'%c' WITH NULL AS E'%s'", table_name, (pg_delim_len ? *pg_delim : '\t'), (pg_null_as_len ? pg_null_as : "\\\\N")); + spprintf(&query, 0, "COPY %s FROM STDIN WITH DELIMITER E'%c' NULL AS E'%s'", table_name, (pg_delim_len ? *pg_delim : '\t'), (pg_null_as_len ? pg_null_as : "\\\\N")); } /* Obtain db Handle */ @@ -583,7 +590,8 @@ static PHP_METHOD(PDO, pgsqlCopyFromArray) query[query_len] = '\0'; if (PQputCopyData(H->server, query, query_len) != 1) { efree(query); - pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "copy failed"); + pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, NULL); + PDO_HANDLE_DBH_ERR(); RETURN_FALSE; } zend_hash_move_forward_ex(Z_ARRVAL_P(pg_rows), &pos); @@ -593,22 +601,25 @@ static PHP_METHOD(PDO, pgsqlCopyFromArray) } if (PQputCopyEnd(H->server, NULL) != 1) { - pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "putcopyend failed"); + pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, NULL); + PDO_HANDLE_DBH_ERR(); RETURN_FALSE; } while ((pgsql_result = PQgetResult(H->server))) { if (PGRES_COMMAND_OK != PQresultStatus(pgsql_result)) { - pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "Copy command failed"); + pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, pdo_pgsql_sqlstate(pgsql_result)); command_failed = 1; } PQclear(pgsql_result); } + PDO_HANDLE_DBH_ERR(); RETURN_BOOL(!command_failed); } else { + pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, pdo_pgsql_sqlstate(pgsql_result)); PQclear(pgsql_result); - pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "Copy command failed"); + PDO_HANDLE_DBH_ERR(); RETURN_FALSE; } } @@ -637,17 +648,20 @@ static PHP_METHOD(PDO, pgsqlCopyFromFile) /* Obtain db Handler */ dbh = zend_object_store_get_object(getThis() TSRMLS_CC); PDO_CONSTRUCT_CHECK; + PDO_DBH_CLEAR_ERR(); - stream = php_stream_open_wrapper_ex(filename, "rb", ENFORCE_SAFE_MODE | REPORT_ERRORS, NULL, FG(default_context)); + stream = php_stream_open_wrapper_ex(filename, "rb", ENFORCE_SAFE_MODE, NULL, FG(default_context)); if (!stream) { - pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "Unable to open the file"); + pdo_pgsql_error_msg(dbh, PGRES_FATAL_ERROR, "Unable to open the file"); + PDO_HANDLE_DBH_ERR(); RETURN_FALSE; } + /* using pre-9.0 syntax as PDO_pgsql is 7.4+ compatible */ if (pg_fields) { - spprintf(&query, 0, "COPY %s (%s) FROM STDIN DELIMITERS E'%c' WITH NULL AS E'%s'", table_name, pg_fields, (pg_delim_len ? *pg_delim : '\t'), (pg_null_as_len ? pg_null_as : "\\\\N")); + spprintf(&query, 0, "COPY %s (%s) FROM STDIN WITH DELIMITER E'%c' NULL AS E'%s'", table_name, pg_fields, (pg_delim_len ? *pg_delim : '\t'), (pg_null_as_len ? pg_null_as : "\\\\N")); } else { - spprintf(&query, 0, "COPY %s FROM STDIN DELIMITERS E'%c' WITH NULL AS E'%s'", table_name, (pg_delim_len ? *pg_delim : '\t'), (pg_null_as_len ? pg_null_as : "\\\\N")); + spprintf(&query, 0, "COPY %s FROM STDIN WITH DELIMITER E'%c' NULL AS E'%s'", table_name, (pg_delim_len ? *pg_delim : '\t'), (pg_null_as_len ? pg_null_as : "\\\\N")); } H = (pdo_pgsql_db_handle *)dbh->driver_data; @@ -674,8 +688,9 @@ static PHP_METHOD(PDO, pgsqlCopyFromFile) while ((buf = php_stream_get_line(stream, NULL, 0, &line_len)) != NULL) { if (PQputCopyData(H->server, buf, line_len) != 1) { efree(buf); - pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "copy failed"); + pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, NULL); php_stream_close(stream); + PDO_HANDLE_DBH_ERR(); RETURN_FALSE; } efree(buf); @@ -683,23 +698,26 @@ static PHP_METHOD(PDO, pgsqlCopyFromFile) php_stream_close(stream); if (PQputCopyEnd(H->server, NULL) != 1) { - pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "putcopyend failed"); + pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, NULL); + PDO_HANDLE_DBH_ERR(); RETURN_FALSE; } while ((pgsql_result = PQgetResult(H->server))) { if (PGRES_COMMAND_OK != PQresultStatus(pgsql_result)) { - pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "Copy command failed"); + pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, pdo_pgsql_sqlstate(pgsql_result)); command_failed = 1; } PQclear(pgsql_result); } + PDO_HANDLE_DBH_ERR(); RETURN_BOOL(!command_failed); } else { - PQclear(pgsql_result); php_stream_close(stream); - pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "Copy command failed"); + pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, pdo_pgsql_sqlstate(pgsql_result)); + PQclear(pgsql_result); + PDO_HANDLE_DBH_ERR(); RETURN_FALSE; } } @@ -730,12 +748,14 @@ static PHP_METHOD(PDO, pgsqlCopyToFile) dbh = zend_object_store_get_object(getThis() TSRMLS_CC); PDO_CONSTRUCT_CHECK; + PDO_DBH_CLEAR_ERR(); H = (pdo_pgsql_db_handle *)dbh->driver_data; - stream = php_stream_open_wrapper_ex(filename, "wb", ENFORCE_SAFE_MODE | REPORT_ERRORS, NULL, FG(default_context)); + stream = php_stream_open_wrapper_ex(filename, "wb", ENFORCE_SAFE_MODE, NULL, FG(default_context)); if (!stream) { - pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "Unable to open the file for writing"); + pdo_pgsql_error_msg(dbh, PGRES_FATAL_ERROR, "Unable to open the file for writing"); + PDO_HANDLE_DBH_ERR(); RETURN_FALSE; } @@ -743,10 +763,11 @@ static PHP_METHOD(PDO, pgsqlCopyToFile) PQclear(pgsql_result); } + /* using pre-9.0 syntax as PDO_pgsql is 7.4+ compatible */ if (pg_fields) { - spprintf(&query, 0, "COPY %s (%s) TO STDIN DELIMITERS E'%c' WITH NULL AS E'%s'", table_name, pg_fields, (pg_delim_len ? *pg_delim : '\t'), (pg_null_as_len ? pg_null_as : "\\\\N")); + spprintf(&query, 0, "COPY %s (%s) TO STDIN WITH DELIMITER E'%c' NULL AS E'%s'", table_name, pg_fields, (pg_delim_len ? *pg_delim : '\t'), (pg_null_as_len ? pg_null_as : "\\\\N")); } else { - spprintf(&query, 0, "COPY %s TO STDIN DELIMITERS E'%c' WITH NULL AS E'%s'", table_name, (pg_delim_len ? *pg_delim : '\t'), (pg_null_as_len ? pg_null_as : "\\\\N")); + spprintf(&query, 0, "COPY %s TO STDIN WITH DELIMITER E'%c' NULL AS E'%s'", table_name, (pg_delim_len ? *pg_delim : '\t'), (pg_null_as_len ? pg_null_as : "\\\\N")); } pgsql_result = PQexec(H->server, query); efree(query); @@ -767,16 +788,18 @@ static PHP_METHOD(PDO, pgsqlCopyToFile) break; /* done */ } else if (ret > 0) { if (php_stream_write(stream, csv, ret) != ret) { - pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "Unable to write to file"); + pdo_pgsql_error_msg(dbh, PGRES_FATAL_ERROR, "Unable to write to file"); PQfreemem(csv); php_stream_close(stream); + PDO_HANDLE_DBH_ERR(); RETURN_FALSE; } else { PQfreemem(csv); } } else { - pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "Copy command failed: getline failed"); + pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, NULL); php_stream_close(stream); + PDO_HANDLE_DBH_ERR(); RETURN_FALSE; } } @@ -788,8 +811,9 @@ static PHP_METHOD(PDO, pgsqlCopyToFile) RETURN_TRUE; } else { php_stream_close(stream); + pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, pdo_pgsql_sqlstate(pgsql_result)); PQclear(pgsql_result); - pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "Copy command failed"); + PDO_HANDLE_DBH_ERR(); RETURN_FALSE; } } @@ -817,6 +841,7 @@ static PHP_METHOD(PDO, pgsqlCopyToArray) dbh = zend_object_store_get_object(getThis() TSRMLS_CC); PDO_CONSTRUCT_CHECK; + PDO_DBH_CLEAR_ERR(); H = (pdo_pgsql_db_handle *)dbh->driver_data; @@ -824,10 +849,11 @@ static PHP_METHOD(PDO, pgsqlCopyToArray) PQclear(pgsql_result); } + /* using pre-9.0 syntax as PDO_pgsql is 7.4+ compatible */ if (pg_fields) { - spprintf(&query, 0, "COPY %s (%s) TO STDIN DELIMITERS E'%c' WITH NULL AS E'%s'", table_name, pg_fields, (pg_delim_len ? *pg_delim : '\t'), (pg_null_as_len ? pg_null_as : "\\\\N")); + spprintf(&query, 0, "COPY %s (%s) TO STDIN WITH DELIMITER E'%c' NULL AS E'%s'", table_name, pg_fields, (pg_delim_len ? *pg_delim : '\t'), (pg_null_as_len ? pg_null_as : "\\\\N")); } else { - spprintf(&query, 0, "COPY %s TO STDIN DELIMITERS E'%c' WITH NULL AS E'%s'", table_name, (pg_delim_len ? *pg_delim : '\t'), (pg_null_as_len ? pg_null_as : "\\\\N")); + spprintf(&query, 0, "COPY %s TO STDIN WITH DELIMITER E'%c' NULL AS E'%s'", table_name, (pg_delim_len ? *pg_delim : '\t'), (pg_null_as_len ? pg_null_as : "\\\\N")); } pgsql_result = PQexec(H->server, query); efree(query); @@ -851,7 +877,8 @@ static PHP_METHOD(PDO, pgsqlCopyToArray) add_next_index_stringl(return_value, csv, ret, 1); PQfreemem(csv); } else { - pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "Copy command failed: getline failed"); + pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, NULL); + PDO_HANDLE_DBH_ERR(); RETURN_FALSE; } } @@ -860,8 +887,9 @@ static PHP_METHOD(PDO, pgsqlCopyToArray) PQclear(pgsql_result); } } else { + pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, pdo_pgsql_sqlstate(pgsql_result)); PQclear(pgsql_result); - pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "Copy command failed"); + PDO_HANDLE_DBH_ERR(); RETURN_FALSE; } } @@ -878,6 +906,7 @@ static PHP_METHOD(PDO, pgsqlLOBCreate) dbh = zend_object_store_get_object(getThis() TSRMLS_CC); PDO_CONSTRUCT_CHECK; + PDO_DBH_CLEAR_ERR(); H = (pdo_pgsql_db_handle *)dbh->driver_data; lfd = lo_creat(H->server, INV_READ|INV_WRITE); @@ -887,8 +916,9 @@ static PHP_METHOD(PDO, pgsqlLOBCreate) spprintf(&buf, 0, "%lu", (long) lfd); RETURN_STRING(buf, 0); } - - pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "HY000"); + + pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, NULL); + PDO_HANDLE_DBH_ERR(); RETURN_FALSE; } /* }}} */ @@ -924,6 +954,7 @@ static PHP_METHOD(PDO, pgsqlLOBOpen) dbh = zend_object_store_get_object(getThis() TSRMLS_CC); PDO_CONSTRUCT_CHECK; + PDO_DBH_CLEAR_ERR(); H = (pdo_pgsql_db_handle *)dbh->driver_data; @@ -936,8 +967,10 @@ static PHP_METHOD(PDO, pgsqlLOBOpen) return; } } else { - pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "HY000"); + pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, NULL); } + + PDO_HANDLE_DBH_ERR(); RETURN_FALSE; } /* }}} */ @@ -964,17 +997,98 @@ static PHP_METHOD(PDO, pgsqlLOBUnlink) dbh = zend_object_store_get_object(getThis() TSRMLS_CC); PDO_CONSTRUCT_CHECK; + PDO_DBH_CLEAR_ERR(); H = (pdo_pgsql_db_handle *)dbh->driver_data; - + if (1 == lo_unlink(H->server, oid)) { RETURN_TRUE; } - pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, "HY000"); + + pdo_pgsql_error(dbh, PGRES_FATAL_ERROR, NULL); + PDO_HANDLE_DBH_ERR(); RETURN_FALSE; } /* }}} */ +/* {{{ proto mixed PDO::pgsqlGetNotify([ int $result_type = PDO::FETCH_USE_DEFAULT] [, int $ms_timeout = 0 ]]) + Get asyncronous notification */ +static PHP_METHOD(PDO, pgsqlGetNotify) +{ + pdo_dbh_t *dbh; + pdo_pgsql_db_handle *H; + long result_type = PDO_FETCH_USE_DEFAULT; + long ms_timeout = 0; + PGnotify *pgsql_notify; + + if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|ll", + &result_type, &ms_timeout)) { + RETURN_FALSE; + } + + dbh = zend_object_store_get_object(getThis() TSRMLS_CC); + PDO_CONSTRUCT_CHECK; + + if (result_type == PDO_FETCH_USE_DEFAULT) { + result_type = dbh->default_fetch_type; + } + + if (result_type != PDO_FETCH_BOTH && result_type != PDO_FETCH_ASSOC && result_type != PDO_FETCH_NUM) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid result type"); + RETURN_FALSE; + } + + if (ms_timeout < 0) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid timeout"); + RETURN_FALSE; + } + + H = (pdo_pgsql_db_handle *)dbh->driver_data; + + PQconsumeInput(H->server); + pgsql_notify = PQnotifies(H->server); + + if (ms_timeout && !pgsql_notify) { + php_pollfd_for_ms(PQsocket(H->server), PHP_POLLREADABLE, ms_timeout); + + PQconsumeInput(H->server); + pgsql_notify = PQnotifies(H->server); + } + + if (!pgsql_notify) { + RETURN_FALSE; + } + + array_init(return_value); + if (result_type == PDO_FETCH_NUM || result_type == PDO_FETCH_BOTH) { + add_index_string(return_value, 0, pgsql_notify->relname, 1); + add_index_long(return_value, 1, pgsql_notify->be_pid); + } + if (result_type == PDO_FETCH_ASSOC || result_type == PDO_FETCH_BOTH) { + add_assoc_string(return_value, "message", pgsql_notify->relname, 1); + add_assoc_long(return_value, "pid", pgsql_notify->be_pid); + } + + PQfreemem(pgsql_notify); +} +/* }}} */ + +/* {{{ proto int PDO::pgsqlGetPid() + Get backend(server) pid */ +static PHP_METHOD(PDO, pgsqlGetPid) +{ + pdo_dbh_t *dbh; + pdo_pgsql_db_handle *H; + + dbh = zend_object_store_get_object(getThis() TSRMLS_CC); + PDO_CONSTRUCT_CHECK; + + H = (pdo_pgsql_db_handle *)dbh->driver_data; + + RETURN_LONG(PQbackendPID(H->server)); +} +/* }}} */ + static const zend_function_entry dbh_methods[] = { PHP_ME(PDO, pgsqlLOBCreate, NULL, ZEND_ACC_PUBLIC) @@ -984,6 +1098,8 @@ static const zend_function_entry dbh_methods[] = { PHP_ME(PDO, pgsqlCopyFromFile, NULL, ZEND_ACC_PUBLIC) PHP_ME(PDO, pgsqlCopyToArray, NULL, ZEND_ACC_PUBLIC) PHP_ME(PDO, pgsqlCopyToFile, NULL, ZEND_ACC_PUBLIC) + PHP_ME(PDO, pgsqlGetNotify, NULL, ZEND_ACC_PUBLIC) + PHP_ME(PDO, pgsqlGetPid, NULL, ZEND_ACC_PUBLIC) PHP_FE_END }; diff --git a/ext/pdo_pgsql/php_pdo_pgsql_int.h b/ext/pdo_pgsql/php_pdo_pgsql_int.h index 02a6717760..5600a92541 100644 --- a/ext/pdo_pgsql/php_pdo_pgsql_int.h +++ b/ext/pdo_pgsql/php_pdo_pgsql_int.h @@ -83,9 +83,11 @@ typedef struct { extern pdo_driver_t pdo_pgsql_driver; -extern int _pdo_pgsql_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, int errcode, const char *sqlstate, const char *file, int line TSRMLS_DC); -#define pdo_pgsql_error(d,e,z) _pdo_pgsql_error(d, NULL, e, z, __FILE__, __LINE__ TSRMLS_CC) -#define pdo_pgsql_error_stmt(s,e,z) _pdo_pgsql_error(s->dbh, s, e, z, __FILE__, __LINE__ TSRMLS_CC) +extern int _pdo_pgsql_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, int errcode, const char *sqlstate, const char *msg, const char *file, int line TSRMLS_DC); +#define pdo_pgsql_error(d,e,z) _pdo_pgsql_error(d, NULL, e, z, NULL, __FILE__, __LINE__ TSRMLS_CC) +#define pdo_pgsql_error_msg(d,e,m) _pdo_pgsql_error(d, NULL, e, NULL, m, __FILE__, __LINE__ TSRMLS_CC) +#define pdo_pgsql_error_stmt(s,e,z) _pdo_pgsql_error(s->dbh, s, e, z, NULL, __FILE__, __LINE__ TSRMLS_CC) +#define pdo_pgsql_error_stmt_msg(s,e,m) _pdo_pgsql_error(s->dbh, s, e, NULL, m, __FILE__, __LINE__ TSRMLS_CC) extern struct pdo_stmt_methods pgsql_stmt_methods; diff --git a/ext/pdo_pgsql/tests/copy_from.phpt b/ext/pdo_pgsql/tests/copy_from.phpt index 10967b0fe9..de1140dfea 100644 --- a/ext/pdo_pgsql/tests/copy_from.phpt +++ b/ext/pdo_pgsql/tests/copy_from.phpt @@ -16,8 +16,6 @@ $db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false); $db->exec('CREATE TABLE test (a integer not null primary key, b text, c integer)'); -try { - echo "Preparing test file and array for CopyFrom tests\n"; $tableRows = array(); @@ -68,10 +66,13 @@ $db->rollback(); echo "Testing pgsqlCopyFromArray() with error\n"; $db->beginTransaction(); -var_dump($db->pgsqlCopyFromArray('test_error',$tableRowsWithDifferentNullValuesAndSelectedFields,";","NULL",'a,c')); +try { + var_dump($db->pgsqlCopyFromArray('test_error',$tableRowsWithDifferentNullValuesAndSelectedFields,";","NULL",'a,c')); +} catch (Exception $e) { + echo "Exception: {$e->getMessage()}\n"; +} $db->rollback(); - echo "Testing pgsqlCopyFromFile() with default parameters\n"; $db->beginTransaction(); var_dump($db->pgsqlCopyFromFile('test',$filename)); @@ -102,14 +103,21 @@ $db->rollback(); echo "Testing pgsqlCopyFromFile() with error\n"; $db->beginTransaction(); -var_dump($db->pgsqlCopyFromFile('test_error',$filenameWithDifferentNullValuesAndSelectedFields,";","NULL",'a,c')); +try { + var_dump($db->pgsqlCopyFromFile('test_error',$filenameWithDifferentNullValuesAndSelectedFields,";","NULL",'a,c')); +} catch (Exception $e) { + echo "Exception: {$e->getMessage()}\n"; +} $db->rollback(); +echo "Testing pgsqlCopyFromFile() with non existing file\n"; +$db->beginTransaction(); +try { + var_dump($db->pgsqlCopyFromFile('test',"nonexisting/foo.csv",";","NULL",'a,c')); } catch (Exception $e) { - /* catch exceptions so that we can show the relative error */ - echo "Exception! at line ", $e->getLine(), "\n"; - var_dump($e->getMessage()); + echo "Exception: {$e->getMessage()}\n"; } +$db->rollback(); // Clean up foreach (array($filename, $filenameWithDifferentNullValues, $filenameWithDifferentNullValuesAndSelectedFields) as $f) { @@ -251,7 +259,7 @@ array(6) { NULL } Testing pgsqlCopyFromArray() with error -bool(false) +Exception: SQLSTATE[42P01]: Undefined table: 7 ERROR: relation "test_error" does not exist Testing pgsqlCopyFromFile() with default parameters bool(true) array(6) { @@ -385,4 +393,7 @@ array(6) { NULL } Testing pgsqlCopyFromFile() with error -bool(false) +Exception: SQLSTATE[42P01]: Undefined table: 7 ERROR: relation "test_error" does not exist +Testing pgsqlCopyFromFile() with non existing file +Exception: SQLSTATE[HY000]: General error: 7 Unable to open the file + diff --git a/ext/pdo_pgsql/tests/copy_to.phpt b/ext/pdo_pgsql/tests/copy_to.phpt index 1dc7d1de33..7bc46c6e0b 100644 --- a/ext/pdo_pgsql/tests/copy_to.phpt +++ b/ext/pdo_pgsql/tests/copy_to.phpt @@ -17,7 +17,6 @@ $db->setAttribute(PDO::ATTR_STRINGIFY_FETCHES, false); $db->exec('CREATE TABLE test (a integer not null primary key, b text, c integer)'); $db->beginTransaction(); -try { echo "Preparing test table for CopyTo tests\n"; $stmt = $db->prepare("INSERT INTO test (a, b, c) values (?, ?, ?)"); @@ -42,8 +41,11 @@ echo "Testing pgsqlCopyToArray() with only selected fields\n"; var_dump($db->pgsqlCopyToArray('test',";","NULL",'a,c')); echo "Testing pgsqlCopyToArray() with error\n"; -var_dump($db->pgsqlCopyToArray('test_error')); - +try { + var_dump($db->pgsqlCopyToArray('test_error')); +} catch (Exception $e) { + echo "Exception: {$e->getMessage()}\n"; +} echo "Testing pgsqlCopyToFile() with default parameters\n"; @@ -58,14 +60,19 @@ var_dump($db->pgsqlCopyToFile('test',$filename,";","NULL",'a,c')); echo file_get_contents($filename); echo "Testing pgsqlCopyToFile() with error\n"; -var_dump($db->pgsqlCopyToFile('test_error',$filename)); - +try { + var_dump($db->pgsqlCopyToFile('test_error',$filename)); +} catch (Exception $e) { + echo "Exception: {$e->getMessage()}\n"; +} +echo "Testing pgsqlCopyToFile() to unwritable file\n"; +try { + var_dump($db->pgsqlCopyToFile('test', 'nonexistent/foo.csv')); } catch (Exception $e) { - /* catch exceptions so that we can show the relative error */ - echo "Exception! at line ", $e->getLine(), "\n"; - var_dump($e->getMessage()); + echo "Exception: {$e->getMessage()}\n"; } + if(isset($filename)) { @unlink($filename); } @@ -109,7 +116,7 @@ array(3) { " } Testing pgsqlCopyToArray() with error -bool(false) +Exception: SQLSTATE[42P01]: Undefined table: 7 ERROR: relation "test_error" does not exist Testing pgsqlCopyToFile() with default parameters bool(true) 0 test insert 0 \N @@ -126,4 +133,7 @@ bool(true) 1;NULL 2;NULL Testing pgsqlCopyToFile() with error -bool(false)
\ No newline at end of file +Exception: SQLSTATE[42P01]: Undefined table: 7 ERROR: relation "test_error" does not exist +Testing pgsqlCopyToFile() to unwritable file +Exception: SQLSTATE[HY000]: General error: 7 Unable to open the file for writing + diff --git a/ext/pdo_pgsql/tests/getnotify.phpt b/ext/pdo_pgsql/tests/getnotify.phpt new file mode 100644 index 0000000000..c093e0357a --- /dev/null +++ b/ext/pdo_pgsql/tests/getnotify.phpt @@ -0,0 +1,109 @@ +--TEST-- +PDO PgSQL LISTEN/NOTIFY support +--SKIPIF-- +<?php # vim:se ft=php: +if (!extension_loaded('pdo') || !extension_loaded('pdo_pgsql')) die('skip not loaded'); +require dirname(__FILE__) . '/config.inc'; +require dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc'; +PDOTest::skip(); +?> +--FILE-- +<?php +require dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc'; +$db = PDOTest::test_factory(dirname(__FILE__) . '/common.phpt'); +$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); + +// pgsqlGetPid should return something meaningful +$pid = $db->pgsqlGetPid(); +var_dump($pid > 0); + +// No listen, no notifies +var_dump($db->pgsqlGetNotify()); + +// Listen started, no notifies +$db->exec("LISTEN notifies_phpt"); +var_dump($db->pgsqlGetNotify()); + +// No parameters, use default PDO::FETCH_NUM +$db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_NUM); +$db->exec("NOTIFY notifies_phpt"); +$notify = $db->pgsqlGetNotify(); +var_dump(count($notify)); +var_dump($notify[0]); +var_dump($notify[1] == $pid); + +// No parameters, use default PDO::FETCH_ASSOC +$db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC); +$db->exec("NOTIFY notifies_phpt"); +$notify = $db->pgsqlGetNotify(); +var_dump(count($notify)); +var_dump($notify['message']); +var_dump($notify['pid'] == $pid); + +// Test PDO::FETCH_NUM as parameter +$db->exec("NOTIFY notifies_phpt"); +$notify = $db->pgsqlGetNotify(PDO::FETCH_NUM); +var_dump(count($notify)); +var_dump($notify[0]); +var_dump($notify[1] == $pid); + +// Test PDO::FETCH_ASSOC as parameter +$db->exec("NOTIFY notifies_phpt"); +$notify = $db->pgsqlGetNotify(PDO::FETCH_ASSOC); +var_dump(count($notify)); +var_dump($notify['message']); +var_dump($notify['pid'] == $pid); + +// Test PDO::FETCH_BOTH as parameter +$db->exec("NOTIFY notifies_phpt"); +$notify = $db->pgsqlGetNotify(PDO::FETCH_BOTH); +var_dump(count($notify)); +var_dump($notify['message']); +var_dump($notify['pid'] == $pid); +var_dump($notify[0]); +var_dump($notify[1] == $pid); + +// Verify that there are no notifies queued +var_dump($db->pgsqlGetNotify()); + + +// Test second parameter, should wait 2 seconds because no notify is queued +$t = microtime(1); +$notify = $db->pgsqlGetNotify(PDO::FETCH_ASSOC, 1000); +var_dump((microtime(1) - $t) >= 1); +var_dump($notify); + +// Test second parameter, should return immediately because a notify is queued +$db->exec("NOTIFY notifies_phpt"); +$t = microtime(1); +$notify = $db->pgsqlGetNotify(PDO::FETCH_ASSOC, 5000); +var_dump((microtime(1) - $t) < 1); +var_dump(count($notify)); + +?> +--EXPECT-- +bool(true) +bool(false) +bool(false) +int(2) +string(13) "notifies_phpt" +bool(true) +int(2) +string(13) "notifies_phpt" +bool(true) +int(2) +string(13) "notifies_phpt" +bool(true) +int(2) +string(13) "notifies_phpt" +bool(true) +int(4) +string(13) "notifies_phpt" +bool(true) +string(13) "notifies_phpt" +bool(true) +bool(false) +bool(true) +bool(false) +bool(true) +int(2) diff --git a/ext/sockets/tests/ipv4loop.phpt b/ext/sockets/tests/ipv4loop.phpt index 9fdcc17dad..920b27b66e 100644 --- a/ext/sockets/tests/ipv4loop.phpt +++ b/ext/sockets/tests/ipv4loop.phpt @@ -13,8 +13,15 @@ IPv4 Loopback test if (!$server) { die('Unable to create AF_INET socket [server]'); } - if (!socket_bind($server, '127.0.0.1', 31337)) { - die('Unable to bind to 127.0.0.1:31337'); + $bound = false; + for($port = 31337; $port < 31357; ++$port) { + if (socket_bind($server, '127.0.0.1', $port)) { + $bound = true; + break; + } + } + if (!$bound) { + die("Unable to bind to 127.0.0.1"); } if (!socket_listen($server, 2)) { die('Unable to listen on socket'); @@ -25,7 +32,7 @@ IPv4 Loopback test if (!$client) { die('Unable to create AF_INET socket [client]'); } - if (!socket_connect($client, '127.0.0.1', 31337)) { + if (!socket_connect($client, '127.0.0.1', $port)) { die('Unable to connect to server socket'); } diff --git a/ext/sockets/tests/ipv6loop.phpt b/ext/sockets/tests/ipv6loop.phpt index 6967605ffa..4720cb49e4 100644 --- a/ext/sockets/tests/ipv6loop.phpt +++ b/ext/sockets/tests/ipv6loop.phpt @@ -14,8 +14,15 @@ IPv6 Loopback test if (!$server) { die('Unable to create AF_INET6 socket [server]'); } - if (!socket_bind($server, '::1', 31337)) { - die('Unable to bind to [::1]:31337'); + $bound = false; + for($port = 31337; $port < 31357; ++$port) { + if (socket_bind($server, '::1', $port)) { + $bound = true; + break; + } + } + if (!$bound) { + die("Unable to bind to [::1]:$port"); } if (!socket_listen($server, 2)) { die('Unable to listen on socket'); @@ -26,7 +33,7 @@ IPv6 Loopback test if (!$client) { die('Unable to create AF_INET6 socket [client]'); } - if (!socket_connect($client, '::1', 31337)) { + if (!socket_connect($client, '::1', $port)) { die('Unable to connect to server socket'); } diff --git a/ext/sockets/tests/socket_getpeername_ipv4loop.phpt b/ext/sockets/tests/socket_getpeername_ipv4loop.phpt index aa59abb8da..b948e0e7f4 100644 --- a/ext/sockets/tests/socket_getpeername_ipv4loop.phpt +++ b/ext/sockets/tests/socket_getpeername_ipv4loop.phpt @@ -14,17 +14,23 @@ ext/sockets - socket_getpeername_ipv4loop - basic test /* Bind and connect sockets to localhost */ $localhost = '127.0.0.1'; - /* Hold the port associated to address */ - $port = 31337; - /* Setup socket server */ $server = socket_create(AF_INET, SOCK_STREAM, getprotobyname('tcp')); if (!$server) { die('Unable to create AF_INET socket [server]'); } - - if (!socket_bind($server, $localhost, $port)) { - die('Unable to bind to '.$localhost.':'.$port); + + $minport = 31337; + $maxport = 31356; + $bound = false; + for($port = $minport; $port <= $maxport; ++$port) { + if (socket_bind($server, $localhost, $port)) { + $bound = true; + break; + } + } + if (!$bound) { + die('Unable to bind to '.$localhost); } if (!socket_listen($server, 2)) { die('Unable to listen on socket'); @@ -45,10 +51,10 @@ ext/sockets - socket_getpeername_ipv4loop - basic test die('Unable to accept connection'); } - if (!socket_getpeername($client, $address, $port)) { + if (!socket_getpeername($client, $address, $peerport)) { die('Unable to retrieve peer name'); } - var_dump($address, $port); + var_dump($address, $port === $peerport); socket_close($client); socket_close($socket); @@ -56,4 +62,4 @@ ext/sockets - socket_getpeername_ipv4loop - basic test ?> --EXPECT-- string(9) "127.0.0.1" -int(31337) +bool(true) diff --git a/ext/sockets/tests/socket_getpeername_ipv6loop.phpt b/ext/sockets/tests/socket_getpeername_ipv6loop.phpt index e865f3e064..5d03e32ce0 100644 --- a/ext/sockets/tests/socket_getpeername_ipv6loop.phpt +++ b/ext/sockets/tests/socket_getpeername_ipv6loop.phpt @@ -15,17 +15,23 @@ require 'ipv6_skipif.inc'; /* Bind and connect sockets to localhost */ $localhost = '::1'; - /* Hold the port associated to address */ - $port = 31337; - /* Setup socket server */ $server = socket_create(AF_INET6, SOCK_STREAM, getprotobyname('tcp')); if (!$server) { die('Unable to create AF_INET6 socket [server]'); } - - if (!socket_bind($server, $localhost, $port)) { - die('Unable to bind to '.$localhost.':'.$port); + + $minport = 31337; + $maxport = 31356; + $bound = false; + for($port = $minport; $port <= $maxport; ++$port) { + if (socket_bind($server, $localhost, $port)) { + $bound = true; + break; + } + } + if (!$bound) { + die('Unable to bind to '.$localhost); } if (!socket_listen($server, 2)) { die('Unable to listen on socket'); @@ -46,10 +52,10 @@ require 'ipv6_skipif.inc'; die('Unable to accept connection'); } - if (!socket_getpeername($client, $address, $port)) { + if (!socket_getpeername($client, $address, $peerport)) { die('Unable to retrieve peer name'); } - var_dump($address, $port); + var_dump($address, $port === $peerport); socket_close($client); socket_close($socket); @@ -57,4 +63,4 @@ require 'ipv6_skipif.inc'; ?> --EXPECT-- string(3) "::1" -int(31337) +bool(true) diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index 9c91404eff..1379117745 100644 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -2679,6 +2679,7 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO(arginfo_unserialize, 0) ZEND_ARG_INFO(0, variable_representation) + ZEND_ARG_INFO(1, consumed) ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_memory_get_usage, 0, 0, 0) diff --git a/ext/standard/credits_ext.h b/ext/standard/credits_ext.h index 2770d162fb..382e70e7d7 100644 --- a/ext/standard/credits_ext.h +++ b/ext/standard/credits_ext.h @@ -42,8 +42,8 @@ CREDIT_LINE("MS SQL", "Frank M. Kromann"); CREDIT_LINE("Multibyte String Functions", "Tsukada Takuya, Rui Hirokawa"); CREDIT_LINE("MySQL driver for PDO", "George Schlossnagle, Wez Furlong, Ilia Alshanetsky, Johannes Schlueter"); CREDIT_LINE("MySQLi", "Zak Greant, Georg Richter, Andrey Hristov, Ulf Wendel"); -CREDIT_LINE("MySQLnd", "Andrey Hristov, Ulf Wendel, Georg Richter, Johannes Schlueter"); -CREDIT_LINE("MySQL", "Zeev Suraski, Zak Greant, Georg Richter, Andrey Hristov"); +CREDIT_LINE("MySQLnd", "Andrey Hristov, Ulf Wendel, Georg Richter"); +CREDIT_LINE("MySQL", "Zeev Suraski, Zak Greant, Georg Richter"); CREDIT_LINE("OCI8", "Stig Bakken, Thies C. Arntzen, Andy Sautins, David Benson, Maxim Maletsky, Harald Radi, Antony Dovgal, Andi Gutmans, Wez Furlong, Christopher Jones, Oracle Corporation"); CREDIT_LINE("ODBC driver for PDO", "Wez Furlong"); CREDIT_LINE("ODBC", "Stig Bakken, Andreas Karajannis, Frank M. Kromann, Daniel R. Kalowsky"); diff --git a/ext/standard/dir.c b/ext/standard/dir.c index ef28e9feaf..55326dbdd3 100644 --- a/ext/standard/dir.c +++ b/ext/standard/dir.c @@ -492,9 +492,7 @@ PHP_FUNCTION(glob) if (!globbuf.gl_pathc || !globbuf.gl_pathv) { no_results: if (PG(open_basedir) && *PG(open_basedir)) { - struct stat s; - - if (0 != VCWD_STAT(pattern, &s) || S_IFDIR != (s.st_mode & S_IFMT)) { + if (php_check_open_basedir_ex(pattern, 0 TSRMLS_CC)) { RETURN_FALSE; } } diff --git a/ext/standard/tests/serialize/serialization_error_001.phpt b/ext/standard/tests/serialize/serialization_error_001.phpt index da6f50cc02..c6c17512f3 100644 --- a/ext/standard/tests/serialize/serialization_error_001.phpt +++ b/ext/standard/tests/serialize/serialization_error_001.phpt @@ -21,7 +21,7 @@ var_dump( unserialize() ); //Test serialize with one more than the expected number of arguments var_dump( serialize(1,2) ); -var_dump( unserialize(1,2) ); +var_dump( unserialize(1,$x,2) ); echo "Done"; ?> @@ -31,12 +31,12 @@ echo "Done"; Warning: serialize() expects exactly 1 parameter, 0 given in %s on line 16 NULL -Warning: unserialize() expects exactly 1 parameter, 0 given in %s on line 17 +Warning: unserialize() expects at least 1 parameter, 0 given in %s on line 17 bool(false) Warning: serialize() expects exactly 1 parameter, 2 given in %s on line 20 NULL -Warning: unserialize() expects exactly 1 parameter, 2 given in %s on line 21 +Warning: unserialize() expects at most 2 parameters, 3 given in %s on line 21 bool(false) Done diff --git a/ext/standard/tests/serialize/unserialize_consumed.phpt b/ext/standard/tests/serialize/unserialize_consumed.phpt new file mode 100644 index 0000000000..6cc11e273f --- /dev/null +++ b/ext/standard/tests/serialize/unserialize_consumed.phpt @@ -0,0 +1,27 @@ +--TEST-- +Unserialization of partial strings +--FILE-- +<?php +$data = [123,4.56,true]; +$ser = serialize($data); +$serlen = strlen($ser); + +$unser = unserialize($ser, $consumed); +echo "Consume full string: "; +var_dump($serlen == $consumed); +echo "Return original data: "; +var_dump($unser === $data); + +$ser .= "junk\x01data"; +$unser = unserialize($ser, $consumed); +echo "Consume full string(junk): "; +var_dump($serlen == $consumed); +echo "Return original data(junk): "; +var_dump($unser === $data); + +--EXPECT-- +Consume full string: bool(true) +Return original data: bool(true) +Consume full string(junk): bool(true) +Return original data(junk): bool(true) + diff --git a/ext/standard/var.c b/ext/standard/var.c index f76a14cfa6..4acc6f57b7 100644 --- a/ext/standard/var.c +++ b/ext/standard/var.c @@ -945,7 +945,7 @@ PHP_FUNCTION(serialize) } /* }}} */ -/* {{{ proto mixed unserialize(string variable_representation) +/* {{{ proto mixed unserialize(string variable_representation[, int &consumed]) Takes a string representation of variable and recreates it */ PHP_FUNCTION(unserialize) { @@ -953,8 +953,9 @@ PHP_FUNCTION(unserialize) int buf_len; const unsigned char *p; php_unserialize_data_t var_hash; + zval *consumed = NULL; - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &buf, &buf_len) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|z", &buf, &buf_len, &consumed) == FAILURE) { RETURN_FALSE; } @@ -973,6 +974,11 @@ PHP_FUNCTION(unserialize) RETURN_FALSE; } PHP_VAR_UNSERIALIZE_DESTROY(var_hash); + + if (consumed) { + zval_dtor(consumed); + ZVAL_LONG(consumed, ((char*)p) - buf); + } } /* }}} */ diff --git a/ext/zip/php_zip.c b/ext/zip/php_zip.c index 37a0cdea19..b73082ba71 100644 --- a/ext/zip/php_zip.c +++ b/ext/zip/php_zip.c @@ -417,7 +417,7 @@ static int php_zip_parse_options(zval *options, long *remove_all_path, ze_zip_object *obj = (ze_zip_object*) zend_object_store_get_object(object TSRMLS_CC); \ intern = obj->za; \ if (!intern) { \ - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid or unitialized Zip object"); \ + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid or uninitialized Zip object"); \ RETURN_FALSE; \ } \ } diff --git a/ext/zlib/tests/gzseek_basic2.phpt b/ext/zlib/tests/gzseek_basic2.phpt index a815b8ff41..82d305d0fb 100644 --- a/ext/zlib/tests/gzseek_basic2.phpt +++ b/ext/zlib/tests/gzseek_basic2.phpt @@ -8,7 +8,7 @@ if (!extension_loaded("zlib")) { ?> --FILE-- <?php -$f = "temp3.txt.gz"; +$f = "gzseek_basic2.gz"; $h = gzopen($f, 'w'); $str1 = "This is the first line."; $str2 = "This is the second line."; @@ -39,4 +39,4 @@ reading the output file This is the first line. string(40) "0000000000000000000000000000000000000000" This is the second line. -===DONE===
\ No newline at end of file +===DONE=== diff --git a/ext/zlib/tests/gzseek_variation1.phpt b/ext/zlib/tests/gzseek_variation1.phpt index 301b57d151..b260783f11 100644 --- a/ext/zlib/tests/gzseek_variation1.phpt +++ b/ext/zlib/tests/gzseek_variation1.phpt @@ -8,7 +8,7 @@ if (!extension_loaded("zlib")) { ?> --FILE-- <?php -$f = "temp3.txt.gz"; +$f = "gzseek_variation1.gz"; $h = gzopen($f, 'w'); $str1 = "This is the first line."; $str2 = "This is the second line."; @@ -30,4 +30,4 @@ unlink($f); This is the first line. string(40) "0000000000000000000000000000000000000000" This is the second line. -===DONE===
\ No newline at end of file +===DONE=== diff --git a/ext/zlib/tests/gzseek_variation4.phpt b/ext/zlib/tests/gzseek_variation4.phpt index fc641f6c82..3d0cf67ceb 100644 --- a/ext/zlib/tests/gzseek_variation4.phpt +++ b/ext/zlib/tests/gzseek_variation4.phpt @@ -8,7 +8,7 @@ if (!extension_loaded("zlib")) { ?> --FILE-- <?php -$f = "temp3.txt.gz"; +$f = "gzseek_variation5.gz"; $h = gzopen($f, 'w'); $str1 = "This is the first line."; $str2 = "This is the second line."; @@ -39,4 +39,4 @@ reading the output file This is the first line. string(40) "0000000000000000000000000000000000000000" This is the second line. -===DONE===
\ No newline at end of file +===DONE=== diff --git a/ext/zlib/tests/gzseek_variation5.phpt b/ext/zlib/tests/gzseek_variation5.phpt index 0167e204c2..93fb19fdbb 100644 --- a/ext/zlib/tests/gzseek_variation5.phpt +++ b/ext/zlib/tests/gzseek_variation5.phpt @@ -8,7 +8,7 @@ if (!extension_loaded("zlib")) { ?> --FILE-- <?php -$f = "temp3.txt.gz"; +$f = "gzseek_variation5.gz"; $h = gzopen($f, 'w'); $str1 = "This is the first line."; $str2 = "This is the second line."; @@ -39,4 +39,4 @@ reading the output file This is the first line. string(40) "0000000000000000000000000000000000000000" This is the second line. -===DONE===
\ No newline at end of file +===DONE=== diff --git a/ext/zlib/tests/gzseek_variation7.phpt b/ext/zlib/tests/gzseek_variation7.phpt index aab0834652..a365272ba2 100644 --- a/ext/zlib/tests/gzseek_variation7.phpt +++ b/ext/zlib/tests/gzseek_variation7.phpt @@ -8,7 +8,7 @@ if (!extension_loaded("zlib")) { ?> --FILE-- <?php -$f = "temp3.txt.gz"; +$f = "gzseek_variation7.gz"; $h = gzopen($f, 'w'); $str1 = "This is the first line."; $str2 = "This is the second line."; @@ -44,4 +44,4 @@ tell=int(47) reading the output file This is the first line.This is the second line. -===DONE===
\ No newline at end of file +===DONE=== |
