summaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
Diffstat (limited to 'ext')
-rw-r--r--ext/curl/interface.c2
-rw-r--r--ext/gd/gd.c12
-rw-r--r--ext/gd/libgd/gd.h3
-rw-r--r--ext/gd/libgd/gd_interpolation.c11
-rw-r--r--ext/gmp/gmp.c1274
-rw-r--r--ext/gmp/tests/004.phpt4
-rw-r--r--ext/gmp/tests/005.phpt2
-rw-r--r--ext/gmp/tests/006.phpt10
-rw-r--r--ext/gmp/tests/007.phpt142
-rw-r--r--ext/gmp/tests/008.phpt62
-rw-r--r--ext/gmp/tests/009.phpt82
-rw-r--r--ext/gmp/tests/010.phpt15
-rw-r--r--ext/gmp/tests/014.phpt7
-rw-r--r--ext/gmp/tests/016.phpt5
-rw-r--r--ext/gmp/tests/033.phpt6
-rw-r--r--ext/gmp/tests/034.phpt2
-rw-r--r--ext/gmp/tests/040.phpt5
-rw-r--r--ext/gmp/tests/cast.phpt22
-rw-r--r--ext/gmp/tests/clone.phpt22
-rw-r--r--ext/gmp/tests/comparison.phpt37
-rw-r--r--ext/gmp/tests/overloading.phpt259
-rw-r--r--ext/gmp/tests/serialize.phpt22
-rw-r--r--ext/hash/tests/hash_file_basic.phpt4
-rw-r--r--ext/hash/tests/hash_file_error.phpt4
-rw-r--r--ext/mbstring/libmbfl/filters/mbfilter_utf8.c184
-rw-r--r--ext/mbstring/libmbfl/filters/mbfilter_utf8.h1
-rw-r--r--ext/mbstring/libmbfl/filters/mbfilter_utf8_mobile.c185
-rw-r--r--ext/mbstring/tests/bug65045.phpt29
-rw-r--r--ext/opcache/Optimizer/compact_literals.c481
-rw-r--r--ext/opcache/Optimizer/optimize_func_calls.c138
-rw-r--r--ext/opcache/Optimizer/pass1_5.c82
-rw-r--r--ext/opcache/Optimizer/zend_optimizer.c193
-rw-r--r--ext/opcache/Optimizer/zend_optimizer.h6
-rw-r--r--ext/opcache/ZendAccelerator.c19
-rw-r--r--ext/opcache/ZendAccelerator.h1
-rw-r--r--ext/opcache/tests/compact_literals.phpt215
-rw-r--r--ext/opcache/tests/optimize_func_calls.phpt130
-rw-r--r--ext/openssl/openssl.c299
-rw-r--r--ext/openssl/php_openssl.h5
-rw-r--r--ext/openssl/tests/openssl_spki_export.phpt62
-rw-r--r--ext/openssl/tests/openssl_spki_export_challenge.phpt105
-rw-r--r--ext/openssl/tests/openssl_spki_new.phpt77
-rw-r--r--ext/openssl/tests/openssl_spki_verify.phpt105
-rw-r--r--ext/pdo/Makefile.frag3
-rw-r--r--ext/pdo/pdo_dbh.c2
-rw-r--r--ext/pdo/php_pdo_error.h47
-rw-r--r--ext/pdo/php_pdo_int.h15
-rw-r--r--ext/pdo_pgsql/pgsql_driver.c186
-rw-r--r--ext/pdo_pgsql/php_pdo_pgsql_int.h8
-rw-r--r--ext/pdo_pgsql/tests/copy_from.phpt31
-rw-r--r--ext/pdo_pgsql/tests/copy_to.phpt30
-rw-r--r--ext/pdo_pgsql/tests/getnotify.phpt109
-rw-r--r--ext/sockets/tests/ipv4loop.phpt13
-rw-r--r--ext/sockets/tests/ipv6loop.phpt13
-rw-r--r--ext/sockets/tests/socket_getpeername_ipv4loop.phpt24
-rw-r--r--ext/sockets/tests/socket_getpeername_ipv6loop.phpt24
-rw-r--r--ext/standard/basic_functions.c1
-rw-r--r--ext/standard/credits_ext.h4
-rw-r--r--ext/standard/dir.c4
-rw-r--r--ext/standard/tests/serialize/serialization_error_001.phpt6
-rw-r--r--ext/standard/tests/serialize/unserialize_consumed.phpt27
-rw-r--r--ext/standard/var.c10
-rw-r--r--ext/zip/php_zip.c2
-rw-r--r--ext/zlib/tests/gzseek_basic2.phpt4
-rw-r--r--ext/zlib/tests/gzseek_variation1.phpt4
-rw-r--r--ext/zlib/tests/gzseek_variation4.phpt4
-rw-r--r--ext/zlib/tests/gzseek_variation5.phpt4
-rw-r--r--ext/zlib/tests/gzseek_variation7.phpt4
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===