@ -25,7 +25,10 @@
# include "php.h"
# include "php_ini.h"
# include "ext/standard/info.h"
# include "ext/standard/php_var.h"
# include "ext/standard/php_smart_str.h"
# include "zend_interfaces.h"
# include "zend_API.h"
# include "zend_exceptions.h"
# include "php_spl.h"
@ -53,7 +56,7 @@ PHPAPI zend_class_entry *spl_ce_RecursiveArrayIterator;
# define SPL_ARRAY_IS_SELF 0x02000000
# define SPL_ARRAY_USE_OTHER 0x04000000
# define SPL_ARRAY_INT_MASK 0xFFFF0000
# define SPL_ARRAY_CLONE_MASK 0x03000007
# define SPL_ARRAY_CLONE_MASK 0x030FFFFF
typedef struct _spl_array_object {
zend_object std ;
@ -69,7 +72,7 @@ typedef struct _spl_array_object {
zend_class_entry * ce_get_iterator ;
} spl_array_object ;
static inline HashTable * spl_array_get_hash_table ( spl_array_object * intern , int check_std_props TSRMLS_DC ) {
static inline HashTable * spl_array_get_hash_table ( spl_array_object * intern , int check_std_props TSRMLS_DC ) { /* {{{ */
if ( ( intern - > ar_flags & SPL_ARRAY_IS_SELF ) ! = 0 ) {
return intern - > std . properties ;
} else if ( ( intern - > ar_flags & SPL_ARRAY_USE_OTHER ) & & ( check_std_props = = 0 | | ( intern - > ar_flags & SPL_ARRAY_STD_PROP_LIST ) = = 0 ) & & Z_TYPE_P ( intern - > array ) = = IS_OBJECT ) {
@ -80,7 +83,7 @@ static inline HashTable *spl_array_get_hash_table(spl_array_object* intern, int
} else {
return HASH_OF ( intern - > array ) ;
}
}
} /* }}} */
SPL_API int spl_hash_verify_pos ( spl_array_object * intern TSRMLS_DC ) /* { { { */
{
@ -553,7 +556,6 @@ SPL_METHOD(Array, offsetSet)
spl_array_write_dimension_ex ( 0 , getThis ( ) , index , value TSRMLS_CC ) ;
} /* }}} */
void spl_array_iterator_append ( zval * object , zval * append_value TSRMLS_DC ) /* { { { */
{
spl_array_object * intern = ( spl_array_object * ) zend_object_store_get_object ( object TSRMLS_CC ) ;
@ -600,7 +602,7 @@ SPL_METHOD(Array, offsetUnset)
spl_array_unset_dimension_ex ( 0 , getThis ( ) , index TSRMLS_CC ) ;
} /* }}} */
/* {{ proto array ArrayObject::getArrayCopy() U
/* {{{ proto array ArrayObject::getArrayCopy() U
proto array ArrayIterator : : getArrayCopy ( ) U
Return a copy of the contained array */
SPL_METHOD ( Array , getArrayCopy )
@ -759,11 +761,11 @@ static int spl_array_next(spl_array_object *intern TSRMLS_DC) /* {{{ */
}
} /* }}} */
/* define an overloaded iterator structure */
/* {{{ define an overloaded iterator structure */
typedef struct {
zend_user_iterator intern ;
spl_array_object * object ;
} spl_array_it ;
} spl_array_it ; /* }}} */
static void spl_array_it_dtor ( zend_object_iterator * iter TSRMLS_DC ) /* { { { */
{
@ -892,7 +894,7 @@ static void spl_array_it_rewind(zend_object_iterator *iter TSRMLS_DC) /* {{{ */
}
/* }}} */
/* iterator handler table */
/* {{{ iterator handler table */
zend_object_iterator_funcs spl_array_it_funcs = {
spl_array_it_dtor ,
spl_array_it_valid ,
@ -900,7 +902,7 @@ zend_object_iterator_funcs spl_array_it_funcs = {
spl_array_it_get_current_key ,
spl_array_it_move_forward ,
spl_array_it_rewind
} ;
} ; /* }}} */
zend_object_iterator * spl_array_get_iterator ( zend_class_entry * ce , zval * object , int by_ref TSRMLS_DC ) /* { { { */
{
@ -1201,6 +1203,7 @@ SPL_METHOD(Array, count)
RETURN_LONG ( count ) ;
} /* }}} */
/* {{{ static void spl_array_method */
static void spl_array_method ( INTERNAL_FUNCTION_PARAMETERS , char * fname , int fname_len , int use_arg )
{
spl_array_object * intern = ( spl_array_object * ) zend_object_store_get_object ( getThis ( ) TSRMLS_CC ) ;
@ -1220,45 +1223,41 @@ static void spl_array_method(INTERNAL_FUNCTION_PARAMETERS, char *fname, int fnam
} else {
zend_call_method ( NULL , NULL , NULL , fname , fname_len , & return_value , 1 , & tmp , NULL TSRMLS_CC ) ;
}
}
} /* }}} */
/* {{{ SPL_ARRAY_METHOD */
# define SPL_ARRAY_METHOD(cname, fname, use_arg) \
SPL_METHOD ( cname , fname ) \
{ \
spl_array_method ( INTERNAL_FUNCTION_PARAM_PASSTHRU , # fname , sizeof ( # fname ) - 1 , use_arg ) ; \
}
/* {{{ proto int ArrayObject::asort() U
/* proto int ArrayObject::asort() U
proto int ArrayIterator : : asort ( ) U
Sort the entries by values . */
SPL_ARRAY_METHOD ( Array , asort , 0 )
/* }}} */
/* {{{ proto int ArrayObject::ksort() U
/* proto int ArrayObject::ksort() U
proto int ArrayIterator : : ksort ( ) U
Sort the entries by key . */
SPL_ARRAY_METHOD ( Array , ksort , 0 )
/* }}} */
/* {{{ proto int ArrayObject::uasort(callback cmp_function) U
/* proto int ArrayObject::uasort(callback cmp_function) U
proto int ArrayIterator : : uasort ( callback cmp_function ) U
Sort the entries by values user defined function . */
SPL_ARRAY_METHOD ( Array , uasort , 1 )
/* }}} */
/* {{{ proto int ArrayObject::uksort(callback cmp_function) U
/* proto int ArrayObject::uksort(callback cmp_function) U
proto int ArrayIterator : : uksort ( callback cmp_function ) U
Sort the entries by key using user defined function . */
SPL_ARRAY_METHOD ( Array , uksort , 1 )
/* }}} */
/* {{{ proto int ArrayObject::natsort() U
/* proto int ArrayObject::natsort() U
proto int ArrayIterator : : natsort ( ) U
Sort the entries by values using " natural order " algorithm . */
SPL_ARRAY_METHOD ( Array , natsort , 0 )
/* }}} */
/* {{{ proto int ArrayObject::natcasesort() U
/* proto int ArrayObject::natcasesort() U
proto int ArrayIterator : : natcasesort ( ) U
Sort the entries by key using case insensitive " natural order " algorithm . */
SPL_ARRAY_METHOD ( Array , natcasesort , 0 )
@ -1324,11 +1323,11 @@ void spl_array_iterator_key(zval *object, zval *return_value TSRMLS_DC) /* {{{ *
}
/* }}} */
/* {{{ proto mixed|NULL ArrayIterator::key() U
/* {{{ proto mixed|NULL ArrayIterator::key() U
Return current array key */
SPL_METHOD ( Array , key )
{
spl_array_iterator_key ( getThis ( ) , return_value TSRMLS_CC ) ;
spl_array_iterator_key ( getThis ( ) , return_value TSRMLS_CC ) ;
}
/* }}} */
@ -1430,6 +1429,153 @@ SPL_METHOD(Array, getChildren)
}
/* }}} */
/* {{{ proto string ArrayObject::serialize()
* serialize the object
*/
SPL_METHOD ( Array , serialize )
{
zval * object = getThis ( ) ;
spl_array_object * intern = ( spl_array_object * ) zend_object_store_get_object ( object TSRMLS_CC ) ;
HashTable * aht = spl_array_get_hash_table ( intern , 0 TSRMLS_CC ) ;
zval * * entry , members , * pmembers ;
HashPosition pos ;
php_serialize_data_t var_hash ;
smart_str buf = { 0 } ;
if ( ! aht ) {
php_error_docref ( NULL TSRMLS_CC , E_NOTICE , " Array was modified outside object and is no longer an array " ) ;
return ;
}
PHP_VAR_SERIALIZE_INIT ( var_hash ) ;
/* storage */
smart_str_appendl ( & buf , " x:i: " , 4 ) ;
smart_str_append_long ( & buf , ( intern - > ar_flags & SPL_ARRAY_CLONE_MASK ) ) ;
smart_str_appendc ( & buf , ' ; ' ) ;
if ( ! ( intern - > ar_flags & SPL_ARRAY_IS_SELF ) ) {
php_var_serialize ( & buf , & intern - > array , & var_hash TSRMLS_CC ) ;
smart_str_appendc ( & buf , ' ; ' ) ;
}
/* members */
smart_str_appendl ( & buf , " m: " , 2 ) ;
INIT_PZVAL ( & members ) ;
Z_ARRVAL ( members ) = intern - > std . properties ;
Z_TYPE ( members ) = IS_ARRAY ;
pmembers = & members ;
php_var_serialize ( & buf , & pmembers , & var_hash TSRMLS_CC ) ; /* finishes the string */
/* done */
PHP_VAR_SERIALIZE_DESTROY ( var_hash ) ;
if ( buf . c ) {
RETURN_STRINGL ( buf . c , buf . len , 0 ) ;
}
RETURN_NULL ( ) ;
} /* }}} */
/* {{{ proto void ArrayObject::unserialize(string serialized) U
* unserialize the object
*/
SPL_METHOD ( Array , unserialize )
{
spl_array_object * intern = ( spl_array_object * ) zend_object_store_get_object ( getThis ( ) TSRMLS_CC ) ;
zstr buf ;
unsigned int buf_len ;
UChar * p , * s ;
zend_uchar buf_type ;
php_unserialize_data_t var_hash ;
zval * pentry , * pmembers , * pflags = NULL ;
long flags ;
if ( zend_parse_parameters ( ZEND_NUM_ARGS ( ) TSRMLS_CC , " t " , & buf , & buf_len , & buf_type ) = = FAILURE ) {
return ;
}
if ( buf_len = = 0 ) {
zend_throw_exception_ex ( spl_ce_UnexpectedValueException , 0 TSRMLS_CC , " Empty serialized string cannot be empty " ) ;
return ;
}
s = p = ( buf_type = = IS_UNICODE ? buf . u : ( UChar * ) buf . s ) ;
PHP_VAR_UNSERIALIZE_INIT ( var_hash ) ;
if ( * p ! = ' x ' | | * + + p ! = ' : ' ) {
goto outexcept ;
}
+ + p ;
ALLOC_INIT_ZVAL ( pflags ) ;
if ( ! php_var_unserialize ( & pflags , & p , s + buf_len , & var_hash TSRMLS_CC ) | | Z_TYPE_P ( pflags ) ! = IS_LONG ) {
zval_ptr_dtor ( & pflags ) ;
goto outexcept ;
}
- - p ; /* for ';' */
flags = Z_LVAL_P ( pflags ) ;
zval_ptr_dtor ( & pflags ) ;
/* flags needs to be verified and we also need to verify whether the next
* thing we get is ' ; ' . After that we require an ' m ' or somethign else
* where ' m ' stands for members and anything else should be an array . If
* neither ' a ' or ' m ' follows we have an error . */
if ( * p ! = ' ; ' ) {
goto outexcept ;
}
+ + p ;
if ( * p ! = ' m ' ) {
if ( * p ! = ' a ' ) {
goto outexcept ;
}
intern - > ar_flags & = ~ SPL_ARRAY_CLONE_MASK ;
intern - > ar_flags | = flags & SPL_ARRAY_CLONE_MASK ;
zval_ptr_dtor ( & intern - > array ) ;
ALLOC_INIT_ZVAL ( intern - > array ) ;
if ( ! php_var_unserialize ( & intern - > array , & p , s + buf_len , & var_hash TSRMLS_CC ) ) {
goto outexcept ;
}
}
if ( * p ! = ' ; ' ) {
goto outexcept ;
}
+ + p ;
/* members */
if ( * p ! = ' m ' | | * + + p ! = ' : ' ) {
goto outexcept ;
}
+ + p ;
ALLOC_INIT_ZVAL ( pmembers ) ;
if ( ! php_var_unserialize ( & pmembers , & p , s + buf_len , & var_hash TSRMLS_CC ) ) {
zval_ptr_dtor ( & pmembers ) ;
goto outexcept ;
}
/* copy members */
zend_hash_copy ( intern - > std . properties , Z_ARRVAL_P ( pmembers ) , ( copy_ctor_func_t ) zval_add_ref , ( void * ) NULL , sizeof ( zval * ) ) ;
zval_ptr_dtor ( & pmembers ) ;
/* done reading $serialized */
PHP_VAR_UNSERIALIZE_DESTROY ( var_hash ) ;
return ;
outexcept :
PHP_VAR_UNSERIALIZE_DESTROY ( var_hash ) ;
zend_throw_exception_ex ( spl_ce_UnexpectedValueException , 0 TSRMLS_CC , " Error at offset %ld of %d bytes " , ( long ) ( ( char * ) p - ( long ) ( buf_type = = IS_UNICODE ? buf . u : ( UChar * ) buf . s ) ) , buf_len ) ;
return ;
} /* }}} */
/* {{{ ZEND_BEGIN_ARG_INFO */
static
ZEND_BEGIN_ARG_INFO ( arginfo_array___construct , 0 )
ZEND_ARG_INFO ( 0 , array )
@ -1473,10 +1619,16 @@ ZEND_END_ARG_INFO()
static
ZEND_BEGIN_ARG_INFO ( arginfo_array_uXsort , 0 )
ZEND_ARG_INFO ( 0 , cmp_function )
ZEND_ARG_INFO ( 0 , cmp_function )
ZEND_END_ARG_INFO ( ) ;
static const zend_function_entry spl_funcs_ArrayObject [ ] = {
static
ZEND_BEGIN_ARG_INFO ( arginfo_array_unserialize , 0 )
ZEND_ARG_INFO ( 0 , serialized )
ZEND_END_ARG_INFO ( ) ;
/* }}} */
static const zend_function_entry spl_funcs_ArrayObject [ ] = { /* {{{ */
SPL_ME ( Array , __construct , arginfo_array___construct , ZEND_ACC_PUBLIC )
SPL_ME ( Array , offsetExists , arginfo_array_offsetGet , ZEND_ACC_PUBLIC )
SPL_ME ( Array , offsetGet , arginfo_array_offsetGet , ZEND_ACC_PUBLIC )
@ -1493,15 +1645,17 @@ static const zend_function_entry spl_funcs_ArrayObject[] = {
SPL_ME ( Array , uksort , arginfo_array_uXsort , ZEND_ACC_PUBLIC )
SPL_ME ( Array , natsort , NULL , ZEND_ACC_PUBLIC )
SPL_ME ( Array , natcasesort , NULL , ZEND_ACC_PUBLIC )
SPL_ME ( Array , unserialize , arginfo_array_unserialize , ZEND_ACC_PUBLIC )
SPL_ME ( Array , serialize , NULL , ZEND_ACC_PUBLIC )
/* ArrayObject specific */
SPL_ME ( Array , getIterator , NULL , ZEND_ACC_PUBLIC )
SPL_ME ( Array , exchangeArray , arginfo_array_exchangeArray , ZEND_ACC_PUBLIC )
SPL_ME ( Array , setIteratorClass , arginfo_array_setIteratorClass , ZEND_ACC_PUBLIC )
SPL_ME ( Array , getIteratorClass , NULL , ZEND_ACC_PUBLIC )
{ NULL , NULL , NULL }
} ;
} ; /* }}} */
static const zend_function_entry spl_funcs_ArrayIterator [ ] = {
static const zend_function_entry spl_funcs_ArrayIterator [ ] = { /* {{{ */
SPL_ME ( Array , __construct , arginfo_array___construct , ZEND_ACC_PUBLIC )
SPL_ME ( Array , offsetExists , arginfo_array_offsetGet , ZEND_ACC_PUBLIC )
SPL_ME ( Array , offsetGet , arginfo_array_offsetGet , ZEND_ACC_PUBLIC )
@ -1518,6 +1672,8 @@ static const zend_function_entry spl_funcs_ArrayIterator[] = {
SPL_ME ( Array , uksort , arginfo_array_uXsort , ZEND_ACC_PUBLIC )
SPL_ME ( Array , natsort , NULL , ZEND_ACC_PUBLIC )
SPL_ME ( Array , natcasesort , NULL , ZEND_ACC_PUBLIC )
SPL_ME ( Array , unserialize , arginfo_array_unserialize , ZEND_ACC_PUBLIC )
SPL_ME ( Array , serialize , NULL , ZEND_ACC_PUBLIC )
/* ArrayIterator specific */
SPL_ME ( Array , rewind , NULL , ZEND_ACC_PUBLIC )
SPL_ME ( Array , current , NULL , ZEND_ACC_PUBLIC )
@ -1526,13 +1682,13 @@ static const zend_function_entry spl_funcs_ArrayIterator[] = {
SPL_ME ( Array , valid , NULL , ZEND_ACC_PUBLIC )
SPL_ME ( Array , seek , arginfo_array_seek , ZEND_ACC_PUBLIC )
{ NULL , NULL , NULL }
} ;
} ; /* }}} */
static const zend_function_entry spl_funcs_RecursiveArrayIterator [ ] = {
static const zend_function_entry spl_funcs_RecursiveArrayIterator [ ] = { /* {{{ */
SPL_ME ( Array , hasChildren , NULL , ZEND_ACC_PUBLIC )
SPL_ME ( Array , getChildren , NULL , ZEND_ACC_PUBLIC )
{ NULL , NULL , NULL }
} ;
} ; /* }}} */
/* {{{ PHP_MINIT_FUNCTION(spl_array) */
PHP_MINIT_FUNCTION ( spl_array )
@ -1540,6 +1696,7 @@ PHP_MINIT_FUNCTION(spl_array)
REGISTER_SPL_STD_CLASS_EX ( ArrayObject , spl_array_object_new , spl_funcs_ArrayObject ) ;
REGISTER_SPL_IMPLEMENTS ( ArrayObject , Aggregate ) ;
REGISTER_SPL_IMPLEMENTS ( ArrayObject , ArrayAccess ) ;
REGISTER_SPL_IMPLEMENTS ( ArrayObject , Serializable ) ;
memcpy ( & spl_handler_ArrayObject , zend_get_std_object_handlers ( ) , sizeof ( zend_object_handlers ) ) ;
spl_handler_ArrayObject . clone_obj = spl_array_object_clone ;
@ -1561,6 +1718,7 @@ PHP_MINIT_FUNCTION(spl_array)
REGISTER_SPL_IMPLEMENTS ( ArrayIterator , Iterator ) ;
REGISTER_SPL_IMPLEMENTS ( ArrayIterator , ArrayAccess ) ;
REGISTER_SPL_IMPLEMENTS ( ArrayIterator , SeekableIterator ) ;
REGISTER_SPL_IMPLEMENTS ( ArrayIterator , Serializable ) ;
memcpy ( & spl_handler_ArrayIterator , & spl_handler_ArrayObject , sizeof ( zend_object_handlers ) ) ;
spl_ce_ArrayIterator - > get_iterator = spl_array_get_iterator ;