From 0170ec19c7723d3dd51c7936fc55e68a882135fe Mon Sep 17 00:00:00 2001 From: "J. King" Date: Sat, 6 Jul 2024 11:01:00 -0400 Subject: [PATCH] Fix language-loading infinite loop when throwing exceptions This loop has existed since the very beginning, and was only ever papered over instead of actually fixing it. --- lib/Lang.php | 24 +++++++++++++++++------- tests/lib/Lang/Setup.php | 5 +---- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/lib/Lang.php b/lib/Lang.php index 37ffb6f3..82bb8d48 100644 --- a/lib/Lang.php +++ b/lib/Lang.php @@ -198,13 +198,17 @@ class Lang { // otherwise start with the strings we already have if we're going from e.g. "fr" to "fr_ca" $strings[] = $this->strings; } - // read files in reverse order - $files = array_reverse($files); - foreach ($files as $file) { + $loaded = array_diff($loaded, $files); + $toThrow = null; + while ($files) { + // read files in reverse order + $file = array_pop($files); if (!file_exists($this->path."$file.php")) { - throw new Lang\Exception("fileMissing", $file); + $toThrow = ["fileMissing", $file]; + break; } elseif (!is_readable($this->path."$file.php")) { - throw new Lang\Exception("fileUnreadable", $file); + $toThrow = ["fileUnreadable", $file]; + break; } try { // we use output buffering in case the language file is corrupted @@ -216,16 +220,22 @@ class Lang { ob_end_clean(); } if (!is_array($arr)) { - throw new Lang\Exception("fileCorrupt", $file); + $toThrow = ["fileCorrupt", $file]; + break; } $strings[] = $arr; + $loaded[] = $file; } // apply the results and return - $this->strings = call_user_func_array("array_replace_recursive", $strings); + $this->strings = array_replace_recursive(...$strings); $this->loaded = $loaded; $this->locale = $this->wanted; $this->synched = true; $this->formatter = null; + if ($toThrow) { + // if not all requested files could be loaded successfully, throw an exception + throw new Lang\Exception(...$toThrow); + } return true; } } diff --git a/tests/lib/Lang/Setup.php b/tests/lib/Lang/Setup.php index 0969bf6b..71140957 100644 --- a/tests/lib/Lang/Setup.php +++ b/tests/lib/Lang/Setup.php @@ -43,11 +43,8 @@ trait Setup { return Glob::glob($this->path."*.php"); }); $this->l = $this->l->get(); - // create a mock Lang object so as not to create a dependency loop self::clearData(false); - Arsse::$lang = $this->mock(Lang::class); - Arsse::$lang->msg->returns(""); - Arsse::$lang = Arsse::$lang->get(); + Arsse::$lang = $this->l; // call the additional setup method if it exists if (method_exists($this, "setUpSeries")) { $this->setUpSeries();