summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristopher Jones <sixd@php.net>2013-07-25 08:53:29 -0700
committerChristopher Jones <sixd@php.net>2013-07-25 08:53:29 -0700
commit42e8f3ca288cd40ffb72a5d37d13754263348dd7 (patch)
tree4c0b8098dd0d0a11119c4dfafacf1da3d0ff6479
parent024972e3b957270f7e233794376b36c1e5081c78 (diff)
parent9776504c5bfa036608fc3fd1ae308c99615972b1 (diff)
downloadphp-git-42e8f3ca288cd40ffb72a5d37d13754263348dd7.tar.gz
Merge branch 'PHP-5.5' of https://git.php.net/repository/php-src into PHP-5.5
# By Johannes Schlüter (3) and others # Via Xinchen Hui (3) and others * 'PHP-5.5' of https://git.php.net/repository/php-src: Upper section name Update NEWs Fixed bug #65328 (Segfault when getting SplStack object Value) Expand the ZEND_STRL macro to handle platforms where strncmp() is a macro. fix missing include Fix bug 65299 Fix compiler warning on redefined constant Fix comment fixed bug #65311 testsuite failure due to incomplete fix to bug28985.phpt fix bug #65028 Phar::buildFromDirectory creates corrupt archives for some specific contents
-rw-r--r--NEWS8
-rw-r--r--Zend/zend_hash.h2
-rw-r--r--ext/openssl/openssl.c3
-rw-r--r--ext/pdo_mysql/mysql_driver.c8
-rw-r--r--ext/pdo_mysql/pdo_mysql.c2
-rw-r--r--ext/pdo_mysql/php_pdo_mysql_int.h2
-rw-r--r--ext/phar/phar.c23
-rw-r--r--ext/phar/tests/bug65028.phpt156
-rw-r--r--ext/soap/tests/bugs/bug28985.phpt4
-rw-r--r--ext/spl/php_spl.c2
-rw-r--r--ext/spl/spl_array.c2
-rw-r--r--ext/spl/tests/bug65328.phpt348
12 files changed, 549 insertions, 11 deletions
diff --git a/NEWS b/NEWS
index 18bb2fd013..ff6ed35b12 100644
--- a/NEWS
+++ b/NEWS
@@ -10,7 +10,15 @@ PHP NEWS
. Fixed bug #65291 (get_defined_constants() causes PHP to crash in a very
limited case). (Arpad)
+- PDO_mysql:
+ . Fixed bug #65299 (pdo mysql parsing errors). (Johannes)
+
+- Phar:
+ . Fixed bug #65028 (Phar::buildFromDirectory creates corrupt archives for
+ some specific contents). (Stas)
+
- SPL:
+ . Fixed bug #65328 (Segfault when getting SplStack object Value). (Laruence)
. Added RecursiveTreeIterator setPostfix and getPostifx methods. (Joshua
Thijssen)
. Fixed bug #61697 (spl_autoload_functions returns lambda functions
diff --git a/Zend/zend_hash.h b/Zend/zend_hash.h
index bf3577124d..69732cd597 100644
--- a/Zend/zend_hash.h
+++ b/Zend/zend_hash.h
@@ -28,7 +28,7 @@
#define HASH_KEY_IS_STRING 1
#define HASH_KEY_IS_LONG 2
#define HASH_KEY_NON_EXISTENT 3
-#define HASH_KEY_NON_EXISTANT HASH_KEY_NON_EXISTENT // Keeping old define (with typo) for backward compatibility
+#define HASH_KEY_NON_EXISTANT HASH_KEY_NON_EXISTENT /* Keeping old define (with typo) for backward compatibility */
#define HASH_UPDATE (1<<0)
#define HASH_ADD (1<<1)
diff --git a/ext/openssl/openssl.c b/ext/openssl/openssl.c
index c939c01b2b..655980e20c 100644
--- a/ext/openssl/openssl.c
+++ b/ext/openssl/openssl.c
@@ -35,6 +35,9 @@
#include "ext/standard/php_fopen_wrappers.h"
#include "ext/standard/md5.h"
#include "ext/standard/base64.h"
+#ifdef PHP_WIN32
+# include "win32/winutil.h"
+#endif
/* OpenSSL includes */
#include <openssl/evp.h>
diff --git a/ext/pdo_mysql/mysql_driver.c b/ext/pdo_mysql/mysql_driver.c
index 54c2e8dd84..cd86503dd7 100644
--- a/ext/pdo_mysql/mysql_driver.c
+++ b/ext/pdo_mysql/mysql_driver.c
@@ -527,9 +527,9 @@ static struct pdo_dbh_methods mysql_methods = {
/* }}} */
#ifdef PHP_WIN32
-# define MYSQL_UNIX_ADDR NULL
+# define PDO_DEFAULT_MYSQL_UNIX_ADDR NULL
#else
-# define MYSQL_UNIX_ADDR PDO_MYSQL_G(default_socket)
+# define PDO_DEFAULT_MYSQL_UNIX_ADDR PDO_MYSQL_G(default_socket)
#endif
/* {{{ pdo_mysql_handle_factory */
@@ -545,7 +545,7 @@ static int pdo_mysql_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_
{ "dbname", "", 0 },
{ "host", "localhost", 0 },
{ "port", "3306", 0 },
- { "unix_socket", MYSQL_UNIX_ADDR, 0 },
+ { "unix_socket", PDO_DEFAULT_MYSQL_UNIX_ADDR, 0 },
};
int connect_opts = 0
#ifdef CLIENT_MULTI_RESULTS
@@ -710,7 +710,7 @@ static int pdo_mysql_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_
}
}
-#if MYSQL_VERSION_ID > 50605 || defined(MYSQLI_USE_MYSQLND)
+#if MYSQL_VERSION_ID > 50605 || defined(PDO_USE_MYSQLND)
{
char *public_key = pdo_attr_strval(driver_options, PDO_MYSQL_ATTR_SERVER_PUBLIC_KEY, NULL TSRMLS_CC);
if (public_key) {
diff --git a/ext/pdo_mysql/pdo_mysql.c b/ext/pdo_mysql/pdo_mysql.c
index 401d20d8b3..78c4ceefe9 100644
--- a/ext/pdo_mysql/pdo_mysql.c
+++ b/ext/pdo_mysql/pdo_mysql.c
@@ -118,7 +118,7 @@ static PHP_MINIT_FUNCTION(pdo_mysql)
REGISTER_PDO_CLASS_CONST_LONG("MYSQL_ATTR_SSL_CA", (long)PDO_MYSQL_ATTR_SSL_CA);
REGISTER_PDO_CLASS_CONST_LONG("MYSQL_ATTR_SSL_CAPATH", (long)PDO_MYSQL_ATTR_SSL_CAPATH);
REGISTER_PDO_CLASS_CONST_LONG("MYSQL_ATTR_SSL_CIPHER", (long)PDO_MYSQL_ATTR_SSL_CIPHER);
-#if MYSQL_VERSION_ID > 50605 || defined(MYSQLI_USE_MYSQLND)
+#if MYSQL_VERSION_ID > 50605 || defined(PDO_USE_MYSQLND)
REGISTER_PDO_CLASS_CONST_LONG("MYSQL_ATTR_SERVER_PUBLIC_KEY", (long)PDO_MYSQL_ATTR_SERVER_PUBLIC_KEY);
#endif
diff --git a/ext/pdo_mysql/php_pdo_mysql_int.h b/ext/pdo_mysql/php_pdo_mysql_int.h
index 42debf07e9..24f7aa2182 100644
--- a/ext/pdo_mysql/php_pdo_mysql_int.h
+++ b/ext/pdo_mysql/php_pdo_mysql_int.h
@@ -171,7 +171,7 @@ enum {
PDO_MYSQL_ATTR_SSL_CA,
PDO_MYSQL_ATTR_SSL_CAPATH,
PDO_MYSQL_ATTR_SSL_CIPHER,
-#if MYSQL_VERSION_ID > 50605 || defined(MYSQLI_USE_MYSQLND)
+#if MYSQL_VERSION_ID > 50605 || defined(PDO_USE_MYSQLND)
PDO_MYSQL_ATTR_SERVER_PUBLIC_KEY
#endif
};
diff --git a/ext/phar/phar.c b/ext/phar/phar.c
index 638c1ef83a..ec8e5fbde7 100644
--- a/ext/phar/phar.c
+++ b/ext/phar/phar.c
@@ -2579,6 +2579,7 @@ int phar_flush(phar_archive_data *phar, char *user_stub, long len, int convert,
php_serialize_data_t metadata_hash;
smart_str main_metadata_str = {0};
int free_user_stub, free_fp = 1, free_ufp = 1;
+ int manifest_hack = 0;
if (phar->is_persistent) {
if (error) {
@@ -2930,6 +2931,12 @@ int phar_flush(phar_archive_data *phar, char *user_stub, long len, int convert,
manifest_len = offset + phar->alias_len + sizeof(manifest) + main_metadata_str.len;
phar_set_32(manifest, manifest_len);
+ /* Hack - see bug #65028, add padding byte to the end of the manifest */
+ if(manifest[0] == '\r' || manifest[0] == '\n') {
+ manifest_len++;
+ phar_set_32(manifest, manifest_len);
+ manifest_hack = 1;
+ }
phar_set_32(manifest+4, new_manifest_count);
if (has_dirs) {
*(manifest + 8) = (unsigned char) (((PHAR_API_VERSION) >> 8) & 0xFF);
@@ -3054,6 +3061,22 @@ int phar_flush(phar_archive_data *phar, char *user_stub, long len, int convert,
return EOF;
}
}
+ /* Hack - see bug #65028, add padding byte to the end of the manifest */
+ if(manifest_hack) {
+ if(1 != php_stream_write(newfile, manifest, 1)) {
+ if (closeoldfile) {
+ php_stream_close(oldfile);
+ }
+
+ php_stream_close(newfile);
+
+ if (error) {
+ spprintf(error, 0, "unable to write manifest padding byte");
+ }
+
+ return EOF;
+ }
+ }
/* now copy the actual file data to the new phar */
offset = php_stream_tell(newfile);
diff --git a/ext/phar/tests/bug65028.phpt b/ext/phar/tests/bug65028.phpt
new file mode 100644
index 0000000000..74273b850b
--- /dev/null
+++ b/ext/phar/tests/bug65028.phpt
@@ -0,0 +1,156 @@
+--TEST--
+Phar - test specific manifest length
+--INI--
+phar.readonly=0
+--SKIPIF--
+<?php if (!extension_loaded("phar")) die("skip"); ?>
+--FILE--
+<?php
+
+$files = array(
+ "lib/widgets/Widgets.php",
+ "lib/events/FormBeginEventArgs.php",
+ "lib/events/FormEndEventArgs.php",
+ "lib/Core.php",
+ "lib/database/MySqlDatabase.php",
+ "lib/utils/DateUtil.php",
+ "js/global.js",
+ "files/_emptyDirectory",
+ "files/search/schema.xml",
+ "vendor/Fusonic/Linq/Internal/WhereIterator.php",
+ "vendor/Fusonic/Linq/Internal/SelectManyIterator.php",
+ "vendor/Fusonic/Linq/Internal/SelectIterator.php",
+ "vendor/Fusonic/Linq/Internal/DiffIterator.php",
+ "vendor/Fusonic/Linq/Internal/GroupIterator.php",
+ "vendor/Fusonic/Linq/Internal/DistinctIterator.php",
+ "vendor/Fusonic/Linq/Internal/LinqHelper.php",
+ "vendor/Fusonic/Linq/Internal/OrderIterator.php",
+ "vendor/Fusonic/Linq/Internal/IntersectIterator.php",
+ "vendor/Fusonic/Linq/GroupedLinq.php",
+ "vendor/Fusonic/Linq.php",
+ "vendor/Fusonic/UI/Widgets/Forms/FormBegin.php",
+ "vendor/Fusonic/UI/Widgets/Forms/FormSectionBuilder.php",
+ "vendor/Fusonic/UI/Widgets/Forms/AutoSelect.php",
+ "vendor/Fusonic/UI/Widgets/Forms/ControlGroup.php",
+ "vendor/Fusonic/UI/Widgets/Forms/FormEnd.php",
+ "vendor/Fusonic/UI/Widgets/WidgetBase.php",
+ "modules/calendar/ajax/calendarGetInvitedUsersContentAjaxHandler.php",
+ "modules/calendar/js/calendarAppointmentForm.js",
+ "modules/calendar/misc/calendarAppointment.php",
+ "modules/calendar/pages/forms/calendarAppointmentForm.php",
+ "modules/calendar/setup/config.xml",
+ "modules/cmt/js/cmtMicroCommentsWidget.js",
+ "modules/cmt/setup/config.xml",
+ "modules/meta/misc/metaContentHelper.php",
+ "modules/meta/setup/config.xml",
+ "modules/brd/misc/brdPostStreamFormatter.php",
+ "modules/brd/misc/brdPost.php",
+ "modules/brd/setup/config/streamContents.xml",
+ "modules/brd/setup/resources/lang/en.xml",
+ "modules/brd/setup/resources/lang/de.xml",
+ "modules/brd/setup/config.xml",
+ "modules/auth/misc/authLoginService.php",
+ "modules/auth/setup/config.xml",
+ "modules/bwd/cache/bwdWordCacheCreator.php",
+ "modules/bwd/bwd.php",
+ "modules/bwd/setup/config.xml",
+ "modules/nws/templates/pages/forms/nwsNewsForm.tpl",
+ "modules/nws/templates/pages/nwsShowNewsPage.tpl",
+ "modules/nws/pages/forms/nwsNewsForm.php",
+ "modules/nws/pages/nwsShowNewsPage.php",
+ "modules/nws/setup/config.xml",
+ "modules/gmp/cache/gmpMarkersCacheCreator.php",
+ "modules/gmp/select/gmpMapContentSelect.php",
+ "modules/gmp/templates/gmpShowAppointmentPage.tpl",
+ "modules/gmp/templates/gmpShowLinkPage.tpl",
+ "modules/gmp/setup/config.xml",
+ "modules/mul/cache/mulVideoPortalCacheCreator.php",
+ "modules/mul/misc/mulPermissionHelper.php",
+ "modules/mul/templates/widgets/mulFileEmbedWidget_Video_Flv.tpl",
+ "modules/mul/setup/config/mulUploadVideoPortalMatches.xml",
+ "modules/mul/setup/config.xml",
+ "modules/cat/select/catCategorySelect.php",
+ "modules/cat/misc/catCategory.php",
+ "modules/cat/templates/pages/forms/catCategoryForm.tpl",
+ "modules/cat/pages/forms/catEditCategoryForm.php",
+ "modules/cat/pages/forms/catAddCategoryForm.php",
+ "modules/cat/setup/config.xml",
+ "modules/sty/events/styPageShowEventHandler.php",
+ "modules/sty/misc/styBox.php",
+ "modules/sty/templates/pages/forms/styLayoutForm.tpl",
+ "modules/sty/templates/pages/forms/styBoxForm.tpl",
+ "modules/sty/templates/pages/forms/styVariantForm.tpl",
+ "modules/sty/setup/resources/lang/en.xml",
+ "modules/sty/setup/resources/lang/de.xml",
+ "modules/sty/setup/config.xml",
+ "modules/reg/misc/regRegistrationHelper.php",
+ "modules/reg/setup/config.xml",
+ "modules/not/misc/notEmailNotificationProvider.php",
+ "modules/not/setup/config.xml",
+ "modules/styfusonic/setup/config.xml",
+ "modules/sys/ajax/sysUserAutoSuggestSelectAjaxHandler.php",
+ "modules/sys/js/sysUserAutoSuggestSelect.js",
+ "modules/sys/select/sysPermissionSelect.php",
+ "modules/sys/misc/sysHtaccessConfigWriter.php",
+ "modules/sys/misc/sysUserRepository.php",
+ "modules/sys/setup/resources/lang/en.xml",
+ "modules/sys/setup/resources/lang/de.xml",
+ "modules/sys/setup/config.xml",
+ "modules/igr/boxes/igrGreatestEntriesBoxTab.php",
+ "modules/igr/boxes/igrTopRatedEntriesBoxTab.php",
+ "modules/igr/setup/config.xml",
+ "modules/rat/ajax/ratRateAjaxHandler.php",
+ "modules/rat/ajax/ratUnlikeAjaxHandler.php",
+ "modules/rat/setup/config.xml",
+ "modules/search/select/searchModuleSelect.php",
+ "modules/search/select/searchOrderSelect.php",
+ "modules/search/misc/searchResultFormatter.php",
+ "modules/search/misc/searchProviderSolr.php",
+ "modules/search/misc/searchProviderLucene.php",
+ "modules/search/misc/searchResultItem.php",
+ "modules/search/misc/searchProviderBase.php",
+ "modules/search/misc/searchIProvider.php",
+ "modules/search/templates/misc/searchResultFormatter.tpl",
+ "modules/search/templates/pages/searchIndexPage.tpl",
+ "modules/search/templates/pages/forms/searchSearchForm.tpl",
+ "modules/search/pages/forms/searchSearchForm.php",
+ "modules/search/css/searchResultFormatter.css",
+ "modules/search/setup/config/sysSettings.xml",
+ "modules/search/setup/resources/lang/en.xml",
+ "modules/search/setup/resources/lang/de.xml",
+ "modules/search/setup/config.xml",
+ "style/Fusonic/40components.css",
+ "style/_emptyDirectory",
+ "index.php",
+// "a", // This will make the test pass
+);
+
+// Create Phar with the filenames above
+$phar = new Phar(__DIR__ . "/bug65028.phar");
+foreach($files as $file)
+{
+ $phar->addFromString($file, "");
+}
+
+// Copy phar
+copy(__DIR__ . "/bug65028.phar", __DIR__ . "/bug65028-copy.phar");
+
+// Open phar
+try
+{
+ $phar = new Phar(__DIR__ . "/bug65028-copy.phar");
+ echo "No exception thrown.\n";
+}
+catch(UnexpectedValueException $ex)
+{
+ echo "Exception thrown: " . $ex->getMessage() . "\n";
+}
+?>
+--CLEAN--
+<?php
+@unlink(__DIR__ . "/bug65028.phar");
+@unlink(__DIR__ . "/bug65028-copy.phar");
+?>
+--EXPECT--
+No exception thrown.
+
diff --git a/ext/soap/tests/bugs/bug28985.phpt b/ext/soap/tests/bugs/bug28985.phpt
index 5134cbf099..73ff899c39 100644
--- a/ext/soap/tests/bugs/bug28985.phpt
+++ b/ext/soap/tests/bugs/bug28985.phpt
@@ -44,7 +44,7 @@ array(42) {
string iUserPassword;
}"
[8]=>
- string(86) "struct MGCodeLibelle {
+ string(87) "struct MGCodeLibelle {
string Code;
string Libelle;
boolean Default;
@@ -203,4 +203,4 @@ array(42) {
string(76) "struct GetEnvironnementResponse {
MGEnvironnement GetEnvironnementResult;
}"
-} \ No newline at end of file
+}
diff --git a/ext/spl/php_spl.c b/ext/spl/php_spl.c
index c3a774ea96..a5ffdb7d14 100644
--- a/ext/spl/php_spl.c
+++ b/ext/spl/php_spl.c
@@ -744,7 +744,7 @@ PHP_FUNCTION(spl_autoload_functions)
add_next_index_string(tmp, alfi->func_ptr->common.function_name, 1);
add_next_index_zval(return_value, tmp);
} else {
- if (strncmp(alfi->func_ptr->common.function_name, ZEND_STRL("__lambda_func"))) {
+ if (strncmp(alfi->func_ptr->common.function_name, "__lambda_func", sizeof("__lambda_func") - 1)) {
add_next_index_string(return_value, alfi->func_ptr->common.function_name, 1);
} else {
char *key;
diff --git a/ext/spl/spl_array.c b/ext/spl/spl_array.c
index ed13b8e576..9ca681688b 100644
--- a/ext/spl/spl_array.c
+++ b/ext/spl/spl_array.c
@@ -1646,7 +1646,7 @@ SPL_METHOD(Array, getChildren)
return;
}
if (instanceof_function(Z_OBJCE_PP(entry), Z_OBJCE_P(getThis()) TSRMLS_CC)) {
- RETURN_ZVAL(*entry, 0, 0);
+ RETURN_ZVAL(*entry, 1, 0);
}
}
diff --git a/ext/spl/tests/bug65328.phpt b/ext/spl/tests/bug65328.phpt
new file mode 100644
index 0000000000..32e6c24fa7
--- /dev/null
+++ b/ext/spl/tests/bug65328.phpt
@@ -0,0 +1,348 @@
+--TEST--
+Bug #65328 (Segfault when getting SplStack object Value)
+--FILE--
+<?php
+/**
+ * @author AlexanderC
+ */
+
+class Tree
+{
+ /**
+ * @var Node
+ */
+ protected $head;
+
+ /**
+ * @param Node $head
+ */
+ public function __construct(Node $head = null)
+ {
+ $this->head = $head ? : new Node('HEAD');
+ }
+
+ /**
+ * @return Node
+ */
+ public function getHead()
+ {
+ return $this->head;
+ }
+
+ /**
+ * @param mixed $uid
+ * @return Node|bool
+ */
+ public function find($uid)
+ {
+ $iterator = $this->getIterator();
+
+ /** @var Node $node */
+ foreach($iterator as $node) {
+ if($node->getUid() === $uid) {
+ return $node;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * @param mixed $uid
+ * @return \SplStack
+ */
+ public function & findAll($uid)
+ {
+ $result = new \SplStack();
+
+ /** @var Node $node */
+ foreach($this->getIterator() as $node) {
+ if($node->getUid() == $uid) {
+ $result->push($node);
+ }
+ }
+
+ return $result;
+ }
+
+ /**
+ * @return \RecursiveIteratorIterator
+ */
+ public function getIterator()
+ {
+ return new \RecursiveIteratorIterator(
+ $this->head->getChildren(),
+ \RecursiveIteratorIterator::SELF_FIRST
+ );
+ }
+}
+
+class Node extends \RecursiveArrayIterator implements \Countable
+{
+ /**
+ * @var array
+ */
+ protected $children = [];
+
+ /**
+ * @var Node
+ */
+ protected $parent;
+
+ /**
+ * @var mixed
+ */
+ protected $data;
+
+ /**
+ * @var mixed
+ */
+ protected $uid;
+
+ /**
+ * @var int
+ */
+ protected $index = 0;
+
+ /**
+ * @var bool
+ */
+ protected $assureUnique;
+
+ /**
+ * @param mixed $data
+ * @param mixed $uid
+ * @param Node $parent
+ * @param bool $assureUnique
+ */
+ public function __construct($data, $uid = null, Node $parent = null, $assureUnique = false)
+ {
+ if(null !== $parent) {
+ $this->parent = $parent;
+ }
+
+ $this->data = $data;
+ $this->uid = $uid ? : uniqid(sha1(serialize($data)), true);
+ $this->assureUnique = $assureUnique;
+ }
+
+ /**
+ * @param mixed $uid
+ */
+ public function setUid($uid)
+ {
+ $this->uid = $uid;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getUid()
+ {
+ return $this->uid;
+ }
+
+ /**
+ * @param Node $child
+ */
+ public function addChild(Node $child)
+ {
+ $child->setParent($this);
+ $this->children[] = $child;
+ }
+
+ /**
+ * @param array $children
+ */
+ public function setChildren(array $children)
+ {
+ $this->children = $children;
+ }
+
+ /**
+ * @return array
+ */
+ public function getChildrenArray()
+ {
+ return $this->children;
+ }
+
+ /**
+ * @param mixed $data
+ */
+ public function setData($data)
+ {
+ $this->data = $data;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getData()
+ {
+ return $this->data;
+ }
+
+ /**
+ * @param Node $parent
+ * @throws \RuntimeException
+ */
+ public function setParent(Node $parent)
+ {
+ if(true === $this->assureUnique && !self::checkUnique($parent, $this->uid)) {
+ throw new \RuntimeException("Node uid is not unique in assigned node tree");
+ }
+
+ $this->parent = $parent;
+ }
+
+ /**
+ * @param Node $node
+ * @param mixed $uid
+ * @return bool
+ */
+ protected static function checkUnique(Node $node, $uid)
+ {
+ $headNode = $node;
+ do {
+ $headNode = $node;
+ } while($node = $node->getParent());
+
+ $tree = new Tree($headNode);
+
+ return !$tree->find($uid);
+ }
+
+ /**
+ * @return \IJsonRPC\Helpers\Tree\Node
+ */
+ public function getParent()
+ {
+ return $this->parent;
+ }
+
+ /**
+ * @return Node
+ */
+ public function current()
+ {
+ return $this->children[$this->index];
+ }
+
+ /**
+ * @return scalar
+ */
+ public function key()
+ {
+ return $this->index;
+ }
+
+ /**
+ * @return void
+ */
+ public function next()
+ {
+ ++$this->index;
+ }
+
+ /**
+ * @return void
+ */
+ public function rewind()
+ {
+ $this->index = 0;
+ }
+
+ /**
+ * @return bool
+ */
+ public function valid()
+ {
+ return array_key_exists($this->index, $this->children);
+ }
+
+ /**
+ * @return int
+ */
+ public function count()
+ {
+ return count($this->children);
+ }
+
+ /**
+ * @return bool
+ */
+ public function hasChildren()
+ {
+ return !empty($this->children);
+ }
+
+ /**
+ * @return \RecursiveArrayIterator
+ */
+ public function getChildren()
+ {
+ return new \RecursiveArrayIterator($this->children);
+ }
+}
+
+$tree = new Tree();
+$node1 = new Node('value1', 1);
+$tree->getHead()->addChild($node1);
+$node2 = new Node('value2', 2);
+$node1->addChild($node2);
+
+print_r($tree->findAll(2)->offsetGet(0));
+--EXPECTF--
+Node Object
+(
+ [children:protected] => Array
+ (
+ )
+
+ [parent:protected] => Node Object
+ (
+ [children:protected] => Array
+ (
+ [0] => Node Object
+ *RECURSION*
+ )
+
+ [parent:protected] => Node Object
+ (
+ [children:protected] => Array
+ (
+ [0] => Node Object
+ *RECURSION*
+ )
+
+ [parent:protected] =>
+ [data:protected] => HEAD
+ [uid:protected] => %s
+ [index:protected] => 0
+ [assureUnique:protected] =>
+ [storage:ArrayIterator:private] => Array
+ (
+ )
+
+ )
+
+ [data:protected] => value1
+ [uid:protected] => 1
+ [index:protected] => 1
+ [assureUnique:protected] =>
+ [storage:ArrayIterator:private] => Array
+ (
+ )
+
+ )
+
+ [data:protected] => value2
+ [uid:protected] => 2
+ [index:protected] => 0
+ [assureUnique:protected] =>
+ [storage:ArrayIterator:private] => Array
+ (
+ )
+
+)