summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohannes Schlüter <johannes@php.net>2013-01-29 19:50:00 +0100
committerJohannes Schlüter <johannes@php.net>2013-01-29 19:50:00 +0100
commit078b025a15a22c290f36e66b0c3336376623266e (patch)
treefcf8dc6d71225f86848056b73d999053730b4e93
parentd7d9ce0f4257d65527766b367aefcea25ef264f4 (diff)
parent3bedc8ec277a246db6d3bfbe6313a861e46c4505 (diff)
downloadphp-git-078b025a15a22c290f36e66b0c3336376623266e.tar.gz
Merge branch 'PHP-5.5' of git.php.net:/php-src into PHP-5.5
-rw-r--r--NEWS56
-rw-r--r--README.PARAMETER_PARSING_API21
-rwxr-xr-xUPGRADING20
-rw-r--r--Zend/tests/bug60833.phpt40
-rw-r--r--Zend/tests/bug63462.phpt74
-rw-r--r--Zend/tests/class_name_as_scalar.phpt77
-rw-r--r--Zend/tests/class_name_as_scalar_error_001.phpt13
-rw-r--r--Zend/tests/class_name_as_scalar_error_002.phpt13
-rw-r--r--Zend/tests/class_name_as_scalar_error_003.phpt13
-rw-r--r--Zend/tests/class_name_as_scalar_error_004.phpt13
-rw-r--r--Zend/tests/class_name_as_scalar_error_005.phpt10
-rw-r--r--Zend/tests/class_name_as_scalar_error_006.phpt10
-rw-r--r--Zend/zend_API.c57
-rw-r--r--Zend/zend_API.h2
-rw-r--r--Zend/zend_compile.c243
-rw-r--r--Zend/zend_compile.h2
-rw-r--r--Zend/zend_language_parser.y10
-rw-r--r--Zend/zend_object_handlers.c10
-rw-r--r--Zend/zend_vm_def.h21
-rw-r--r--Zend/zend_vm_execute.h81
-rw-r--r--ext/curl/config.m42
-rw-r--r--ext/curl/config.w322
-rw-r--r--ext/curl/interface.c144
-rw-r--r--ext/curl/php_curl.h17
-rw-r--r--ext/curl/tests/bug27023.phpt2
-rw-r--r--ext/curl/tests/curl_file_serialize.phpt21
-rw-r--r--ext/curl/tests/curl_file_upload.phpt85
-rw-r--r--ext/curl/tests/curl_setopt_error.phpt4
-rw-r--r--ext/date/php_date.c24
-rw-r--r--ext/gd/config.w323
-rw-r--r--ext/intl/ERROR.CONVENTIONS115
-rw-r--r--ext/intl/breakiterator/breakiterator_class.cpp2
-rw-r--r--ext/intl/calendar/calendar_methods.cpp2
-rw-r--r--ext/intl/config.m42
-rw-r--r--ext/intl/config.w323
-rw-r--r--ext/intl/converter/converter.c1173
-rw-r--r--ext/intl/converter/converter.h28
-rw-r--r--ext/intl/php_intl.c5
-rw-r--r--ext/intl/tests/uconverter___construct_error.phpt14
-rw-r--r--ext/intl/tests/uconverter_enum.phpt21
-rw-r--r--ext/intl/tests/uconverter_func_basic.phpt17
-rw-r--r--ext/intl/tests/uconverter_func_subst.phpt31
-rw-r--r--ext/intl/tests/uconverter_oop_algo.phpt18
-rw-r--r--ext/intl/tests/uconverter_oop_basic.phpt21
-rw-r--r--ext/intl/tests/uconverter_oop_callback.phpt52
-rw-r--r--ext/intl/tests/uconverter_oop_callback_return.phpt40
-rw-r--r--ext/intl/tests/uconverter_oop_subst.phpt24
-rw-r--r--ext/mysqlnd/mysqlnd_structs.h2
-rw-r--r--ext/pdo/pdo_stmt.c1
-rw-r--r--ext/pdo/tests/pdo_036.phpt8
-rw-r--r--ext/reflection/php_reflection.c54
-rw-r--r--ext/reflection/tests/bug64007.phpt19
-rw-r--r--ext/spl/spl_directory.c4
-rw-r--r--ext/spl/tests/bug64023.phpt20
-rw-r--r--ext/standard/html.c4
-rw-r--r--ext/standard/http_fopen_wrapper.c6
-rw-r--r--ext/standard/tests/strings/get_html_translation_table_basic10.phpt121
-rw-r--r--ext/standard/var_unserializer.c62
-rw-r--r--ext/standard/var_unserializer.re6
-rw-r--r--main/main.c1
-rw-r--r--main/php_globals.h1
-rw-r--r--main/php_open_temporary_file.c23
-rw-r--r--main/streams/php_stream_plain_wrapper.h2
-rw-r--r--php.ini-development4
-rw-r--r--php.ini-production4
-rw-r--r--tests/basic/req60524.phpt8
-rw-r--r--tests/classes/unset_properties.phpt6
67 files changed, 2678 insertions, 336 deletions
diff --git a/NEWS b/NEWS
index 6395b34f53..f26806d916 100644
--- a/NEWS
+++ b/NEWS
@@ -1,9 +1,42 @@
PHP NEWS
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
-?? ??? 201?, PHP 5.5.0 Alpha 3
+?? ??? 201?, PHP 5.5.0 Beta 1
+- Core:
+ . Fixed bug #60833 (self, parent, static behave inconsistently
+ case-sensitive). (Stas, mario at include-once dot org)
+ . Implemented FR #60524 (specify temp dir by php.ini). (ALeX Kazik).
+
+- cURL:
+ . Implemented FR #46439 - added CURLFile for safer file uploads.
+ (Stas)
+
+24 Jan 2013, PHP 5.5.0 Alpha 4
- Core:
. Fixed bug #63980 (object members get trimmed by zero bytes). (Laruence)
+ . Implemented RFC for Class Name Resolution As Scalar Via "class" Keyword.
+ (Ralph Schindler, Nikita Popov, Lars)
+
+- DateTime
+ . Added DateTimeImmutable - a variant of DateTime that only returns the
+ modified state instead of changing itself. (Derick)
+
+- FPM:
+ . Fixed bug #63999 (php with fpm fails to build on Solaris 10 or 11). (Adam)
+
+- pgsql:
+ . Bug #46408: Locale number format settings can cause pg_query_params to
+ break with numerics. (asmecher, Lars)
+
+- dba:
+ . Bug #62489: dba_insert not working as expected.
+ (marc-bennewitz at arcor dot de, Lars)
+
+- Reflection:
+ . Fixed bug #64007 (There is an ability to create instance of Generator by hand).
+ (Laruence)
+
+10 Jan 2013, PHP 5.5.0 Alpha 3
- General improvements:
. Fixed bug #63874 (Segfault if php_strip_whitespace has heredoc). (Pierrick)
@@ -19,26 +52,11 @@ PHP NEWS
- cURL:
. Added new functions curl_escape, curl_multi_setopt, curl_multi_strerror
- curl_pause, curl_reset, curl_share_close, curl_share_init,
- curl_share_setopt curl_strerror and curl_unescape. (Pierrick)
+ curl_pause, curl_reset, curl_share_close, curl_share_init,
+ curl_share_setopt curl_strerror and curl_unescape. (Pierrick)
. Addes new curl options CURLOPT_TELNETOPTIONS, CURLOPT_GSSAPI_DELEGATION,
CURLOPT_ACCEPTTIMEOUT_MS, CURLOPT_SSL_OPTIONS, CURLOPT_TCP_KEEPALIVE,
- CURLOPT_TCP_KEEPIDLE and CURLOPT_TCP_KEEPINTVL. (Pierrick)
-
-- DateTime
- . Added DateTimeImmutable - a variant of DateTime that only returns the
- modified state instead of changing itself. (Derick)
-
-- FPM:
- . Fixed bug #63999 (php with fpm fails to build on Solaris 10 or 11). (Adam)
-
-- pgsql:
- . Bug #46408: Locale number format settings can cause pg_query_params to
- break with numerics. (asmecher, Lars)
-
-- dba:
- . Bug #62489: dba_insert not working as expected.
- (marc-bennewitz at arcor dot de, Lars)
+ CURLOPT_TCP_KEEPIDLE and CURLOPT_TCP_KEEPINTVL. (Pierrick)
18 Dec 2012, PHP 5.5.0 Alpha 2
diff --git a/README.PARAMETER_PARSING_API b/README.PARAMETER_PARSING_API
index 927e48188c..edcee0f2ea 100644
--- a/README.PARAMETER_PARSING_API
+++ b/README.PARAMETER_PARSING_API
@@ -28,6 +28,17 @@ Both functions return SUCCESS or FAILURE depending on the result.
The auto-conversions are performed as necessary. Arrays, objects, and
resources cannot be auto-converted.
+PHP 5.5 includes a new function:
+
+int zend_parse_parameter(int flags, int arg_num TSRMLS_DC, zval **arg, const char *spec, ...);
+
+This function behaves like zend_parse_parameters_ex() except that instead of
+reading the arguments from the stack, it receives a single zval to convert
+(passed with double indirection). The passed zval may be changed in place as
+part of the conversion process.
+
+See also https://wiki.php.net/rfc/zpp_improv#expose_zend_parse_arg_as_zend_parse_parameter
+
Type specifiers
---------------
@@ -65,9 +76,13 @@ Type specifiers
will not be touched by the parsing function if they are not
passed to it.
/ - use SEPARATE_ZVAL_IF_NOT_REF() on the parameter it follows
- ! - the parameter it follows can be of specified type or NULL (applies
- to all specifiers except for 'b', 'l', and 'd'). If NULL is passed, the
- results pointer is set to NULL as well.
+ ! - the parameter it follows can be of specified type or NULL. If NULL is
+ passed and the output for such type is a pointer, then the output
+ pointer is set to a native NULL pointer.
+ For 'b', 'l' and 'd', an extra argument of type zend_bool* must be
+ passed after the corresponding bool*, long* or double* arguments,
+ respectively. A non-zero value will be written to the zend_bool iif a
+ PHP NULL is passed.
Note on 64bit compatibility
diff --git a/UPGRADING b/UPGRADING
index 6c53084cdd..22ad969157 100755
--- a/UPGRADING
+++ b/UPGRADING
@@ -24,6 +24,8 @@ PHP 5.5 UPGRADE NOTES
- Drop Windows XP and 2003 support. (Pierre)
- All internal case insensitivity handling for class, function and constant
names is done according to ASCII rules, current locale settings are ignored.
+- self, parent & static keywords now are always case-insensitive (see bug
+ #60833).
- php_logo_guid(), php_egg_logo_guid(), php_real_logo_guid() and
zend_logo_guid() have been removed
- Removal of Logo GUIDs
@@ -75,6 +77,8 @@ PHP 5.5 UPGRADE NOTES
for example. (https://wiki.php.net/rfc/empty_isset_exprs)
- Added generators.
(https://wiki.php.net/rfc/generators)
+- ClassName::class syntax returning full class name for a class as
+ a string constant. (https://wiki.php.net/rfc/class_name_scalars)
========================================
2. Changes in SAPI modules
@@ -149,6 +153,10 @@ PHP 5.5 UPGRADE NOTES
Furthermore both set_error_handler(NULL) and set_exception_handler(NULL) will
now return the previously defined error/exception handler. Previously
bool(true) was returned.
+- setcookie(), setrawcookie() and ext/session now send Max-Age headers alongside
+ Expires headers. (see https://wiki.php.net/rfc/cookie_max-age)
+- curl_setopt now accepts new option CURLOPT_SAFE_UPLOAD and CURLFile object for
+ safer file uploads (see https://wiki.php.net/rfc/curl-file-upload)
========================================
5. New Functions
@@ -161,6 +169,9 @@ PHP 5.5 UPGRADE NOTES
- password_needs_rehash()
- password_verify()
+- cURL:
+ - curl_file_create
+
- Hash:
- hash_pbkdf2()
@@ -261,6 +272,9 @@ PHP 5.5 UPGRADE NOTES
- IntlRuleBasedBreakIterator
- IntlCodePointBreakIterator
+- cURL:
+ - CURLFile
+
========================================
7. Removed Extensions
========================================
@@ -280,10 +294,16 @@ PHP 5.5 UPGRADE NOTES
- mysqli:
- Added MYSQLI_SERVER_PUBLIC_KEY constant to be used with mysqli_options()
+- cURL:
+ - Added CURLOPT_SAFE_UPLOAD to be used with curl_setopt().
+
========================================
10. Changes to INI File Handling
========================================
+- Core:
+ - Added sys_temp_dir INI directive, for specifying temp firectory.
+
- Intl:
- Added intl.use_exceptions INI directive, which controls what happens when
global errors are set together with intl.error_level.
diff --git a/Zend/tests/bug60833.phpt b/Zend/tests/bug60833.phpt
new file mode 100644
index 0000000000..deb6c0f691
--- /dev/null
+++ b/Zend/tests/bug60833.phpt
@@ -0,0 +1,40 @@
+--TEST--
+Bug #60833 (self, parent, static behave inconsistently case-sensitive)
+--FILE--
+<?php
+class A {
+ static $x = "A";
+ function testit() {
+ $this->v1 = new sELF;
+ $this->v2 = new SELF;
+ }
+}
+
+class B extends A {
+ static $x = "B";
+ function testit() {
+ PARENT::testit();
+ $this->v3 = new sELF;
+ $this->v4 = new PARENT;
+ $this->v4 = STATIC::$x;
+ }
+}
+$t = new B();
+$t->testit();
+var_dump($t);
+?>
+--EXPECTF--
+object(B)#%d (4) {
+ ["v1"]=>
+ object(A)#%d (0) {
+ }
+ ["v2"]=>
+ object(A)#%d (0) {
+ }
+ ["v3"]=>
+ object(B)#%d (0) {
+ }
+ ["v4"]=>
+ string(1) "B"
+}
+
diff --git a/Zend/tests/bug63462.phpt b/Zend/tests/bug63462.phpt
new file mode 100644
index 0000000000..e936a6fa69
--- /dev/null
+++ b/Zend/tests/bug63462.phpt
@@ -0,0 +1,74 @@
+--TEST--
+Test script to verify that magic methods should be called only once when accessing an unset property.
+--CREDITS--
+Marco Pivetta <ocramius@gmail.com>
+--FILE--
+<?php
+class Test {
+ public $publicProperty;
+ protected $protectedProperty;
+ private $privateProperty;
+
+ public function __construct() {
+ unset(
+ $this->publicProperty,
+ $this->protectedProperty,
+ $this->privateProperty
+ );
+ }
+
+ function __get($name) {
+ echo '__get ' . $name . "\n";
+ return $this->$name;
+ }
+
+ function __set($name, $value) {
+ echo '__set ' . $name . "\n";
+ $this->$name = $value;
+ }
+
+ function __isset($name) {
+ echo '__isset ' . $name . "\n";
+ return isset($this->$name);
+ }
+}
+
+$test = new Test();
+
+$test->nonExisting;
+$test->publicProperty;
+$test->protectedProperty;
+$test->privateProperty;
+isset($test->nonExisting);
+isset($test->publicProperty);
+isset($test->protectedProperty);
+isset($test->privateProperty);
+$test->nonExisting = 'value';
+$test->publicProperty = 'value';
+$test->protectedProperty = 'value';
+$test->privateProperty = 'value';
+
+?>
+
+--EXPECTF--
+__get nonExisting
+
+Notice: Undefined property: Test::$nonExisting in %s on line %d
+__get publicProperty
+
+Notice: Undefined property: Test::$publicProperty in %s on line %d
+__get protectedProperty
+
+Notice: Undefined property: Test::$protectedProperty in %s on line %d
+__get privateProperty
+
+Notice: Undefined property: Test::$privateProperty in %s on line %d
+__isset nonExisting
+__isset publicProperty
+__isset protectedProperty
+__isset privateProperty
+__set nonExisting
+__set publicProperty
+__set protectedProperty
+__set privateProperty
+
diff --git a/Zend/tests/class_name_as_scalar.phpt b/Zend/tests/class_name_as_scalar.phpt
new file mode 100644
index 0000000000..38e55b16d5
--- /dev/null
+++ b/Zend/tests/class_name_as_scalar.phpt
@@ -0,0 +1,77 @@
+--TEST--
+class name as scalar from ::class keyword
+--FILE--
+<?php
+
+namespace Foo\Bar {
+ class One {
+ // compile time constants
+ const A = self::class;
+ const B = Two::class;
+ }
+ class Two extends One {
+ public static function run() {
+ var_dump(self::class); // self compile time lookup
+ var_dump(static::class); // runtime lookup
+ var_dump(parent::class); // runtime lookup
+ var_dump(Baz::class); // default compile time lookup
+ }
+ }
+ class Three extends Two {
+ // compile time static lookups
+ public static function checkCompileTime(
+ $one = self::class,
+ $two = Baz::class,
+ $three = One::A,
+ $four = self::B
+ ) {
+ var_dump($one, $two, $three, $four);
+ }
+ }
+ echo "In NS\n";
+ var_dump(Moo::CLASS); // resolve in namespace
+}
+
+namespace {
+ use Bee\Bop as Moo,
+ Foo\Bar\One;
+ echo "Top\n";
+ var_dump(One::class); // resolve from use
+ var_dump(Boo::class); // resolve in global namespace
+ var_dump(Moo::CLASS); // resolve from use as
+ var_dump(\Moo::Class); // resolve fully qualified
+ $class = One::class; // assign class as scalar to var
+ $x = new $class; // create new class from original scalar assignment
+ var_dump($x);
+ Foo\Bar\Two::run(); // resolve runtime lookups
+ echo "Parent\n";
+ Foo\Bar\Three::run(); // resolve runtime lookups with inheritance
+ echo "Compile Check\n";
+ Foo\Bar\Three::checkCompileTime();
+}
+
+?>
+--EXPECTF--
+In NS
+string(11) "Foo\Bar\Moo"
+Top
+string(11) "Foo\Bar\One"
+string(3) "Boo"
+string(7) "Bee\Bop"
+string(3) "Moo"
+object(Foo\Bar\One)#1 (0) {
+}
+string(11) "Foo\Bar\Two"
+string(11) "Foo\Bar\Two"
+string(11) "Foo\Bar\One"
+string(11) "Foo\Bar\Baz"
+Parent
+string(11) "Foo\Bar\Two"
+string(13) "Foo\Bar\Three"
+string(11) "Foo\Bar\One"
+string(11) "Foo\Bar\Baz"
+Compile Check
+string(13) "Foo\Bar\Three"
+string(11) "Foo\Bar\Baz"
+string(11) "Foo\Bar\One"
+string(11) "Foo\Bar\Two"
diff --git a/Zend/tests/class_name_as_scalar_error_001.phpt b/Zend/tests/class_name_as_scalar_error_001.phpt
new file mode 100644
index 0000000000..1c7aa7ea84
--- /dev/null
+++ b/Zend/tests/class_name_as_scalar_error_001.phpt
@@ -0,0 +1,13 @@
+--TEST--
+class name as scalar from ::class keyword error using static in class constant
+--FILE--
+<?php
+
+namespace Foo\Bar {
+ class One {
+ const Baz = static::class;
+ }
+}
+?>
+--EXPECTF--
+Fatal error: static::class cannot be used for compile-time class name resolution in %s on line %d
diff --git a/Zend/tests/class_name_as_scalar_error_002.phpt b/Zend/tests/class_name_as_scalar_error_002.phpt
new file mode 100644
index 0000000000..59b7a2edc9
--- /dev/null
+++ b/Zend/tests/class_name_as_scalar_error_002.phpt
@@ -0,0 +1,13 @@
+--TEST--
+class name as scalar from ::class keyword error using parent in class constant
+--FILE--
+<?php
+
+namespace Foo\Bar {
+ class One {
+ const Baz = parent::class;
+ }
+}
+?>
+--EXPECTF--
+Fatal error: parent::class cannot be used for compile-time class name resolution in %s on line %d
diff --git a/Zend/tests/class_name_as_scalar_error_003.phpt b/Zend/tests/class_name_as_scalar_error_003.phpt
new file mode 100644
index 0000000000..9299041693
--- /dev/null
+++ b/Zend/tests/class_name_as_scalar_error_003.phpt
@@ -0,0 +1,13 @@
+--TEST--
+class name as scalar from ::class keyword error using static in method signature
+--FILE--
+<?php
+
+namespace Foo\Bar {
+ class One {
+ public function baz($x = static::class) {}
+ }
+}
+?>
+--EXPECTF--
+Fatal error: static::class cannot be used for compile-time class name resolution in %s on line %d
diff --git a/Zend/tests/class_name_as_scalar_error_004.phpt b/Zend/tests/class_name_as_scalar_error_004.phpt
new file mode 100644
index 0000000000..c00037fca3
--- /dev/null
+++ b/Zend/tests/class_name_as_scalar_error_004.phpt
@@ -0,0 +1,13 @@
+--TEST--
+class name as scalar from ::class keyword error using parent in method signature
+--FILE--
+<?php
+
+namespace Foo\Bar {
+ class One {
+ public function baz($x = parent::class) {}
+ }
+}
+?>
+--EXPECTF--
+Fatal error: parent::class cannot be used for compile-time class name resolution in %s on line %d
diff --git a/Zend/tests/class_name_as_scalar_error_005.phpt b/Zend/tests/class_name_as_scalar_error_005.phpt
new file mode 100644
index 0000000000..39de69ffb3
--- /dev/null
+++ b/Zend/tests/class_name_as_scalar_error_005.phpt
@@ -0,0 +1,10 @@
+--TEST--
+class name as scalar from ::class keyword error using static non class context
+--FILE--
+<?php
+
+$x = static::class;
+
+?>
+--EXPECTF--
+Fatal error: Cannot access static::class when no class scope is active in %s on line %d \ No newline at end of file
diff --git a/Zend/tests/class_name_as_scalar_error_006.phpt b/Zend/tests/class_name_as_scalar_error_006.phpt
new file mode 100644
index 0000000000..a4cc9a528b
--- /dev/null
+++ b/Zend/tests/class_name_as_scalar_error_006.phpt
@@ -0,0 +1,10 @@
+--TEST--
+class name as scalar from ::class keyword error using parent in non class context
+--FILE--
+<?php
+
+$x = parent::class;
+
+?>
+--EXPECTF--
+Fatal error: Cannot access parent::class when no class scope is active in %s on line %d
diff --git a/Zend/zend_API.c b/Zend/zend_API.c
index eec4ab0bb1..95c90ea753 100644
--- a/Zend/zend_API.c
+++ b/Zend/zend_API.c
@@ -306,16 +306,14 @@ static const char *zend_parse_arg_impl(int arg_num, zval **arg, va_list *va, con
{
const char *spec_walk = *spec;
char c = *spec_walk++;
- int return_null = 0;
+ int check_null = 0;
/* scan through modifiers */
while (1) {
if (*spec_walk == '/') {
SEPARATE_ZVAL_IF_NOT_REF(arg);
} else if (*spec_walk == '!') {
- if (Z_TYPE_PP(arg) == IS_NULL) {
- return_null = 1;
- }
+ check_null = 1;
} else {
break;
}
@@ -327,6 +325,12 @@ static const char *zend_parse_arg_impl(int arg_num, zval **arg, va_list *va, con
case 'L':
{
long *p = va_arg(*va, long *);
+
+ if (check_null) {
+ zend_bool *p = va_arg(*va, zend_bool *);
+ *p = (Z_TYPE_PP(arg) == IS_NULL);
+ }
+
switch (Z_TYPE_PP(arg)) {
case IS_STRING:
{
@@ -380,6 +384,12 @@ static const char *zend_parse_arg_impl(int arg_num, zval **arg, va_list *va, con
case 'd':
{
double *p = va_arg(*va, double *);
+
+ if (check_null) {
+ zend_bool *p = va_arg(*va, zend_bool *);
+ *p = (Z_TYPE_PP(arg) == IS_NULL);
+ }
+
switch (Z_TYPE_PP(arg)) {
case IS_STRING:
{
@@ -418,7 +428,7 @@ static const char *zend_parse_arg_impl(int arg_num, zval **arg, va_list *va, con
int *pl = va_arg(*va, int *);
switch (Z_TYPE_PP(arg)) {
case IS_NULL:
- if (return_null) {
+ if (check_null) {
*p = NULL;
*pl = 0;
break;
@@ -462,6 +472,12 @@ static const char *zend_parse_arg_impl(int arg_num, zval **arg, va_list *va, con
case 'b':
{
zend_bool *p = va_arg(*va, zend_bool *);
+
+ if (check_null) {
+ zend_bool *p = va_arg(*va, zend_bool *);
+ *p = (Z_TYPE_PP(arg) == IS_NULL);
+ }
+
switch (Z_TYPE_PP(arg)) {
case IS_NULL:
case IS_STRING:
@@ -484,7 +500,7 @@ static const char *zend_parse_arg_impl(int arg_num, zval **arg, va_list *va, con
case 'r':
{
zval **p = va_arg(*va, zval **);
- if (return_null) {
+ if (check_null && Z_TYPE_PP(arg) == IS_NULL) {
*p = NULL;
break;
}
@@ -499,7 +515,7 @@ static const char *zend_parse_arg_impl(int arg_num, zval **arg, va_list *va, con
case 'a':
{
zval **p = va_arg(*va, zval **);
- if (return_null) {
+ if (check_null && Z_TYPE_PP(arg) == IS_NULL) {
*p = NULL;
break;
}
@@ -514,7 +530,7 @@ static const char *zend_parse_arg_impl(int arg_num, zval **arg, va_list *va, con
case 'h':
{
HashTable **p = va_arg(*va, HashTable **);
- if (return_null) {
+ if (check_null && Z_TYPE_PP(arg) == IS_NULL) {
*p = NULL;
break;
}
@@ -534,7 +550,7 @@ static const char *zend_parse_arg_impl(int arg_num, zval **arg, va_list *va, con
case 'o':
{
zval **p = va_arg(*va, zval **);
- if (return_null) {
+ if (check_null && Z_TYPE_PP(arg) == IS_NULL) {
*p = NULL;
break;
}
@@ -551,7 +567,7 @@ static const char *zend_parse_arg_impl(int arg_num, zval **arg, va_list *va, con
zval **p = va_arg(*va, zval **);
zend_class_entry *ce = va_arg(*va, zend_class_entry *);
- if (return_null) {
+ if (check_null && Z_TYPE_PP(arg) == IS_NULL) {
*p = NULL;
break;
}
@@ -573,7 +589,7 @@ static const char *zend_parse_arg_impl(int arg_num, zval **arg, va_list *va, con
zend_class_entry **lookup, **pce = va_arg(*va, zend_class_entry **);
zend_class_entry *ce_base = *pce;
- if (return_null) {
+ if (check_null && Z_TYPE_PP(arg) == IS_NULL) {
*pce = NULL;
break;
}
@@ -607,7 +623,7 @@ static const char *zend_parse_arg_impl(int arg_num, zval **arg, va_list *va, con
zend_fcall_info_cache *fcc = va_arg(*va, zend_fcall_info_cache *);
char *is_callable_error = NULL;
- if (return_null) {
+ if (check_null && Z_TYPE_PP(arg) == IS_NULL) {
fci->size = 0;
fcc->initialized = 0;
break;
@@ -637,7 +653,7 @@ static const char *zend_parse_arg_impl(int arg_num, zval **arg, va_list *va, con
case 'z':
{
zval **p = va_arg(*va, zval **);
- if (return_null) {
+ if (check_null && Z_TYPE_PP(arg) == IS_NULL) {
*p = NULL;
} else {
*p = *arg;
@@ -648,7 +664,7 @@ static const char *zend_parse_arg_impl(int arg_num, zval **arg, va_list *va, con
case 'Z':
{
zval ***p = va_arg(*va, zval ***);
- if (return_null) {
+ if (check_null && Z_TYPE_PP(arg) == IS_NULL) {
*p = NULL;
} else {
*p = arg;
@@ -697,6 +713,19 @@ static int zend_parse_arg(int arg_num, zval **arg, va_list *va, const char **spe
}
/* }}} */
+ZEND_API int zend_parse_parameter(int flags, int arg_num TSRMLS_DC, zval **arg, const char *spec, ...)
+{
+ va_list va;
+ int ret;
+ int quiet = flags & ZEND_PARSE_PARAMS_QUIET;
+
+ va_start(va, spec);
+ ret = zend_parse_arg(arg_num, arg, &va, &spec, quiet TSRMLS_CC);
+ va_end(va);
+
+ return ret;
+}
+
static int zend_parse_va_args(int num_args, const char *type_spec, va_list *va, int flags TSRMLS_DC) /* {{{ */
{
const char *spec_walk;
diff --git a/Zend/zend_API.h b/Zend/zend_API.h
index 4a3985e0f4..8574f90eb5 100644
--- a/Zend/zend_API.h
+++ b/Zend/zend_API.h
@@ -258,6 +258,8 @@ ZEND_API char *zend_zval_type_name(const zval *arg);
ZEND_API int zend_parse_method_parameters(int num_args TSRMLS_DC, zval *this_ptr, const char *type_spec, ...);
ZEND_API int zend_parse_method_parameters_ex(int flags, int num_args TSRMLS_DC, zval *this_ptr, const char *type_spec, ...);
+ZEND_API int zend_parse_parameter(int flags, int arg_num TSRMLS_DC, zval **arg, const char *spec, ...);
+
/* End of parameter parsing API -- andrei */
ZEND_API int zend_register_functions(zend_class_entry *scope, const zend_function_entry *functions, HashTable *function_table, int type TSRMLS_DC);
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c
index 43b891695e..1a8d108900 100644
--- a/Zend/zend_compile.c
+++ b/Zend/zend_compile.c
@@ -5,7 +5,7 @@
| Copyright (c) 1998-2013 Zend Technologies Ltd. (http://www.zend.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 2.00 of the Zend license, |
- | that is bundled with this package in the file LICENSE, and is |
+ | that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.zend.com/license/2_00.txt. |
| If you did not receive a copy of the Zend license and are unable to |
@@ -107,7 +107,7 @@ ZEND_API zend_executor_globals executor_globals;
static void zend_duplicate_property_info(zend_property_info *property_info) /* {{{ */
{
- if (!IS_INTERNED(property_info->name)) {
+ if (!IS_INTERNED(property_info->name)) {
property_info->name = estrndup(property_info->name, property_info->name_length);
}
if (property_info->doc_comment) {
@@ -118,7 +118,7 @@ static void zend_duplicate_property_info(zend_property_info *property_info) /* {
static void zend_duplicate_property_info_internal(zend_property_info *property_info) /* {{{ */
{
- if (!IS_INTERNED(property_info->name)) {
+ if (!IS_INTERNED(property_info->name)) {
property_info->name = zend_strndup(property_info->name, property_info->name_length);
}
}
@@ -383,7 +383,7 @@ int zend_add_func_name_literal(zend_op_array *op_array, const zval *zv TSRMLS_DC
zval c;
int lc_literal;
- if (op_array->last_literal > 0 &&
+ if (op_array->last_literal > 0 &&
&op_array->literals[op_array->last_literal - 1].constant == zv &&
op_array->literals[op_array->last_literal - 1].cache_slot == -1) {
/* we already have function name as last literal (do nothing) */
@@ -391,7 +391,7 @@ int zend_add_func_name_literal(zend_op_array *op_array, const zval *zv TSRMLS_DC
} else {
ret = zend_add_literal(op_array, zv TSRMLS_CC);
}
-
+
lc_name = zend_str_tolower_dup(Z_STRVAL_P(zv), Z_STRLEN_P(zv));
ZVAL_STRINGL(&c, lc_name, Z_STRLEN_P(zv), 0);
lc_literal = zend_add_literal(CG(active_op_array), &c TSRMLS_CC);
@@ -410,7 +410,7 @@ int zend_add_ns_func_name_literal(zend_op_array *op_array, const zval *zv TSRMLS
zval c;
int lc_literal;
- if (op_array->last_literal > 0 &&
+ if (op_array->last_literal > 0 &&
&op_array->literals[op_array->last_literal - 1].constant == zv &&
op_array->literals[op_array->last_literal - 1].cache_slot == -1) {
/* we already have function name as last literal (do nothing) */
@@ -443,7 +443,7 @@ int zend_add_class_name_literal(zend_op_array *op_array, const zval *zv TSRMLS_D
zval c;
int lc_literal;
- if (op_array->last_literal > 0 &&
+ if (op_array->last_literal > 0 &&
&op_array->literals[op_array->last_literal - 1].constant == zv &&
op_array->literals[op_array->last_literal - 1].cache_slot == -1) {
/* we already have function name as last literal (do nothing) */
@@ -477,7 +477,7 @@ int zend_add_const_name_literal(zend_op_array *op_array, const zval *zv, int unq
int name_len, ns_len;
zval c;
- if (op_array->last_literal > 0 &&
+ if (op_array->last_literal > 0 &&
&op_array->literals[op_array->last_literal - 1].constant == zv &&
op_array->literals[op_array->last_literal - 1].cache_slot == -1) {
/* we already have function name as last literal (do nothing) */
@@ -486,7 +486,7 @@ int zend_add_const_name_literal(zend_op_array *op_array, const zval *zv, int unq
ret = zend_add_literal(op_array, zv TSRMLS_CC);
}
- /* skip leading '\\' */
+ /* skip leading '\\' */
if (Z_STRVAL_P(zv)[0] == '\\') {
name_len = Z_STRLEN_P(zv) - 1;
name = Z_STRVAL_P(zv) + 1;
@@ -816,7 +816,7 @@ void fetch_array_dim(znode *result, const znode *parent, const znode *dim TSRMLS
opline.result.var = opline.op1.var;
zend_llist_add_element(fetch_list_ptr, &opline);
}
-
+
init_op(&opline TSRMLS_CC);
opline.opcode = ZEND_FETCH_DIM_W; /* the backpatching routine assumes W */
opline.result_type = IS_VAR;
@@ -830,12 +830,12 @@ void fetch_array_dim(znode *result, const znode *parent, const znode *dim TSRMLS
ZEND_HANDLE_NUMERIC_EX(Z_STRVAL(CONSTANT(opline.op2.constant)), Z_STRLEN(CONSTANT(opline.op2.constant))+1, index, numeric = 1);
if (numeric) {
zval_dtor(&CONSTANT(opline.op2.constant));
- ZVAL_LONG(&CONSTANT(opline.op2.constant), index);
+ ZVAL_LONG(&CONSTANT(opline.op2.constant), index);
} else {
CALCULATE_LITERAL_HASH(opline.op2.constant);
}
}
-
+
GET_NODE(result, opline.result);
zend_llist_add_element(fetch_list_ptr, &opline);
@@ -940,7 +940,7 @@ void zend_do_assign(znode *result, znode *variable, znode *value TSRMLS_DC) /* {
opline->result.var = get_temporary_variable(CG(active_op_array));
opline->op1_type = IS_CONST;
LITERAL_STRINGL(opline->op1,
- CG(active_op_array)->vars[value->u.op.var].name,
+ CG(active_op_array)->vars[value->u.op.var].name,
CG(active_op_array)->vars[value->u.op.var].name_len, 1);
CALCULATE_LITERAL_HASH(opline->op1.constant);
SET_UNUSED(opline->op2);
@@ -1569,7 +1569,7 @@ void zend_do_begin_function_declaration(znode *function_token, znode *function_n
if (is_method) {
int result;
-
+
lcname = zend_new_interned_string(zend_str_tolower_dup(name, name_len), name_len + 1, 1 TSRMLS_CC);
if (IS_INTERNED(lcname)) {
@@ -1624,7 +1624,7 @@ void zend_do_begin_function_declaration(znode *function_token, znode *function_n
}
} else {
char *class_lcname;
-
+
class_lcname = do_alloca(CG(active_class_entry)->name_length + 1, use_heap);
zend_str_tolower_copy(class_lcname, CG(active_class_entry)->name, CG(active_class_entry)->name_length);
/* Improve after RC: cache the lowercase class name */
@@ -1675,7 +1675,7 @@ void zend_do_begin_function_declaration(znode *function_token, znode *function_n
} else if ((name_len == sizeof(ZEND_TOSTRING_FUNC_NAME)-1) && (!memcmp(lcname, ZEND_TOSTRING_FUNC_NAME, sizeof(ZEND_TOSTRING_FUNC_NAME)-1))) {
if (fn_flags & ((ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC) ^ ZEND_ACC_PUBLIC)) {
zend_error(E_WARNING, "The magic method __toString() must have public visibility and cannot be static");
- }
+ }
CG(active_class_entry)->__tostring = (zend_function *) CG(active_op_array);
} else if (!(fn_flags & ZEND_ACC_STATIC)) {
CG(active_op_array)->fn_flags |= ZEND_ACC_ALLOW_STATIC;
@@ -1806,14 +1806,14 @@ void zend_do_end_function_declaration(const znode *function_token TSRMLS_DC) /*
if (CG(active_class_entry)) {
zend_check_magic_method_implementation(CG(active_class_entry), (zend_function*)CG(active_op_array), E_COMPILE_ERROR TSRMLS_CC);
} else {
- /* we don't care if the function name is longer, in fact lowercasing only
+ /* we don't care if the function name is longer, in fact lowercasing only
* the beginning of the name speeds up the check process */
name_len = strlen(CG(active_op_array)->function_name);
zend_str_tolower_copy(lcname, CG(active_op_array)->function_name, MIN(name_len, sizeof(lcname)-1));
lcname[sizeof(lcname)-1] = '\0'; /* zend_str_tolower_copy won't necessarily set the zero byte */
if (name_len == sizeof(ZEND_AUTOLOAD_FUNC_NAME) - 1 && !memcmp(lcname, ZEND_AUTOLOAD_FUNC_NAME, sizeof(ZEND_AUTOLOAD_FUNC_NAME)) && CG(active_op_array)->num_args != 1) {
zend_error(E_COMPILE_ERROR, "%s() must take exactly 1 argument", ZEND_AUTOLOAD_FUNC_NAME);
- }
+ }
}
CG(active_op_array)->line_end = zend_get_compiled_lineno(TSRMLS_C);
@@ -1939,7 +1939,7 @@ int zend_do_begin_function_call(znode *function_name, zend_bool check_namespace
internal function with short name */
zend_do_begin_dynamic_function_call(function_name, 1 TSRMLS_CC);
return 1;
- }
+ }
lcname = zend_str_tolower_dup(function_name->u.constant.value.str.val, function_name->u.constant.value.str.len);
if ((zend_hash_find(CG(function_table), lcname, function_name->u.constant.value.str.len+1, (void **) &function)==FAILURE) ||
@@ -1948,10 +1948,10 @@ int zend_do_begin_function_call(znode *function_name, zend_bool check_namespace
zend_do_begin_dynamic_function_call(function_name, 0 TSRMLS_CC);
efree(lcname);
return 1; /* Dynamic */
- }
+ }
efree(function_name->u.constant.value.str.val);
function_name->u.constant.value.str.val = lcname;
-
+
zend_stack_push(&CG(function_call_stack), (void *) &function, sizeof(zend_function *));
if (CG(context).nested_calls + 1 > CG(active_op_array)->nested_calls) {
CG(active_op_array)->nested_calls = CG(context).nested_calls + 1;
@@ -1984,7 +1984,7 @@ void zend_do_begin_method_call(znode *left_bracket TSRMLS_DC) /* {{{ */
name = CONSTANT(last_op->op2.constant);
if (Z_TYPE(name) != IS_STRING) {
zend_error(E_COMPILE_ERROR, "Method name must be a string");
- }
+ }
if (!IS_INTERNED(Z_STRVAL(name))) {
Z_STRVAL(name) = estrndup(Z_STRVAL(name), Z_STRLEN(name));
}
@@ -2119,6 +2119,53 @@ void zend_resolve_non_class_name(znode *element_name, zend_bool check_namespace
}
/* }}} */
+void zend_do_resolve_class_name(znode *result, znode *class_name, int is_static TSRMLS_DC) /* {{{ */
+{
+ char *lcname;
+ int lctype;
+ znode constant_name;
+
+ lcname = zend_str_tolower_dup(Z_STRVAL(class_name->u.constant), class_name->u.constant.value.str.len);
+ lctype = zend_get_class_fetch_type(lcname, strlen(lcname));
+ switch (lctype) {
+ case ZEND_FETCH_CLASS_SELF:
+ if (!CG(active_class_entry)) {
+ zend_error(E_COMPILE_ERROR, "Cannot access self::class when no class scope is active");
+ }
+ zval_dtor(&class_name->u.constant);
+ class_name->op_type = IS_CONST;
+ ZVAL_STRINGL(&class_name->u.constant, CG(active_class_entry)->name, CG(active_class_entry)->name_length, 1);
+ *result = *class_name;
+ break;
+ case ZEND_FETCH_CLASS_STATIC:
+ case ZEND_FETCH_CLASS_PARENT:
+ if (is_static) {
+ zend_error(E_COMPILE_ERROR,
+ "%s::class cannot be used for compile-time class name resolution",
+ lctype == ZEND_FETCH_CLASS_STATIC ? "static" : "parent"
+ );
+ }
+ if (!CG(active_class_entry)) {
+ zend_error(E_COMPILE_ERROR,
+ "Cannot access %s::class when no class scope is active",
+ lctype == ZEND_FETCH_CLASS_STATIC ? "static" : "parent"
+ );
+ }
+ constant_name.op_type = IS_CONST;
+ ZVAL_STRINGL(&constant_name.u.constant, "class", sizeof("class")-1, 1);
+ zend_do_fetch_constant(result, class_name, &constant_name, ZEND_RT, 1 TSRMLS_CC);
+ break;
+ case ZEND_FETCH_CLASS_DEFAULT:
+ zend_resolve_class_name(class_name, ZEND_FETCH_CLASS_GLOBAL, 1 TSRMLS_CC);
+ *result = *class_name;
+ break;
+ }
+
+ efree(lcname);
+
+}
+/* }}} */
+
void zend_resolve_class_name(znode *class_name, ulong fetch_type, int check_ns_name TSRMLS_DC) /* {{{ */
{
char *compound;
@@ -2141,7 +2188,7 @@ void zend_resolve_class_name(znode *class_name, ulong fetch_type, int check_ns_n
if (ZEND_FETCH_CLASS_DEFAULT != zend_get_class_fetch_type(Z_STRVAL(class_name->u.constant), Z_STRLEN(class_name->u.constant))) {
zend_error(E_COMPILE_ERROR, "'\\%s' is an invalid class name", Z_STRVAL(class_name->u.constant));
}
- } else {
+ } else {
if (CG(current_import)) {
len = compound - Z_STRVAL(class_name->u.constant);
lcname = zend_str_tolower_dup(Z_STRVAL(class_name->u.constant), len);
@@ -2506,8 +2553,8 @@ void zend_do_pass_param(znode *param, zend_uchar op, int offset TSRMLS_DC) /* {{
zend_error(E_COMPILE_ERROR, "Call-time pass-by-reference has been removed");
}
return;
- }
-
+ }
+
if (function_ptr) {
if (ARG_MAY_BE_SENT_BY_REF(function_ptr, (zend_uint) offset)) {
if (param->op_type & (IS_VAR|IS_CV) && original_op != ZEND_SEND_VAL) {
@@ -2678,7 +2725,7 @@ void zend_do_return(znode *expr, int do_end_vparse TSRMLS_DC) /* {{{ */
SET_UNUSED(opline->op1);
SET_UNUSED(opline->op2);
}
-
+
opline = get_next_op(CG(active_op_array) TSRMLS_CC);
opline->opcode = returns_reference ? ZEND_RETURN_BY_REF : ZEND_RETURN;
@@ -2893,10 +2940,10 @@ void zend_do_end_finally(znode *try_token, znode* catch_token, znode *finally_to
{
if (catch_token->op_type == IS_UNUSED && finally_token->op_type == IS_UNUSED) {
zend_error(E_COMPILE_ERROR, "Cannot use try without catch or finally");
- }
+ }
if (finally_token->op_type != IS_UNUSED) {
zend_op *opline;
-
+
CG(active_op_array)->try_catch_array[try_token->u.op.opline_num].finally_op = finally_token->u.op.opline_num + 1;
CG(active_op_array)->try_catch_array[try_token->u.op.opline_num].finally_end = get_next_op_number(CG(active_op_array));
CG(active_op_array)->has_finally_block = 1;
@@ -2905,11 +2952,11 @@ void zend_do_end_finally(znode *try_token, znode* catch_token, znode *finally_to
opline->opcode = ZEND_FAST_RET;
SET_UNUSED(opline->op1);
SET_UNUSED(opline->op2);
-
+
CG(active_op_array)->opcodes[finally_token->u.op.opline_num].op1.opline_num = get_next_op_number(CG(active_op_array));
CG(context).in_finally--;
- }
+ }
}
/* }}} */
@@ -3016,7 +3063,7 @@ static void do_inherit_parent_constructor(zend_class_entry *ce) /* {{{ */
lc_class_name = zend_str_tolower_dup(ce->name, ce->name_length);
if (!zend_hash_exists(&ce->function_table, lc_class_name, ce->name_length+1)) {
lc_parent_class_name = zend_str_tolower_dup(ce->parent->name, ce->parent->name_length);
- if (!zend_hash_exists(&ce->function_table, lc_parent_class_name, ce->parent->name_length+1) &&
+ if (!zend_hash_exists(&ce->function_table, lc_parent_class_name, ce->parent->name_length+1) &&
zend_hash_find(&ce->parent->function_table, lc_parent_class_name, ce->parent->name_length+1, (void **)&function)==SUCCESS) {
if (function->common.fn_flags & ZEND_ACC_CTOR) {
/* inherit parent's constructor */
@@ -3155,8 +3202,8 @@ static zend_bool zend_do_perform_implementation_check(const zend_function *fe, c
return 0;
}
}
- }
- }
+ }
+ }
if (fe->common.arg_info[i].type_hint != proto->common.arg_info[i].type_hint) {
/* Incompatible type hint */
return 0;
@@ -3185,7 +3232,7 @@ static zend_bool zend_do_perform_implementation_check(const zend_function *fe, c
buf = erealloc(buf, length); \
}
-static char * zend_get_function_declaration(zend_function *fptr TSRMLS_DC) /* {{{ */
+static char * zend_get_function_declaration(zend_function *fptr TSRMLS_DC) /* {{{ */
{
char *offset, *buf;
zend_uint length = 1024;
@@ -3202,7 +3249,7 @@ static char * zend_get_function_declaration(zend_function *fptr TSRMLS_DC) /* {{
*(offset++) = ':';
*(offset++) = ':';
}
-
+
{
size_t name_len = strlen(fptr->common.function_name);
REALLOC_BUF_IF_EXCEED(buf, offset, length, name_len);
@@ -3243,7 +3290,7 @@ static char * zend_get_function_declaration(zend_function *fptr TSRMLS_DC) /* {{
offset += type_name_len;
*(offset++) = ' ';
}
-
+
if (arg_info->pass_by_reference) {
*(offset++) = '&';
}
@@ -3345,7 +3392,7 @@ static char * zend_get_function_declaration(zend_function *fptr TSRMLS_DC) /* {{
*offset = '\0';
return buf;
-}
+}
/* }}} */
static void do_inheritance_check_on_method(zend_function *child, zend_function *parent TSRMLS_DC) /* {{{ */
@@ -3357,7 +3404,7 @@ static void do_inheritance_check_on_method(zend_function *child, zend_function *
&& parent->common.fn_flags & ZEND_ACC_ABSTRACT
&& parent->common.scope != (child->common.prototype ? child->common.prototype->common.scope : child->common.scope)
&& child->common.fn_flags & (ZEND_ACC_ABSTRACT|ZEND_ACC_IMPLEMENTED_ABSTRACT)) {
- zend_error(E_COMPILE_ERROR, "Can't inherit abstract function %s::%s() (previously declared abstract in %s)",
+ zend_error(E_COMPILE_ERROR, "Can't inherit abstract function %s::%s() (previously declared abstract in %s)",
parent->common.scope->name,
child->common.function_name,
child->common.prototype ? child->common.prototype->common.scope->name : child->common.scope->name);
@@ -3397,7 +3444,7 @@ static void do_inheritance_check_on_method(zend_function *child, zend_function *
}
if (parent_flags & ZEND_ACC_PRIVATE) {
- child->common.prototype = NULL;
+ child->common.prototype = NULL;
} else if (parent_flags & ZEND_ACC_ABSTRACT) {
child->common.fn_flags |= ZEND_ACC_IMPLEMENTED_ABSTRACT;
child->common.prototype = parent;
@@ -3408,12 +3455,12 @@ static void do_inheritance_check_on_method(zend_function *child, zend_function *
if (child->common.prototype && (child->common.prototype->common.fn_flags & ZEND_ACC_ABSTRACT)) {
if (!zend_do_perform_implementation_check(child, child->common.prototype TSRMLS_CC)) {
- zend_error(E_COMPILE_ERROR, "Declaration of %s::%s() must be compatible with %s", ZEND_FN_SCOPE_NAME(child), child->common.function_name, zend_get_function_declaration(child->common.prototype? child->common.prototype : parent TSRMLS_CC));
+ zend_error(E_COMPILE_ERROR, "Declaration of %s::%s() must be compatible with %s", ZEND_FN_SCOPE_NAME(child), child->common.function_name, zend_get_function_declaration(child->common.prototype? child->common.prototype : parent TSRMLS_CC));
}
} else if (EG(error_reporting) & E_STRICT || EG(user_error_handler)) { /* Check E_STRICT (or custom error handler) before the check so that we save some time */
if (!zend_do_perform_implementation_check(child, parent TSRMLS_CC)) {
char *method_prototype = zend_get_function_declaration(child->common.prototype? child->common.prototype : parent TSRMLS_CC);
- zend_error(E_STRICT, "Declaration of %s::%s() should be compatible with %s", ZEND_FN_SCOPE_NAME(child), child->common.function_name, method_prototype);
+ zend_error(E_STRICT, "Declaration of %s::%s() should be compatible with %s", ZEND_FN_SCOPE_NAME(child), child->common.function_name, method_prototype);
efree(method_prototype);
}
}
@@ -3432,9 +3479,9 @@ static zend_bool do_inherit_method_check(HashTable *child_function_table, zend_f
}
return 1; /* method doesn't exist in child, copy from parent */
}
-
+
do_inheritance_check_on_method(child, parent TSRMLS_CC);
-
+
return 0;
}
/* }}} */
@@ -3465,7 +3512,7 @@ static zend_bool do_inherit_property_access_check(HashTable *target_ht, zend_pro
zend_error(E_COMPILE_ERROR, "Cannot redeclare %s%s::$%s as %s%s::$%s",
(parent_info->flags & ZEND_ACC_STATIC) ? "static " : "non static ", parent_ce->name, hash_key->arKey,
(child_info->flags & ZEND_ACC_STATIC) ? "static " : "non static ", ce->name, hash_key->arKey);
-
+
}
if(parent_info->flags & ZEND_ACC_CHANGED) {
@@ -3731,10 +3778,10 @@ ZEND_API void zend_do_implement_interface(zend_class_entry *ce, zend_class_entry
}
}
ce->interfaces[ce->num_interfaces++] = iface;
-
+
zend_hash_merge_ex(&ce->constants_table, &iface->constants_table, (copy_ctor_func_t) zval_add_ref, sizeof(zval *), (merge_checker_func_t) do_inherit_constant_check, iface);
zend_hash_merge_ex(&ce->function_table, &iface->function_table, (copy_ctor_func_t) do_inherit_method, sizeof(zend_function), (merge_checker_func_t) do_inherit_method_check, ce);
-
+
do_implement_interface(ce, iface TSRMLS_CC);
zend_do_inherit_interfaces(ce, iface TSRMLS_CC);
}
@@ -3774,10 +3821,10 @@ static zend_bool zend_traits_method_compatibility_check(zend_function *fn, zend_
{
zend_uint fn_flags = fn->common.scope->ce_flags;
zend_uint other_flags = other_fn->common.scope->ce_flags;
-
+
return zend_do_perform_implementation_check(fn, other_fn TSRMLS_CC)
&& zend_do_perform_implementation_check(other_fn, fn TSRMLS_CC)
- && ((fn_flags & (ZEND_ACC_FINAL|ZEND_ACC_STATIC)) ==
+ && ((fn_flags & (ZEND_ACC_FINAL|ZEND_ACC_STATIC)) ==
(other_flags & (ZEND_ACC_FINAL|ZEND_ACC_STATIC))); /* equal final and static qualifier */
}
/* }}} */
@@ -3790,7 +3837,7 @@ static void zend_add_magic_methods(zend_class_entry* ce, const char* mname, uint
if (ce->constructor) {
zend_error(E_COMPILE_ERROR, "%s has colliding constructor definitions coming from traits", ce->name);
}
- ce->constructor = fe; fe->common.fn_flags |= ZEND_ACC_CTOR;
+ ce->constructor = fe; fe->common.fn_flags |= ZEND_ACC_CTOR;
} else if (!strncmp(mname, ZEND_DESTRUCTOR_FUNC_NAME, mname_len)) {
ce->destructor = fe; fe->common.fn_flags |= ZEND_ACC_DTOR;
} else if (!strncmp(mname, ZEND_GET_FUNC_NAME, mname_len)) {
@@ -3927,7 +3974,7 @@ static int zend_traits_copy_functions(zend_function *fn TSRMLS_DC, int num_args,
ce = va_arg(args, zend_class_entry*);
overriden = va_arg(args, HashTable**);
exclude_table = va_arg(args, HashTable*);
-
+
fnname_len = strlen(fn->common.function_name);
/* apply aliases which are qualified with a class name, there should not be any ambiguity */
@@ -3941,9 +3988,9 @@ static int zend_traits_copy_functions(zend_function *fn TSRMLS_DC, int num_args,
&& alias->trait_method->mname_len == fnname_len
&& (zend_binary_strcasecmp(alias->trait_method->method_name, alias->trait_method->mname_len, fn->common.function_name, fnname_len) == 0)) {
fn_copy = *fn;
-
+
/* if it is 0, no modifieres has been changed */
- if (alias->modifiers) {
+ if (alias->modifiers) {
fn_copy.common.fn_flags = alias->modifiers | (fn->common.fn_flags ^ (fn->common.fn_flags & ZEND_ACC_PPP_MASK));
}
@@ -4046,7 +4093,7 @@ static void zend_traits_init_trait_structures(zend_class_entry *ce TSRMLS_DC) /*
cur_method_ref->ce->name,
cur_method_ref->method_name);
}
-
+
/** With the other traits, we are more permissive.
We do not give errors for those. This allows to be more
defensive in such definitions.
@@ -4060,20 +4107,20 @@ static void zend_traits_init_trait_structures(zend_class_entry *ce TSRMLS_DC) /*
if (!(cur_precedence->exclude_from_classes[j] = zend_fetch_class(class_name, name_length, ZEND_FETCH_CLASS_TRAIT |ZEND_FETCH_CLASS_NO_AUTOLOAD TSRMLS_CC))) {
zend_error(E_COMPILE_ERROR, "Could not find trait %s", class_name);
- }
+ }
zend_check_trait_usage(ce, cur_precedence->exclude_from_classes[j] TSRMLS_CC);
/* make sure that the trait method is not from a class mentioned in
exclude_from_classes, for consistency */
if (cur_precedence->trait_method->ce == cur_precedence->exclude_from_classes[i]) {
zend_error(E_COMPILE_ERROR,
- "Inconsistent insteadof definition. "
+ "Inconsistent insteadof definition. "
"The method %s is to be used from %s, but %s is also on the exclude list",
cur_method_ref->method_name,
cur_precedence->trait_method->ce->name,
cur_precedence->trait_method->ce->name);
}
-
+
efree(class_name);
j++;
}
@@ -4113,7 +4160,7 @@ static void zend_traits_init_trait_structures(zend_class_entry *ce TSRMLS_DC) /*
static void zend_traits_compile_exclude_table(HashTable* exclude_table, zend_trait_precedence **precedences, zend_class_entry *trait) /* {{{ */
{
size_t i = 0, j;
-
+
if (!precedences) {
return;
}
@@ -4124,7 +4171,7 @@ static void zend_traits_compile_exclude_table(HashTable* exclude_table, zend_tra
if (precedences[i]->exclude_from_classes[j] == trait) {
zend_uint lcname_len = precedences[i]->trait_method->mname_len;
char *lcname = zend_str_tolower_dup(precedences[i]->trait_method->method_name, lcname_len);
-
+
if (zend_hash_add(exclude_table, lcname, lcname_len, NULL, 0, NULL) == FAILURE) {
efree(lcname);
zend_error(E_COMPILE_ERROR, "Failed to evaluate a trait precedence (%s). Method of trait %s was defined to be excluded multiple times", precedences[i]->trait_method->method_name, trait->name);
@@ -4161,7 +4208,7 @@ static void zend_do_traits_method_binding(zend_class_entry *ce TSRMLS_DC) /* {{{
zend_hash_apply_with_arguments(&ce->traits[i]->function_table TSRMLS_CC, (apply_func_args_t)zend_traits_copy_functions, 3, ce, &overriden, NULL);
}
}
-
+
zend_hash_apply_with_argument(&ce->function_table, (apply_func_arg_t)zend_fixup_trait_method, ce TSRMLS_CC);
if (overriden) {
@@ -4199,7 +4246,7 @@ static void zend_do_traits_property_binding(zend_class_entry *ce TSRMLS_DC) /* {
const char* class_name_unused;
zend_bool not_compatible;
zval* prop_value;
- char* doc_comment;
+ char* doc_comment;
zend_uint flags;
/* In the following steps the properties are inserted into the property table
@@ -4228,10 +4275,10 @@ static void zend_do_traits_property_binding(zend_class_entry *ce TSRMLS_DC) /* {
/* next: check for conflicts with current class */
if (zend_hash_quick_find(&ce->properties_info, prop_name, prop_name_length+1, prop_hash, (void **) &coliding_prop) == SUCCESS) {
- if (coliding_prop->flags & ZEND_ACC_SHADOW) {
+ if (coliding_prop->flags & ZEND_ACC_SHADOW) {
zend_hash_quick_del(&ce->properties_info, prop_name, prop_name_length+1, prop_hash);
flags |= ZEND_ACC_CHANGED;
- } else {
+ } else {
if ((coliding_prop->flags & (ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC))
== (flags & (ZEND_ACC_PPP_MASK | ZEND_ACC_STATIC))) {
/* flags are identical, now the value needs to be checked */
@@ -4252,14 +4299,14 @@ static void zend_do_traits_property_binding(zend_class_entry *ce TSRMLS_DC) /* {
}
if (not_compatible) {
- zend_error(E_COMPILE_ERROR,
+ zend_error(E_COMPILE_ERROR,
"%s and %s define the same property ($%s) in the composition of %s. However, the definition differs and is considered incompatible. Class was composed",
find_first_definition(ce, i, prop_name, prop_name_length, prop_hash, coliding_prop->ce)->name,
property_info->ce->name,
prop_name,
ce->name);
} else {
- zend_error(E_STRICT,
+ zend_error(E_STRICT,
"%s and %s define the same property ($%s) in the composition of %s. This might be incompatible, to improve maintainability consider using accessor methods in traits instead. Class was composed",
find_first_definition(ce, i, prop_name, prop_name_length, prop_hash, coliding_prop->ce)->name,
property_info->ce->name,
@@ -4279,8 +4326,8 @@ static void zend_do_traits_property_binding(zend_class_entry *ce TSRMLS_DC) /* {
Z_ADDREF_P(prop_value);
doc_comment = property_info->doc_comment ? estrndup(property_info->doc_comment, property_info->doc_comment_len) : NULL;
- zend_declare_property_ex(ce, prop_name, prop_name_length,
- prop_value, flags,
+ zend_declare_property_ex(ce, prop_name, prop_name_length,
+ prop_value, flags,
doc_comment, property_info->doc_comment_len TSRMLS_CC);
}
}
@@ -4292,7 +4339,7 @@ static void zend_do_check_for_inconsistent_traits_aliasing(zend_class_entry *ce
int i = 0;
zend_trait_alias* cur_alias;
char* lc_method_name;
-
+
if (ce->trait_aliases) {
while (ce->trait_aliases[i]) {
cur_alias = ce->trait_aliases[i];
@@ -4313,7 +4360,7 @@ static void zend_do_check_for_inconsistent_traits_aliasing(zend_class_entry *ce
we check against it and abort.
2) it is just a plain old inconsitency/typo/bug
as in the case where alias is set. */
-
+
lc_method_name = zend_str_tolower_dup(cur_alias->trait_method->method_name,
cur_alias->trait_method->mname_len);
if (zend_hash_exists(&ce->function_table,
@@ -4350,7 +4397,7 @@ ZEND_API void zend_do_bind_traits(zend_class_entry *ce TSRMLS_DC) /* {{{ */
/* first care about all methods to be flattened into the class */
zend_do_traits_method_binding(ce TSRMLS_CC);
-
+
/* Aliases which have not been applied indicate typos/bugs. */
zend_do_check_for_inconsistent_traits_aliasing(ce TSRMLS_CC);
@@ -4359,7 +4406,7 @@ ZEND_API void zend_do_bind_traits(zend_class_entry *ce TSRMLS_DC) /* {{{ */
/* verify that all abstract methods from traits have been implemented */
zend_verify_abstract_class(ce TSRMLS_CC);
-
+
/* now everything should be fine and an added ZEND_ACC_IMPLICIT_ABSTRACT_CLASS should be removed */
if (ce->ce_flags & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS) {
ce->ce_flags -= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
@@ -4409,7 +4456,7 @@ void zend_prepare_reference(znode *result, znode *class_name, znode *method_name
zend_trait_method_reference *method_ref = emalloc(sizeof(zend_trait_method_reference));
method_ref->ce = NULL;
- /* REM: There should not be a need for copying,
+ /* REM: There should not be a need for copying,
zend_do_begin_class_declaration is also just using that string */
if (class_name) {
zend_resolve_class_name(class_name, ZEND_FETCH_CLASS_GLOBAL, 1 TSRMLS_CC);
@@ -4983,7 +5030,7 @@ void zend_do_begin_class_declaration(const znode *class_token, znode *class_name
build_runtime_defined_function_key(&key, lcname, new_class_entry->name_length TSRMLS_CC);
opline->op1.constant = zend_add_literal(CG(active_op_array), &key TSRMLS_CC);
Z_HASH_P(&CONSTANT(opline->op1.constant)) = zend_hash_func(Z_STRVAL(CONSTANT(opline->op1.constant)), Z_STRLEN(CONSTANT(opline->op1.constant)));
-
+
opline->op2_type = IS_CONST;
if (doing_inheritance) {
@@ -5000,7 +5047,7 @@ void zend_do_begin_class_declaration(const znode *class_token, znode *class_name
LITERAL_STRINGL(opline->op2, lcname, new_class_entry->name_length, 0);
CALCULATE_LITERAL_HASH(opline->op2.constant);
-
+
zend_hash_quick_update(CG(class_table), Z_STRVAL(key), Z_STRLEN(key), Z_HASH_P(&CONSTANT(opline->op1.constant)), &new_class_entry, sizeof(zend_class_entry *), NULL);
CG(active_class_entry) = new_class_entry;
@@ -5051,7 +5098,7 @@ void zend_do_end_class_declaration(const znode *class_token, const znode *parent
}
ce->info.user.line_end = zend_get_compiled_lineno(TSRMLS_C);
-
+
/* Check for traits and proceed like with interfaces.
* The only difference will be a combined handling of them in the end.
* Thus, we need another opcode here. */
@@ -5076,7 +5123,7 @@ void zend_do_end_class_declaration(const znode *class_token, const znode *parent
}
}
/* Inherit interfaces; reset number to zero, we need it for above check and
- * will restore it during actual implementation.
+ * will restore it during actual implementation.
* The ZEND_ACC_IMPLEMENT_INTERFACES flag disables double call to
* zend_verify_abstract_class() */
if (ce->num_interfaces > 0) {
@@ -5278,7 +5325,7 @@ void zend_do_declare_class_constant(znode *var_name, const znode *value TSRMLS_D
ALLOC_ZVAL(property);
*property = value->u.constant;
-
+
cname = zend_new_interned_string(var_name->u.constant.value.str.val, var_name->u.constant.value.str.len+1, 0 TSRMLS_CC);
if (IS_INTERNED(cname)) {
@@ -5291,7 +5338,7 @@ void zend_do_declare_class_constant(znode *var_name, const znode *value TSRMLS_D
zend_error(E_COMPILE_ERROR, "Cannot redefine class constant %s::%s", CG(active_class_entry)->name, var_name->u.constant.value.str.val);
}
FREE_PNODE(var_name);
-
+
if (CG(doc_comment)) {
efree(CG(doc_comment));
CG(doc_comment) = NULL;
@@ -5380,17 +5427,17 @@ void zend_do_halt_compiler_register(TSRMLS_D) /* {{{ */
char *name, *cfilename;
char haltoff[] = "__COMPILER_HALT_OFFSET__";
int len, clen;
-
+
if (CG(has_bracketed_namespaces) && CG(in_namespace)) {
zend_error(E_COMPILE_ERROR, "__HALT_COMPILER() can only be used from the outermost scope");
}
-
+
cfilename = zend_get_compiled_filename(TSRMLS_C);
clen = strlen(cfilename);
zend_mangle_property_name(&name, &len, haltoff, sizeof(haltoff) - 1, cfilename, clen, 0);
zend_register_long_constant(name, len+1, zend_get_scanned_file_offset(TSRMLS_C), CONST_CS, 0 TSRMLS_CC);
pefree(name, 0);
-
+
if (CG(in_namespace)) {
zend_do_end_namespace(TSRMLS_C);
}
@@ -5467,7 +5514,7 @@ static zend_constant* zend_get_ct_const(const zval *const_name, int all_internal
}
} else if (zend_hash_find(EG(zend_constants), Z_STRVAL_P(const_name), Z_STRLEN_P(const_name)+1, (void **) &c) == FAILURE) {
char *lookup_name = zend_str_tolower_dup(Z_STRVAL_P(const_name), Z_STRLEN_P(const_name));
-
+
if (zend_hash_find(EG(zend_constants), lookup_name, Z_STRLEN_P(const_name)+1, (void **) &c)==SUCCESS) {
if ((c->flags & CONST_CT_SUBST) && !(c->flags & CONST_CS)) {
efree(lookup_name);
@@ -5520,7 +5567,7 @@ void zend_do_fetch_constant(znode *result, znode *constant_container, znode *con
case ZEND_CT:
/* this is a class constant */
type = zend_get_class_fetch_type(Z_STRVAL(constant_container->u.constant), Z_STRLEN(constant_container->u.constant));
-
+
if (ZEND_FETCH_CLASS_STATIC == type) {
zend_error(E_ERROR, "\"static::\" is not allowed in compile-time constants");
} else if (ZEND_FETCH_CLASS_DEFAULT == type) {
@@ -5584,7 +5631,7 @@ void zend_do_fetch_constant(znode *result, znode *constant_container, znode *con
compound = memchr(Z_STRVAL(constant_name->u.constant), '\\', Z_STRLEN(constant_name->u.constant));
zend_resolve_non_class_name(constant_name, check_namespace TSRMLS_CC);
-
+
if(zend_constant_ct_subst(result, &constant_name->u.constant, 1 TSRMLS_CC)) {
break;
}
@@ -5600,7 +5647,7 @@ void zend_do_fetch_constant(znode *result, znode *constant_container, znode *con
/* the name is unambiguous */
opline->extended_value = 0;
opline->op2.constant = zend_add_const_name_literal(CG(active_op_array), &constant_name->u.constant, 0 TSRMLS_CC);
- } else {
+ } else {
opline->extended_value = IS_CONSTANT_UNQUALIFIED;
if (CG(current_namespace)) {
opline->extended_value |= IS_CONSTANT_IN_NAMESPACE;
@@ -5674,7 +5721,7 @@ void zend_do_init_array(znode *result, const znode *expr, const znode *offset, z
ZEND_HANDLE_NUMERIC_EX(Z_STRVAL(CONSTANT(opline->op2.constant)), Z_STRLEN(CONSTANT(opline->op2.constant))+1, index, numeric = 1);
if (numeric) {
zval_dtor(&CONSTANT(opline->op2.constant));
- ZVAL_LONG(&CONSTANT(opline->op2.constant), index);
+ ZVAL_LONG(&CONSTANT(opline->op2.constant), index);
} else {
CALCULATE_LITERAL_HASH(opline->op2.constant);
}
@@ -5706,7 +5753,7 @@ void zend_do_add_array_element(znode *result, const znode *expr, const znode *of
ZEND_HANDLE_NUMERIC_EX(Z_STRVAL(CONSTANT(opline->op2.constant)), Z_STRLEN(CONSTANT(opline->op2.constant))+1, index, numeric = 1);
if (numeric) {
zval_dtor(&CONSTANT(opline->op2.constant));
- ZVAL_LONG(&CONSTANT(opline->op2.constant), index);
+ ZVAL_LONG(&CONSTANT(opline->op2.constant), index);
} else {
CALCULATE_LITERAL_HASH(opline->op2.constant);
}
@@ -5966,7 +6013,7 @@ void zend_do_fetch_lexical_variable(znode *varname, zend_bool is_ref TSRMLS_DC)
Z_TYPE(value.u.constant) |= is_ref ? IS_LEXICAL_REF : IS_LEXICAL_VAR;
Z_SET_REFCOUNT_P(&value.u.constant, 1);
Z_UNSET_ISREF_P(&value.u.constant);
-
+
zend_do_fetch_static_variable(varname, &value, is_ref ? ZEND_FETCH_STATIC : ZEND_FETCH_LEXICAL TSRMLS_CC);
}
/* }}} */
@@ -6482,7 +6529,7 @@ void zend_do_jmp_set(const znode *value, znode *jmp_token, znode *colon_token TS
opline->result.var = get_temporary_variable(CG(active_op_array));
SET_NODE(opline->op1, value);
SET_UNUSED(opline->op2);
-
+
GET_NODE(colon_token, opline->result);
jmp_token->u.op.opline_num = op_number;
@@ -6511,11 +6558,11 @@ void zend_do_jmp_set_else(znode *result, const znode *false_value, const znode *
opline->extended_value = 0;
SET_NODE(opline->op1, false_value);
SET_UNUSED(opline->op2);
-
+
GET_NODE(result, opline->result);
CG(active_op_array)->opcodes[jmp_token->u.op.opline_num].op2.opline_num = get_next_op_number(CG(active_op_array));
-
+
DEC_BPC(CG(active_op_array));
}
/* }}} */
@@ -6728,7 +6775,7 @@ again:
CG(increment_lineno) = 1;
}
if (CG(has_bracketed_namespaces) && !CG(in_namespace)) {
- goto again;
+ goto again;
}
retval = ';'; /* implicit ; */
break;
@@ -6818,13 +6865,13 @@ ZEND_API void zend_initialize_class_data(zend_class_entry *ce, zend_bool nullify
int zend_get_class_fetch_type(const char *class_name, uint class_name_len) /* {{{ */
{
if ((class_name_len == sizeof("self")-1) &&
- !memcmp(class_name, "self", sizeof("self")-1)) {
- return ZEND_FETCH_CLASS_SELF;
+ !strncasecmp(class_name, "self", sizeof("self")-1)) {
+ return ZEND_FETCH_CLASS_SELF;
} else if ((class_name_len == sizeof("parent")-1) &&
- !memcmp(class_name, "parent", sizeof("parent")-1)) {
+ !strncasecmp(class_name, "parent", sizeof("parent")-1)) {
return ZEND_FETCH_CLASS_PARENT;
} else if ((class_name_len == sizeof("static")-1) &&
- !memcmp(class_name, "static", sizeof("static")-1)) {
+ !strncasecmp(class_name, "static", sizeof("static")-1)) {
return ZEND_FETCH_CLASS_STATIC;
} else {
return ZEND_FETCH_CLASS_DEFAULT;
@@ -6937,7 +6984,7 @@ void zend_do_begin_namespace(const znode *name, zend_bool with_bracket TSRMLS_DC
efree(CG(current_import));
CG(current_import) = NULL;
}
-
+
if (CG(doc_comment)) {
efree(CG(doc_comment));
CG(doc_comment) = NULL;
@@ -7109,7 +7156,7 @@ ZEND_API size_t zend_dirname(char *path, size_t len)
len_adjust += 2;
if (2 == len) {
/* Return "c:" on Win32 for dirname("c:").
- * It would be more consistent to return "c:."
+ * It would be more consistent to return "c:."
* but that would require making the string *longer*.
*/
return len;
@@ -7117,7 +7164,7 @@ ZEND_API size_t zend_dirname(char *path, size_t len)
}
#elif defined(NETWARE)
/*
- * Find the first occurence of : from the left
+ * Find the first occurence of : from the left
* move the path pointer to the position just after :
* increment the len_adjust to the length of path till colon character(inclusive)
* If there is no character beyond : simple return len
diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h
index 0f58b55500..8042dd54ee 100644
--- a/Zend/zend_compile.h
+++ b/Zend/zend_compile.h
@@ -638,6 +638,8 @@ void zend_verify_namespace(TSRMLS_D);
void zend_do_use(znode *name, znode *new_name, int is_global TSRMLS_DC);
void zend_do_end_compilation(TSRMLS_D);
+void zend_do_resolve_class_name(znode *result, znode *class_name, int is_static TSRMLS_DC);
+
void zend_do_label(znode *label TSRMLS_DC);
void zend_do_goto(const znode *label TSRMLS_DC);
void zend_resolve_goto_label(zend_op_array *op_array, zend_op *opline, int pass2 TSRMLS_DC);
diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y
index 781d806fe7..ccbc9b174c 100644
--- a/Zend/zend_language_parser.y
+++ b/Zend/zend_language_parser.y
@@ -942,6 +942,7 @@ common_scalar:
static_scalar: /* compile-time evaluated scalars */
common_scalar { $$ = $1; }
+ | static_class_name_scalar { $$ = $1; }
| namespace_name { zend_do_fetch_constant(&$$, NULL, &$1, ZEND_CT, 1 TSRMLS_CC); }
| T_NAMESPACE T_NS_SEPARATOR namespace_name { $$.op_type = IS_CONST; ZVAL_EMPTY_STRING(&$$.u.constant); zend_do_build_namespace_name(&$$, &$$, &$3 TSRMLS_CC); $3 = $$; zend_do_fetch_constant(&$$, NULL, &$3, ZEND_CT, 0 TSRMLS_CC); }
| T_NS_SEPARATOR namespace_name { char *tmp = estrndup(Z_STRVAL($2.u.constant), Z_STRLEN($2.u.constant)+1); memcpy(&(tmp[1]), Z_STRVAL($2.u.constant), Z_STRLEN($2.u.constant)+1); tmp[0] = '\\'; efree(Z_STRVAL($2.u.constant)); Z_STRVAL($2.u.constant) = tmp; ++Z_STRLEN($2.u.constant); zend_do_fetch_constant(&$$, NULL, &$2, ZEND_CT, 0 TSRMLS_CC); }
@@ -959,6 +960,7 @@ static_class_constant:
scalar:
T_STRING_VARNAME { $$ = $1; }
+ | class_name_scalar { $$ = $1; }
| class_constant { $$ = $1; }
| namespace_name { zend_do_fetch_constant(&$$, NULL, &$1, ZEND_RT, 1 TSRMLS_CC); }
| T_NAMESPACE T_NS_SEPARATOR namespace_name { $$.op_type = IS_CONST; ZVAL_EMPTY_STRING(&$$.u.constant); zend_do_build_namespace_name(&$$, &$$, &$3 TSRMLS_CC); $3 = $$; zend_do_fetch_constant(&$$, NULL, &$3, ZEND_RT, 0 TSRMLS_CC); }
@@ -1200,6 +1202,14 @@ class_constant:
| variable_class_name T_PAAMAYIM_NEKUDOTAYIM T_STRING { zend_do_fetch_constant(&$$, &$1, &$3, ZEND_RT, 0 TSRMLS_CC); }
;
+static_class_name_scalar:
+ class_name T_PAAMAYIM_NEKUDOTAYIM T_CLASS { zend_do_resolve_class_name(&$$, &$1, 1 TSRMLS_CC); }
+;
+
+class_name_scalar:
+ class_name T_PAAMAYIM_NEKUDOTAYIM T_CLASS { zend_do_resolve_class_name(&$$, &$1, 0 TSRMLS_CC); }
+;
+
%%
/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c
index 20d4e124c5..176d451e05 100644
--- a/Zend/zend_object_handlers.c
+++ b/Zend/zend_object_handlers.c
@@ -394,6 +394,16 @@ static int zend_get_property_guard(zend_object *zobj, zend_property_info *proper
info.name = Z_STRVAL_P(member);
info.name_length = Z_STRLEN_P(member);
info.h = zend_get_hash_value(Z_STRVAL_P(member), Z_STRLEN_P(member) + 1);
+ } else if(property_info->name[0] == '\0'){
+ const char *class_name = NULL, *prop_name = NULL;
+ zend_unmangle_property_name(property_info->name, property_info->name_length, &class_name, &prop_name);
+ if(class_name) {
+ /* use unmangled name for protected properties */
+ info.name = prop_name;
+ info.name_length = strlen(prop_name);
+ info.h = zend_get_hash_value(info.name, info.name_length+1);
+ property_info = &info;
+ }
}
if (!zobj->guards) {
ALLOC_HASHTABLE(zobj->guards);
diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h
index 3f9cc126ed..4dd544e578 100644
--- a/Zend/zend_vm_def.h
+++ b/Zend/zend_vm_def.h
@@ -974,27 +974,15 @@ ZEND_VM_HANDLER(40, ZEND_ECHO, CONST|TMP|VAR|CV, ANY)
{
USE_OPLINE
zend_free_op free_op1;
- zval z_copy;
zval *z;
SAVE_OPLINE();
z = GET_OP1_ZVAL_PTR(BP_VAR_R);
- if (OP1_TYPE != IS_CONST &&
- UNEXPECTED(Z_TYPE_P(z) == IS_OBJECT) &&
- Z_OBJ_HT_P(z)->get_method != NULL) {
- if (OP1_TYPE == IS_TMP_VAR) {
- INIT_PZVAL(z);
- }
- if (zend_std_cast_object_tostring(z, &z_copy, IS_STRING TSRMLS_CC) == SUCCESS) {
- zend_print_variable(&z_copy);
- zval_dtor(&z_copy);
- } else {
- zend_print_variable(z);
- }
- } else {
- zend_print_variable(z);
+ if (OP1_TYPE == IS_TMP_VAR && Z_TYPE_P(z) == IS_OBJECT) {
+ INIT_PZVAL(z);
}
+ zend_print_variable(z);
FREE_OP1();
CHECK_EXCEPTION();
@@ -3563,6 +3551,9 @@ ZEND_VM_HANDLER(99, ZEND_FETCH_CONSTANT, VAR|CONST|UNUSED, CONST)
}
ZVAL_COPY_VALUE(&EX_T(opline->result.var).tmp_var, *value);
zval_copy_ctor(&EX_T(opline->result.var).tmp_var);
+ } else if (Z_STRLEN_P(opline->op2.zv) == sizeof("class")-1 && strcmp(Z_STRVAL_P(opline->op2.zv), "class") == 0) {
+ /* "class" is assigned as a case-sensitive keyword from zend_do_resolve_class_name */
+ ZVAL_STRINGL(&EX_T(opline->result.var).tmp_var, ce->name, ce->name_length, 1);
} else {
zend_error_noreturn(E_ERROR, "Undefined class constant '%s'", Z_STRVAL_P(opline->op2.zv));
}
diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h
index 614249f993..25ac1ea89e 100644
--- a/Zend/zend_vm_execute.h
+++ b/Zend/zend_vm_execute.h
@@ -2091,27 +2091,15 @@ static int ZEND_FASTCALL ZEND_ECHO_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
- zval z_copy;
zval *z;
SAVE_OPLINE();
z = opline->op1.zv;
- if (IS_CONST != IS_CONST &&
- UNEXPECTED(Z_TYPE_P(z) == IS_OBJECT) &&
- Z_OBJ_HT_P(z)->get_method != NULL) {
- if (IS_CONST == IS_TMP_VAR) {
- INIT_PZVAL(z);
- }
- if (zend_std_cast_object_tostring(z, &z_copy, IS_STRING TSRMLS_CC) == SUCCESS) {
- zend_print_variable(&z_copy);
- zval_dtor(&z_copy);
- } else {
- zend_print_variable(z);
- }
- } else {
- zend_print_variable(z);
+ if (IS_CONST == IS_TMP_VAR && Z_TYPE_P(z) == IS_OBJECT) {
+ INIT_PZVAL(z);
}
+ zend_print_variable(z);
CHECK_EXCEPTION();
ZEND_VM_NEXT_OPCODE();
@@ -3731,6 +3719,9 @@ static int ZEND_FASTCALL ZEND_FETCH_CONSTANT_SPEC_CONST_CONST_HANDLER(ZEND_OPCO
}
ZVAL_COPY_VALUE(&EX_T(opline->result.var).tmp_var, *value);
zval_copy_ctor(&EX_T(opline->result.var).tmp_var);
+ } else if (Z_STRLEN_P(opline->op2.zv) == sizeof("class")-1 && strcmp(Z_STRVAL_P(opline->op2.zv), "class") == 0) {
+ /* "class" is assigned as a case-sensitive keyword from zend_do_resolve_class_name */
+ ZVAL_STRINGL(&EX_T(opline->result.var).tmp_var, ce->name, ce->name_length, 1);
} else {
zend_error_noreturn(E_ERROR, "Undefined class constant '%s'", Z_STRVAL_P(opline->op2.zv));
}
@@ -7408,27 +7399,15 @@ static int ZEND_FASTCALL ZEND_ECHO_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
zend_free_op free_op1;
- zval z_copy;
zval *z;
SAVE_OPLINE();
z = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC);
- if (IS_TMP_VAR != IS_CONST &&
- UNEXPECTED(Z_TYPE_P(z) == IS_OBJECT) &&
- Z_OBJ_HT_P(z)->get_method != NULL) {
- if (IS_TMP_VAR == IS_TMP_VAR) {
- INIT_PZVAL(z);
- }
- if (zend_std_cast_object_tostring(z, &z_copy, IS_STRING TSRMLS_CC) == SUCCESS) {
- zend_print_variable(&z_copy);
- zval_dtor(&z_copy);
- } else {
- zend_print_variable(z);
- }
- } else {
- zend_print_variable(z);
+ if (IS_TMP_VAR == IS_TMP_VAR && Z_TYPE_P(z) == IS_OBJECT) {
+ INIT_PZVAL(z);
}
+ zend_print_variable(z);
zval_dtor(free_op1.var);
CHECK_EXCEPTION();
@@ -12619,27 +12598,15 @@ static int ZEND_FASTCALL ZEND_ECHO_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
zend_free_op free_op1;
- zval z_copy;
zval *z;
SAVE_OPLINE();
z = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC);
- if (IS_VAR != IS_CONST &&
- UNEXPECTED(Z_TYPE_P(z) == IS_OBJECT) &&
- Z_OBJ_HT_P(z)->get_method != NULL) {
- if (IS_VAR == IS_TMP_VAR) {
- INIT_PZVAL(z);
- }
- if (zend_std_cast_object_tostring(z, &z_copy, IS_STRING TSRMLS_CC) == SUCCESS) {
- zend_print_variable(&z_copy);
- zval_dtor(&z_copy);
- } else {
- zend_print_variable(z);
- }
- } else {
- zend_print_variable(z);
+ if (IS_VAR == IS_TMP_VAR && Z_TYPE_P(z) == IS_OBJECT) {
+ INIT_PZVAL(z);
}
+ zend_print_variable(z);
if (free_op1.var) {zval_ptr_dtor(&free_op1.var);};
CHECK_EXCEPTION();
@@ -15595,6 +15562,9 @@ static int ZEND_FASTCALL ZEND_FETCH_CONSTANT_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE
}
ZVAL_COPY_VALUE(&EX_T(opline->result.var).tmp_var, *value);
zval_copy_ctor(&EX_T(opline->result.var).tmp_var);
+ } else if (Z_STRLEN_P(opline->op2.zv) == sizeof("class")-1 && strcmp(Z_STRVAL_P(opline->op2.zv), "class") == 0) {
+ /* "class" is assigned as a case-sensitive keyword from zend_do_resolve_class_name */
+ ZVAL_STRINGL(&EX_T(opline->result.var).tmp_var, ce->name, ce->name_length, 1);
} else {
zend_error_noreturn(E_ERROR, "Undefined class constant '%s'", Z_STRVAL_P(opline->op2.zv));
}
@@ -25170,6 +25140,9 @@ static int ZEND_FASTCALL ZEND_FETCH_CONSTANT_SPEC_UNUSED_CONST_HANDLER(ZEND_OPC
}
ZVAL_COPY_VALUE(&EX_T(opline->result.var).tmp_var, *value);
zval_copy_ctor(&EX_T(opline->result.var).tmp_var);
+ } else if (Z_STRLEN_P(opline->op2.zv) == sizeof("class")-1 && strcmp(Z_STRVAL_P(opline->op2.zv), "class") == 0) {
+ /* "class" is assigned as a case-sensitive keyword from zend_do_resolve_class_name */
+ ZVAL_STRINGL(&EX_T(opline->result.var).tmp_var, ce->name, ce->name_length, 1);
} else {
zend_error_noreturn(E_ERROR, "Undefined class constant '%s'", Z_STRVAL_P(opline->op2.zv));
}
@@ -30205,27 +30178,15 @@ static int ZEND_FASTCALL ZEND_ECHO_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
- zval z_copy;
zval *z;
SAVE_OPLINE();
z = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var TSRMLS_CC);
- if (IS_CV != IS_CONST &&
- UNEXPECTED(Z_TYPE_P(z) == IS_OBJECT) &&
- Z_OBJ_HT_P(z)->get_method != NULL) {
- if (IS_CV == IS_TMP_VAR) {
- INIT_PZVAL(z);
- }
- if (zend_std_cast_object_tostring(z, &z_copy, IS_STRING TSRMLS_CC) == SUCCESS) {
- zend_print_variable(&z_copy);
- zval_dtor(&z_copy);
- } else {
- zend_print_variable(z);
- }
- } else {
- zend_print_variable(z);
+ if (IS_CV == IS_TMP_VAR && Z_TYPE_P(z) == IS_OBJECT) {
+ INIT_PZVAL(z);
}
+ zend_print_variable(z);
CHECK_EXCEPTION();
ZEND_VM_NEXT_OPCODE();
diff --git a/ext/curl/config.m4 b/ext/curl/config.m4
index 92559be7c4..e549330c50 100644
--- a/ext/curl/config.m4
+++ b/ext/curl/config.m4
@@ -149,6 +149,6 @@ int main(int argc, char *argv[])
AC_DEFINE(PHP_CURL_URL_WRAPPERS,1,[ ])
fi
- PHP_NEW_EXTENSION(curl, interface.c multi.c share.c streams.c, $ext_shared)
+ PHP_NEW_EXTENSION(curl, interface.c multi.c share.c streams.c curl_file.c, $ext_shared)
PHP_SUBST(CURL_SHARED_LIBADD)
fi
diff --git a/ext/curl/config.w32 b/ext/curl/config.w32
index a056845575..5acda7ec9e 100644
--- a/ext/curl/config.w32
+++ b/ext/curl/config.w32
@@ -13,7 +13,7 @@ if (PHP_CURL != "no") {
&& (((PHP_ZLIB=="no") && (CHECK_LIB("zlib_a.lib;zlib.lib", "curl", PHP_CURL))) ||
(PHP_ZLIB_SHARED && CHECK_LIB("zlib.lib", "curl", PHP_CURL)) || (PHP_ZLIB == "yes" && (!PHP_ZLIB_SHARED)))
) {
- EXTENSION("curl", "interface.c multi.c share.c streams.c", true);
+ EXTENSION("curl", "interface.c multi.c share.c streams.c curl_file.c", true);
AC_DEFINE('HAVE_CURL', 1, 'Have cURL library');
AC_DEFINE('HAVE_CURL_SSL', 1, 'Have SSL suppurt in cURL');
AC_DEFINE('HAVE_CURL_EASY_STRERROR', 1, 'Have curl_easy_strerror in cURL');
diff --git a/ext/curl/interface.c b/ext/curl/interface.c
index 2e055811e3..07141485ab 100644
--- a/ext/curl/interface.c
+++ b/ext/curl/interface.c
@@ -317,7 +317,7 @@ ZEND_END_ARG_INFO()
#if LIBCURL_VERSION_NUM >= 0x070c01 /* 7.12.1 */
ZEND_BEGIN_ARG_INFO(arginfo_curl_reset, 0)
ZEND_ARG_INFO(0, ch)
-ZEND_END_ARG_INFO()
+ZEND_END_ARG_INFO()
#endif
#if LIBCURL_VERSION_NUM > 0x070f03 /* 7.15.4 */
@@ -403,6 +403,12 @@ ZEND_BEGIN_ARG_INFO(arginfo_curl_pause, 0)
ZEND_ARG_INFO(0, bitmask)
ZEND_END_ARG_INFO()
#endif
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_curlfile_create, 0, 0, 1)
+ ZEND_ARG_INFO(0, filename)
+ ZEND_ARG_INFO(0, mimetype)
+ ZEND_ARG_INFO(0, postname)
+ZEND_END_ARG_INFO()
/* }}} */
/* {{{ curl_functions[]
@@ -446,6 +452,7 @@ const zend_function_entry curl_functions[] = {
PHP_FE(curl_share_init, arginfo_curl_share_init)
PHP_FE(curl_share_close, arginfo_curl_share_close)
PHP_FE(curl_share_setopt, arginfo_curl_share_setopt)
+ PHP_FE(curl_file_create, arginfo_curlfile_create)
PHP_FE_END
};
/* }}} */
@@ -526,7 +533,7 @@ PHP_MINFO_FUNCTION(curl)
#endif
#if LIBCURL_VERSION_NUM >= 0x071600 /* 7.22.0 */
{"NTLMWB", CURL_VERSION_NTLM_WB},
-#endif
+#endif
#if LIBCURL_VERSION_NUM >= 0x070a08 /* 7.10.8 */
{"SPNEGO", CURL_VERSION_SPNEGO},
#endif
@@ -804,7 +811,7 @@ PHP_MINIT_FUNCTION(curl)
REGISTER_CURL_CONSTANT(CURLINFO_STARTTRANSFER_TIME);
REGISTER_CURL_CONSTANT(CURLINFO_TOTAL_TIME);
- /* Other */
+ /* Other */
REGISTER_CURL_CONSTANT(CURLMSG_DONE);
REGISTER_CURL_CONSTANT(CURLVERSION_NOW);
@@ -846,7 +853,7 @@ PHP_MINIT_FUNCTION(curl)
REGISTER_CURL_CONSTANT(CURL_SSLVERSION_SSLv2);
REGISTER_CURL_CONSTANT(CURL_SSLVERSION_SSLv3);
REGISTER_CURL_CONSTANT(CURL_SSLVERSION_TLSv1);
-
+
/* Curl TIMECOND constants (CURLOPT_TIMECONDITION) */
REGISTER_CURL_CONSTANT(CURL_TIMECOND_IFMODSINCE);
REGISTER_CURL_CONSTANT(CURL_TIMECOND_IFUNMODSINCE);
@@ -910,7 +917,7 @@ PHP_MINIT_FUNCTION(curl)
#if LIBCURL_VERSION_NUM >= 0x070d00 /* Available since 7.13.0 */
REGISTER_CURL_CONSTANT(CURLOPT_FTP_ACCOUNT);
-#endif
+#endif
#if LIBCURL_VERSION_NUM >= 0x070b02 /* Available since 7.11.2 */
REGISTER_CURL_CONSTANT(CURLOPT_TCP_NODELAY);
@@ -918,7 +925,7 @@ PHP_MINIT_FUNCTION(curl)
#if LIBCURL_VERSION_NUM >= 0x070c02 /* Available since 7.12.2 */
REGISTER_CURL_CONSTANT(CURLINFO_OS_ERRNO);
-#endif
+#endif
#if LIBCURL_VERSION_NUM >= 0x070c03 /* Available since 7.12.3 */
REGISTER_CURL_CONSTANT(CURLINFO_NUM_CONNECTS);
@@ -959,7 +966,7 @@ PHP_MINIT_FUNCTION(curl)
REGISTER_CURL_CONSTANT(CURLOPT_FTP_ALTERNATIVE_TO_USER);
REGISTER_CURL_CONSTANT(CURLOPT_MAX_RECV_SPEED_LARGE);
REGISTER_CURL_CONSTANT(CURLOPT_MAX_SEND_SPEED_LARGE);
-#endif
+#endif
#if LIBCURL_VERSION_NUM >= 0x071000 /* Available since 7.16.0 */
REGISTER_CURL_CONSTANT(CURLOPT_SSL_SESSIONID_CACHE);
@@ -1003,7 +1010,7 @@ PHP_MINIT_FUNCTION(curl)
REGISTER_CURL_CONSTANT(CURLUSESSL_CONTROL);
REGISTER_CURL_CONSTANT(CURLUSESSL_NONE);
REGISTER_CURL_CONSTANT(CURLUSESSL_TRY);
-#endif
+#endif
#if LIBCURL_VERSION_NUM >= 0x071101 /* Available since 7.17.1 */
REGISTER_CURL_CONSTANT(CURLOPT_SSH_HOST_PUBLIC_KEY_MD5);
@@ -1053,7 +1060,7 @@ PHP_MINIT_FUNCTION(curl)
REGISTER_CURL_CONSTANT(CURLOPT_USERNAME);
#endif
-#if LIBCURL_VERSION_NUM >= 0x071303 /* Available since 7.19.3 */
+#if LIBCURL_VERSION_NUM >= 0x071303 /* Available since 7.19.3 */
REGISTER_CURL_CONSTANT(CURLAUTH_DIGEST_IE);
#endif
@@ -1135,7 +1142,7 @@ PHP_MINIT_FUNCTION(curl)
REGISTER_CURL_CONSTANT(CURL_FNMATCHFUNC_FAIL);
REGISTER_CURL_CONSTANT(CURL_FNMATCHFUNC_MATCH);
REGISTER_CURL_CONSTANT(CURL_FNMATCHFUNC_NOMATCH);
-#endif
+#endif
#if LIBCURL_VERSION_NUM >= 0x071502 /* Available since 7.21.2 */
REGISTER_CURL_CONSTANT(CURLPROTO_GOPHER);
@@ -1187,6 +1194,7 @@ PHP_MINIT_FUNCTION(curl)
#if CURLOPT_PASSWDFUNCTION != 0
REGISTER_CURL_CONSTANT(CURLOPT_PASSWDFUNCTION);
#endif
+ REGISTER_CURL_CONSTANT(CURLOPT_SAFE_UPLOAD);
#ifdef PHP_CURL_NEED_OPENSSL_TSL
if (!CRYPTO_get_id_callback()) {
@@ -1229,6 +1237,8 @@ PHP_MINIT_FUNCTION(curl)
}
#endif
+ curlfile_register_class(TSRMLS_C);
+
return SUCCESS;
}
/* }}} */
@@ -1275,7 +1285,7 @@ PHP_MSHUTDOWN_FUNCTION(curl)
/* {{{ curl_write_nothing
* Used as a work around. See _php_curl_close_ex
*/
-static size_t curl_write_nothing(char *data, size_t size, size_t nmemb, void *ctx)
+static size_t curl_write_nothing(char *data, size_t size, size_t nmemb, void *ctx)
{
return size * nmemb;
}
@@ -1812,6 +1822,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 */
}
/* }}} */
@@ -1833,7 +1844,7 @@ static void split_certinfo(char *string, zval *hash)
split = strstr(s, "; ");
if(split)
*split = '\0';
-
+
key = s;
tmp = memchr(key, '=', 64);
if(tmp) {
@@ -1853,13 +1864,13 @@ static void split_certinfo(char *string, zval *hash)
static void create_certinfo(struct curl_certinfo *ci, zval *listcode TSRMLS_DC)
{
int i;
-
+
if(ci) {
zval *certhash = NULL;
-
+
for(i=0; i<ci->num_of_certs; i++) {
struct curl_slist *slist;
-
+
MAKE_STD_ZVAL(certhash);
array_init(certhash);
for(slist = ci->certinfo[i]; slist; slist = slist->next) {
@@ -1876,14 +1887,14 @@ static void create_certinfo(struct curl_certinfo *ci, zval *listcode TSRMLS_DC)
MAKE_STD_ZVAL(hash);
array_init(hash);
-
+
split_certinfo(&slist->data[len+1], hash);
add_assoc_zval(certhash, s, hash);
} else {
add_assoc_string(certhash, s, &slist->data[len+1], 1);
}
} else {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not extract hash key from certificate info");
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not extract hash key from certificate info");
}
}
add_next_index_zval(listcode, certhash);
@@ -2056,7 +2067,7 @@ PHP_FUNCTION(curl_copy_handle)
if (ch->handlers->fnmatch->func_name) {
zval_add_ref(&ch->handlers->fnmatch->func_name);
dupch->handlers->fnmatch->func_name = ch->handlers->fnmatch->func_name;
- }
+ }
dupch->handlers->fnmatch->method = ch->handlers->fnmatch->method;
curl_easy_setopt(dupch->cp, CURLOPT_FNMATCH_DATA, (void *) dupch);
}
@@ -2135,7 +2146,7 @@ static int _php_curl_setopt(php_curl *ch, long option, zval **zvalue, zval *retu
#if LIBCURL_VERSION_NUM >= 0x070a06 /* Available since 7.10.6 */
case CURLOPT_HTTPAUTH:
#endif
-#if LIBCURL_VERSION_NUM >= 0x070a07 /* Available since 7.10.7 */
+#if LIBCURL_VERSION_NUM >= 0x070a07 /* Available since 7.10.7 */
case CURLOPT_FTP_CREATE_MISSING_DIRS:
case CURLOPT_PROXYAUTH:
#endif
@@ -2185,11 +2196,11 @@ static int _php_curl_setopt(php_curl *ch, long option, zval **zvalue, zval *retu
case CURLOPT_USE_SSL:
#elif LIBCURL_VERSION_NUM >= 0x070b00 /* Available since 7.11.0 */
case CURLOPT_FTP_SSL:
-#endif
+#endif
#if LIBCURL_VERSION_NUM >= 0x071100 /* Available since 7.17.0 */
case CURLOPT_APPEND:
case CURLOPT_DIRLISTONLY:
-#else
+#else
case CURLOPT_FTPAPPEND:
case CURLOPT_FTPLISTONLY:
#endif
@@ -2247,6 +2258,10 @@ static int _php_curl_setopt(php_curl *ch, long option, zval **zvalue, zval *retu
#endif
error = curl_easy_setopt(ch->cp, option, Z_LVAL_PP(zvalue));
break;
+ case CURLOPT_SAFE_UPLOAD:
+ convert_to_long_ex(zvalue);
+ ch->safe_upload = (Z_LVAL_PP(zvalue) != 0);
+ break;
/* String options */
case CURLOPT_CAINFO:
@@ -2282,7 +2297,7 @@ static int _php_curl_setopt(php_curl *ch, long option, zval **zvalue, zval *retu
#endif
#if LIBCURL_VERSION_NUM >= 0x071004 /* Available since 7.16.4 */
case CURLOPT_KRBLEVEL:
-#else
+#else
case CURLOPT_KRB4LEVEL:
#endif
#if LIBCURL_VERSION_NUM >= 0x071101 /* Available since 7.17.1 */
@@ -2307,7 +2322,7 @@ static int _php_curl_setopt(php_curl *ch, long option, zval **zvalue, zval *retu
case CURLOPT_TLSAUTH_PASSWORD:
case CURLOPT_TLSAUTH_USERNAME:
#endif
-#if LIBCURL_VERSION_NUM >= 0x071506 /* Available since 7.21.6 */
+#if LIBCURL_VERSION_NUM >= 0x071506 /* Available since 7.21.6 */
case CURLOPT_ACCEPT_ENCODING:
case CURLOPT_TRANSFER_ENCODING:
#else
@@ -2315,7 +2330,7 @@ static int _php_curl_setopt(php_curl *ch, long option, zval **zvalue, zval *retu
#endif
#if LIBCURL_VERSION_NUM >= 0x071800 /* Available since 7.24.0 */
case CURLOPT_DNS_SERVERS:
-#endif
+#endif
#if LIBCURL_VERSION_NUM >= 0x071900 /* Available since 7.25.0 */
case CURLOPT_MAIL_AUTH:
#endif
@@ -2339,8 +2354,8 @@ string_copy:
#if LIBCURL_VERSION_NUM >= 0x071100
/* Strings passed to libcurl as ’char *’ arguments, are copied by the library... NOTE: before 7.17.0 strings were not copied. */
error = curl_easy_setopt(ch->cp, option, Z_STRVAL_PP(zvalue));
-#else
- goto string_copy;
+#else
+ goto string_copy;
#endif
}
}
@@ -2350,7 +2365,7 @@ string_copy:
/* Curl file handle options */
case CURLOPT_FILE:
case CURLOPT_INFILE:
- case CURLOPT_STDERR:
+ case CURLOPT_STDERR:
case CURLOPT_WRITEHEADER: {
FILE *fp = NULL;
int type;
@@ -2560,9 +2575,6 @@ string_copy:
ulong num_key;
int numeric_key;
- SEPARATE_ZVAL(current);
- convert_to_string_ex(current);
-
zend_hash_get_current_key_ex(postfields, &string_key, &string_key_len, &num_key, 0, NULL);
/* Pretend we have a string_key here */
@@ -2574,15 +2586,59 @@ string_copy:
numeric_key = 0;
}
+ if(Z_TYPE_PP(current) == IS_OBJECT && instanceof_function(Z_OBJCE_PP(current), curl_CURLFile_class TSRMLS_CC)) {
+ /* new-style file upload */
+ zval *prop;
+ char *type = NULL, *filename = NULL;
+
+ prop = zend_read_property(curl_CURLFile_class, *current, "name", sizeof("name")-1, 0 TSRMLS_CC);
+ if(Z_TYPE_P(prop) != IS_STRING) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid filename for key %s", string_key);
+ } else {
+ postval = Z_STRVAL_P(prop);
+
+ if (php_check_open_basedir(postval TSRMLS_CC)) {
+ RETVAL_FALSE;
+ return 1;
+ }
+
+ prop = zend_read_property(curl_CURLFile_class, *current, "mime", sizeof("mime")-1, 0 TSRMLS_CC);
+ if(Z_TYPE_P(prop) == IS_STRING && Z_STRLEN_P(prop) > 0) {
+ type = Z_STRVAL_P(prop);
+ }
+ prop = zend_read_property(curl_CURLFile_class, *current, "postname", sizeof("postname")-1, 0 TSRMLS_CC);
+ if(Z_TYPE_P(prop) == IS_STRING && Z_STRLEN_P(prop) > 0) {
+ filename = Z_STRVAL_P(prop);
+ }
+ error = curl_formadd(&first, &last,
+ CURLFORM_COPYNAME, string_key,
+ CURLFORM_NAMELENGTH, (long)string_key_len - 1,
+ CURLFORM_FILENAME, filename ? filename : postval,
+ CURLFORM_CONTENTTYPE, type ? type : "application/octet-stream",
+ CURLFORM_FILE, postval,
+ CURLFORM_END);
+ }
+
+ if (numeric_key) {
+ efree(string_key);
+ }
+ continue;
+ }
+
+ SEPARATE_ZVAL(current);
+ convert_to_string_ex(current);
+
postval = Z_STRVAL_PP(current);
/* The arguments after _NAMELENGTH and _CONTENTSLENGTH
* must be explicitly cast to long in curl_formadd
* use since curl needs a long not an int. */
- if (*postval == '@') {
+ if (!ch->safe_upload && *postval == '@') {
char *type, *filename;
++postval;
+ php_error_docref("curl.curlfile" TSRMLS_CC, E_DEPRECATED, "The usage of the @filename API for file uploading is deprecated. Please use the CURLFile class instead");
+
if ((type = php_memnstr(postval, ";type=", sizeof(";type=") - 1, postval + Z_STRLEN_PP(current)))) {
*type = '\0';
}
@@ -2725,7 +2781,7 @@ string_copy:
/* the following options deal with files, therefore the open_basedir check
* is required.
*/
- case CURLOPT_COOKIEFILE:
+ case CURLOPT_COOKIEFILE:
case CURLOPT_COOKIEJAR:
case CURLOPT_RANDOM_FILE:
case CURLOPT_SSLCERT:
@@ -2829,7 +2885,7 @@ PHP_FUNCTION(curl_setopt)
ZEND_FETCH_RESOURCE(ch, php_curl *, &zid, -1, le_curl_name, le_curl);
- if (options <= 0) {
+ if (options <= 0 && options != CURLOPT_SAFE_UPLOAD) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid curl configuration option");
RETURN_FALSE;
}
@@ -3045,7 +3101,7 @@ PHP_FUNCTION(curl_getinfo)
CAAS("redirect_url", s_code);
}
#endif
-#if LIBCURL_VERSION_NUM >= 0x071300 /* Available since 7.19.0 */
+#if LIBCURL_VERSION_NUM >= 0x071300 /* Available since 7.19.0 */
if (curl_easy_getinfo(ch->cp, CURLINFO_PRIMARY_IP, &s_code) == CURLE_OK) {
CAAS("primary_ip", s_code);
}
@@ -3085,7 +3141,7 @@ PHP_FUNCTION(curl_getinfo)
struct curl_certinfo *ci = NULL;
array_init(return_value);
-
+
if (curl_easy_getinfo(ch->cp, CURLINFO_CERTINFO, &ci) == CURLE_OK) {
create_certinfo(ci, return_value TSRMLS_CC);
} else {
@@ -3100,7 +3156,7 @@ PHP_FUNCTION(curl_getinfo)
case CURLINFO_STRING:
{
char *s_code = NULL;
-
+
if (curl_easy_getinfo(ch->cp, option, &s_code) == CURLE_OK && s_code) {
RETURN_STRING(s_code, 1);
} else {
@@ -3111,7 +3167,7 @@ PHP_FUNCTION(curl_getinfo)
case CURLINFO_LONG:
{
long code = 0;
-
+
if (curl_easy_getinfo(ch->cp, option, &code) == CURLE_OK) {
RETURN_LONG(code);
} else {
@@ -3221,16 +3277,16 @@ static void _php_curl_close_ex(php_curl *ch TSRMLS_DC)
_php_curl_verify_handlers(ch, 0 TSRMLS_CC);
- /*
+ /*
* Libcurl is doing connection caching. When easy handle is cleaned up,
- * if the handle was previously used by the curl_multi_api, the connection
+ * if the handle was previously used by the curl_multi_api, the connection
* remains open un the curl multi handle is cleaned up. Some protocols are
- * sending content like the FTP one, and libcurl try to use the
+ * sending content like the FTP one, and libcurl try to use the
* WRITEFUNCTION or the HEADERFUNCTION. Since structures used in those
* callback are freed, we need to use an other callback to which avoid
* segfaults.
*
- * Libcurl commit d021f2e8a00 fix this issue and should be part of 7.28.2
+ * Libcurl commit d021f2e8a00 fix this issue and should be part of 7.28.2
*/
curl_easy_setopt(ch->cp, CURLOPT_HEADERFUNCTION, curl_write_nothing);
curl_easy_setopt(ch->cp, CURLOPT_WRITEFUNCTION, curl_write_nothing);
@@ -3349,7 +3405,7 @@ static void _php_curl_reset_handlers(php_curl *ch)
}
ch->handlers->write->fp = NULL;
ch->handlers->write->method = PHP_CURL_STDOUT;
-
+
if (ch->handlers->write_header->stream) {
Z_DELREF_P(ch->handlers->write_header->stream);
ch->handlers->write_header->stream = NULL;
@@ -3443,7 +3499,7 @@ PHP_FUNCTION(curl_escape)
/* {{{ proto void curl_unescape(resource ch, string str)
URL decodes the given string */
-PHP_FUNCTION(curl_unescape)
+PHP_FUNCTION(curl_unescape)
{
char *str = NULL, *out = NULL;
int str_len = 0, out_len;
@@ -3481,7 +3537,7 @@ PHP_FUNCTION(curl_pause)
ZEND_FETCH_RESOURCE(ch, php_curl *, &zid, -1, le_curl_name, le_curl);
- RETURN_LONG(curl_easy_pause(ch->cp, bitmask));
+ RETURN_LONG(curl_easy_pause(ch->cp, bitmask));
}
/* }}} */
#endif
diff --git a/ext/curl/php_curl.h b/ext/curl/php_curl.h
index a8c26c0528..c4222c0588 100644
--- a/ext/curl/php_curl.h
+++ b/ext/curl/php_curl.h
@@ -34,6 +34,14 @@
#define PHP_CURL_DEBUG 0
+#ifdef PHP_WIN32
+# define PHP_CURL_API __declspec(dllexport)
+#elif defined(__GNUC__) && __GNUC__ >= 4
+# define PHP_CURL_API __attribute__ ((visibility("default")))
+#else
+# define PHP_CURL_API
+#endif
+
#include <curl/curl.h>
#include <curl/multi.h>
@@ -103,6 +111,8 @@ PHP_FUNCTION(curl_multi_setopt);
#if LIBCURL_VERSION_NUM >= 0x071200 /* 7.18.0 */
PHP_FUNCTION(curl_pause);
#endif
+PHP_FUNCTION(curl_file_create);
+
void _php_curl_multi_close(zend_rsrc_list_entry * TSRMLS_DC);
void _php_curl_share_close(zend_rsrc_list_entry * TSRMLS_DC);
@@ -171,8 +181,11 @@ typedef struct {
long id;
zend_bool in_callback;
zval *clone;
+ zend_bool safe_upload;
} php_curl;
+#define CURLOPT_SAFE_UPLOAD -1
+
typedef struct {
int still_running;
CURLM *multi;
@@ -211,7 +224,7 @@ typedef struct {
fd_set readfds, writefds, excfds;
int maxfd;
-
+
char errstr[CURL_ERROR_SIZE + 1];
CURLMcode mcode;
int pending;
@@ -219,6 +232,8 @@ typedef struct {
struct curl_slist *headers_slist; /* holds custom headers sent out in the request */
} php_curl_stream;
+void curlfile_register_class(TSRMLS_D);
+PHP_CURL_API extern zend_class_entry *curl_CURLFile_class;
#else
#define curl_module_ptr NULL
diff --git a/ext/curl/tests/bug27023.phpt b/ext/curl/tests/bug27023.phpt
index b738c956e9..62effec990 100644
--- a/ext/curl/tests/bug27023.phpt
+++ b/ext/curl/tests/bug27023.phpt
@@ -1,5 +1,7 @@
--TEST--
Bug #27023 (CURLOPT_POSTFIELDS does not parse content types for files)
+--INI--
+error_reporting = E_ALL & ~E_DEPRECATED
--SKIPIF--
<?php
if (!extension_loaded("curl")) {
diff --git a/ext/curl/tests/curl_file_serialize.phpt b/ext/curl/tests/curl_file_serialize.phpt
new file mode 100644
index 0000000000..43b272ad64
--- /dev/null
+++ b/ext/curl/tests/curl_file_serialize.phpt
@@ -0,0 +1,21 @@
+--TEST--
+CURL file uploading
+--SKIPIF--
+<?php
+if (!extension_loaded("curl")) {
+ exit("skip curl extension not loaded");
+}
+?>
+--FILE--
+<?php
+$data = 'a:2:{s:4:"file";O:8:"CURLFile":3:{s:4:"name";s:13:"testdata1.txt";s:4:"mime";s:0:"";s:8:"postname";s:0:"";}s:4:"data";s:3:"foo";}';
+var_dump(unserialize($data));
+?>
+--EXPECTF--
+Fatal error: Uncaught exception 'Exception' with message 'Unserialization of CURLFile instances is not allowed' in %s
+Stack trace:
+#0 [internal function]: CURLFile->__wakeup()
+#1 %s
+#2 {main}
+ thrown in %s on line %d
+
diff --git a/ext/curl/tests/curl_file_upload.phpt b/ext/curl/tests/curl_file_upload.phpt
new file mode 100644
index 0000000000..d3168e578a
--- /dev/null
+++ b/ext/curl/tests/curl_file_upload.phpt
@@ -0,0 +1,85 @@
+--TEST--
+CURL file uploading
+--SKIPIF--
+<?php
+if (!extension_loaded("curl")) {
+ exit("skip curl extension not loaded");
+}
+if (false === getenv('PHP_CURL_HTTP_REMOTE_SERVER')) {
+ exit("skip PHP_CURL_HTTP_REMOTE_SERVER env variable is not defined");
+}
+?>
+--FILE--
+<?php
+
+function testcurl($ch, $name, $mime = '', $postname = '')
+{
+ if(!empty($postname)) {
+ $file = new CurlFile($name, $mime, $postname);
+ } else if(!empty($mime)) {
+ $file = new CurlFile($name, $mime);
+ } else {
+ $file = new CurlFile($name);
+ }
+ curl_setopt($ch, CURLOPT_POSTFIELDS, array("file" => $file));
+ var_dump(curl_exec($ch));
+}
+
+$host = getenv('PHP_CURL_HTTP_REMOTE_SERVER');
+$ch = curl_init();
+curl_setopt($ch, CURLOPT_URL, "{$host}/get.php?test=file");
+curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+
+testcurl($ch, __DIR__ . '/curl_testdata1.txt');
+testcurl($ch, __DIR__ . '/curl_testdata1.txt', 'text/plain');
+testcurl($ch, __DIR__ . '/curl_testdata1.txt', '', 'foo.txt');
+testcurl($ch, __DIR__ . '/curl_testdata1.txt', 'text/plain', 'foo.txt');
+
+$file = new CurlFile(__DIR__ . '/curl_testdata1.txt');
+$file->setMimeType('text/plain');
+var_dump($file->getMimeType());
+var_dump($file->getFilename());
+curl_setopt($ch, CURLOPT_POSTFIELDS, array("file" => $file));
+var_dump(curl_exec($ch));
+
+$file = curl_file_create(__DIR__ . '/curl_testdata1.txt');
+$file->setPostFilename('foo.txt');
+var_dump($file->getPostFilename());
+curl_setopt($ch, CURLOPT_POSTFIELDS, array("file" => $file));
+var_dump(curl_exec($ch));
+
+$params = array('file' => '@' . __DIR__ . '/curl_testdata1.txt');
+curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
+var_dump(curl_exec($ch));
+
+curl_setopt($ch, CURLOPT_SAFE_UPLOAD, true);
+$params = array('file' => '@' . __DIR__ . '/curl_testdata1.txt');
+curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
+var_dump(curl_exec($ch));
+
+curl_setopt($ch, CURLOPT_URL, "{$host}/get.php?test=post");
+$params = array('file' => '@' . __DIR__ . '/curl_testdata1.txt');
+curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
+var_dump(curl_exec($ch));
+
+curl_close($ch);
+?>
+--EXPECTF--
+string(%d) "curl_testdata1.txt|application/octet-stream"
+string(%d) "curl_testdata1.txt|text/plain"
+string(%d) "foo.txt|application/octet-stream"
+string(%d) "foo.txt|text/plain"
+string(%d) "text/plain"
+string(%d) "%s/curl_testdata1.txt"
+string(%d) "curl_testdata1.txt|text/plain"
+string(%d) "foo.txt"
+string(%d) "foo.txt|application/octet-stream"
+
+Deprecated: curl_setopt(): The usage of the @filename API for file uploading is deprecated. Please use the CURLFile class instead in %s on line %d
+string(%d) "curl_testdata1.txt|application/octet-stream"
+string(0) ""
+string(%d) "array(1) {
+ ["file"]=>
+ string(%d) "@%s/curl_testdata1.txt"
+}
+"
diff --git a/ext/curl/tests/curl_setopt_error.phpt b/ext/curl/tests/curl_setopt_error.phpt
index ad73318f1c..01593aff22 100644
--- a/ext/curl/tests/curl_setopt_error.phpt
+++ b/ext/curl/tests/curl_setopt_error.phpt
@@ -14,14 +14,14 @@ curl_setopt(false);
curl_setopt($ch);
curl_setopt($ch, false);
-curl_setopt($ch, -1);
+curl_setopt($ch, -10);
curl_setopt($ch, '');
curl_setopt($ch, 1, false);
curl_setopt(false, false, false);
curl_setopt($ch, '', false);
curl_setopt($ch, 1, '');
-curl_setopt($ch, -1, 0);
+curl_setopt($ch, -10, 0);
?>
--EXPECTF--
*** curl_setopt() call with incorrect parameters
diff --git a/ext/date/php_date.c b/ext/date/php_date.c
index 54dc2f5b70..f4115dc7e1 100644
--- a/ext/date/php_date.c
+++ b/ext/date/php_date.c
@@ -2883,14 +2883,18 @@ PHP_FUNCTION(date_format)
}
/* }}} */
-static void php_date_modify(zval *object, char *modify, int modify_len, zval *return_value TSRMLS_DC)
+static int php_date_modify(zval *object, char *modify, int modify_len TSRMLS_DC)
{
php_date_obj *dateobj;
timelib_time *tmp_time;
timelib_error_container *err = NULL;
dateobj = (php_date_obj *) zend_object_store_get_object(object TSRMLS_CC);
- DATE_CHECK_INITIALIZED(dateobj->time, DateTime);
+
+ if (!(dateobj->time)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "The DateTime object has not been correctly initialized by its constructor");
+ return 0;
+ }
tmp_time = timelib_strtotime(modify, modify_len, &err, DATE_TIMEZONEDB, php_date_parse_tzfile_wrapper);
@@ -2901,7 +2905,7 @@ static void php_date_modify(zval *object, char *modify, int modify_len, zval *re
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Failed to parse time string (%s) at position %d (%c): %s", modify,
err->error_messages[0].position, err->error_messages[0].character, err->error_messages[0].message);
timelib_time_dtor(tmp_time);
- RETURN_FALSE;
+ return 0;
}
memcpy(&dateobj->time->relative, &tmp_time->relative, sizeof(struct timelib_rel_time));
@@ -2937,6 +2941,8 @@ static void php_date_modify(zval *object, char *modify, int modify_len, zval *re
timelib_update_ts(dateobj->time, NULL);
timelib_update_from_sse(dateobj->time);
dateobj->time->have_relative = 0;
+
+ return 1;
}
/* {{{ proto DateTime date_modify(DateTime object, string modify)
@@ -2952,9 +2958,11 @@ PHP_FUNCTION(date_modify)
RETURN_FALSE;
}
- php_date_modify(object, modify, modify_len, return_value TSRMLS_CC);
+ if (php_date_modify(object, modify, modify_len TSRMLS_CC)) {
+ RETURN_ZVAL(object, 1, 0);
+ }
- RETURN_ZVAL(object, 1, 0);
+ RETURN_FALSE;
}
/* }}} */
@@ -2971,9 +2979,11 @@ PHP_METHOD(DateTimeImmutable, modify)
}
new_object = date_clone_immutable(object TSRMLS_CC);
- php_date_modify(new_object, modify, modify_len, return_value TSRMLS_CC);
+ if (php_date_modify(new_object, modify, modify_len TSRMLS_CC)) {
+ RETURN_ZVAL(new_object, 0, 1);
+ }
- RETURN_ZVAL(new_object, 0, 1);
+ RETURN_FALSE;
}
/* }}} */
diff --git a/ext/gd/config.w32 b/ext/gd/config.w32
index 8c932a037c..22584ddd46 100644
--- a/ext/gd/config.w32
+++ b/ext/gd/config.w32
@@ -11,7 +11,8 @@ if (PHP_GD != "no") {
CHECK_LIB("freetype_a.lib;freetype.lib", "gd", PHP_GD) &&
CHECK_LIB("libpng_a.lib;libpng.lib", "gd", PHP_GD) &&
CHECK_HEADER_ADD_INCLUDE("gd.h", "CFLAGS_GD", PHP_GD + ";ext\\gd\\libgd") &&
- CHECK_HEADER_ADD_INCLUDE("png.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include\\libpng12") &&
+ (CHECK_HEADER_ADD_INCLUDE("png.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include\\libpng15") ||
+ CHECK_HEADER_ADD_INCLUDE("png.h", "CFLAGS_GD", PHP_GD + ";" + PHP_PHP_BUILD + "\\include\\libpng12")) &&
(CHECK_LIB("libiconv_a.lib;libiconv.lib", "gd", PHP_GD) || CHECK_LIB("iconv_a.lib;iconv.lib", "gd", PHP_GD)) &&
CHECK_HEADER_ADD_INCLUDE("iconv.h", "CFLAGS_GD", PHP_GD) &&
(((PHP_ZLIB=="no") && (CHECK_LIB("zlib_a.lib;zlib.lib", "gd", PHP_GD) )) ||
diff --git a/ext/intl/ERROR.CONVENTIONS b/ext/intl/ERROR.CONVENTIONS
new file mode 100644
index 0000000000..6f9079c56d
--- /dev/null
+++ b/ext/intl/ERROR.CONVENTIONS
@@ -0,0 +1,115 @@
+The intl extension has particular conventions regarding error reporting.
+These conventions are enumerated in this document.
+
+:: The last error is always stored globally.
+
+The global error code can be obtained in userland with intl_get_error_code().
+This is a U_* error code defined by ICU, but it does not have necessarily to be
+returned obtained after a call to an ICU function. That is to say, the internal
+PHP wrapper functions can set these error codes when appropriate. For instance,
+in response to bad arguments (e.g. zend_parse_parameters() failure), the PHP
+wrapper function should set the global error code to U_ILLEGAL_ARGUMENT_ERROR).
+
+The error code (an integer) can be converter to the corresponding enum name
+string in userland with intl_error_name().
+
+The associated message can be obtained with intl_get_error_message(). This is a
+message set by the PHP wrapping code, not by ICU. The message should include the
+name of the function that failed in order to make debugging easier (though if
+you activate warnings with intl.error_level or exceptions with
+intl.use_exceptions you get more fine-grained information about where the
+error ocurred).
+
+The internal PHP code can set the global last error with:
+void intl_error_set_code(intl_error* err, UErrorCode err_code TSRMLS_DC);
+void intl_error_set_custom_msg(intl_error* err, char* msg, int copyMsg TSRMLS_DC);
+void intl_error_set(intl_error* err, UErrorCode code, char* msg, int copyMsg TSRMLS_DC);
+
+and by passing NULL as the first parameter. The last function is a combination
+of the first two. If the message is not a static buffer, copyMsg should be 1.
+This makes the message string be copied and freed when no longer needed. There's
+no way to pass ownership of the string without it being copied.
+
+
+:: The last is ALSO stored in the object whose method call triggered the error,
+ unless the error is due to bad arguments, in which case only the global error
+ should be set
+
+Objects store an intl_error structed in their private data. For instance:
+typedef struct {
+ zend_object zo;
+ intl_error err;
+ Calendar* ucal;
+} Calendar_object;
+
+The global error and the object error can be SIMULTANEOUSLY set with these
+functions:
+void intl_errors_set_custom_msg(intl_error* err, char* msg, int copyMsg TSRMLS_DC);
+void intl_errors_set_code(intl_error* err, UErrorCode err_code TSRMLS_DC);
+void intl_errors_set(intl_error* err, UErrorCode code, char* msg, int copyMsg TSRMLS_DC);
+
+by passing a pointer to the object's intl_error structed as the first parameter.
+Node the extra 's' in the functions' names ('errors', not 'error').
+
+Static methods should only set the global error.
+
+
+:: Intl classes that can be instantiated should provide ::getErrorCode() and
+ getErrorMessage() methods
+
+These methods are used to retrieve the error codes stored in the object's
+private intl_error structured and mirror the global intl_get_error_code() and
+intl_get_error_message().
+
+
+:: Intl methods and functions should return FALSE on error (even argument
+ parsing errors), not NULL. Constructors and factory methods are the
+ exception; these should return NULL, not FALSE.
+
+Not that constructors in Intl generally (always?) don't throws exceptions.
+They instead destroy the object to that the result of new IntlClass() can
+be NULL. This may be surprising.
+
+
+:: Intl functions and methods should reset the global error before doing
+ anything else (even parse the arguments); instance methods should also reset
+ the object's private error
+
+Errors should be lost after a function call. This is different from the way
+ICU operates, where functions return immediately if an error is set.
+
+Error resetting can be done with:
+void intl_error_reset(NULL TSRMLS_DC); /* reset global error */
+void intl_errors_reset(intl_error* err TSRMLS_DC ); /* reset global and object error */
+
+In practice, intl_errors_reset() is not used because most classes have also
+plain functions mapped to the same internal functions as their instance methods.
+Fetching of the object is done with zend_parse_method_parameters() instead of
+directly using getThis(). Therefore, no reference to object is obtained until
+the arguments are fully parsed. Without a reference to the object, there's no
+way to reset the object's internal error code. Instead, resetting of the
+object's internal error code is done upon fetching the object from its zval.
+
+Example:
+U_CFUNC PHP_FUNCTION(breakiter_set_text)
+{
+ /* ... variable declations ... */
+ BREAKITER_METHOD_INIT_VARS; /* macro also resets global error */
+ object = getThis();
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s",
+ &text, &text_len) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "breakiter_set_text: bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ /* ... */
+
+ BREAKITER_METHOD_FETCH_OBJECT; /* macro also resets object's error */
+
+ /* ... */
+}
+
+Implementations of ::getErrorCode() and ::getErrorMessage() should not reset the
+object's error code.
diff --git a/ext/intl/breakiterator/breakiterator_class.cpp b/ext/intl/breakiterator/breakiterator_class.cpp
index de4bfbb7b0..7bf271a344 100644
--- a/ext/intl/breakiterator/breakiterator_class.cpp
+++ b/ext/intl/breakiterator/breakiterator_class.cpp
@@ -296,7 +296,7 @@ static const zend_function_entry BreakIterator_class_functions[] = {
PHP_ME_MAPPING(following, breakiter_following, ainfo_biter_offset, ZEND_ACC_PUBLIC)
PHP_ME_MAPPING(preceding, breakiter_preceding, ainfo_biter_offset, ZEND_ACC_PUBLIC)
PHP_ME_MAPPING(isBoundary, breakiter_is_boundary, ainfo_biter_offset, ZEND_ACC_PUBLIC)
- PHP_ME_MAPPING(getLocale, breakiter_get_locale, ainfo_biter_void, ZEND_ACC_PUBLIC)
+ PHP_ME_MAPPING(getLocale, breakiter_get_locale, ainfo_biter_get_locale, ZEND_ACC_PUBLIC)
PHP_ME_MAPPING(getPartsIterator, breakiter_get_parts_iterator, ainfo_biter_getPartsIterator, ZEND_ACC_PUBLIC)
PHP_ME_MAPPING(getErrorCode, breakiter_get_error_code, ainfo_biter_void, ZEND_ACC_PUBLIC)
diff --git a/ext/intl/calendar/calendar_methods.cpp b/ext/intl/calendar/calendar_methods.cpp
index f2758fdcc8..2d33bd1952 100644
--- a/ext/intl/calendar/calendar_methods.cpp
+++ b/ext/intl/calendar/calendar_methods.cpp
@@ -782,7 +782,7 @@ U_CFUNC PHP_FUNCTION(intlcal_get_time_zone)
TimeZone *tz = co->ucal->getTimeZone().clone();
if (tz == NULL) {
- intl_error_set(NULL, U_MEMORY_ALLOCATION_ERROR,
+ intl_errors_set(CALENDAR_ERROR_P(co), U_MEMORY_ALLOCATION_ERROR,
"intlcal_get_time_zone: could not clone TimeZone", 0 TSRMLS_CC);
RETURN_FALSE;
}
diff --git a/ext/intl/config.m4 b/ext/intl/config.m4
index 7c95c130f2..4630a302ef 100644
--- a/ext/intl/config.m4
+++ b/ext/intl/config.m4
@@ -34,6 +34,7 @@ if test "$PHP_INTL" != "no"; then
common/common_error.c \
common/common_enum.cpp \
common/common_date.cpp \
+ converter/converter.c \
formatter/formatter.c \
formatter/formatter_main.c \
formatter/formatter_class.c \
@@ -86,6 +87,7 @@ if test "$PHP_INTL" != "no"; then
idn/idn.c \
$icu_spoof_src, $ext_shared,,$ICU_INCS -Wno-write-strings)
PHP_ADD_BUILD_DIR($ext_builddir/collator)
+ PHP_ADD_BUILD_DIR($ext_builddir/converter)
PHP_ADD_BUILD_DIR($ext_builddir/common)
PHP_ADD_BUILD_DIR($ext_builddir/formatter)
PHP_ADD_BUILD_DIR($ext_builddir/normalizer)
diff --git a/ext/intl/config.w32 b/ext/intl/config.w32
index a49918794c..bb1dca8124 100644
--- a/ext/intl/config.w32
+++ b/ext/intl/config.w32
@@ -26,6 +26,9 @@ if (PHP_INTL != "no") {
common_enum.cpp \
common_date.cpp \
", "intl");
+ ADD_SOURCES(configure_module_dirname + "/converter", "\
+ converter.c \
+ ", "intl");
ADD_SOURCES(configure_module_dirname + "/formatter", "\
formatter.c \
formatter_attr.c \
diff --git a/ext/intl/converter/converter.c b/ext/intl/converter/converter.c
new file mode 100644
index 0000000000..387760a9d1
--- /dev/null
+++ b/ext/intl/converter/converter.c
@@ -0,0 +1,1173 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | 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. |
+ +----------------------------------------------------------------------+
+ | Authors: Sara Golemon <pollita@php.net> |
+ +----------------------------------------------------------------------+
+ */
+
+#include "converter.h"
+#include "zend_exceptions.h"
+
+#include <unicode/utypes.h>
+#include <unicode/ucnv.h>
+#include <unicode/ustring.h>
+
+#include "ext/intl/intl_error.h"
+
+typedef struct _php_converter_object {
+ zend_object obj;
+#ifdef ZTS
+ void ***tsrm_ls;
+#endif
+ UConverter *src, *dest;
+ zend_fcall_info to_cb, from_cb;
+ zend_fcall_info_cache to_cache, from_cache;
+ intl_error error;
+} php_converter_object;
+
+static zend_class_entry *php_converter_ce;
+static zend_object_handlers php_converter_object_handlers;
+
+#define CONV_GET(pzv) ((php_converter_object*)zend_objects_get_address((pzv) TSRMLS_CC))
+#define THROW_UFAILURE(obj, fname, error) php_converter_throw_failure(obj, error TSRMLS_CC, \
+ fname "() returned error %ld: %s", (long)error, u_errorName(error))
+
+/* {{{ php_converter_throw_failure */
+static inline void php_converter_throw_failure(php_converter_object *objval, UErrorCode error TSRMLS_DC, const char *format, ...) {
+ intl_error *err = objval ? &(objval->error) : NULL;
+ char message[1024];
+ va_list vargs;
+
+ va_start(vargs, format);
+ vsnprintf(message, sizeof(message), format, vargs);
+ va_end(vargs);
+
+ intl_errors_set(err, error, message, 1 TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ php_converter_default_callback */
+static void php_converter_default_callback(zval *return_value, zval *zobj, long reason, zval *error TSRMLS_DC) {
+ /* Basic functionality so children can call parent::toUCallback() */
+ switch (reason) {
+ case UCNV_UNASSIGNED:
+ case UCNV_ILLEGAL:
+ case UCNV_IRREGULAR:
+ {
+ php_converter_object *objval = (php_converter_object*)CONV_GET(zobj);
+ char chars[127];
+ int8_t chars_len = sizeof(chars);
+ UErrorCode error = U_ZERO_ERROR;
+
+ /* Yes, this is fairly wasteful at first glance,
+ * but considering that the alternative is to store
+ * what's sent into setSubstChars() and the fact
+ * that this is an extremely unlikely codepath
+ * I'd rather take the CPU hit here, than waste time
+ * storing a value I'm unlikely to use.
+ */
+ ucnv_getSubstChars(objval->src, chars, &chars_len, &error);
+ if (U_FAILURE(error)) {
+ THROW_UFAILURE(objval, "ucnv_getSubstChars", error);
+ chars[0] = 0x1A;
+ chars[1] = 0;
+ chars_len = 1;
+ }
+ RETVAL_STRINGL(chars, chars_len, 1);
+ }
+ }
+ zval_dtor(error);
+ ZVAL_LONG(error, U_ZERO_ERROR);
+}
+/* }}} */
+
+/* {{{ proto void UConverter::toUCallback(long $reason,
+ string $source, string $codeUnits,
+ long &$error) */
+ZEND_BEGIN_ARG_INFO_EX(php_converter_toUCallback_arginfo, 0, ZEND_RETURN_VALUE, 4)
+ ZEND_ARG_INFO(0, reason)
+ ZEND_ARG_INFO(0, source)
+ ZEND_ARG_INFO(0, codeUnits)
+ ZEND_ARG_INFO(1, error)
+ZEND_END_ARG_INFO();
+static PHP_METHOD(UConverter, toUCallback) {
+ long reason;
+ zval *source, *codeUnits, *error;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lzzz",
+ &reason, &source, &codeUnits, &error) == FAILURE) {
+ return;
+ }
+
+ php_converter_default_callback(return_value, getThis(), reason, error TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ proto void UConverter::fromUCallback(long $reason,
+ Array $source, long $codePoint,
+ long &$error) */
+ZEND_BEGIN_ARG_INFO_EX(php_converter_fromUCallback_arginfo, 0, ZEND_RETURN_VALUE, 4)
+ ZEND_ARG_INFO(0, reason)
+ ZEND_ARG_INFO(0, source)
+ ZEND_ARG_INFO(0, codePoint)
+ ZEND_ARG_INFO(1, error)
+ZEND_END_ARG_INFO();
+static PHP_METHOD(UConverter, fromUCallback) {
+ long reason;
+ zval *source, *codePoint, *error;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lzzz",
+ &reason, &source, &codePoint, &error) == FAILURE) {
+ return;
+ }
+
+ php_converter_default_callback(return_value, getThis(), reason, error TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ php_converter_check_limits */
+static inline zend_bool php_converter_check_limits(php_converter_object *objval, long available, long needed TSRMLS_DC) {
+ if (available < needed) {
+ php_converter_throw_failure(objval, U_BUFFER_OVERFLOW_ERROR TSRMLS_CC, "Buffer overrun %ld bytes needed, %ld available", needed, available);
+ return 0;
+ }
+ return 1;
+}
+/* }}} */
+
+#define TARGET_CHECK(cnvargs, needed) php_converter_check_limits(objval, cnvargs->targetLimit - cnvargs->target, needed TSRMLS_CC)
+
+/* {{{ php_converter_append_toUnicode_target */
+static void php_converter_append_toUnicode_target(zval *val, UConverterToUnicodeArgs *args, php_converter_object *objval TSRMLS_DC) {
+ switch (Z_TYPE_P(val)) {
+ case IS_NULL:
+ /* Code unit is being skipped */
+ return;
+ case IS_LONG:
+ {
+ long lval = Z_LVAL_P(val);
+ if ((lval < 0) || (lval > 0x10FFFF)) {
+ php_converter_throw_failure(objval, U_ILLEGAL_ARGUMENT_ERROR TSRMLS_CC, "Invalid codepoint U+%04lx", lval);
+ return;
+ }
+ if (lval > 0xFFFF) {
+ /* Supplemental planes U+010000 - U+10FFFF */
+ if (TARGET_CHECK(args, 2)) {
+ /* TODO: Find the ICU call which does this properly */
+ *(args->target++) = (UChar)(((lval - 0x10000) >> 10) | 0xD800);
+ *(args->target++) = (UChar)(((lval - 0x10000) & 0x3FF) | 0xDC00);
+ }
+ return;
+ }
+ /* Non-suggogate BMP codepoint */
+ if (TARGET_CHECK(args, 1)) {
+ *(args->target++) = (UChar)lval;
+ }
+ return;
+ }
+ case IS_STRING:
+ {
+ const char *strval = Z_STRVAL_P(val);
+ int i = 0, strlen = Z_STRLEN_P(val);
+
+ while((i != strlen) && TARGET_CHECK(args, 1)) {
+ UChar c;
+ U8_NEXT(strval, i, strlen, c);
+ *(args->target++) = c;
+ }
+ return;
+ }
+ case IS_ARRAY:
+ {
+ HashTable *ht = Z_ARRVAL_P(val);
+ HashPosition pos;
+ zval **tmpzval;
+
+ for(zend_hash_internal_pointer_reset_ex(ht, &pos);
+ zend_hash_get_current_data_ex(ht, (void**)&tmpzval, &pos) == SUCCESS;
+ zend_hash_move_forward_ex(ht, &pos)) {
+ php_converter_append_toUnicode_target(*tmpzval, args, objval TSRMLS_CC);
+ }
+ return;
+ }
+ default:
+ php_converter_throw_failure(objval, U_ILLEGAL_ARGUMENT_ERROR TSRMLS_CC,
+ "toUCallback() specified illegal type for substitution character");
+ }
+}
+/* }}} */
+
+/* {{{ php_converter_to_u_callback */
+static void php_converter_to_u_callback(const void *context,
+ UConverterToUnicodeArgs *args,
+ const char *codeUnits, int32_t length,
+ UConverterCallbackReason reason,
+ UErrorCode *pErrorCode) {
+ php_converter_object *objval = (php_converter_object*)context;
+ zval *zreason, *zsource, *zcodeunits, *zerror, *retval = NULL;
+ zval **zargs[4];
+#ifdef ZTS
+ TSRMLS_D = objval->tsrm_ls;
+#endif
+
+ MAKE_STD_ZVAL(zreason);
+ ZVAL_LONG(zreason, reason);
+ zargs[0] = &zreason;
+
+ MAKE_STD_ZVAL(zsource);
+ ZVAL_STRINGL(zsource, args->source, args->sourceLimit - args->source, 1);
+ zargs[1] = &zsource;
+
+ MAKE_STD_ZVAL(zcodeunits);
+ ZVAL_STRINGL(zcodeunits, codeUnits, length, 1);
+ zargs[2] = &zcodeunits;
+
+ MAKE_STD_ZVAL(zerror);
+ ZVAL_LONG(zerror, *pErrorCode);
+ zargs[3] = &zerror;
+
+ objval->to_cb.param_count = 4;
+ objval->to_cb.params = zargs;
+ objval->to_cb.retval_ptr_ptr = &retval;
+ objval->to_cb.no_separation = 0;
+ if (zend_call_function(&(objval->to_cb), &(objval->to_cache) TSRMLS_CC) == FAILURE) {
+ /* Unlikely */
+ php_converter_throw_failure(objval, U_INTERNAL_PROGRAM_ERROR TSRMLS_CC, "Unexpected failure calling toUCallback()");
+ } else if (retval) {
+ php_converter_append_toUnicode_target(retval, args, objval TSRMLS_CC);
+ zval_ptr_dtor(&retval);
+ }
+
+ if (Z_TYPE_P(zerror) == IS_LONG) {
+ *pErrorCode = Z_LVAL_P(zerror);
+ }
+
+ zval_ptr_dtor(&zreason);
+ zval_ptr_dtor(&zsource);
+ zval_ptr_dtor(&zcodeunits);
+ zval_ptr_dtor(&zerror);
+}
+/* }}} */
+
+/* {{{ php_converter_append_fromUnicode_target */
+static void php_converter_append_fromUnicode_target(zval *val, UConverterFromUnicodeArgs *args, php_converter_object *objval TSRMLS_DC) {
+ switch (Z_TYPE_P(val)) {
+ case IS_NULL:
+ /* Ignore */
+ return;
+ case IS_LONG:
+ if (TARGET_CHECK(args, 1)) {
+ *(args->target++) = Z_LVAL_P(val);
+ }
+ return;
+ case IS_STRING:
+ {
+ int vallen = Z_STRLEN_P(val);
+ if (TARGET_CHECK(args, vallen)) {
+ memcpy(args->target, Z_STRVAL_P(val), vallen);
+ args->target += vallen;
+ }
+ return;
+ }
+ case IS_ARRAY:
+ {
+ HashTable *ht = Z_ARRVAL_P(val);
+ HashPosition pos;
+ zval **tmpzval;
+ for(zend_hash_internal_pointer_reset_ex(ht, &pos);
+ zend_hash_get_current_data_ex(ht, (void**)&tmpzval, &pos) == SUCCESS;
+ zend_hash_move_forward_ex(ht, &pos)) {
+ php_converter_append_fromUnicode_target(*tmpzval, args, objval TSRMLS_CC);
+ }
+ return;
+ }
+ default:
+ php_converter_throw_failure(objval, U_ILLEGAL_ARGUMENT_ERROR TSRMLS_CC, "fromUCallback() specified illegal type for substitution character");
+ }
+}
+/* }}} */
+
+/* {{{ php_converter_from_u_callback */
+static void php_converter_from_u_callback(const void *context,
+ UConverterFromUnicodeArgs *args,
+ const UChar *codeUnits, int32_t length, UChar32 codePoint,
+ UConverterCallbackReason reason,
+ UErrorCode *pErrorCode) {
+ php_converter_object *objval = (php_converter_object*)context;
+ zval *zreason, *zsource, *zcodepoint, *zerror, *retval = NULL;
+ zval **zargs[4];
+ int i;
+#ifdef ZTS
+ TSRMLS_D = objval->tsrm_ls;
+#endif
+
+ MAKE_STD_ZVAL(zreason);
+ ZVAL_LONG(zreason, reason);
+ zargs[0] = &zreason;
+
+ MAKE_STD_ZVAL(zsource);
+ array_init(zsource);
+ i = 0;
+ while (i < length) {
+ UChar32 c;
+ U16_NEXT(codeUnits, i, length, c);
+ add_next_index_long(zsource, c);
+ }
+ zargs[1] = &zsource;
+
+ MAKE_STD_ZVAL(zcodepoint);
+ ZVAL_LONG(zcodepoint, codePoint);
+ zargs[2] = &zcodepoint;
+
+ MAKE_STD_ZVAL(zerror);
+ ZVAL_LONG(zerror, *pErrorCode);
+ zargs[3] = &zerror;
+
+ objval->from_cb.param_count = 4;
+ objval->from_cb.params = zargs;
+ objval->from_cb.retval_ptr_ptr = &retval;
+ objval->from_cb.no_separation = 0;
+ if (zend_call_function(&(objval->from_cb), &(objval->from_cache) TSRMLS_CC) == FAILURE) {
+ /* Unlikely */
+ php_converter_throw_failure(objval, U_INTERNAL_PROGRAM_ERROR TSRMLS_CC, "Unexpected failure calling fromUCallback()");
+ } else if (retval) {
+ php_converter_append_fromUnicode_target(retval, args, objval TSRMLS_CC);
+ zval_ptr_dtor(&retval);
+ }
+
+ if (Z_TYPE_P(zerror) == IS_LONG) {
+ *pErrorCode = Z_LVAL_P(zerror);
+ }
+
+ zval_ptr_dtor(&zreason);
+ zval_ptr_dtor(&zsource);
+ zval_ptr_dtor(&zcodepoint);
+ zval_ptr_dtor(&zerror);
+}
+/* }}} */
+
+/* {{{ php_converter_set_callbacks */
+static inline zend_bool php_converter_set_callbacks(php_converter_object *objval, UConverter *cnv TSRMLS_DC) {
+ zend_bool ret = 1;
+ UErrorCode error = U_ZERO_ERROR;
+
+ if (objval->obj.ce == php_converter_ce) {
+ /* Short-circuit having to go through method calls and data marshalling
+ * when we're using default behavior
+ */
+ return 1;
+ }
+
+ ucnv_setToUCallBack(cnv, (UConverterToUCallback)php_converter_to_u_callback, (const void*)objval,
+ NULL, NULL, &error);
+ if (U_FAILURE(error)) {
+ THROW_UFAILURE(objval, "ucnv_setToUCallBack", error);
+ ret = 0;
+ }
+
+ error = U_ZERO_ERROR;
+ ucnv_setFromUCallBack(cnv, (UConverterFromUCallback)php_converter_from_u_callback, (const void*)objval,
+ NULL, NULL, &error);
+ if (U_FAILURE(error)) {
+ THROW_UFAILURE(objval, "ucnv_setFromUCallBack", error);
+ ret = 0;
+ }
+ return ret;
+}
+/* }}} */
+
+/* {{{ php_converter_set_encoding */
+static zend_bool php_converter_set_encoding(php_converter_object *objval,
+ UConverter **pcnv,
+ const char *enc, int enc_len
+ TSRMLS_DC) {
+ UErrorCode error = U_ZERO_ERROR;
+ UConverter *cnv = ucnv_open(enc, &error);
+
+ if (error == U_AMBIGUOUS_ALIAS_WARNING) {
+ UErrorCode getname_error = U_ZERO_ERROR;
+ const char *actual_encoding = ucnv_getName(cnv, &getname_error);
+ if (U_FAILURE(getname_error)) {
+ /* Should never happen */
+ actual_encoding = "(unknown)";
+ }
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Ambiguous encoding specified, using %s", actual_encoding);
+ } else if (U_FAILURE(error)) {
+ if (objval) {
+ THROW_UFAILURE(objval, "ucnv_open", error);
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error setting encoding: %d - %s", (int)error, u_errorName(error));
+ }
+ return 0;
+ }
+
+ if (objval && !php_converter_set_callbacks(objval, cnv TSRMLS_CC)) {
+ return 0;
+ }
+
+ if (*pcnv) {
+ ucnv_close(*pcnv);
+ }
+ *pcnv = cnv;
+ return 1;
+}
+/* }}} */
+
+/* {{{ php_converter_do_set_encoding */
+ZEND_BEGIN_ARG_INFO_EX(php_converter_set_encoding_arginfo, 0, ZEND_RETURN_VALUE, 1)
+ ZEND_ARG_INFO(0, encoding)
+ZEND_END_ARG_INFO();
+static void php_converter_do_set_encoding(UConverter *cnv, INTERNAL_FUNCTION_PARAMETERS) {
+ php_converter_object *objval = CONV_GET(getThis());
+ char *enc;
+ int enc_len;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &enc, &enc_len) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "Bad arguments, "
+ "expected one string argument", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+ intl_errors_reset(&objval->error TSRMLS_CC);
+
+ RETURN_BOOL(php_converter_set_encoding(objval, &(objval->src), enc, enc_len TSRMLS_CC));
+}
+/* }}} */
+
+/* {{{ proto bool UConverter::setSourceEncoding(string encoding) */
+static PHP_METHOD(UConverter, setSourceEncoding) {
+ php_converter_object *objval = CONV_GET(getThis());
+ php_converter_do_set_encoding(objval->src, INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+/* }}} */
+
+/* {{{ proto bool UConverter::setDestinationEncoding(string encoding) */
+static PHP_METHOD(UConverter, setDestinationEncoding) {
+ php_converter_object *objval = CONV_GET(getThis());
+ php_converter_do_set_encoding(objval->dest, INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+/* }}} */
+
+/* {{{ php_converter_do_get_encoding */
+ZEND_BEGIN_ARG_INFO_EX(php_converter_get_encoding_arginfo, 0, ZEND_RETURN_VALUE, 0)
+ZEND_END_ARG_INFO();
+static void php_converter_do_get_encoding(php_converter_object *objval, UConverter *cnv, INTERNAL_FUNCTION_PARAMETERS) {
+ const char *name;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "Expected no arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ intl_errors_reset(&objval->error TSRMLS_CC);
+
+ if (!cnv) {
+ RETURN_NULL();
+ }
+
+ name = ucnv_getName(cnv, &objval->error.code);
+ if (U_FAILURE(objval->error.code)) {
+ THROW_UFAILURE(objval, "ucnv_getName()", objval->error.code);
+ RETURN_FALSE;
+ }
+
+ RETURN_STRING(name, 1);
+}
+/* }}} */
+
+/* {{{ proto string UConverter::getSourceEncoding() */
+static PHP_METHOD(UConverter, getSourceEncoding) {
+ php_converter_object *objval = CONV_GET(getThis());
+ php_converter_do_get_encoding(objval, objval->src, INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+/* }}} */
+
+/* {{{ proto string UConverter::getDestinationEncoding() */
+static PHP_METHOD(UConverter, getDestinationEncoding) {
+ php_converter_object *objval = CONV_GET(getThis());
+ php_converter_do_get_encoding(objval, objval->dest, INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+/* }}} */
+
+/* {{{ php_converter_do_get_type */
+ZEND_BEGIN_ARG_INFO_EX(php_converter_get_type_arginfo, 0, ZEND_RETURN_VALUE, 0)
+ZEND_END_ARG_INFO();
+static void php_converter_do_get_type(php_converter_object *objval, UConverter *cnv, INTERNAL_FUNCTION_PARAMETERS) {
+ UConverterType t;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "Expected no arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+ intl_errors_reset(&objval->error TSRMLS_CC);
+
+ if (!cnv) {
+ RETURN_NULL();
+ }
+
+ t = ucnv_getType(cnv);
+ if (U_FAILURE(objval->error.code)) {
+ THROW_UFAILURE(objval, "ucnv_getType", objval->error.code);
+ RETURN_FALSE;
+ }
+
+ RETURN_LONG(t);
+}
+/* }}} */
+
+/* {{{ proto long UConverter::getSourceType() */
+static PHP_METHOD(UConverter, getSourceType) {
+ php_converter_object *objval = CONV_GET(getThis());
+ php_converter_do_get_type(objval, objval->src, INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+/* }}} */
+
+/* {{{ proto long UConverter::getDestinationType() */
+static PHP_METHOD(UConverter, getDestinationType) {
+ php_converter_object *objval = CONV_GET(getThis());
+ php_converter_do_get_type(objval, objval->dest, INTERNAL_FUNCTION_PARAM_PASSTHRU);
+}
+/* }}} */
+
+/* {{{ php_converter_resolve_callback */
+static void php_converter_resolve_callback(zval *zobj,
+ php_converter_object *objval,
+ const char *callback_name,
+ zend_fcall_info *finfo,
+ zend_fcall_info_cache *fcache TSRMLS_DC) {
+ char *errstr = NULL;
+ zval caller;
+
+ array_init(&caller);
+ Z_ADDREF_P(zobj);
+ add_index_zval(&caller, 0, zobj);
+ add_index_string(&caller, 1, callback_name, 1);
+ if (zend_fcall_info_init(&caller, 0, finfo, fcache, NULL, &errstr TSRMLS_CC) == FAILURE) {
+ php_converter_throw_failure(objval, U_INTERNAL_PROGRAM_ERROR TSRMLS_CC, "Error setting converter callback: %s", errstr);
+ }
+ zval_dtor(&caller);
+ if (errstr) {
+ efree(errstr);
+ }
+}
+/* }}} */
+
+/* {{{ proto void UConverter::__construct([string dest = 'utf-8',[string src = 'utf-8']]) */
+ZEND_BEGIN_ARG_INFO_EX(php_converter_arginfo, 0, ZEND_RETURN_VALUE, 0)
+ ZEND_ARG_INFO(0, destination_encoding)
+ ZEND_ARG_INFO(0, source_encoding)
+ZEND_END_ARG_INFO();
+
+static PHP_METHOD(UConverter, __construct) {
+ php_converter_object *objval = CONV_GET(getThis());
+ char *src = "utf-8";
+ int src_len = sizeof("utf-8") - 1;
+ char *dest = src;
+ int dest_len = src_len;
+
+ intl_error_reset(NULL TSRMLS_CC);
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!s!",
+ &dest, &dest_len, &src, &src_len) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "UConverter::__construct(): bad arguments", 0 TSRMLS_CC);
+ return;
+ }
+
+ php_converter_set_encoding(objval, &(objval->src), src, src_len TSRMLS_CC);
+ php_converter_set_encoding(objval, &(objval->dest), dest, dest_len TSRMLS_CC);
+ php_converter_resolve_callback(getThis(), objval, "toUCallback", &(objval->to_cb), &(objval->to_cache) TSRMLS_CC);
+ php_converter_resolve_callback(getThis(), objval, "fromUCallback", &(objval->from_cb), &(objval->from_cache) TSRMLS_CC);
+}
+/* }}} */
+
+/* {{{ proto bool UConverter::setSubstChars(string $chars) */
+ZEND_BEGIN_ARG_INFO_EX(php_converter_setSubstChars_arginfo, 0, ZEND_RETURN_VALUE, 1)
+ ZEND_ARG_INFO(0, chars)
+ZEND_END_ARG_INFO();
+
+static PHP_METHOD(UConverter, setSubstChars) {
+ php_converter_object *objval = CONV_GET(getThis());
+ char *chars;
+ int chars_len, ret = 1;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &chars, &chars_len) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "UConverter::setSubstChars(): bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+ intl_errors_reset(&objval->error TSRMLS_CC);
+
+ if (objval->src) {
+ UErrorCode error = U_ZERO_ERROR;
+ ucnv_setSubstChars(objval->src, chars, chars_len, &error);
+ if (U_FAILURE(error)) {
+ THROW_UFAILURE(objval, "ucnv_setSubstChars", error);
+ ret = 0;
+ }
+ } else {
+ php_converter_throw_failure(objval, U_INVALID_STATE_ERROR TSRMLS_CC, "Source Converter has not been initialized yet");
+ ret = 0;
+ }
+
+ if (objval->dest) {
+ UErrorCode error = U_ZERO_ERROR;
+ ucnv_setSubstChars(objval->dest, chars, chars_len, &error);
+ if (U_FAILURE(error)) {
+ THROW_UFAILURE(objval, "ucnv_setSubstChars", error);
+ ret = 0;
+ }
+ } else {
+ php_converter_throw_failure(objval, U_INVALID_STATE_ERROR TSRMLS_CC, "Destination Converter has not been initialized yet");
+ ret = 0;
+ }
+
+ RETURN_BOOL(ret);
+}
+/* }}} */
+
+/* {{{ proto string UConverter::getSubstChars() */
+ZEND_BEGIN_ARG_INFO_EX(php_converter_getSubstChars_arginfo, 0, ZEND_RETURN_VALUE, 0)
+ZEND_END_ARG_INFO();
+
+static PHP_METHOD(UConverter, getSubstChars) {
+ php_converter_object *objval = CONV_GET(getThis());
+ char chars[127];
+ int8_t chars_len = sizeof(chars);
+ UErrorCode error = U_ZERO_ERROR;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "UConverter::getSubstChars(): expected no arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+ intl_errors_reset(&objval->error TSRMLS_CC);
+
+ if (!objval->src) {
+ RETURN_NULL();
+ }
+
+ /* src and dest get the same subst chars set,
+ * so it doesn't really matter which one we read from
+ */
+ ucnv_getSubstChars(objval->src, chars, &chars_len, &error);
+ if (U_FAILURE(error)) {
+ THROW_UFAILURE(objval, "ucnv_getSubstChars", error);
+ RETURN_FALSE;
+ }
+
+ RETURN_STRINGL(chars, chars_len, 1);
+}
+/* }}} */
+
+/* {{{ php_converter_do_convert */
+static zend_bool php_converter_do_convert(UConverter *dest_cnv, char **pdest, int32_t *pdest_len,
+ UConverter *src_cnv, const char *src, int32_t src_len,
+ php_converter_object *objval
+ TSRMLS_DC) {
+ UErrorCode error = U_ZERO_ERROR;
+ int32_t dest_len,
+ temp_len;
+ char *dest;
+ UChar *temp;
+
+ if (!src_cnv || !dest_cnv) {
+ php_converter_throw_failure(objval, U_INVALID_STATE_ERROR TSRMLS_CC,
+ "Internal converters not initialized");
+ return 0;
+ }
+
+ /* Get necessary buffer size first */
+ temp_len = 1 + ucnv_toUChars(src_cnv, NULL, 0, src, src_len, &error);
+ if (U_FAILURE(error) && error != U_BUFFER_OVERFLOW_ERROR) {
+ THROW_UFAILURE(objval, "ucnv_toUChars", error);
+ return 0;
+ }
+ temp = safe_emalloc(sizeof(UChar), temp_len, sizeof(UChar));
+
+ /* Convert to intermediate UChar* array */
+ error = U_ZERO_ERROR;
+ temp_len = ucnv_toUChars(src_cnv, temp, temp_len, src, src_len, &error);
+ if (U_FAILURE(error)) {
+ THROW_UFAILURE(objval, "ucnv_toUChars", error);
+ efree(temp);
+ return 0;
+ }
+ temp[temp_len] = 0;
+
+ /* Get necessary output buffer size */
+ dest_len = 1 + ucnv_fromUChars(dest_cnv, NULL, 0, temp, temp_len, &error);
+ if (U_FAILURE(error) && error != U_BUFFER_OVERFLOW_ERROR) {
+ THROW_UFAILURE(objval, "ucnv_fromUChars", error);
+ efree(temp);
+ return 0;
+ }
+ dest = safe_emalloc(sizeof(char), dest_len, sizeof(char));
+
+ /* Convert to final encoding */
+ error = U_ZERO_ERROR;
+ dest_len = ucnv_fromUChars(dest_cnv, dest, dest_len, temp, temp_len, &error);
+ efree(temp);
+ if (U_FAILURE(error)) {
+ THROW_UFAILURE(objval, "ucnv_fromUChars", error);
+ efree(dest);
+ return 0;
+ }
+
+ *pdest = dest;
+ if (pdest_len) {
+ *pdest_len = dest_len;
+ }
+
+ return 1;
+}
+/* }}} */
+
+/* {{{ proto string UConverter::reasonText(long reason) */
+#define UCNV_REASON_CASE(v) case (UCNV_ ## v) : RETURN_STRINGL( "REASON_" #v , sizeof( "REASON_" #v ) - 1, 1);
+ZEND_BEGIN_ARG_INFO_EX(php_converter_reasontext_arginfo, 0, ZEND_RETURN_VALUE, 0)
+ ZEND_ARG_INFO(0, reason)
+ZEND_END_ARG_INFO();
+static PHP_METHOD(UConverter, reasonText) {
+ long reason;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &reason) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "UConverter::reasonText(): bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+ intl_error_reset(NULL TSRMLS_CC);
+
+ switch (reason) {
+ UCNV_REASON_CASE(UNASSIGNED)
+ UCNV_REASON_CASE(ILLEGAL)
+ UCNV_REASON_CASE(IRREGULAR)
+ UCNV_REASON_CASE(RESET)
+ UCNV_REASON_CASE(CLOSE)
+ UCNV_REASON_CASE(CLONE)
+ default:
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown UConverterCallbackReason: %ld", reason);
+ RETURN_FALSE;
+ }
+}
+/* }}} */
+
+/* {{{ proto string UConverter::convert(string str[, bool reverse]) */
+ZEND_BEGIN_ARG_INFO_EX(php_converter_convert_arginfo, 0, ZEND_RETURN_VALUE, 1)
+ ZEND_ARG_INFO(0, str)
+ ZEND_ARG_INFO(0, reverse)
+ZEND_END_ARG_INFO();
+
+static PHP_METHOD(UConverter, convert) {
+ php_converter_object *objval = CONV_GET(getThis());
+ char *str, *dest;
+ int str_len, dest_len;
+ zend_bool reverse = 0;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b",
+ &str, &str_len, &reverse) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "UConverter::convert(): bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+ intl_errors_reset(&objval->error TSRMLS_CC);
+
+ if (php_converter_do_convert(reverse ? objval->src : objval->dest,
+ &dest, &dest_len,
+ reverse ? objval->dest : objval->src,
+ str, str_len,
+ objval TSRMLS_CC)) {
+ RETURN_STRINGL(dest, dest_len, 0);
+ } else {
+ RETURN_FALSE;
+ }
+}
+/* }}} */
+
+/* {{{ proto string UConverter::transcode(string $str, string $toEncoding, string $fromEncoding[, Array $options = array()]) */
+ZEND_BEGIN_ARG_INFO_EX(php_converter_transcode_arginfo, 0, ZEND_RETURN_VALUE, 3)
+ ZEND_ARG_INFO(0, str)
+ ZEND_ARG_INFO(0, toEncoding)
+ ZEND_ARG_INFO(0, fromEncoding)
+ ZEND_ARG_ARRAY_INFO(0, options, 1)
+ZEND_END_ARG_INFO();
+
+static PHP_METHOD(UConverter, transcode) {
+ char *str, *src, *dest;
+ int str_len, src_len, dest_len;
+ zval *options = NULL;
+ UConverter *src_cnv = NULL, *dest_cnv = NULL;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sss|a!",
+ &str, &str_len, &dest, &dest_len, &src, &src_len, &options) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "UConverter::transcode(): bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+ intl_error_reset(NULL TSRMLS_CC);
+
+ if (php_converter_set_encoding(NULL, &src_cnv, src, src_len TSRMLS_CC) &&
+ php_converter_set_encoding(NULL, &dest_cnv, dest, dest_len TSRMLS_CC)) {
+ char *out = NULL;
+ int out_len = 0;
+ UErrorCode error = U_ZERO_ERROR;
+
+ if (options && zend_hash_num_elements(Z_ARRVAL_P(options))) {
+ zval **tmpzval;
+
+ if (U_SUCCESS(error) &&
+ zend_hash_find(Z_ARRVAL_P(options), "from_subst", sizeof("from_subst"), (void**)&tmpzval) == SUCCESS &&
+ Z_TYPE_PP(tmpzval) == IS_STRING) {
+ error = U_ZERO_ERROR;
+ ucnv_setSubstChars(src_cnv, Z_STRVAL_PP(tmpzval), Z_STRLEN_PP(tmpzval) & 0x7F, &error);
+ }
+ if (U_SUCCESS(error) &&
+ zend_hash_find(Z_ARRVAL_P(options), "to_subst", sizeof("to_subst"), (void**)&tmpzval) == SUCCESS &&
+ Z_TYPE_PP(tmpzval) == IS_STRING) {
+ error = U_ZERO_ERROR;
+ ucnv_setSubstChars(dest_cnv, Z_STRVAL_PP(tmpzval), Z_STRLEN_PP(tmpzval) & 0x7F, &error);
+ }
+ }
+
+ if (U_SUCCESS(error) &&
+ php_converter_do_convert(dest_cnv, &out, &out_len, src_cnv, str, str_len, NULL TSRMLS_CC)) {
+ RETVAL_STRINGL(out, out_len, 0);
+ }
+
+ if (U_FAILURE(error)) {
+ THROW_UFAILURE(NULL, "transcode", error);
+ RETVAL_FALSE;
+ }
+ } else {
+ RETVAL_FALSE;
+ }
+
+ if (src_cnv) {
+ ucnv_close(src_cnv);
+ }
+ if (dest_cnv) {
+ ucnv_close(dest_cnv);
+ }
+}
+/* }}} */
+
+/* {{{ proto int UConverter::getErrorCode() */
+ZEND_BEGIN_ARG_INFO_EX(php_converter_geterrorcode_arginfo, 0, ZEND_RETURN_VALUE, 0)
+ZEND_END_ARG_INFO();
+static PHP_METHOD(UConverter, getErrorCode) {
+ php_converter_object *objval = CONV_GET(getThis());
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "UConverter::getErrorCode(): expected no arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ RETURN_LONG(intl_error_get_code(&(objval->error) TSRMLS_CC));
+}
+/* }}} */
+
+/* {{{ proto string UConverter::getErrorMessage() */
+ZEND_BEGIN_ARG_INFO_EX(php_converter_geterrormsg_arginfo, 0, ZEND_RETURN_VALUE, 0)
+ZEND_END_ARG_INFO();
+static PHP_METHOD(UConverter, getErrorMessage) {
+ php_converter_object *objval = CONV_GET(getThis());
+ char *message = intl_error_get_message(&(objval->error) TSRMLS_CC);
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "UConverter::getErrorMessage(): expected no arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+
+ if (message) {
+ RETURN_STRING(message, 1);
+ } else {
+ RETURN_NULL();
+ }
+}
+/* }}} */
+
+/* {{{ proto array UConverter::getAvailable() */
+ZEND_BEGIN_ARG_INFO_EX(php_converter_getavailable_arginfo, 0, ZEND_RETURN_VALUE, 0)
+ZEND_END_ARG_INFO();
+static PHP_METHOD(UConverter, getAvailable) {
+ int32_t i,
+ count = ucnv_countAvailable();
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "UConverter::getErrorMessage(): expected no arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+ intl_error_reset(NULL TSRMLS_CC);
+
+ array_init(return_value);
+ for(i = 0; i < count; i++) {
+ const char *name = ucnv_getAvailableName(i);
+ add_next_index_string(return_value, name, 1);
+ }
+}
+/* }}} */
+
+/* {{{ proto array UConverter::getAliases(string name) */
+ZEND_BEGIN_ARG_INFO_EX(php_converter_getaliases_arginfo, 0, ZEND_RETURN_VALUE, 0)
+ ZEND_ARG_INFO(0, name)
+ZEND_END_ARG_INFO();
+static PHP_METHOD(UConverter, getAliases) {
+ char *name;
+ int name_len;
+ UErrorCode error = U_ZERO_ERROR;
+ uint16_t i, count;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &name, &name_len) == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "UConverter::getAliases(): bad arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+ intl_error_reset(NULL TSRMLS_CC);
+
+ count = ucnv_countAliases(name, &error);
+ if (U_FAILURE(error)) {
+ THROW_UFAILURE(NULL, "ucnv_countAliases", error);
+ RETURN_FALSE;
+ }
+
+ array_init(return_value);
+ for(i = 0; i < count; i++) {
+ const char *alias;
+
+ error = U_ZERO_ERROR;
+ alias = ucnv_getAlias(name, i, &error);
+ if (U_FAILURE(error)) {
+ THROW_UFAILURE(NULL, "ucnv_getAlias", error);
+ zval_dtor(return_value);
+ RETURN_NULL();
+ }
+ add_next_index_string(return_value, alias, 1);
+ }
+}
+/* }}} */
+
+/* {{{ proto array UConverter::getStandards() */
+ZEND_BEGIN_ARG_INFO_EX(php_converter_getstandards_arginfo, 0, ZEND_RETURN_VALUE, 0)
+ZEND_END_ARG_INFO();
+static PHP_METHOD(UConverter, getStandards) {
+ uint16_t i, count;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR,
+ "UConverter::getStandards(): expected no arguments", 0 TSRMLS_CC);
+ RETURN_FALSE;
+ }
+ intl_error_reset(NULL TSRMLS_CC);
+
+ array_init(return_value);
+ count = ucnv_countStandards();
+ for(i = 0; i < count; i++) {
+ UErrorCode error = U_ZERO_ERROR;
+ const char *name = ucnv_getStandard(i, &error);
+ if (U_FAILURE(error)) {
+ THROW_UFAILURE(NULL, "ucnv_getStandard", error);
+ zval_dtor(return_value);
+ RETURN_NULL();
+ }
+ add_next_index_string(return_value, name, 1);
+ }
+}
+/* }}} */
+
+static zend_function_entry php_converter_methods[] = {
+ PHP_ME(UConverter, __construct, php_converter_arginfo, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
+
+ /* Encoding selection */
+ PHP_ME(UConverter, setSourceEncoding, php_converter_set_encoding_arginfo, ZEND_ACC_PUBLIC)
+ PHP_ME(UConverter, setDestinationEncoding, php_converter_set_encoding_arginfo, ZEND_ACC_PUBLIC)
+ PHP_ME(UConverter, getSourceEncoding, php_converter_get_encoding_arginfo, ZEND_ACC_PUBLIC)
+ PHP_ME(UConverter, getDestinationEncoding, php_converter_get_encoding_arginfo, ZEND_ACC_PUBLIC)
+
+ /* Introspection for algorithmic converters */
+ PHP_ME(UConverter, getSourceType, php_converter_get_type_arginfo, ZEND_ACC_PUBLIC)
+ PHP_ME(UConverter, getDestinationType, php_converter_get_type_arginfo, ZEND_ACC_PUBLIC)
+
+ /* Basic codeunit error handling */
+ PHP_ME(UConverter, getSubstChars, php_converter_getSubstChars_arginfo, ZEND_ACC_PUBLIC)
+ PHP_ME(UConverter, setSubstChars, php_converter_setSubstChars_arginfo, ZEND_ACC_PUBLIC)
+
+ /* Default callback handlers */
+ PHP_ME(UConverter, toUCallback, php_converter_toUCallback_arginfo, ZEND_ACC_PUBLIC)
+ PHP_ME(UConverter, fromUCallback, php_converter_fromUCallback_arginfo, ZEND_ACC_PUBLIC)
+
+ /* Core conversion workhorses */
+ PHP_ME(UConverter, convert, php_converter_convert_arginfo, ZEND_ACC_PUBLIC)
+ PHP_ME(UConverter, transcode, php_converter_transcode_arginfo, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+
+ /* Error inspection */
+ PHP_ME(UConverter, getErrorCode, php_converter_geterrorcode_arginfo, ZEND_ACC_PUBLIC)
+ PHP_ME(UConverter, getErrorMessage, php_converter_geterrormsg_arginfo, ZEND_ACC_PUBLIC)
+
+ /* Ennumeration and lookup */
+ PHP_ME(UConverter, reasonText, php_converter_reasontext_arginfo, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+ PHP_ME(UConverter, getAvailable, php_converter_getavailable_arginfo, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+ PHP_ME(UConverter, getAliases, php_converter_getaliases_arginfo, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+ PHP_ME(UConverter, getStandards, php_converter_getstandards_arginfo, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+ { NULL, NULL, NULL }
+};
+
+/* {{{ Converter create/clone/destroy */
+static void php_converter_free_object(php_converter_object *objval TSRMLS_DC) {
+ if (objval->src) {
+ ucnv_close(objval->src);
+ }
+
+ if (objval->dest) {
+ ucnv_close(objval->dest);
+ }
+
+ intl_error_reset(&(objval->error) TSRMLS_CC);
+ zend_object_std_dtor(&(objval->obj) TSRMLS_CC);
+
+ efree(objval);
+}
+
+static zend_object_value php_converter_object_ctor(zend_class_entry *ce, php_converter_object **pobjval TSRMLS_DC) {
+ php_converter_object *objval;
+ zend_object_value retval;
+
+ objval = ecalloc(1, sizeof(php_converter_object));
+ objval->obj.ce = ce;
+
+#ifdef ZTS
+ objval->tsrm_ls = TSRMLS_C;
+#endif
+ intl_error_init(&(objval->error) TSRMLS_CC);
+
+ retval.handle = zend_objects_store_put(objval, NULL, (zend_objects_free_object_storage_t)php_converter_free_object, NULL TSRMLS_CC);
+ retval.handlers = &php_converter_object_handlers;
+ *pobjval = objval;
+
+ return retval;
+}
+
+static zend_object_value php_converter_create_object(zend_class_entry *ce TSRMLS_DC) {
+ php_converter_object *objval = NULL;
+ zend_object_value retval = php_converter_object_ctor(ce, &objval TSRMLS_CC);
+
+ object_properties_init(&(objval->obj), ce);
+
+ return retval;
+}
+
+static zend_object_value php_converter_clone_object(zval *object TSRMLS_DC) {
+ php_converter_object *objval, *oldobj = (php_converter_object*)zend_objects_get_address(object TSRMLS_CC);
+ zend_object_value retval = php_converter_object_ctor(Z_OBJCE_P(object), &objval TSRMLS_CC);
+ UErrorCode error = U_ZERO_ERROR;
+
+ intl_errors_reset(&oldobj->error TSRMLS_CC);
+
+ objval->src = ucnv_safeClone(oldobj->src, NULL, NULL, &error);
+ if (U_SUCCESS(error)) {
+ error = U_ZERO_ERROR;
+ objval->dest = ucnv_safeClone(oldobj->dest, NULL, NULL, &error);
+ }
+ if (U_FAILURE(error)) {
+ char *err_msg;
+ THROW_UFAILURE(oldobj, "ucnv_safeClone", error);
+
+ err_msg = intl_error_get_message(&oldobj->error TSRMLS_CC);
+ zend_throw_exception(NULL, err_msg, 0 TSRMLS_CC);
+ efree(err_msg);
+
+ return retval;
+ }
+
+ /* Update contexts for converter error handlers */
+ php_converter_set_callbacks(objval, objval->src TSRMLS_CC);
+ php_converter_set_callbacks(objval, objval->dest TSRMLS_CC);
+
+ zend_objects_clone_members(&(objval->obj), retval, &(oldobj->obj), Z_OBJ_HANDLE_P(object) TSRMLS_CC);
+
+ /* Newly cloned object deliberately does not inherit error state from original object */
+
+ return retval;
+}
+/* }}} */
+
+#define CONV_REASON_CONST(v) zend_declare_class_constant_long(php_converter_ce, "REASON_" #v, sizeof("REASON_" #v) - 1, UCNV_ ## v TSRMLS_CC)
+#define CONV_TYPE_CONST(v) zend_declare_class_constant_long(php_converter_ce, #v , sizeof(#v) - 1, UCNV_ ## v TSRMLS_CC)
+
+/* {{{ php_converter_minit */
+int php_converter_minit(INIT_FUNC_ARGS) {
+ zend_class_entry ce;
+
+ INIT_CLASS_ENTRY(ce, "UConverter", php_converter_methods);
+ php_converter_ce = zend_register_internal_class(&ce TSRMLS_CC);
+ php_converter_ce->create_object = php_converter_create_object;
+ memcpy(&php_converter_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
+ php_converter_object_handlers.clone_obj = php_converter_clone_object;
+
+ /* enum UConverterCallbackReason */
+ CONV_REASON_CONST(UNASSIGNED);
+ CONV_REASON_CONST(ILLEGAL);
+ CONV_REASON_CONST(IRREGULAR);
+ CONV_REASON_CONST(RESET);
+ CONV_REASON_CONST(CLOSE);
+ CONV_REASON_CONST(CLONE);
+
+ /* enum UConverterType */
+ CONV_TYPE_CONST(UNSUPPORTED_CONVERTER);
+ CONV_TYPE_CONST(SBCS);
+ CONV_TYPE_CONST(DBCS);
+ CONV_TYPE_CONST(MBCS);
+ CONV_TYPE_CONST(LATIN_1);
+ CONV_TYPE_CONST(UTF8);
+ CONV_TYPE_CONST(UTF16_BigEndian);
+ CONV_TYPE_CONST(UTF16_LittleEndian);
+ CONV_TYPE_CONST(UTF32_BigEndian);
+ CONV_TYPE_CONST(UTF32_LittleEndian);
+ CONV_TYPE_CONST(EBCDIC_STATEFUL);
+ CONV_TYPE_CONST(ISO_2022);
+ CONV_TYPE_CONST(LMBCS_1);
+ CONV_TYPE_CONST(LMBCS_2);
+ CONV_TYPE_CONST(LMBCS_3);
+ CONV_TYPE_CONST(LMBCS_4);
+ CONV_TYPE_CONST(LMBCS_5);
+ CONV_TYPE_CONST(LMBCS_6);
+ CONV_TYPE_CONST(LMBCS_8);
+ CONV_TYPE_CONST(LMBCS_11);
+ CONV_TYPE_CONST(LMBCS_16);
+ CONV_TYPE_CONST(LMBCS_17);
+ CONV_TYPE_CONST(LMBCS_18);
+ CONV_TYPE_CONST(LMBCS_19);
+ CONV_TYPE_CONST(LMBCS_LAST);
+ CONV_TYPE_CONST(HZ);
+ CONV_TYPE_CONST(SCSU);
+ CONV_TYPE_CONST(ISCII);
+ CONV_TYPE_CONST(US_ASCII);
+ CONV_TYPE_CONST(UTF7);
+ CONV_TYPE_CONST(BOCU1);
+ CONV_TYPE_CONST(UTF16);
+ CONV_TYPE_CONST(UTF32);
+ CONV_TYPE_CONST(CESU8);
+ CONV_TYPE_CONST(IMAP_MAILBOX);
+
+ return SUCCESS;
+}
+/* }}} */
+
+/*
+ * 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/intl/converter/converter.h b/ext/intl/converter/converter.h
new file mode 100644
index 0000000000..bd316fcf98
--- /dev/null
+++ b/ext/intl/converter/converter.h
@@ -0,0 +1,28 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | 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. |
+ +----------------------------------------------------------------------+
+ | Authors: Sara Golemon <pollita@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#ifndef PHP_INTL_CONVERTER_H
+#define PHP_INTL_CONVERTER_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "php.h"
+
+int php_converter_minit(INIT_FUNC_ARGS);
+
+#endif /* PHP_INTL_CONVERTER_H */
diff --git a/ext/intl/php_intl.c b/ext/intl/php_intl.c
index d3d477c971..a2c4d77651 100644
--- a/ext/intl/php_intl.c
+++ b/ext/intl/php_intl.c
@@ -34,6 +34,8 @@
#include "collator/collator_create.h"
#include "collator/collator_error.h"
+#include "converter/converter.h"
+
#include "formatter/formatter.h"
#include "formatter/formatter_class.h"
#include "formatter/formatter_attr.h"
@@ -986,6 +988,9 @@ PHP_MINIT_FUNCTION( intl )
/* Global error handling. */
intl_error_init( NULL TSRMLS_CC );
+ /* 'Converter' class for codepage conversions */
+ php_converter_minit(INIT_FUNC_ARGS_PASSTHRU);
+
return SUCCESS;
}
/* }}} */
diff --git a/ext/intl/tests/uconverter___construct_error.phpt b/ext/intl/tests/uconverter___construct_error.phpt
new file mode 100644
index 0000000000..1b2480818b
--- /dev/null
+++ b/ext/intl/tests/uconverter___construct_error.phpt
@@ -0,0 +1,14 @@
+--TEST--
+Basic UConverter::convert() usage
+--INI--
+intl.error_level = E_WARNING
+--SKIPIF--
+<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
+--FILE--
+<?php
+$c = new UConverter('utf-8', "\x80");
+var_dump($c);
+--EXPECTF--
+Warning: UConverter::__construct(): ucnv_open() returned error 4: U_FILE_ACCESS_ERROR in %s on line %d
+object(UConverter)#%d (0) {
+}
diff --git a/ext/intl/tests/uconverter_enum.phpt b/ext/intl/tests/uconverter_enum.phpt
new file mode 100644
index 0000000000..67e02c9d75
--- /dev/null
+++ b/ext/intl/tests/uconverter_enum.phpt
@@ -0,0 +1,21 @@
+--TEST--
+UConverter Enumerations
+--SKIPIF--
+<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
+--FILE--
+<?php
+$avail = UConverter::getAvailable();
+var_dump(count($avail) > 100);
+var_dump(in_array('UTF-7', $avail));
+var_dump(in_array('CESU-8', $avail));
+var_dump(in_array('ISO-8859-1', $avail));
+
+$latin1 = UConverter::getAliases('latin1');
+var_dump(in_array('ISO-8859-1', $latin1));
+
+--EXPECT--
+bool(true)
+bool(true)
+bool(true)
+bool(true)
+bool(true)
diff --git a/ext/intl/tests/uconverter_func_basic.phpt b/ext/intl/tests/uconverter_func_basic.phpt
new file mode 100644
index 0000000000..da8956beae
--- /dev/null
+++ b/ext/intl/tests/uconverter_func_basic.phpt
@@ -0,0 +1,17 @@
+--TEST--
+Basic UConverter::transcode() usage
+--SKIPIF--
+<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
+--FILE--
+<?php
+var_dump(UConverter::transcode("This is an ascii string", 'utf-8', 'latin1'));
+// urlencode so that non-ascii shows up parsable in phpt file
+var_dump(urlencode(UConverter::transcode("Espa\xF1ol", 'utf-8', 'latin1')));
+var_dump(urlencode(UConverter::transcode("Stra\xDFa", 'utf-8', 'latin1')));
+
+var_dump(bin2hex(UConverter::transcode("\xE4", 'utf-8', 'koi8-r')));
+--EXPECT--
+string(23) "This is an ascii string"
+string(12) "Espa%C3%B1ol"
+string(11) "Stra%C3%9Fa"
+string(4) "d094"
diff --git a/ext/intl/tests/uconverter_func_subst.phpt b/ext/intl/tests/uconverter_func_subst.phpt
new file mode 100644
index 0000000000..5cac5ce59c
--- /dev/null
+++ b/ext/intl/tests/uconverter_func_subst.phpt
@@ -0,0 +1,31 @@
+--TEST--
+Basic UConverter::convert() w/ Subsitution
+--SKIPIF--
+<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
+--INI--
+intl.use_exceptions=false
+--FILE--
+<?php
+foreach(array('?','','??') as $subst) {
+ $opts = array('to_subst' => $subst);
+ $ret = UConverter::transcode("This is an ascii string", 'ascii', 'utf-8', $opts);
+ if ($ret === FALSE) {
+ echo "Error: ", intl_get_error_message(), "\n";
+ } else {
+ var_dump($ret);
+ }
+ $ret = UConverter::transcode("Snowman: (\xE2\x98\x83)", 'ascii', 'utf-8', $opts);
+ if ($ret === FALSE) {
+ echo "Error: ", intl_get_error_message(), "\n";
+ } else {
+ var_dump($ret);
+ }
+}
+
+--EXPECTF--
+string(23) "This is an ascii string"
+string(12) "Snowman: (?)"
+Error: transcode() returned error 1: U_ILLEGAL_ARGUMENT_ERROR: U_ILLEGAL_ARGUMENT_ERROR
+Error: transcode() returned error 1: U_ILLEGAL_ARGUMENT_ERROR: U_ILLEGAL_ARGUMENT_ERROR
+Error: transcode() returned error 1: U_ILLEGAL_ARGUMENT_ERROR: U_ILLEGAL_ARGUMENT_ERROR
+Error: transcode() returned error 1: U_ILLEGAL_ARGUMENT_ERROR: U_ILLEGAL_ARGUMENT_ERROR
diff --git a/ext/intl/tests/uconverter_oop_algo.phpt b/ext/intl/tests/uconverter_oop_algo.phpt
new file mode 100644
index 0000000000..349182ce32
--- /dev/null
+++ b/ext/intl/tests/uconverter_oop_algo.phpt
@@ -0,0 +1,18 @@
+--TEST--
+UConverter Algorithmic converters
+--SKIPIF--
+<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
+--FILE--
+<?php
+$c = new UConverter('utf-8', 'latin1');
+var_dump(UConverter::LATIN_1 === $c->getSourceType());
+var_dump(UConverter::UTF8 === $c->getDestinationType());
+
+$c = new UConverter('koi8-r', 'utf-32be');
+var_dump(UConverter::UTF32_BigEndian === $c->getSourceType());
+var_dump(UConverter::SBCS === $c->getDestinationType());
+--EXPECT--
+bool(true)
+bool(true)
+bool(true)
+bool(true)
diff --git a/ext/intl/tests/uconverter_oop_basic.phpt b/ext/intl/tests/uconverter_oop_basic.phpt
new file mode 100644
index 0000000000..2b8909ff31
--- /dev/null
+++ b/ext/intl/tests/uconverter_oop_basic.phpt
@@ -0,0 +1,21 @@
+--TEST--
+Basic UConverter::convert() usage
+--SKIPIF--
+<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
+--FILE--
+<?php
+$c = new UConverter('utf-8', 'latin1');
+var_dump($c->convert("This is an ascii string"));
+// urlencode so that non-ascii shows up parsable in phpt file
+var_dump(urlencode($c->convert("Espa\xF1ol"))); // U+00F1 LATIN SMALL LETTER N WITH TILDE
+var_dump(urlencode($c->convert("Stra\xDFa"))); // U+00DF LATIN SMALL LETTER SHARP S
+var_dump(urlencode($c->convert("Stra\xC3\x9Fa", true))); // Reverse prior op
+
+$k = new UConverter('utf-8', 'koi8-r');
+var_dump(bin2hex($k->convert("\xE4"))); // U+0414 CYRILLIC CAPITAL LETTER DE
+--EXPECT--
+string(23) "This is an ascii string"
+string(12) "Espa%C3%B1ol"
+string(11) "Stra%C3%9Fa"
+string(8) "Stra%DFa"
+string(4) "d094"
diff --git a/ext/intl/tests/uconverter_oop_callback.phpt b/ext/intl/tests/uconverter_oop_callback.phpt
new file mode 100644
index 0000000000..47daf43305
--- /dev/null
+++ b/ext/intl/tests/uconverter_oop_callback.phpt
@@ -0,0 +1,52 @@
+--TEST--
+UConverter::convert() w/ Callback Reasons
+--SKIPIF--
+<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
+--FILE--
+<?php
+class MyConverter extends UConverter {
+ /**
+ * Called during conversion from source encoding to internal UChar representation
+ */
+ public function toUCallback($reason, $source, $codeUnits, &$error) {
+ echo "toUCallback(", UConverter::reasonText($reason), ", ...)\n";
+ return parent::toUCallback($reason, $source, $codeUnits, $error);
+ }
+
+ /**
+ * Called during conversion from internal UChar to destination encoding
+ */
+ public function fromUCallback($reason, $source, $codePoint, &$error) {
+ echo "fromUCallback(", UConverter::reasonText($reason), ", ...)\n";
+ return parent::fromUCallback($reason, $source, $codePoint, $error);
+ }
+
+}
+
+$c = new MyConverter('ascii', 'utf-8');
+foreach(array("regular", "irregul\xC1\xA1r", "\xC2\xA1unsupported!") as $word) {
+ $c->convert($word);
+}
+--EXPECT--
+toUCallback(REASON_RESET, ...)
+toUCallback(REASON_RESET, ...)
+fromUCallback(REASON_RESET, ...)
+fromUCallback(REASON_RESET, ...)
+toUCallback(REASON_RESET, ...)
+toUCallback(REASON_ILLEGAL, ...)
+toUCallback(REASON_RESET, ...)
+toUCallback(REASON_ILLEGAL, ...)
+fromUCallback(REASON_RESET, ...)
+fromUCallback(REASON_UNASSIGNED, ...)
+fromUCallback(REASON_RESET, ...)
+fromUCallback(REASON_UNASSIGNED, ...)
+toUCallback(REASON_RESET, ...)
+toUCallback(REASON_RESET, ...)
+fromUCallback(REASON_RESET, ...)
+fromUCallback(REASON_UNASSIGNED, ...)
+fromUCallback(REASON_RESET, ...)
+fromUCallback(REASON_UNASSIGNED, ...)
+toUCallback(REASON_CLOSE, ...)
+fromUCallback(REASON_CLOSE, ...)
+toUCallback(REASON_CLOSE, ...)
+fromUCallback(REASON_CLOSE, ...)
diff --git a/ext/intl/tests/uconverter_oop_callback_return.phpt b/ext/intl/tests/uconverter_oop_callback_return.phpt
new file mode 100644
index 0000000000..cd7e7a5834
--- /dev/null
+++ b/ext/intl/tests/uconverter_oop_callback_return.phpt
@@ -0,0 +1,40 @@
+--TEST--
+UConverter::convert() w/ Callback Return Values
+--SKIPIF--
+<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
+--FILE--
+<?php
+class MyConverter extends UConverter {
+ public function toUCallback($reason, $source, $codeUnits, &$error) {
+ $error = U_ZERO_ERROR;
+ switch ($codeUnits) {
+ case "\x80": return NULL;
+ case "\x81": return 'a';
+ case "\x82": return ord('b');
+ case "\x83": return array('c');
+ }
+ }
+
+ /**
+ * Called during conversion from internal UChar to destination encoding
+ */
+ public function fromUCallback($reason, $source, $codePoint, &$error) {
+ $error = U_ZERO_ERROR;
+ switch ($codePoint) {
+ case 0x00F1: return "A";
+ case 0x00F2: return ord("B");
+ case 0x00F3: return array("C");
+ case 0x00F4: return NULL;
+ }
+ }
+
+}
+
+$c = new MyConverter('ascii', 'utf-8');
+// This line will trigger toUCallback
+var_dump($c->convert("\x80\x81\x82\x83"));
+// This line will trigger fromUCallback
+var_dump($c->convert("\xC3\xB1\xC3\xB2\xC3\xB3\xC3\xB4"));
+--EXPECT--
+string(3) "abc"
+string(3) "ABC"
diff --git a/ext/intl/tests/uconverter_oop_subst.phpt b/ext/intl/tests/uconverter_oop_subst.phpt
new file mode 100644
index 0000000000..d21d95f8d0
--- /dev/null
+++ b/ext/intl/tests/uconverter_oop_subst.phpt
@@ -0,0 +1,24 @@
+--TEST--
+Basic UConverter::convert() w/ Subsitution
+--SKIPIF--
+<?php if( !extension_loaded( 'intl' ) ) print 'skip'; ?>
+--INI--
+intl.use_exceptions=false
+--FILE--
+<?php
+$c = new UConverter('ascii', 'utf-8');
+
+foreach(array('?','','<unknown>') as $subst) {
+ if (!$c->setSubstChars($subst)) {
+ echo "**Disallowed\n";
+ continue;
+ }
+ var_dump($c->convert("This is an ascii string"));
+ var_dump($c->convert("Snowman: (\xE2\x98\x83)"));
+}
+
+--EXPECT--
+string(23) "This is an ascii string"
+string(12) "Snowman: (?)"
+**Disallowed
+**Disallowed
diff --git a/ext/mysqlnd/mysqlnd_structs.h b/ext/mysqlnd/mysqlnd_structs.h
index ecb1d89216..b88004a9f1 100644
--- a/ext/mysqlnd/mysqlnd_structs.h
+++ b/ext/mysqlnd/mysqlnd_structs.h
@@ -195,7 +195,7 @@ typedef struct st_mysqlnd_net_options
unsigned int timeout_read;
unsigned int timeout_write;
- unsigned int net_read_buffer_size;
+ size_t net_read_buffer_size;
/* SSL information */
char *ssl_key;
diff --git a/ext/pdo/pdo_stmt.c b/ext/pdo/pdo_stmt.c
index a469d09fc2..5dc445ff8d 100644
--- a/ext/pdo/pdo_stmt.c
+++ b/ext/pdo/pdo_stmt.c
@@ -2733,6 +2733,7 @@ static union _zend_function *row_get_ctor(zval *object TSRMLS_DC)
ctor.function_name = "__construct";
ctor.scope = pdo_row_ce;
ctor.handler = ZEND_FN(dbstmt_constructor);
+ ctor.fn_flags = ZEND_ACC_PUBLIC;
return (union _zend_function*)&ctor;
}
diff --git a/ext/pdo/tests/pdo_036.phpt b/ext/pdo/tests/pdo_036.phpt
index 94006c9e80..55c88762ba 100644
--- a/ext/pdo/tests/pdo_036.phpt
+++ b/ext/pdo/tests/pdo_036.phpt
@@ -5,19 +5,19 @@ Testing PDORow and PDOStatement instances with Reflection
--FILE--
<?php
-$instance = new reflectionclass('pdorow');
+$instance = new reflectionclass('pdostatement');
$x = $instance->newInstance();
var_dump($x);
-$instance = new reflectionclass('pdostatement');
+$instance = new reflectionclass('pdorow');
$x = $instance->newInstance();
var_dump($x);
?>
--EXPECTF--
-object(PDORow)#%d (0) {
-}
object(PDOStatement)#%d (1) {
[%u|b%"queryString"]=>
NULL
}
+
+Fatal error: PDORow::__construct(): You should not create a PDOStatement manually in %spdo_036.php on line %d
diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c
index ff3a6a5087..15befa2fc7 100644
--- a/ext/reflection/php_reflection.c
+++ b/ext/reflection/php_reflection.c
@@ -4192,32 +4192,40 @@ ZEND_METHOD(reflection_class, newInstance)
{
zval *retval_ptr = NULL;
reflection_object *intern;
- zend_class_entry *ce;
+ zend_class_entry *ce, *old_scope;
+ zend_function *constructor;
METHOD_NOTSTATIC(reflection_class_ptr);
GET_REFLECTION_OBJECT_PTR(ce);
+ object_init_ex(return_value, ce);
+
+ old_scope = EG(scope);
+ EG(scope) = ce;
+ constructor = Z_OBJ_HT_P(return_value)->get_constructor(return_value TSRMLS_CC);
+ EG(scope) = old_scope;
+
/* Run the constructor if there is one */
- if (ce->constructor) {
+ if (constructor) {
zval ***params = NULL;
int num_args = 0;
zend_fcall_info fci;
zend_fcall_info_cache fcc;
- if (!(ce->constructor->common.fn_flags & ZEND_ACC_PUBLIC)) {
+ if (!(constructor->common.fn_flags & ZEND_ACC_PUBLIC)) {
zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Access to non-public constructor of class %s", ce->name);
- return;
+ zval_dtor(return_value);
+ RETURN_NULL();
}
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "*", &params, &num_args) == FAILURE) {
if (params) {
efree(params);
}
+ zval_dtor(return_value);
RETURN_FALSE;
}
- object_init_ex(return_value, ce);
-
fci.size = sizeof(fci);
fci.function_table = EG(function_table);
fci.function_name = NULL;
@@ -4229,7 +4237,7 @@ ZEND_METHOD(reflection_class, newInstance)
fci.no_separation = 1;
fcc.initialized = 1;
- fcc.function_handler = ce->constructor;
+ fcc.function_handler = constructor;
fcc.calling_scope = EG(scope);
fcc.called_scope = Z_OBJCE_P(return_value);
fcc.object_ptr = return_value;
@@ -4242,6 +4250,7 @@ ZEND_METHOD(reflection_class, newInstance)
zval_ptr_dtor(&retval_ptr);
}
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invocation of %s's constructor failed", ce->name);
+ zval_dtor(return_value);
RETURN_NULL();
}
if (retval_ptr) {
@@ -4250,9 +4259,7 @@ ZEND_METHOD(reflection_class, newInstance)
if (params) {
efree(params);
}
- } else if (!ZEND_NUM_ARGS()) {
- object_init_ex(return_value, ce);
- } else {
+ } else if (ZEND_NUM_ARGS()) {
zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Class %s does not have a constructor, so you cannot pass any constructor arguments", ce->name);
}
}
@@ -4282,9 +4289,10 @@ ZEND_METHOD(reflection_class, newInstanceArgs)
{
zval *retval_ptr = NULL;
reflection_object *intern;
- zend_class_entry *ce;
+ zend_class_entry *ce, *old_scope;
int argc = 0;
HashTable *args;
+ zend_function *constructor;
METHOD_NOTSTATIC(reflection_class_ptr);
@@ -4293,19 +4301,28 @@ ZEND_METHOD(reflection_class, newInstanceArgs)
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|h", &args) == FAILURE) {
return;
}
+
if (ZEND_NUM_ARGS() > 0) {
argc = args->nNumOfElements;
}
+ object_init_ex(return_value, ce);
+
+ old_scope = EG(scope);
+ EG(scope) = ce;
+ constructor = Z_OBJ_HT_P(return_value)->get_constructor(return_value TSRMLS_CC);
+ EG(scope) = old_scope;
+
/* Run the constructor if there is one */
- if (ce->constructor) {
+ if (constructor) {
zval ***params = NULL;
zend_fcall_info fci;
zend_fcall_info_cache fcc;
- if (!(ce->constructor->common.fn_flags & ZEND_ACC_PUBLIC)) {
+ if (!(constructor->common.fn_flags & ZEND_ACC_PUBLIC)) {
zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Access to non-public constructor of class %s", ce->name);
- return;
+ zval_dtor(return_value);
+ RETURN_NULL();
}
if (argc) {
@@ -4314,8 +4331,6 @@ ZEND_METHOD(reflection_class, newInstanceArgs)
params -= argc;
}
- object_init_ex(return_value, ce);
-
fci.size = sizeof(fci);
fci.function_table = EG(function_table);
fci.function_name = NULL;
@@ -4327,7 +4342,7 @@ ZEND_METHOD(reflection_class, newInstanceArgs)
fci.no_separation = 1;
fcc.initialized = 1;
- fcc.function_handler = ce->constructor;
+ fcc.function_handler = constructor;
fcc.calling_scope = EG(scope);
fcc.called_scope = Z_OBJCE_P(return_value);
fcc.object_ptr = return_value;
@@ -4340,6 +4355,7 @@ ZEND_METHOD(reflection_class, newInstanceArgs)
zval_ptr_dtor(&retval_ptr);
}
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invocation of %s's constructor failed", ce->name);
+ zval_dtor(return_value);
RETURN_NULL();
}
if (retval_ptr) {
@@ -4348,9 +4364,7 @@ ZEND_METHOD(reflection_class, newInstanceArgs)
if (params) {
efree(params);
}
- } else if (!ZEND_NUM_ARGS() || !argc) {
- object_init_ex(return_value, ce);
- } else {
+ } else if (argc) {
zend_throw_exception_ex(reflection_exception_ptr, 0 TSRMLS_CC, "Class %s does not have a constructor, so you cannot pass any constructor arguments", ce->name);
}
}
diff --git a/ext/reflection/tests/bug64007.phpt b/ext/reflection/tests/bug64007.phpt
new file mode 100644
index 0000000000..32ec6a5610
--- /dev/null
+++ b/ext/reflection/tests/bug64007.phpt
@@ -0,0 +1,19 @@
+--TEST--
+Bug #64007 (There is an ability to create instance of Generator by hand)
+--FILE--
+<?php
+$reflection = new ReflectionClass('Generator');
+try {
+ $generator = $reflection->newInstanceWithoutConstructor();
+ var_dump($generator);
+} catch (Exception $e) {
+ var_dump($e->getMessage());
+}
+
+$generator = $reflection->newInstance();
+var_dump($generator);
+?>
+--EXPECTF--
+string(97) "Class Generator is an internal class that cannot be instantiated without invoking its constructor"
+
+Catchable fatal error: The "Generator" class is reserved for internal use and cannot be manually instantiated in %sbug64007.php on line %d
diff --git a/ext/spl/spl_directory.c b/ext/spl/spl_directory.c
index 61d6324d52..f43a3709e1 100644
--- a/ext/spl/spl_directory.c
+++ b/ext/spl/spl_directory.c
@@ -1874,6 +1874,10 @@ static int spl_filesystem_object_cast(zval *readobj, zval *writeobj, int type TS
spl_filesystem_object *intern = (spl_filesystem_object*)zend_object_store_get_object(readobj TSRMLS_CC);
if (type == IS_STRING) {
+ if (Z_OBJCE_P(readobj)->__tostring) {
+ return std_object_handlers.cast_object(readobj, writeobj, type TSRMLS_CC);
+ }
+
switch (intern->type) {
case SPL_FS_INFO:
case SPL_FS_FILE:
diff --git a/ext/spl/tests/bug64023.phpt b/ext/spl/tests/bug64023.phpt
new file mode 100644
index 0000000000..2c177f9512
--- /dev/null
+++ b/ext/spl/tests/bug64023.phpt
@@ -0,0 +1,20 @@
+--TEST--
+Bug #64023: Overloading __toString() in SplFileInfo has no effect
+--FILE--
+<?php
+class A extends \SplFileInfo
+{
+ public function __toString() {return ' -expected- ';}
+}
+
+$a = new A('/');
+
+// Works
+echo $a, $a->__toString(), $a->__toString() . '', "\n";
+
+// Does not work - outputs parent::__toString()
+echo $a . '', "\n";
+
+--EXPECT--
+ -expected- -expected- -expected-
+ -expected-
diff --git a/ext/standard/html.c b/ext/standard/html.c
index 79a6737ca5..414fa65c91 100644
--- a/ext/standard/html.c
+++ b/ext/standard/html.c
@@ -1628,8 +1628,8 @@ PHP_FUNCTION(get_html_translation_table)
unsigned i, j, k,
max_i, max_j, max_k;
/* no mapping to unicode required */
- if (CHARSET_SINGLE_BYTE(charset)) {
- max_i = 1; max_j = 1; max_k = 64;
+ if (CHARSET_SINGLE_BYTE(charset)) { /* ISO-8859-1 */
+ max_i = 1; max_j = 4; max_k = 64;
} else {
max_i = 0x1E; max_j = 64; max_k = 64;
}
diff --git a/ext/standard/http_fopen_wrapper.c b/ext/standard/http_fopen_wrapper.c
index 85a61167aa..870f904e9c 100644
--- a/ext/standard/http_fopen_wrapper.c
+++ b/ext/standard/http_fopen_wrapper.c
@@ -113,6 +113,7 @@ php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, char *path,
int redirected = ((flags & HTTP_WRAPPER_REDIRECTED) != 0);
int follow_location = 1;
php_stream_filter *transfer_encoding = NULL;
+ int response_code;
tmp_line[0] = '\0';
@@ -657,7 +658,6 @@ finish:
if (php_stream_get_line(stream, tmp_line, sizeof(tmp_line) - 1, &tmp_line_len) != NULL) {
zval *http_response;
- int response_code;
if (tmp_line_len > 9) {
response_code = atoi(tmp_line + 9);
@@ -731,7 +731,9 @@ finish:
http_header_line[http_header_line_length] = '\0';
if (!strncasecmp(http_header_line, "Location: ", 10)) {
- if (context && php_stream_context_get_option(context, "http", "follow_location", &tmpzval) == SUCCESS) {
+ /* we only care about Location for 300, 301, 302, 303 and 307 */
+ /* see http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.1 */
+ if ((response_code >= 300 && response_code < 304 || 307 == response_code) && context && php_stream_context_get_option(context, "http", "follow_location", &tmpzval) == SUCCESS) {
SEPARATE_ZVAL(tmpzval);
convert_to_long_ex(tmpzval);
follow_location = Z_LVAL_PP(tmpzval);
diff --git a/ext/standard/tests/strings/get_html_translation_table_basic10.phpt b/ext/standard/tests/strings/get_html_translation_table_basic10.phpt
new file mode 100644
index 0000000000..a5a356885d
--- /dev/null
+++ b/ext/standard/tests/strings/get_html_translation_table_basic10.phpt
@@ -0,0 +1,121 @@
+--TEST--
+Test get_html_translation_table() function: htmlentities/HTML 4/ISO-8859-1 (bug #64011)
+--FILE--
+<?php
+
+function so($a,$b) { return ord($a) - ord($b); }
+
+$table = HTML_ENTITIES;
+$tt = get_html_translation_table($table, ENT_COMPAT, "ISO-8859-1");
+uksort( $tt, 'so' );
+var_dump( count($tt) );
+print_r( $tt );
+echo "Done\n";
+
+?>
+--EXPECT--
+int(100)
+Array
+(
+ ["] => &quot;
+ [&] => &amp;
+ [<] => &lt;
+ [>] => &gt;
+ [ ] => &nbsp;
+ [¡] => &iexcl;
+ [¢] => &cent;
+ [£] => &pound;
+ [¤] => &curren;
+ [¥] => &yen;
+ [¦] => &brvbar;
+ [§] => &sect;
+ [¨] => &uml;
+ [©] => &copy;
+ [ª] => &ordf;
+ [«] => &laquo;
+ [¬] => &not;
+ [­] => &shy;
+ [®] => &reg;
+ [¯] => &macr;
+ [°] => &deg;
+ [±] => &plusmn;
+ [²] => &sup2;
+ [³] => &sup3;
+ [´] => &acute;
+ [µ] => &micro;
+ [¶] => &para;
+ [·] => &middot;
+ [¸] => &cedil;
+ [¹] => &sup1;
+ [º] => &ordm;
+ [»] => &raquo;
+ [¼] => &frac14;
+ [½] => &frac12;
+ [¾] => &frac34;
+ [¿] => &iquest;
+ [À] => &Agrave;
+ [Á] => &Aacute;
+ [Â] => &Acirc;
+ [Ã] => &Atilde;
+ [Ä] => &Auml;
+ [Å] => &Aring;
+ [Æ] => &AElig;
+ [Ç] => &Ccedil;
+ [È] => &Egrave;
+ [É] => &Eacute;
+ [Ê] => &Ecirc;
+ [Ë] => &Euml;
+ [Ì] => &Igrave;
+ [Í] => &Iacute;
+ [Î] => &Icirc;
+ [Ï] => &Iuml;
+ [Ð] => &ETH;
+ [Ñ] => &Ntilde;
+ [Ò] => &Ograve;
+ [Ó] => &Oacute;
+ [Ô] => &Ocirc;
+ [Õ] => &Otilde;
+ [Ö] => &Ouml;
+ [×] => &times;
+ [Ø] => &Oslash;
+ [Ù] => &Ugrave;
+ [Ú] => &Uacute;
+ [Û] => &Ucirc;
+ [Ü] => &Uuml;
+ [Ý] => &Yacute;
+ [Þ] => &THORN;
+ [ß] => &szlig;
+ [à] => &agrave;
+ [á] => &aacute;
+ [â] => &acirc;
+ [ã] => &atilde;
+ [ä] => &auml;
+ [å] => &aring;
+ [æ] => &aelig;
+ [ç] => &ccedil;
+ [è] => &egrave;
+ [é] => &eacute;
+ [ê] => &ecirc;
+ [ë] => &euml;
+ [ì] => &igrave;
+ [í] => &iacute;
+ [î] => &icirc;
+ [ï] => &iuml;
+ [ð] => &eth;
+ [ñ] => &ntilde;
+ [ò] => &ograve;
+ [ó] => &oacute;
+ [ô] => &ocirc;
+ [õ] => &otilde;
+ [ö] => &ouml;
+ [÷] => &divide;
+ [ø] => &oslash;
+ [ù] => &ugrave;
+ [ú] => &uacute;
+ [û] => &ucirc;
+ [ü] => &uuml;
+ [ý] => &yacute;
+ [þ] => &thorn;
+ [ÿ] => &yuml;
+)
+Done
diff --git a/ext/standard/var_unserializer.c b/ext/standard/var_unserializer.c
index 857b2d4568..3730ff8e81 100644
--- a/ext/standard/var_unserializer.c
+++ b/ext/standard/var_unserializer.c
@@ -1,4 +1,4 @@
-/* Generated by re2c 0.13.5 */
+/* Generated by re2c 0.13.5 on Mon Jan 21 11:41:53 2013 */
#line 1 "ext/standard/var_unserializer.re"
/*
+----------------------------------------------------------------------+
@@ -427,7 +427,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER)
-#line 425 "ext/standard/var_unserializer.c"
+#line 431 "ext/standard/var_unserializer.c"
{
YYCTYPE yych;
static const unsigned char yybm[] = {
@@ -487,9 +487,9 @@ yy2:
yych = *(YYMARKER = ++YYCURSOR);
if (yych == ':') goto yy95;
yy3:
-#line 747 "ext/standard/var_unserializer.re"
+#line 759 "ext/standard/var_unserializer.re"
{ return 0; }
-#line 487 "ext/standard/var_unserializer.c"
+#line 493 "ext/standard/var_unserializer.c"
yy4:
yych = *(YYMARKER = ++YYCURSOR);
if (yych == ':') goto yy89;
@@ -532,13 +532,13 @@ yy13:
goto yy3;
yy14:
++YYCURSOR;
-#line 741 "ext/standard/var_unserializer.re"
+#line 753 "ext/standard/var_unserializer.re"
{
/* this is the case where we have less data than planned */
php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Unexpected end of serialized data");
return 0; /* not sure if it should be 0 or 1 here? */
}
-#line 536 "ext/standard/var_unserializer.c"
+#line 542 "ext/standard/var_unserializer.c"
yy16:
yych = *++YYCURSOR;
goto yy3;
@@ -568,7 +568,7 @@ yy20:
yych = *++YYCURSOR;
if (yych != '"') goto yy18;
++YYCURSOR;
-#line 624 "ext/standard/var_unserializer.re"
+#line 630 "ext/standard/var_unserializer.re"
{
size_t len, len2, len3, maxlen;
long elements;
@@ -691,7 +691,7 @@ yy20:
return object_common2(UNSERIALIZE_PASSTHRU, elements);
}
-#line 683 "ext/standard/var_unserializer.c"
+#line 695 "ext/standard/var_unserializer.c"
yy25:
yych = *++YYCURSOR;
if (yych <= ',') {
@@ -716,7 +716,7 @@ yy27:
yych = *++YYCURSOR;
if (yych != '"') goto yy18;
++YYCURSOR;
-#line 616 "ext/standard/var_unserializer.re"
+#line 622 "ext/standard/var_unserializer.re"
{
INIT_PZVAL(*rval);
@@ -724,7 +724,7 @@ yy27:
return object_common2(UNSERIALIZE_PASSTHRU,
object_common1(UNSERIALIZE_PASSTHRU, ZEND_STANDARD_CLASS_DEF_PTR));
}
-#line 716 "ext/standard/var_unserializer.c"
+#line 728 "ext/standard/var_unserializer.c"
yy32:
yych = *++YYCURSOR;
if (yych == '+') goto yy33;
@@ -745,7 +745,7 @@ yy34:
yych = *++YYCURSOR;
if (yych != '{') goto yy18;
++YYCURSOR;
-#line 596 "ext/standard/var_unserializer.re"
+#line 602 "ext/standard/var_unserializer.re"
{
long elements = parse_iv(start + 2);
/* use iv() not uiv() in order to check data range */
@@ -765,7 +765,7 @@ yy34:
return finish_nested_data(UNSERIALIZE_PASSTHRU);
}
-#line 757 "ext/standard/var_unserializer.c"
+#line 769 "ext/standard/var_unserializer.c"
yy39:
yych = *++YYCURSOR;
if (yych == '+') goto yy40;
@@ -786,7 +786,7 @@ yy41:
yych = *++YYCURSOR;
if (yych != '"') goto yy18;
++YYCURSOR;
-#line 567 "ext/standard/var_unserializer.re"
+#line 573 "ext/standard/var_unserializer.re"
{
size_t len, maxlen;
char *str;
@@ -815,7 +815,7 @@ yy41:
ZVAL_STRINGL(*rval, str, len, 0);
return 1;
}
-#line 807 "ext/standard/var_unserializer.c"
+#line 819 "ext/standard/var_unserializer.c"
yy46:
yych = *++YYCURSOR;
if (yych == '+') goto yy47;
@@ -836,7 +836,7 @@ yy48:
yych = *++YYCURSOR;
if (yych != '"') goto yy18;
++YYCURSOR;
-#line 539 "ext/standard/var_unserializer.re"
+#line 545 "ext/standard/var_unserializer.re"
{
size_t len, maxlen;
char *str;
@@ -864,7 +864,7 @@ yy48:
ZVAL_STRINGL(*rval, str, len, 1);
return 1;
}
-#line 856 "ext/standard/var_unserializer.c"
+#line 868 "ext/standard/var_unserializer.c"
yy53:
yych = *++YYCURSOR;
if (yych <= '/') {
@@ -952,7 +952,7 @@ yy61:
}
yy63:
++YYCURSOR;
-#line 529 "ext/standard/var_unserializer.re"
+#line 535 "ext/standard/var_unserializer.re"
{
#if SIZEOF_LONG == 4
use_double:
@@ -962,7 +962,7 @@ use_double:
ZVAL_DOUBLE(*rval, zend_strtod((const char *)start + 2, NULL));
return 1;
}
-#line 954 "ext/standard/var_unserializer.c"
+#line 966 "ext/standard/var_unserializer.c"
yy65:
yych = *++YYCURSOR;
if (yych <= ',') {
@@ -1021,7 +1021,7 @@ yy73:
yych = *++YYCURSOR;
if (yych != ';') goto yy18;
++YYCURSOR;
-#line 514 "ext/standard/var_unserializer.re"
+#line 520 "ext/standard/var_unserializer.re"
{
*p = YYCURSOR;
INIT_PZVAL(*rval);
@@ -1036,7 +1036,7 @@ yy73:
return 1;
}
-#line 1028 "ext/standard/var_unserializer.c"
+#line 1040 "ext/standard/var_unserializer.c"
yy76:
yych = *++YYCURSOR;
if (yych == 'N') goto yy73;
@@ -1063,7 +1063,7 @@ yy79:
if (yych <= '9') goto yy79;
if (yych != ';') goto yy18;
++YYCURSOR;
-#line 487 "ext/standard/var_unserializer.re"
+#line 493 "ext/standard/var_unserializer.re"
{
#if SIZEOF_LONG == 4
int digits = YYCURSOR - start - 3;
@@ -1090,7 +1090,7 @@ yy79:
ZVAL_LONG(*rval, parse_iv(start + 2));
return 1;
}
-#line 1082 "ext/standard/var_unserializer.c"
+#line 1094 "ext/standard/var_unserializer.c"
yy83:
yych = *++YYCURSOR;
if (yych <= '/') goto yy18;
@@ -1098,24 +1098,24 @@ yy83:
yych = *++YYCURSOR;
if (yych != ';') goto yy18;
++YYCURSOR;
-#line 480 "ext/standard/var_unserializer.re"
+#line 486 "ext/standard/var_unserializer.re"
{
*p = YYCURSOR;
INIT_PZVAL(*rval);
ZVAL_BOOL(*rval, parse_iv(start + 2));
return 1;
}
-#line 1097 "ext/standard/var_unserializer.c"
+#line 1109 "ext/standard/var_unserializer.c"
yy87:
++YYCURSOR;
-#line 473 "ext/standard/var_unserializer.re"
+#line 479 "ext/standard/var_unserializer.re"
{
*p = YYCURSOR;
INIT_PZVAL(*rval);
ZVAL_NULL(*rval);
return 1;
}
-#line 1107 "ext/standard/var_unserializer.c"
+#line 1119 "ext/standard/var_unserializer.c"
yy89:
yych = *++YYCURSOR;
if (yych <= ',') {
@@ -1138,7 +1138,7 @@ yy91:
if (yych <= '9') goto yy91;
if (yych != ';') goto yy18;
++YYCURSOR;
-#line 450 "ext/standard/var_unserializer.re"
+#line 456 "ext/standard/var_unserializer.re"
{
long id;
@@ -1161,7 +1161,7 @@ yy91:
return 1;
}
-#line 1153 "ext/standard/var_unserializer.c"
+#line 1165 "ext/standard/var_unserializer.c"
yy95:
yych = *++YYCURSOR;
if (yych <= ',') {
@@ -1184,7 +1184,7 @@ yy97:
if (yych <= '9') goto yy97;
if (yych != ';') goto yy18;
++YYCURSOR;
-#line 429 "ext/standard/var_unserializer.re"
+#line 435 "ext/standard/var_unserializer.re"
{
long id;
@@ -1205,9 +1205,9 @@ yy97:
return 1;
}
-#line 1197 "ext/standard/var_unserializer.c"
+#line 1209 "ext/standard/var_unserializer.c"
}
-#line 749 "ext/standard/var_unserializer.re"
+#line 761 "ext/standard/var_unserializer.re"
return 0;
diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re
index e54449a78c..204995783f 100644
--- a/ext/standard/var_unserializer.re
+++ b/ext/standard/var_unserializer.re
@@ -678,10 +678,13 @@ object ":" uiv ":" ["] {
do {
/* Try to find class directly */
+ BG(serialize_lock) = 1;
if (zend_lookup_class(class_name, len2, &pce TSRMLS_CC) == SUCCESS) {
+ BG(serialize_lock) = 0;
ce = *pce;
break;
}
+ BG(serialize_lock) = 0;
/* Check for unserialize callback */
if ((PG(unserialize_callback_func) == NULL) || (PG(unserialize_callback_func)[0] == '\0')) {
@@ -696,7 +699,9 @@ object ":" uiv ":" ["] {
args[0] = &arg_func_name;
MAKE_STD_ZVAL(arg_func_name);
ZVAL_STRING(arg_func_name, class_name, 1);
+ BG(serialize_lock) = 1;
if (call_user_function_ex(CG(function_table), NULL, user_func, &retval_ptr, 1, args, 0, NULL TSRMLS_CC) != SUCCESS) {
+ BG(serialize_lock) = 0;
php_error_docref(NULL TSRMLS_CC, E_WARNING, "defined (%s) but not found", user_func->value.str.val);
incomplete_class = 1;
ce = PHP_IC_ENTRY;
@@ -704,6 +709,7 @@ object ":" uiv ":" ["] {
zval_ptr_dtor(&arg_func_name);
break;
}
+ BG(serialize_lock) = 0;
if (retval_ptr) {
zval_ptr_dtor(&retval_ptr);
}
diff --git a/main/main.c b/main/main.c
index f87a1427fe..325ef7ed53 100644
--- a/main/main.c
+++ b/main/main.c
@@ -521,6 +521,7 @@ PHP_INI_BEGIN()
STD_PHP_INI_ENTRY("default_mimetype", SAPI_DEFAULT_MIMETYPE, PHP_INI_ALL, OnUpdateString, default_mimetype, sapi_globals_struct,sapi_globals)
STD_PHP_INI_ENTRY("error_log", NULL, PHP_INI_ALL, OnUpdateErrorLog, error_log, php_core_globals, core_globals)
STD_PHP_INI_ENTRY("extension_dir", PHP_EXTENSION_DIR, PHP_INI_SYSTEM, OnUpdateStringUnempty, extension_dir, php_core_globals, core_globals)
+ STD_PHP_INI_ENTRY("sys_temp_dir", NULL, PHP_INI_SYSTEM, OnUpdateStringUnempty, sys_temp_dir, php_core_globals, core_globals)
STD_PHP_INI_ENTRY("include_path", PHP_INCLUDE_PATH, PHP_INI_ALL, OnUpdateStringUnempty, include_path, php_core_globals, core_globals)
PHP_INI_ENTRY("max_execution_time", "30", PHP_INI_ALL, OnUpdateTimeout)
STD_PHP_INI_ENTRY("open_basedir", NULL, PHP_INI_ALL, OnUpdateBaseDir, open_basedir, php_core_globals, core_globals)
diff --git a/main/php_globals.h b/main/php_globals.h
index 170431d079..256765d665 100644
--- a/main/php_globals.h
+++ b/main/php_globals.h
@@ -85,6 +85,7 @@ struct _php_core_globals {
char *open_basedir;
char *extension_dir;
char *php_binary;
+ char *sys_temp_dir;
char *upload_tmp_dir;
long upload_max_filesize;
diff --git a/main/php_open_temporary_file.c b/main/php_open_temporary_file.c
index b43d6a7835..054d497be6 100644
--- a/main/php_open_temporary_file.c
+++ b/main/php_open_temporary_file.c
@@ -189,13 +189,28 @@ PHPAPI void php_shutdown_temporary_directory(void)
/*
* Determine where to place temporary files.
*/
-PHPAPI const char* php_get_temporary_directory(void)
+PHPAPI const char* php_get_temporary_directory(TSRMLS_D)
{
/* Did we determine the temporary directory already? */
if (temporary_directory) {
return temporary_directory;
}
+ /* Is there a temporary directory "sys_temp_dir" in .ini defined? */
+ {
+ char *sys_temp_dir = PG(sys_temp_dir);
+ if (sys_temp_dir) {
+ int len = strlen(sys_temp_dir);
+ if (len >= 2 && sys_temp_dir[len - 1] == DEFAULT_SLASH) {
+ temporary_directory = zend_strndup(sys_temp_dir, len - 1);
+ return temporary_directory;
+ } else if (len >= 1 && sys_temp_dir[len - 1] != DEFAULT_SLASH) {
+ temporary_directory = zend_strndup(sys_temp_dir, len);
+ return temporary_directory;
+ }
+ }
+ }
+
#ifdef PHP_WIN32
/* We can't count on the environment variables TEMP or TMP,
* and so must make the Win32 API call to get the default
@@ -263,7 +278,7 @@ PHPAPI int php_open_temporary_fd_ex(const char *dir, const char *pfx, char **ope
if (!dir || *dir == '\0') {
def_tmp:
- temp_dir = php_get_temporary_directory();
+ temp_dir = php_get_temporary_directory(TSRMLS_C);
if (temp_dir && *temp_dir != '\0' && (!open_basedir_check || !php_check_open_basedir(temp_dir TSRMLS_CC))) {
return php_do_open_temporary_file(temp_dir, pfx, opened_path_p TSRMLS_CC);
@@ -294,12 +309,12 @@ PHPAPI FILE *php_open_temporary_file(const char *dir, const char *pfx, char **op
if (fd == -1) {
return NULL;
}
-
+
fp = fdopen(fd, "r+b");
if (fp == NULL) {
close(fd);
}
-
+
return fp;
}
/* }}} */
diff --git a/main/streams/php_stream_plain_wrapper.h b/main/streams/php_stream_plain_wrapper.h
index 4b3875577d..d88b30c479 100644
--- a/main/streams/php_stream_plain_wrapper.h
+++ b/main/streams/php_stream_plain_wrapper.h
@@ -31,7 +31,7 @@ PHPAPI php_stream *_php_stream_fopen(const char *filename, const char *mode, cha
#define php_stream_fopen(filename, mode, opened) _php_stream_fopen((filename), (mode), (opened), 0 STREAMS_CC TSRMLS_CC)
PHPAPI php_stream *_php_stream_fopen_with_path(char *filename, char *mode, char *path, char **opened_path, int options STREAMS_DC TSRMLS_DC);
-#define php_stream_fopen_with_path(filename, mode, path, opened) _php_stream_fopen_with_path((filename), (mode), (path), (opened) STREAMS_CC TSRMLS_CC)
+#define php_stream_fopen_with_path(filename, mode, path, opened) _php_stream_fopen_with_path((filename), (mode), (path), (opened), 0 STREAMS_CC TSRMLS_CC)
PHPAPI php_stream *_php_stream_fopen_from_file(FILE *file, const char *mode STREAMS_DC TSRMLS_DC);
#define php_stream_fopen_from_file(file, mode) _php_stream_fopen_from_file((file), (mode) STREAMS_CC TSRMLS_CC)
diff --git a/php.ini-development b/php.ini-development
index a97cd0f9da..93a4b7d8a5 100644
--- a/php.ini-development
+++ b/php.ini-development
@@ -729,6 +729,10 @@ user_dir =
; On windows:
; extension_dir = "ext"
+; Directory where the temporary files should be placed.
+; Defaults to the system default (see sys_get_temp_dir)
+; sys_temp_dir = "/tmp"
+
; Whether or not to enable the dl() function. The dl() function does NOT work
; properly in multithreaded servers, such as IIS or Zeus, and is automatically
; disabled on them.
diff --git a/php.ini-production b/php.ini-production
index dce8fc970c..7d84c9b879 100644
--- a/php.ini-production
+++ b/php.ini-production
@@ -729,6 +729,10 @@ user_dir =
; On windows:
; extension_dir = "ext"
+; Directory where the temporary files should be placed.
+; Defaults to the system default (see sys_get_temp_dir)
+; sys_temp_dir = "/tmp"
+
; Whether or not to enable the dl() function. The dl() function does NOT work
; properly in multithreaded servers, such as IIS or Zeus, and is automatically
; disabled on them.
diff --git a/tests/basic/req60524.phpt b/tests/basic/req60524.phpt
new file mode 100644
index 0000000000..6803e1fd88
--- /dev/null
+++ b/tests/basic/req60524.phpt
@@ -0,0 +1,8 @@
+--TEST--
+Req #60524 (Specify temporary directory)
+--INI--
+sys_temp_dir=/path/to/temp/dir
+--FILE--
+<?php echo sys_get_temp_dir(); ?>
+--EXPECT--
+/path/to/temp/dir
diff --git a/tests/classes/unset_properties.phpt b/tests/classes/unset_properties.phpt
index 7f9b569887..264e720c9e 100644
--- a/tests/classes/unset_properties.phpt
+++ b/tests/classes/unset_properties.phpt
@@ -140,15 +140,15 @@ true
new publicProperty value via public access
protectedProperty set
-__isset "protectedProperty"__isset "protectedProperty"false
+__isset "protectedProperty"false
__get "protectedProperty"
__set "protectedProperty" to "new protectedProperty value via setter"
__isset "protectedProperty"true
new protectedProperty value via setter
privateProperty set
-__isset "privateProperty"__isset "privateProperty"false
+__isset "privateProperty"false
__get "privateProperty"
__set "privateProperty" to "new privateProperty value via setter"
__isset "privateProperty"true
-new privateProperty value via setter \ No newline at end of file
+new privateProperty value via setter