From 46696f212416fe4a4e7b3761d6af37daf76b4dd3 Mon Sep 17 00:00:00 2001 From: camer0n Date: Mon, 28 Apr 2025 08:59:28 -0700 Subject: [PATCH] Issue #5482 Session handling of array data. --- e107_admin/theme.php | 9 +- e107_handlers/session_handler.php | 174 ++++++++++++++---------- e107_tests/tests/unit/e_sessionTest.php | 27 +++- 3 files changed, 132 insertions(+), 78 deletions(-) diff --git a/e107_admin/theme.php b/e107_admin/theme.php index f93556bf5..944dde572 100644 --- a/e107_admin/theme.php +++ b/e107_admin/theme.php @@ -640,6 +640,8 @@ class theme_admin_ui extends e_admin_ui public function InfoPage() { + + if(!empty($_GET['src'])) // online mode. { $string = base64_decode($_GET['src']); @@ -657,7 +659,7 @@ class theme_admin_ui extends e_admin_ui $tm = (string) $this->getId(); $themeMeta = e107::getTheme($tm)->get(); - echo $this->themeObj->renderThemeInfo($themeMeta); + return $this->themeObj->renderThemeInfo($themeMeta); } @@ -1176,6 +1178,9 @@ class theme_admin_form_ui extends e_admin_form_ui e107::getSession()->set('thememanager/online/'.$theme['id'], $theme); + $saved = e107::getSession()->get('thememanager/online/'.$theme['id']); + + $d = http_build_query($srcData,false); $base64 = base64_encode($d); @@ -1388,7 +1393,7 @@ class theme_builder extends e_admin_ui $newThemeXML = e_THEME.$this->themeName."/theme.xml"; if(file_exists($newThemeXML)) { - $info = e107::getTheme()->getThemeInfo($this->themeName); + $info = e107::getTheme()::getThemeInfo($this->themeName); e107::getDebug()->log($info); diff --git a/e107_handlers/session_handler.php b/e107_handlers/session_handler.php index 3a34ac00e..b570a8fd7 100644 --- a/e107_handlers/session_handler.php +++ b/e107_handlers/session_handler.php @@ -260,21 +260,58 @@ class e_session /** * Retrieve value from current session namespace - * Equals to $_SESSION[NAMESPACE][$key] + * Equals to $_SESSION[NAMESPACE][$key] or a multi-dimensional array for keys starting with $key/ * @param string $key * @param bool $clear unset key * @return mixed */ public function get($key, $clear = false) { - $ret = $this->_data[$key] ?? null; - if($clear) $this->clear($key); + $result = []; + + // Check for keys starting with $key/ + foreach ($this->_data as $dataKey => $value) { + if (strpos($dataKey, $key . '/') === 0) { + $subKeys = explode('/', substr($dataKey, strlen($key . '/'))); + $current = &$result; + foreach ($subKeys as $k) { + if (!isset($current[$k])) { + $current[$k] = []; + } + $current = &$current[$k]; + } + $current = $value; + } + } + + // Merge with direct key value if it exists + if (isset($this->_data[$key])) { + if (is_array($this->_data[$key]) && is_array($result)) { + $result = array_merge_recursive($this->_data[$key], $result); + } else { + $result = $this->_data[$key]; + } + } + + // Return null if no data found + $ret = empty($result) && !isset($this->_data[$key]) ? null : $result; + + if ($clear) { + $this->clear($key); + // Clear all related keys + foreach (array_keys($this->_data) as $dataKey) { + if (strpos($dataKey, $key . '/') === 0) { + unset($this->_data[$dataKey]); + } + } + } + return $ret; } /** * Retrieve value from current session namespace - * If key is null, returns all current session namespace data + * If key is null, returns all current session namespace data as a multi-dimensional array * * @param string|null $key * @param bool $clear @@ -282,51 +319,64 @@ class e_session */ public function getData($key = null, $clear = false) { - if(null === $key) - { - $ret = $this->_data; - if($clear) $this->clearData(); - return $ret; + if (null === $key) { + $result = []; + foreach ($this->_data as $dataKey => $value) { + $keys = explode('/', $dataKey); + $current = &$result; + foreach ($keys as $k) { + if (!isset($current[$k])) { + $current[$k] = []; + } + $current = &$current[$k]; + } + $current = $value; + } + if ($clear) { + $this->clearData(); + } + return $result; } return $this->get($key, $clear); } + /** + * Flatten a nested array into path-based keys. + * + * @param array $array The nested array to flatten + * @param string $prefix The prefix for the current key path + * @return array Flat array of key-value pairs + */ + private function flattenArray($array, $prefix = '') + { + $result = []; + foreach ($array as $key => $value) { + $newKey = $prefix ? $prefix . '/' . $key : $key; + if (is_array($value)) { + $result = array_merge($result, $this->flattenArray($value, $newKey)); + } else { + $result[$newKey] = $value; + } + } + return $result; + } + /** * Set value in current session namespace * Equals to $_SESSION[NAMESPACE][$key] = $value - * @param string $key Also accepts multi-dimensional format. key1/key2 - * @param mixed $value + * @param string $key Also accepts path-based format (e.g., key1/key2) + * @param mixed $value Any value type (string, array, integer, etc.) * @return e_session */ public function set($key, $value) { - if(strpos($key,'/') !== false) // multi-dimensional - { - $keyArr = explode('/',$key); - $count = count($keyArr); - - if($count === 2) - { - list($k1, $k2) = $keyArr; - $this->_data[$k1][$k2] = $value; - } - elseif($count === 3) - { - list($k1, $k2, $k3) = $keyArr; - $this->_data[$k1][$k2][$k3] = $value; - } - } - else - { - $this->_data[$key] = $value; - } - + $this->_data[$key] = $value; return $this; } /** * Set value in current session namespace - * If $key is array, the whole namespace array will be replaced with it, + * If $key is array, the whole namespace array will be replaced with it (flattened), * $value will be ignored * @param string|array|null $key * @param mixed $value @@ -334,9 +384,8 @@ class e_session */ public function setData($key, $value = null) { - if(is_array($key)) - { - $this->_data = $key; + if (is_array($key)) { + $this->_data = $this->flattenArray($key); return $this; } return $this->set($key, $value); @@ -382,33 +431,12 @@ class e_session */ public function clear($key = null) { - if($key === null) // clear all under this namespace. - { - $this->_data = array(); // must be set to array() not unset. + if ($key === null) { + $this->_data = array(); return $this; } - if(strpos($key,'/') !== false) // multi-dimensional - { - $keyArr = explode('/',$key); - $count = count($keyArr); - - if($count === 2) - { - list($k1, $k2) = $keyArr; - unset($this->_data[$k1][$k2]); - } - elseif($count === 3) - { - list($k1, $k2, $k3) = $keyArr; - unset($this->_data[$k1][$k2][$k3]); - } - } - else - { - unset($this->_data[$key]); - } - + unset($this->_data[$key]); return $this; } @@ -953,17 +981,17 @@ class e_core_session extends e_session $details = "HOST: ".$_SERVER['HTTP_HOST']."\n"; $details .= "REQUEST_URI: ".$_SERVER['REQUEST_URI']."\n"; - $details .= ($_POST['e-token']) ? "e-token (POST): ".$_POST['e-token']."\n" : ""; - $details .= ($_GET['e-token']) ? "e-token (GET): ".$_GET['e-token']."\n" : ""; - $details .= ($_POST['e_token']) ? "AJAX e_token (POST): ".$_POST['e_token']."\n" : ""; + $details .= ($_POST['e-token']) ? "e-token (POST): ".$_POST['e-token']."\n" : ""; + $details .= ($_GET['e-token']) ? "e-token (GET): ".$_GET['e-token']."\n" : ""; + $details .= ($_POST['e_token']) ? "AJAX e_token (POST): ".$_POST['e_token']."\n" : ""; /* - $utoken = $this->getFormToken(false); - $details .= "raw token: ".$utoken."\n"; - $details .= "checkFormToken (e-token should match this): ".md5($utoken)."\n"; - $details .= "md5(e-token): ".md5($_POST['e-token'])."\n";*/ + $utoken = $this->getFormToken(false); + $details .= "raw token: ".$utoken."\n"; + $details .= "checkFormToken (e-token should match this): ".md5($utoken)."\n"; + $details .= "md5(e-token): ".md5($_POST['e-token'])."\n";*/ /* - $regenerate = $this->get('__form_token_regenerate'); - $details .= "Regenerate after: ".date('r', $regenerate)." (".$regenerate.")\n"; + $regenerate = $this->get('__form_token_regenerate'); + $details .= "Regenerate after: ".date('r', $regenerate)." (".$regenerate.")\n"; */ $details .= "has __form_token: "; @@ -1275,10 +1303,10 @@ class e_session_db implements SessionHandlerInterface * @param int $max_lifetime * @return bool */ - public function gc(int $max_lifetime): int|false - { - return $this->_db->delete($this->getTable(), '`session_expires`<'.time()); - } + public function gc(int $max_lifetime): int|false + { + return $this->_db->delete($this->getTable(), '`session_expires`<'.time()); + } /** * Allow only well formed session id string diff --git a/e107_tests/tests/unit/e_sessionTest.php b/e107_tests/tests/unit/e_sessionTest.php index 666976c4c..4883f3516 100644 --- a/e107_tests/tests/unit/e_sessionTest.php +++ b/e107_tests/tests/unit/e_sessionTest.php @@ -63,7 +63,7 @@ ); $result = $this->sess->get('clear'); - $this->assertSame($expected, $result); + $this::assertSame($expected, $result); } @@ -77,7 +77,7 @@ $result = $this->sess->get('whatever'); - $this->assertEquals($expected, $result); + $this::assertEquals($expected, $result); // Multi-dimensional array support. @@ -92,9 +92,30 @@ ); $result = $newsess->get('customer'); - $this->assertSame($expected, $result); + $this::assertSame($expected, $result); } + + function testSetGetArrayDepth() + { + // Flat + $array = ['a', 'b', 'c']; + e107::getSession()->set('thememanager', $array); + $result = e107::getSession()->get('thememanager'); + $this::assertSame($array, $result); + + // 1-level deep + $array2 = ['d', 'e', 'f']; + e107::getSession()->set('thememanager/online', $array2); + $result = e107::getSession()->get('thememanager/online'); + $this::assertSame($array2, $result); + + // 2-levels deep + $array3 = ['g', 'h', 'i']; + e107::getSession()->set('thememanager/online/55', $array3); + $result = e107::getSession()->get('thememanager/online/55'); + $this::assertSame($array3, $result); + } /* public function testGetOption() {