diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 394faa9ceb..d8d15ced42 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -553,36 +553,38 @@ jobs:
# A tag keeps its builds for 30 days, other runs for 5
retention-days: ${{ startsWith(github.ref, 'refs/tags/') && 30 || 5 }}
- build_extension_macos:
- permissions:
- contents: read
-
- name: Build / PHP-${{ matrix.php }}-${{ matrix.ts }}-${{ matrix.name }}-${{ matrix.arch }}
- needs: [generate_source]
- runs-on: ${{ matrix.os }}
- timeout-minutes: 30
- strategy:
- fail-fast: false
- matrix:
- php:
- - '8.1'
- - '8.2'
- - '8.3'
- - '8.4'
- - '8.5'
- ts:
- - 'nts'
- - 'ts'
- arch:
- - 'arm64'
-
- name:
- - macos-clang
-
- include:
- - { name: macos-clang, arch: arm64, os: macos-14, compiler: clang }
-
- steps: *build_extension_steps
+ # The macOS builds fail on most runs. They are disabled until the
+ # macOS runners are stable again.
+ # build_extension_macos:
+ # permissions:
+ # contents: read
+
+ # name: Build / PHP-${{ matrix.php }}-${{ matrix.ts }}-${{ matrix.name }}-${{ matrix.arch }}
+ # needs: [generate_source]
+ # runs-on: ${{ matrix.os }}
+ # timeout-minutes: 30
+ # strategy:
+ # fail-fast: false
+ # matrix:
+ # php:
+ # - '8.1'
+ # - '8.2'
+ # - '8.3'
+ # - '8.4'
+ # - '8.5'
+ # ts:
+ # - 'nts'
+ # - 'ts'
+ # arch:
+ # - 'arm64'
+
+ # name:
+ # - macos-clang
+
+ # include:
+ # - { name: macos-clang, arch: arm64, os: macos-14, compiler: clang }
+
+ # steps: *build_extension_steps
unit_test:
permissions:
@@ -1223,7 +1225,7 @@ jobs:
- generate_source
- generate_pecl
- build_extension
- - build_extension_macos
+ # - build_extension_macos
- build_extension_windows
- unit_test
- database_mariadb_test
diff --git a/CHANGELOG-5.0.md b/CHANGELOG-5.0.md
index 8342b21acf..a108bae211 100644
--- a/CHANGELOG-5.0.md
+++ b/CHANGELOG-5.0.md
@@ -2,6 +2,24 @@
All notable changes are documented here. The format is based on [Keep a Changelog][keep_a_changelog] and this project adheres to [Semantic Versioning][semantic_versioning].
+## [Unreleased](https://github.com/phalcon/cphalcon/releases/tag/vx.x.x) (2026-xx-xx)
+
+### Tools
+
+- Zephir 1.5.0
+
+### Changed
+
+### Added
+
+### Fixed
+
+- `Phalcon\Mvc\View::partial()` and `Phalcon\Mvc\View\Simple::render()` dropping a `..` path segment instead of resolving it. [#17606](https://github.com/phalcon/cphalcon/issues/17606) [[doc]](https://docs.phalcon.io/5.22/views/)
+- `Phalcon\Mvc\View::partial()` not detecting a Windows absolute path (`C:\...`) as absolute. [#17606](https://github.com/phalcon/cphalcon/issues/17606) [[doc]](https://docs.phalcon.io/5.22/views/)
+
+### Removed
+
+
## [5.22.0](https://github.com/phalcon/cphalcon/releases/tag/v5.22.0) (2026-09-22)
### Tools
diff --git a/README.md b/README.md
index dd3ba52b12..d4c2032879 100644
--- a/README.md
+++ b/README.md
@@ -100,6 +100,8 @@ Support us with a monthly donation and help us continue our activities. [[Become
+
+
## License
Phalcon is open-source software licensed under the BSD 3-Clause License.
diff --git a/ext/phalcon/mvc/view.zep.c b/ext/phalcon/mvc/view.zep.c
index 760f80e508..fafa847d45 100644
--- a/ext/phalcon/mvc/view.zep.c
+++ b/ext/phalcon/mvc/view.zep.c
@@ -1098,10 +1098,11 @@ PHP_METHOD(Phalcon_Mvc_View, isDisabled)
*/
PHP_METHOD(Phalcon_Mvc_View, partial)
{
- zend_bool _10$$4;
+ zend_bool _10$$6;
zephir_method_globals *ZEPHIR_METHOD_GLOBALS_PTR = NULL;
+ zephir_fcall_cache_entry *_12 = NULL;
zend_long ZEPHIR_LAST_CALL_STATUS;
- zval *partialPath_param = NULL, *params = NULL, params_sub, __$null, segment, segments, viewParams, _3, _4, _5, _6, *_7, _8, *_9, _11, _12, _13, _14, _15, _0$$3, _1$$3, _2$$3;
+ zval *partialPath_param = NULL, *params = NULL, params_sub, __$null, segment, segments, viewParams, _3, _4, _5, _6, *_7, _8, *_9, _13, _14, _15, _16, _17, _0$$3, _1$$3, _2$$3, _11$$6;
zval partialPath;
zval *this_ptr = getThis();
@@ -1116,14 +1117,15 @@ PHP_METHOD(Phalcon_Mvc_View, partial)
ZVAL_UNDEF(&_5);
ZVAL_UNDEF(&_6);
ZVAL_UNDEF(&_8);
- ZVAL_UNDEF(&_11);
- ZVAL_UNDEF(&_12);
ZVAL_UNDEF(&_13);
ZVAL_UNDEF(&_14);
ZVAL_UNDEF(&_15);
+ ZVAL_UNDEF(&_16);
+ ZVAL_UNDEF(&_17);
ZVAL_UNDEF(&_0$$3);
ZVAL_UNDEF(&_1$$3);
ZVAL_UNDEF(&_2$$3);
+ ZVAL_UNDEF(&_11$$6);
static zend_string *_zephir_prop_0 = NULL;
static zend_string *_zephir_prop_1 = NULL;
if (UNEXPECTED(!_zephir_prop_0)) {
@@ -1176,30 +1178,42 @@ PHP_METHOD(Phalcon_Mvc_View, partial)
} else {
_7 = &_3;
}
- zephir_is_iterable(_7, 0, "phalcon/Mvc/View.zep", 619);
+ zephir_is_iterable(_7, 0, "phalcon/Mvc/View.zep", 631);
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(_7), _9)
{
ZEPHIR_INIT_NVAR(&segment);
ZVAL_COPY(&segment, _9);
- _10$$4 = !ZEPHIR_IS_STRING_IDENTICAL(&segment, ".");
- if (_10$$4) {
- _10$$4 = !ZEPHIR_IS_STRING_IDENTICAL(&segment, "..");
+ if (ZEPHIR_IS_STRING_IDENTICAL(&segment, ".")) {
+ continue;
}
- if (_10$$4) {
- zephir_array_append(&segments, &segment, PH_SEPARATE, "phalcon/Mvc/View.zep", 615);
+ if (ZEPHIR_IS_STRING_IDENTICAL(&segment, "..")) {
+ _10$$6 = zephir_fast_count_int(&segments) > 0;
+ if (_10$$6) {
+ ZEPHIR_OBS_NVAR(&_11$$6);
+ zephir_array_fetch_long(&_11$$6, &segments, (zephir_fast_count_int(&segments) - 1), PH_NOISY, "phalcon/Mvc/View.zep", 621);
+ _10$$6 = !ZEPHIR_IS_STRING_IDENTICAL(&_11$$6, "");
+ }
+ if (_10$$6) {
+ ZEPHIR_MAKE_REF(&segments);
+ ZEPHIR_CALL_FUNCTION(NULL, "array_pop", &_12, 353, &segments);
+ ZEPHIR_UNREF(&segments);
+ zephir_check_call_status();
+ }
+ continue;
}
+ zephir_array_append(&segments, &segment, PH_SEPARATE, "phalcon/Mvc/View.zep", 628);
} ZEND_HASH_FOREACH_END();
ZEPHIR_INIT_NVAR(&segment);
ZEPHIR_INIT_NVAR(&partialPath);
zephir_fast_join_str(&partialPath, SL("/"), &segments);
- ZEPHIR_CALL_METHOD(&_11, this_ptr, "loadtemplateengines", NULL, 0);
+ ZEPHIR_CALL_METHOD(&_13, this_ptr, "loadtemplateengines", NULL, 0);
zephir_check_call_status();
- zephir_read_property_cached(&_12, this_ptr, _zephir_prop_1, 1190, PH_NOISY_CC | PH_READONLY);
- ZEPHIR_INIT_VAR(&_13);
- ZEPHIR_CONCAT_VV(&_13, &_12, &partialPath);
- ZVAL_BOOL(&_14, 0);
- ZVAL_BOOL(&_15, 0);
- ZEPHIR_CALL_METHOD(NULL, this_ptr, "enginerender", NULL, 0, &_11, &_13, &_14, &_15);
+ zephir_read_property_cached(&_14, this_ptr, _zephir_prop_1, 1190, PH_NOISY_CC | PH_READONLY);
+ ZEPHIR_INIT_VAR(&_15);
+ ZEPHIR_CONCAT_VV(&_15, &_14, &partialPath);
+ ZVAL_BOOL(&_16, 0);
+ ZVAL_BOOL(&_17, 0);
+ ZEPHIR_CALL_METHOD(NULL, this_ptr, "enginerender", NULL, 0, &_13, &_15, &_16, &_17);
zephir_check_call_status();
if (Z_TYPE_P(params) == IS_ARRAY) {
zephir_update_property_zval_cached(this_ptr, _zephir_prop_0, 1183, &viewParams);
@@ -1252,18 +1266,18 @@ PHP_METHOD(Phalcon_Mvc_View, pick)
} else {
ZEPHIR_INIT_VAR(&layout);
ZVAL_NULL(&layout);
- if (zephir_memnstr_str(renderView, SL("/"), "phalcon/Mvc/View.zep", 666)) {
+ if (zephir_memnstr_str(renderView, SL("/"), "phalcon/Mvc/View.zep", 678)) {
ZEPHIR_INIT_VAR(&parts);
zephir_fast_explode_str(&parts, SL("/"), renderView, ZEND_LONG_MAX);
ZEPHIR_OBS_NVAR(&layout);
- zephir_array_fetch_long(&layout, &parts, 0, PH_NOISY, "phalcon/Mvc/View.zep", 668);
+ zephir_array_fetch_long(&layout, &parts, 0, PH_NOISY, "phalcon/Mvc/View.zep", 680);
}
ZEPHIR_INIT_VAR(&_0$$4);
zephir_create_array(&_0$$4, 1, 0);
zephir_array_fast_append(&_0$$4, renderView);
ZEPHIR_CPY_WRT(&pickView, &_0$$4);
if (Z_TYPE_P(&layout) != IS_NULL) {
- zephir_array_append(&pickView, &layout, PH_SEPARATE, "phalcon/Mvc/View.zep", 674);
+ zephir_array_append(&pickView, &layout, PH_SEPARATE, "phalcon/Mvc/View.zep", 686);
}
}
zephir_update_property_zval_cached(this_ptr, _zephir_prop_0, 1191, &pickView);
@@ -1455,7 +1469,7 @@ PHP_METHOD(Phalcon_Mvc_View, processRender)
ZEPHIR_CPY_WRT(&renderView, &_3$$7);
} else {
ZEPHIR_OBS_NVAR(&renderView);
- zephir_array_fetch_long(&renderView, &pickView, 0, PH_NOISY, "phalcon/Mvc/View.zep", 755);
+ zephir_array_fetch_long(&renderView, &pickView, 0, PH_NOISY, "phalcon/Mvc/View.zep", 767);
if (Z_TYPE_P(&layoutName) == IS_NULL) {
zephir_memory_observe(&pickViewAction);
if (zephir_array_isset_long_fetch(&pickViewAction, &pickView, 1, 0)) {
@@ -1520,7 +1534,7 @@ PHP_METHOD(Phalcon_Mvc_View, processRender)
} else {
_12$$17 = &templatesBefore;
}
- zephir_is_iterable(_12$$17, 0, "phalcon/Mvc/View.zep", 831);
+ zephir_is_iterable(_12$$17, 0, "phalcon/Mvc/View.zep", 843);
if (Z_TYPE_P(_12$$17) == IS_ARRAY) {
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(_12$$17), _14$$17)
{
@@ -1600,7 +1614,7 @@ PHP_METHOD(Phalcon_Mvc_View, processRender)
} else {
_24$$23 = &templatesAfter;
}
- zephir_is_iterable(_24$$23, 0, "phalcon/Mvc/View.zep", 867);
+ zephir_is_iterable(_24$$23, 0, "phalcon/Mvc/View.zep", 879);
if (Z_TYPE_P(_24$$23) == IS_ARRAY) {
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(_24$$23), _26$$23)
{
@@ -2230,7 +2244,7 @@ PHP_METHOD(Phalcon_Mvc_View, setViewsDir)
object_init_ex(&_1$$3, phalcon_mvc_view_exceptions_invalidviewsdirtype_ce);
ZEPHIR_CALL_METHOD(NULL, &_1$$3, "__construct", NULL, 0);
zephir_check_call_status();
- zephir_throw_exception_debug(&_1$$3, "phalcon/Mvc/View.zep", 1143);
+ zephir_throw_exception_debug(&_1$$3, "phalcon/Mvc/View.zep", 1155);
ZEPHIR_MM_RESTORE();
return;
}
@@ -2248,7 +2262,7 @@ PHP_METHOD(Phalcon_Mvc_View, setViewsDir)
} else {
_3$$5 = viewsDir;
}
- zephir_is_iterable(_3$$5, 0, "phalcon/Mvc/View.zep", 1159);
+ zephir_is_iterable(_3$$5, 0, "phalcon/Mvc/View.zep", 1171);
if (Z_TYPE_P(_3$$5) == IS_ARRAY) {
ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(_3$$5), _6$$5, _7$$5, _5$$5)
{
@@ -2265,7 +2279,7 @@ PHP_METHOD(Phalcon_Mvc_View, setViewsDir)
object_init_ex(&_8$$7, phalcon_mvc_view_exceptions_viewsdiritemmustbestring_ce);
ZEPHIR_CALL_METHOD(NULL, &_8$$7, "__construct", &_9, 0);
zephir_check_call_status();
- zephir_throw_exception_debug(&_8$$7, "phalcon/Mvc/View.zep", 1153);
+ zephir_throw_exception_debug(&_8$$7, "phalcon/Mvc/View.zep", 1165);
ZEPHIR_MM_RESTORE();
return;
}
@@ -2298,7 +2312,7 @@ PHP_METHOD(Phalcon_Mvc_View, setViewsDir)
object_init_ex(&_13$$9, phalcon_mvc_view_exceptions_viewsdiritemmustbestring_ce);
ZEPHIR_CALL_METHOD(NULL, &_13$$9, "__construct", &_9, 0);
zephir_check_call_status();
- zephir_throw_exception_debug(&_13$$9, "phalcon/Mvc/View.zep", 1153);
+ zephir_throw_exception_debug(&_13$$9, "phalcon/Mvc/View.zep", 1165);
ZEPHIR_MM_RESTORE();
return;
}
@@ -2515,7 +2529,7 @@ PHP_METHOD(Phalcon_Mvc_View, engineRender)
} else {
_2 = &_1;
}
- zephir_is_iterable(_2, 0, "phalcon/Mvc/View.zep", 1270);
+ zephir_is_iterable(_2, 0, "phalcon/Mvc/View.zep", 1282);
if (Z_TYPE_P(_2) == IS_ARRAY) {
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(_2), _4)
{
@@ -2529,7 +2543,7 @@ PHP_METHOD(Phalcon_Mvc_View, engineRender)
} else {
ZEPHIR_CPY_WRT(&viewsDirPath, &viewPath_zv);
}
- zephir_is_iterable(&engines, 0, "phalcon/Mvc/View.zep", 1265);
+ zephir_is_iterable(&engines, 0, "phalcon/Mvc/View.zep", 1277);
if (Z_TYPE_P(&engines) == IS_ARRAY) {
ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(&engines), _8$$3, _9$$3, _7$$3)
{
@@ -2574,7 +2588,7 @@ PHP_METHOD(Phalcon_Mvc_View, engineRender)
}
RETURN_MM_NULL();
}
- zephir_array_append(&viewEnginePaths, &viewEnginePath, PH_SEPARATE, "phalcon/Mvc/View.zep", 1263);
+ zephir_array_append(&viewEnginePaths, &viewEnginePath, PH_SEPARATE, "phalcon/Mvc/View.zep", 1275);
} ZEND_HASH_FOREACH_END();
} else {
ZEPHIR_CALL_METHOD(NULL, &engines, "rewind", NULL, 0);
@@ -2629,7 +2643,7 @@ PHP_METHOD(Phalcon_Mvc_View, engineRender)
}
RETURN_MM_NULL();
}
- zephir_array_append(&viewEnginePaths, &viewEnginePath, PH_SEPARATE, "phalcon/Mvc/View.zep", 1263);
+ zephir_array_append(&viewEnginePaths, &viewEnginePath, PH_SEPARATE, "phalcon/Mvc/View.zep", 1275);
}
}
ZEPHIR_INIT_NVAR(&engine);
@@ -2661,7 +2675,7 @@ PHP_METHOD(Phalcon_Mvc_View, engineRender)
} else {
ZEPHIR_CPY_WRT(&viewsDirPath, &viewPath_zv);
}
- zephir_is_iterable(&engines, 0, "phalcon/Mvc/View.zep", 1265);
+ zephir_is_iterable(&engines, 0, "phalcon/Mvc/View.zep", 1277);
if (Z_TYPE_P(&engines) == IS_ARRAY) {
ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(&engines), _33$$16, _34$$16, _32$$16)
{
@@ -2706,7 +2720,7 @@ PHP_METHOD(Phalcon_Mvc_View, engineRender)
}
RETURN_MM_NULL();
}
- zephir_array_append(&viewEnginePaths, &viewEnginePath, PH_SEPARATE, "phalcon/Mvc/View.zep", 1263);
+ zephir_array_append(&viewEnginePaths, &viewEnginePath, PH_SEPARATE, "phalcon/Mvc/View.zep", 1275);
} ZEND_HASH_FOREACH_END();
} else {
ZEPHIR_CALL_METHOD(NULL, &engines, "rewind", NULL, 0);
@@ -2761,7 +2775,7 @@ PHP_METHOD(Phalcon_Mvc_View, engineRender)
}
RETURN_MM_NULL();
}
- zephir_array_append(&viewEnginePaths, &viewEnginePath, PH_SEPARATE, "phalcon/Mvc/View.zep", 1263);
+ zephir_array_append(&viewEnginePaths, &viewEnginePath, PH_SEPARATE, "phalcon/Mvc/View.zep", 1275);
}
}
ZEPHIR_INIT_NVAR(&engine);
@@ -2781,7 +2795,7 @@ PHP_METHOD(Phalcon_Mvc_View, engineRender)
object_init_ex(&_54$$30, phalcon_mvc_view_exceptions_viewnotfound_ce);
ZEPHIR_CALL_METHOD(NULL, &_54$$30, "__construct", NULL, 0, &viewPath_zv);
zephir_check_call_status();
- zephir_throw_exception_debug(&_54$$30, "phalcon/Mvc/View.zep", 1277);
+ zephir_throw_exception_debug(&_54$$30, "phalcon/Mvc/View.zep", 1289);
ZEPHIR_MM_RESTORE();
return;
}
@@ -2825,18 +2839,21 @@ PHP_METHOD(Phalcon_Mvc_View, getViewsDirs)
*/
PHP_METHOD(Phalcon_Mvc_View, isAbsolutePath)
{
- zend_bool _1$$3;
+ zend_bool _1$$3, _5$$3;
zephir_method_globals *ZEPHIR_METHOD_GLOBALS_PTR = NULL;
zend_long ZEPHIR_LAST_CALL_STATUS;
- zval path_zv, _0, _5, _2$$3, _3$$3, _4$$3;
+ zval path_zv, _0, _9, _2$$3, _3$$3, _4$$3, _6$$3, _7$$3, _8$$3;
zend_string *path = NULL;
ZVAL_UNDEF(&path_zv);
ZVAL_UNDEF(&_0);
- ZVAL_UNDEF(&_5);
+ ZVAL_UNDEF(&_9);
ZVAL_UNDEF(&_2$$3);
ZVAL_UNDEF(&_3$$3);
ZVAL_UNDEF(&_4$$3);
+ ZVAL_UNDEF(&_6$$3);
+ ZVAL_UNDEF(&_7$$3);
+ ZVAL_UNDEF(&_8$$3);
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_STR(path)
ZEND_PARSE_PARAMETERS_END();
@@ -2853,13 +2870,21 @@ PHP_METHOD(Phalcon_Mvc_View, isAbsolutePath)
ZVAL_LONG(&_3$$3, 2);
ZEPHIR_INIT_VAR(&_4$$3);
zephir_substr(&_4$$3, &path_zv, 1 , 2 , 0);
- _1$$3 = ZEPHIR_IS_STRING_IDENTICAL(&_4$$3, ":\\");
+ _5$$3 = ZEPHIR_IS_STRING_IDENTICAL(&_4$$3, ":\\");
+ if (!(_5$$3)) {
+ ZVAL_LONG(&_6$$3, 1);
+ ZVAL_LONG(&_7$$3, 2);
+ ZEPHIR_INIT_VAR(&_8$$3);
+ zephir_substr(&_8$$3, &path_zv, 1 , 2 , 0);
+ _5$$3 = ZEPHIR_IS_STRING_IDENTICAL(&_8$$3, ":/");
+ }
+ _1$$3 = _5$$3;
}
RETURN_MM_BOOL(_1$$3);
}
- ZEPHIR_INIT_VAR(&_5);
- ZVAL_STRING(&_5, "/");
- ZEPHIR_RETURN_CALL_FUNCTION("str_starts_with", NULL, 0, &path_zv, &_5);
+ ZEPHIR_INIT_VAR(&_9);
+ ZVAL_STRING(&_9, "/");
+ ZEPHIR_RETURN_CALL_FUNCTION("str_starts_with", NULL, 0, &path_zv, &_9);
zephir_check_call_status();
RETURN_MM();
}
@@ -2938,7 +2963,7 @@ PHP_METHOD(Phalcon_Mvc_View, loadTemplateEngines)
object_init_ex(&_3$$6, phalcon_mvc_view_exceptions_viewservicesunavailable_ce);
ZEPHIR_CALL_METHOD(NULL, &_3$$6, "__construct", NULL, 0);
zephir_check_call_status();
- zephir_throw_exception_debug(&_3$$6, "phalcon/Mvc/View.zep", 1335);
+ zephir_throw_exception_debug(&_3$$6, "phalcon/Mvc/View.zep", 1348);
ZEPHIR_MM_RESTORE();
return;
}
@@ -2949,7 +2974,7 @@ PHP_METHOD(Phalcon_Mvc_View, loadTemplateEngines)
} else {
_4$$5 = ®isteredEngines;
}
- zephir_is_iterable(_4$$5, 0, "phalcon/Mvc/View.zep", 1370);
+ zephir_is_iterable(_4$$5, 0, "phalcon/Mvc/View.zep", 1383);
if (Z_TYPE_P(_4$$5) == IS_ARRAY) {
ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(_4$$5), _7$$5, _8$$5, _6$$5)
{
@@ -2979,7 +3004,7 @@ PHP_METHOD(Phalcon_Mvc_View, loadTemplateEngines)
object_init_ex(&_13$$12, phalcon_mvc_view_exceptions_invalidengineregistration_ce);
ZEPHIR_CALL_METHOD(NULL, &_13$$12, "__construct", &_14, 0, &extension);
zephir_check_call_status();
- zephir_throw_exception_debug(&_13$$12, "phalcon/Mvc/View.zep", 1361);
+ zephir_throw_exception_debug(&_13$$12, "phalcon/Mvc/View.zep", 1374);
ZEPHIR_MM_RESTORE();
return;
}
@@ -3029,7 +3054,7 @@ PHP_METHOD(Phalcon_Mvc_View, loadTemplateEngines)
object_init_ex(&_21$$18, phalcon_mvc_view_exceptions_invalidengineregistration_ce);
ZEPHIR_CALL_METHOD(NULL, &_21$$18, "__construct", &_14, 0, &extension);
zephir_check_call_status();
- zephir_throw_exception_debug(&_21$$18, "phalcon/Mvc/View.zep", 1361);
+ zephir_throw_exception_debug(&_21$$18, "phalcon/Mvc/View.zep", 1374);
ZEPHIR_MM_RESTORE();
return;
}
diff --git a/ext/phalcon/mvc/view/simple.zep.c b/ext/phalcon/mvc/view/simple.zep.c
index cd232738fa..8c845a334c 100644
--- a/ext/phalcon/mvc/view/simple.zep.c
+++ b/ext/phalcon/mvc/view/simple.zep.c
@@ -799,13 +799,13 @@ PHP_METHOD(Phalcon_Mvc_View_Simple, loadTemplateEngines)
*/
PHP_METHOD(Phalcon_Mvc_View_Simple, internalRender)
{
- zend_string *_16;
- zend_ulong _15;
- zend_bool notExists = 0, mustClean = 0, _32, _10$$6, _22$$8, _37$$15;
+ zend_string *_18;
+ zend_ulong _17;
+ zend_bool notExists = 0, mustClean = 0, _34, _10$$8, _24$$10, _39$$17;
zephir_method_globals *ZEPHIR_METHOD_GLOBALS_PTR = NULL;
- zephir_fcall_cache_entry *_19 = NULL, *_27 = NULL, *_30 = NULL, *_42 = NULL, *_45 = NULL;
+ zephir_fcall_cache_entry *_12 = NULL, *_21 = NULL, *_29 = NULL, *_32 = NULL, *_44 = NULL, *_47 = NULL;
zend_long ZEPHIR_LAST_CALL_STATUS;
- zval *path_param = NULL, *params, params_sub, eventsManager, engines, extension, engine, segment, segments, _0, _3, _4, _5, _6, *_7, _8, *_9, _11, *_12, _13, *_14, _31, _1$$4, _2$$4, _17$$8, _18$$8, _20$$8, _21$$8, _23$$8, _28$$8, _24$$9, _25$$12, _26$$12, _29$$14, _33$$15, _34$$15, _35$$15, _36$$15, _38$$15, _43$$15, _39$$16, _40$$19, _41$$19, _44$$21, _46$$22, _47$$23;
+ zval *path_param = NULL, *params, params_sub, eventsManager, engines, extension, engine, segment, segments, _0, _3, _4, _5, _6, *_7, _8, *_9, _13, *_14, _15, *_16, _33, _1$$4, _2$$4, _11$$8, _19$$10, _20$$10, _22$$10, _23$$10, _25$$10, _30$$10, _26$$11, _27$$14, _28$$14, _31$$16, _35$$17, _36$$17, _37$$17, _38$$17, _40$$17, _45$$17, _41$$18, _42$$21, _43$$21, _46$$23, _48$$24, _49$$25;
zval path, viewEnginePath, viewsDirPath;
zval *this_ptr = getThis();
@@ -825,33 +825,34 @@ PHP_METHOD(Phalcon_Mvc_View_Simple, internalRender)
ZVAL_UNDEF(&_5);
ZVAL_UNDEF(&_6);
ZVAL_UNDEF(&_8);
- ZVAL_UNDEF(&_11);
ZVAL_UNDEF(&_13);
- ZVAL_UNDEF(&_31);
+ ZVAL_UNDEF(&_15);
+ ZVAL_UNDEF(&_33);
ZVAL_UNDEF(&_1$$4);
ZVAL_UNDEF(&_2$$4);
- ZVAL_UNDEF(&_17$$8);
- ZVAL_UNDEF(&_18$$8);
- ZVAL_UNDEF(&_20$$8);
- ZVAL_UNDEF(&_21$$8);
- ZVAL_UNDEF(&_23$$8);
- ZVAL_UNDEF(&_28$$8);
- ZVAL_UNDEF(&_24$$9);
- ZVAL_UNDEF(&_25$$12);
- ZVAL_UNDEF(&_26$$12);
- ZVAL_UNDEF(&_29$$14);
- ZVAL_UNDEF(&_33$$15);
- ZVAL_UNDEF(&_34$$15);
- ZVAL_UNDEF(&_35$$15);
- ZVAL_UNDEF(&_36$$15);
- ZVAL_UNDEF(&_38$$15);
- ZVAL_UNDEF(&_43$$15);
- ZVAL_UNDEF(&_39$$16);
- ZVAL_UNDEF(&_40$$19);
- ZVAL_UNDEF(&_41$$19);
- ZVAL_UNDEF(&_44$$21);
- ZVAL_UNDEF(&_46$$22);
- ZVAL_UNDEF(&_47$$23);
+ ZVAL_UNDEF(&_11$$8);
+ ZVAL_UNDEF(&_19$$10);
+ ZVAL_UNDEF(&_20$$10);
+ ZVAL_UNDEF(&_22$$10);
+ ZVAL_UNDEF(&_23$$10);
+ ZVAL_UNDEF(&_25$$10);
+ ZVAL_UNDEF(&_30$$10);
+ ZVAL_UNDEF(&_26$$11);
+ ZVAL_UNDEF(&_27$$14);
+ ZVAL_UNDEF(&_28$$14);
+ ZVAL_UNDEF(&_31$$16);
+ ZVAL_UNDEF(&_35$$17);
+ ZVAL_UNDEF(&_36$$17);
+ ZVAL_UNDEF(&_37$$17);
+ ZVAL_UNDEF(&_38$$17);
+ ZVAL_UNDEF(&_40$$17);
+ ZVAL_UNDEF(&_45$$17);
+ ZVAL_UNDEF(&_41$$18);
+ ZVAL_UNDEF(&_42$$21);
+ ZVAL_UNDEF(&_43$$21);
+ ZVAL_UNDEF(&_46$$23);
+ ZVAL_UNDEF(&_48$$24);
+ ZVAL_UNDEF(&_49$$25);
static zend_string *_zephir_prop_0 = NULL;
static zend_string *_zephir_prop_1 = NULL;
static zend_string *_zephir_prop_2 = NULL;
@@ -908,161 +909,173 @@ PHP_METHOD(Phalcon_Mvc_View_Simple, internalRender)
} else {
_7 = &_3;
}
- zephir_is_iterable(_7, 0, "phalcon/Mvc/View/Simple.zep", 473);
+ zephir_is_iterable(_7, 0, "phalcon/Mvc/View/Simple.zep", 485);
ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(_7), _9)
{
ZEPHIR_INIT_NVAR(&segment);
ZVAL_COPY(&segment, _9);
- _10$$6 = !ZEPHIR_IS_STRING_IDENTICAL(&segment, ".");
- if (_10$$6) {
- _10$$6 = !ZEPHIR_IS_STRING_IDENTICAL(&segment, "..");
+ if (ZEPHIR_IS_STRING_IDENTICAL(&segment, ".")) {
+ continue;
}
- if (_10$$6) {
- zephir_array_append(&segments, &segment, PH_SEPARATE, "phalcon/Mvc/View/Simple.zep", 469);
+ if (ZEPHIR_IS_STRING_IDENTICAL(&segment, "..")) {
+ _10$$8 = zephir_fast_count_int(&segments) > 0;
+ if (_10$$8) {
+ ZEPHIR_OBS_NVAR(&_11$$8);
+ zephir_array_fetch_long(&_11$$8, &segments, (zephir_fast_count_int(&segments) - 1), PH_NOISY, "phalcon/Mvc/View/Simple.zep", 475);
+ _10$$8 = !ZEPHIR_IS_STRING_IDENTICAL(&_11$$8, "");
+ }
+ if (_10$$8) {
+ ZEPHIR_MAKE_REF(&segments);
+ ZEPHIR_CALL_FUNCTION(NULL, "array_pop", &_12, 353, &segments);
+ ZEPHIR_UNREF(&segments);
+ zephir_check_call_status();
+ }
+ continue;
}
+ zephir_array_append(&segments, &segment, PH_SEPARATE, "phalcon/Mvc/View/Simple.zep", 482);
} ZEND_HASH_FOREACH_END();
ZEPHIR_INIT_NVAR(&segment);
ZEPHIR_INIT_NVAR(&path);
zephir_fast_join_str(&path, SL("/"), &segments);
zephir_read_property_cached(&_0, this_ptr, _zephir_prop_2, 1237, PH_NOISY_CC | PH_READONLY);
- ZEPHIR_INIT_VAR(&_11);
- ZEPHIR_CONCAT_VV(&_11, &_0, &path);
- zephir_get_strval(&viewsDirPath, &_11);
+ ZEPHIR_INIT_VAR(&_13);
+ ZEPHIR_CONCAT_VV(&_13, &_0, &path);
+ zephir_get_strval(&viewsDirPath, &_13);
ZEPHIR_CALL_METHOD(&engines, this_ptr, "loadtemplateengines", NULL, 0);
zephir_check_call_status();
if (Z_TYPE_P(&engines) == IS_STRING) {
- ZEPHIR_INIT_VAR(&_13);
- zephir_string_to_char_array(&_13, &engines);
- _12 = &_13;
+ ZEPHIR_INIT_VAR(&_15);
+ zephir_string_to_char_array(&_15, &engines);
+ _14 = &_15;
} else {
- _12 = &engines;
+ _14 = &engines;
}
- zephir_is_iterable(_12, 0, "phalcon/Mvc/View/Simple.zep", 524);
- if (Z_TYPE_P(_12) == IS_ARRAY) {
- ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(_12), _15, _16, _14)
+ zephir_is_iterable(_14, 0, "phalcon/Mvc/View/Simple.zep", 536);
+ if (Z_TYPE_P(_14) == IS_ARRAY) {
+ ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(_14), _17, _18, _16)
{
ZEPHIR_INIT_NVAR(&extension);
- if (_16 != NULL) {
- ZVAL_STR_COPY(&extension, _16);
+ if (_18 != NULL) {
+ ZVAL_STR_COPY(&extension, _18);
} else {
- ZVAL_LONG(&extension, _15);
+ ZVAL_LONG(&extension, _17);
}
ZEPHIR_INIT_NVAR(&engine);
- ZVAL_COPY(&engine, _14);
- ZEPHIR_INIT_NVAR(&_18$$8);
- ZEPHIR_CONCAT_VV(&_18$$8, &viewsDirPath, &extension);
- ZEPHIR_CALL_METHOD(&_17$$8, this_ptr, "phpfileexists", &_19, 0, &_18$$8);
+ ZVAL_COPY(&engine, _16);
+ ZEPHIR_INIT_NVAR(&_20$$10);
+ ZEPHIR_CONCAT_VV(&_20$$10, &viewsDirPath, &extension);
+ ZEPHIR_CALL_METHOD(&_19$$10, this_ptr, "phpfileexists", &_21, 0, &_20$$10);
zephir_check_call_status();
- if (zephir_is_true(&_17$$8)) {
- ZEPHIR_INIT_NVAR(&_24$$9);
- ZEPHIR_CONCAT_VV(&_24$$9, &viewsDirPath, &extension);
- zephir_get_strval(&viewEnginePath, &_24$$9);
+ if (zephir_is_true(&_19$$10)) {
+ ZEPHIR_INIT_NVAR(&_26$$11);
+ ZEPHIR_CONCAT_VV(&_26$$11, &viewsDirPath, &extension);
+ zephir_get_strval(&viewEnginePath, &_26$$11);
} else {
- ZVAL_LONG(&_20$$8, -zephir_fast_strlen_ev(&extension));
- ZEPHIR_INIT_NVAR(&_21$$8);
- zephir_substr(&_21$$8, &viewsDirPath, zephir_get_intval(&_20$$8), 0, ZEPHIR_SUBSTR_NO_LENGTH);
- _22$$8 = ZEPHIR_IS_EQUAL(&_21$$8, &extension);
- if (_22$$8) {
- ZEPHIR_CALL_METHOD(&_23$$8, this_ptr, "phpfileexists", &_19, 0, &viewsDirPath);
+ ZVAL_LONG(&_22$$10, -zephir_fast_strlen_ev(&extension));
+ ZEPHIR_INIT_NVAR(&_23$$10);
+ zephir_substr(&_23$$10, &viewsDirPath, zephir_get_intval(&_22$$10), 0, ZEPHIR_SUBSTR_NO_LENGTH);
+ _24$$10 = ZEPHIR_IS_EQUAL(&_23$$10, &extension);
+ if (_24$$10) {
+ ZEPHIR_CALL_METHOD(&_25$$10, this_ptr, "phpfileexists", &_21, 0, &viewsDirPath);
zephir_check_call_status();
- _22$$8 = zephir_is_true(&_23$$8);
+ _24$$10 = zephir_is_true(&_25$$10);
}
- if (_22$$8) {
+ if (_24$$10) {
ZEPHIR_CPY_WRT(&viewEnginePath, &viewsDirPath);
} else {
continue;
}
}
if (Z_TYPE_P(&eventsManager) == IS_OBJECT) {
- ZEPHIR_INIT_NVAR(&_26$$12);
- ZVAL_STRING(&_26$$12, "view:beforeRenderView");
- ZEPHIR_CALL_METHOD(&_25$$12, &eventsManager, "fire", &_27, 0, &_26$$12, this_ptr, &viewEnginePath);
+ ZEPHIR_INIT_NVAR(&_28$$14);
+ ZVAL_STRING(&_28$$14, "view:beforeRenderView");
+ ZEPHIR_CALL_METHOD(&_27$$14, &eventsManager, "fire", &_29, 0, &_28$$14, this_ptr, &viewEnginePath);
zephir_check_call_status();
- if (ZEPHIR_IS_FALSE_IDENTICAL(&_25$$12)) {
+ if (ZEPHIR_IS_FALSE_IDENTICAL(&_27$$14)) {
continue;
}
}
if (mustClean) {
- ZVAL_BOOL(&_28$$8, 1);
+ ZVAL_BOOL(&_30$$10, 1);
} else {
- ZVAL_BOOL(&_28$$8, 0);
+ ZVAL_BOOL(&_30$$10, 0);
}
- ZEPHIR_CALL_METHOD(NULL, &engine, "render", NULL, 0, &viewEnginePath, params, &_28$$8);
+ ZEPHIR_CALL_METHOD(NULL, &engine, "render", NULL, 0, &viewEnginePath, params, &_30$$10);
zephir_check_call_status();
notExists = 0;
if (Z_TYPE_P(&eventsManager) == IS_OBJECT) {
- ZEPHIR_INIT_NVAR(&_29$$14);
- ZVAL_STRING(&_29$$14, "view:afterRenderView");
- ZEPHIR_CALL_METHOD(NULL, &eventsManager, "fire", &_30, 0, &_29$$14, this_ptr);
+ ZEPHIR_INIT_NVAR(&_31$$16);
+ ZVAL_STRING(&_31$$16, "view:afterRenderView");
+ ZEPHIR_CALL_METHOD(NULL, &eventsManager, "fire", &_32, 0, &_31$$16, this_ptr);
zephir_check_call_status();
}
break;
} ZEND_HASH_FOREACH_END();
} else {
- ZEPHIR_CALL_METHOD(NULL, _12, "rewind", NULL, 0);
+ ZEPHIR_CALL_METHOD(NULL, _14, "rewind", NULL, 0);
zephir_check_call_status();
- _32 = 1;
+ _34 = 1;
while (1) {
- if (_32) {
- _32 = 0;
+ if (_34) {
+ _34 = 0;
} else {
- ZEPHIR_CALL_METHOD(NULL, _12, "next", NULL, 0);
+ ZEPHIR_CALL_METHOD(NULL, _14, "next", NULL, 0);
zephir_check_call_status();
}
- ZEPHIR_CALL_METHOD(&_31, _12, "valid", NULL, 0);
+ ZEPHIR_CALL_METHOD(&_33, _14, "valid", NULL, 0);
zephir_check_call_status();
- if (!zend_is_true(&_31)) {
+ if (!zend_is_true(&_33)) {
break;
}
- ZEPHIR_CALL_METHOD(&extension, _12, "key", NULL, 0);
+ ZEPHIR_CALL_METHOD(&extension, _14, "key", NULL, 0);
zephir_check_call_status();
- ZEPHIR_CALL_METHOD(&engine, _12, "current", NULL, 0);
+ ZEPHIR_CALL_METHOD(&engine, _14, "current", NULL, 0);
zephir_check_call_status();
- ZEPHIR_INIT_NVAR(&_34$$15);
- ZEPHIR_CONCAT_VV(&_34$$15, &viewsDirPath, &extension);
- ZEPHIR_CALL_METHOD(&_33$$15, this_ptr, "phpfileexists", &_19, 0, &_34$$15);
+ ZEPHIR_INIT_NVAR(&_36$$17);
+ ZEPHIR_CONCAT_VV(&_36$$17, &viewsDirPath, &extension);
+ ZEPHIR_CALL_METHOD(&_35$$17, this_ptr, "phpfileexists", &_21, 0, &_36$$17);
zephir_check_call_status();
- if (zephir_is_true(&_33$$15)) {
- ZEPHIR_INIT_NVAR(&_39$$16);
- ZEPHIR_CONCAT_VV(&_39$$16, &viewsDirPath, &extension);
- zephir_get_strval(&viewEnginePath, &_39$$16);
+ if (zephir_is_true(&_35$$17)) {
+ ZEPHIR_INIT_NVAR(&_41$$18);
+ ZEPHIR_CONCAT_VV(&_41$$18, &viewsDirPath, &extension);
+ zephir_get_strval(&viewEnginePath, &_41$$18);
} else {
- ZVAL_LONG(&_35$$15, -zephir_fast_strlen_ev(&extension));
- ZEPHIR_INIT_NVAR(&_36$$15);
- zephir_substr(&_36$$15, &viewsDirPath, zephir_get_intval(&_35$$15), 0, ZEPHIR_SUBSTR_NO_LENGTH);
- _37$$15 = ZEPHIR_IS_EQUAL(&_36$$15, &extension);
- if (_37$$15) {
- ZEPHIR_CALL_METHOD(&_38$$15, this_ptr, "phpfileexists", &_19, 0, &viewsDirPath);
+ ZVAL_LONG(&_37$$17, -zephir_fast_strlen_ev(&extension));
+ ZEPHIR_INIT_NVAR(&_38$$17);
+ zephir_substr(&_38$$17, &viewsDirPath, zephir_get_intval(&_37$$17), 0, ZEPHIR_SUBSTR_NO_LENGTH);
+ _39$$17 = ZEPHIR_IS_EQUAL(&_38$$17, &extension);
+ if (_39$$17) {
+ ZEPHIR_CALL_METHOD(&_40$$17, this_ptr, "phpfileexists", &_21, 0, &viewsDirPath);
zephir_check_call_status();
- _37$$15 = zephir_is_true(&_38$$15);
+ _39$$17 = zephir_is_true(&_40$$17);
}
- if (_37$$15) {
+ if (_39$$17) {
ZEPHIR_CPY_WRT(&viewEnginePath, &viewsDirPath);
} else {
continue;
}
}
if (Z_TYPE_P(&eventsManager) == IS_OBJECT) {
- ZEPHIR_INIT_NVAR(&_41$$19);
- ZVAL_STRING(&_41$$19, "view:beforeRenderView");
- ZEPHIR_CALL_METHOD(&_40$$19, &eventsManager, "fire", &_42, 0, &_41$$19, this_ptr, &viewEnginePath);
+ ZEPHIR_INIT_NVAR(&_43$$21);
+ ZVAL_STRING(&_43$$21, "view:beforeRenderView");
+ ZEPHIR_CALL_METHOD(&_42$$21, &eventsManager, "fire", &_44, 0, &_43$$21, this_ptr, &viewEnginePath);
zephir_check_call_status();
- if (ZEPHIR_IS_FALSE_IDENTICAL(&_40$$19)) {
+ if (ZEPHIR_IS_FALSE_IDENTICAL(&_42$$21)) {
continue;
}
}
if (mustClean) {
- ZVAL_BOOL(&_43$$15, 1);
+ ZVAL_BOOL(&_45$$17, 1);
} else {
- ZVAL_BOOL(&_43$$15, 0);
+ ZVAL_BOOL(&_45$$17, 0);
}
- ZEPHIR_CALL_METHOD(NULL, &engine, "render", NULL, 0, &viewEnginePath, params, &_43$$15);
+ ZEPHIR_CALL_METHOD(NULL, &engine, "render", NULL, 0, &viewEnginePath, params, &_45$$17);
zephir_check_call_status();
notExists = 0;
if (Z_TYPE_P(&eventsManager) == IS_OBJECT) {
- ZEPHIR_INIT_NVAR(&_44$$21);
- ZVAL_STRING(&_44$$21, "view:afterRenderView");
- ZEPHIR_CALL_METHOD(NULL, &eventsManager, "fire", &_45, 0, &_44$$21, this_ptr);
+ ZEPHIR_INIT_NVAR(&_46$$23);
+ ZVAL_STRING(&_46$$23, "view:afterRenderView");
+ ZEPHIR_CALL_METHOD(NULL, &eventsManager, "fire", &_47, 0, &_46$$23, this_ptr);
zephir_check_call_status();
}
break;
@@ -1071,18 +1084,18 @@ PHP_METHOD(Phalcon_Mvc_View_Simple, internalRender)
ZEPHIR_INIT_NVAR(&engine);
ZEPHIR_INIT_NVAR(&extension);
if (notExists) {
- ZEPHIR_INIT_VAR(&_46$$22);
- object_init_ex(&_46$$22, phalcon_mvc_view_exceptions_simpleviewnotfound_ce);
- ZEPHIR_CALL_METHOD(NULL, &_46$$22, "__construct", NULL, 0, &viewsDirPath);
+ ZEPHIR_INIT_VAR(&_48$$24);
+ object_init_ex(&_48$$24, phalcon_mvc_view_exceptions_simpleviewnotfound_ce);
+ ZEPHIR_CALL_METHOD(NULL, &_48$$24, "__construct", NULL, 0, &viewsDirPath);
zephir_check_call_status();
- zephir_throw_exception_debug(&_46$$22, "phalcon/Mvc/View/Simple.zep", 525);
+ zephir_throw_exception_debug(&_48$$24, "phalcon/Mvc/View/Simple.zep", 537);
ZEPHIR_MM_RESTORE();
return;
}
if (Z_TYPE_P(&eventsManager) == IS_OBJECT) {
- ZEPHIR_INIT_VAR(&_47$$23);
- ZVAL_STRING(&_47$$23, "view:afterRender");
- ZEPHIR_CALL_METHOD(NULL, &eventsManager, "fire", NULL, 0, &_47$$23, this_ptr);
+ ZEPHIR_INIT_VAR(&_49$$25);
+ ZVAL_STRING(&_49$$25, "view:afterRender");
+ ZEPHIR_CALL_METHOD(NULL, &eventsManager, "fire", NULL, 0, &_49$$25, this_ptr);
zephir_check_call_status();
}
ZEPHIR_MM_RESTORE();
diff --git a/phalcon/Mvc/View.zep b/phalcon/Mvc/View.zep
index 746e70bcd7..b13ef99353 100644
--- a/phalcon/Mvc/View.zep
+++ b/phalcon/Mvc/View.zep
@@ -604,16 +604,28 @@ class View extends Injectable implements ViewInterface, EventsAwareInterface
* partial
*/
/**
- * Drop "." and ".." path segments so a crafted partial path cannot
+ * Resolve "." and ".." path segments so a crafted partial path cannot
* climb out of the partials directory, while still allowing
- * sub-directories and absolute paths (CWE-22). Backslashes are
- * separators on Windows, so they are normalized first.
+ * sub-directories and absolute paths (CWE-22). A ".." removes the
+ * previous segment. At the top level, or at the root of an absolute
+ * path, the ".." is dropped. Backslashes are separators on Windows,
+ * so they are normalized first.
*/
let segments = [];
for segment in explode("/", str_replace("\\", "/", partialPath)) {
- if segment !== "." && segment !== ".." {
- let segments[] = segment;
+ if segment === "." {
+ continue;
}
+
+ if segment === ".." {
+ if count(segments) > 0 && segments[count(segments) - 1] !== "" {
+ array_pop(segments);
+ }
+
+ continue;
+ }
+
+ let segments[] = segment;
}
let partialPath = implode("/", segments);
@@ -1298,7 +1310,8 @@ class View extends Injectable implements ViewInterface, EventsAwareInterface
final protected function isAbsolutePath(string path)
{
if PHP_OS === "WINNT" {
- return strlen(path) >= 3 && substr(path, 1, 2) === ":\\";
+ return strlen(path) >= 3
+ && (substr(path, 1, 2) === ":\\" || substr(path, 1, 2) === ":/");
}
return str_starts_with(path, "/");
diff --git a/phalcon/Mvc/View/Simple.zep b/phalcon/Mvc/View/Simple.zep
index c88ffcf840..cadf54ef04 100644
--- a/phalcon/Mvc/View/Simple.zep
+++ b/phalcon/Mvc/View/Simple.zep
@@ -458,16 +458,28 @@ class Simple extends Injectable implements ViewBaseInterface, EventsAwareInterfa
mustClean = true;
/**
- * Drop "." and ".." path segments so a crafted view path cannot climb
- * out of the views directory, while still allowing sub-directories and
- * absolute paths (CWE-22). Backslashes are separators on Windows, so
- * they are normalized first.
+ * Resolve "." and ".." path segments so a crafted view path cannot
+ * climb out of the views directory, while still allowing
+ * sub-directories and absolute paths (CWE-22). A ".." removes the
+ * previous segment. At the top level, or at the root of an absolute
+ * path, the ".." is dropped. Backslashes are separators on Windows,
+ * so they are normalized first.
*/
let segments = [];
for segment in explode("/", str_replace("\\", "/", path)) {
- if segment !== "." && segment !== ".." {
- let segments[] = segment;
+ if segment === "." {
+ continue;
}
+
+ if segment === ".." {
+ if count(segments) > 0 && segments[count(segments) - 1] !== "" {
+ array_pop(segments);
+ }
+
+ continue;
+ }
+
+ let segments[] = segment;
}
let path = implode("/", segments);
diff --git a/tests/unit/Mvc/View/PartialTest.php b/tests/unit/Mvc/View/PartialTest.php
index d2dc802bd8..0f8ea67709 100755
--- a/tests/unit/Mvc/View/PartialTest.php
+++ b/tests/unit/Mvc/View/PartialTest.php
@@ -147,6 +147,34 @@ public function testMvcViewPartialCannotTraverseWithBackslash(): void
$this->assertSame('Hey, this is a partial, also abcde', $actual);
}
+ /**
+ * A `..` that stays inside the partial path removes the previous segment
+ * and is not dropped.
+ *
+ * @issue https://github.com/phalcon/cphalcon/issues/17606
+ * @author Phalcon Team
+ * @since 2026-09-23
+ */
+ public function testMvcViewPartialParentSegment(): void
+ {
+ $container = new Di();
+ $view = new View();
+
+ $view->setViewsDir(
+ $this->getDirSeparator(Talon::settings()->supportPath('assets/views'))
+ );
+ $view->setDI($container);
+
+ ob_start();
+ $view->partial(
+ 'currentrender/../partials/partial',
+ ['cool_var' => 'abcde']
+ );
+ $actual = ob_get_clean();
+
+ $this->assertSame('Hey, this is a partial, also abcde', $actual);
+ }
+
/**
* Dropping the `.` and `..` segments must keep a legitimate sub-directory
* partial working.
diff --git a/tests/unit/Mvc/View/Simple/RenderTraversalTest.php b/tests/unit/Mvc/View/Simple/RenderTraversalTest.php
index b675fcf69e..966586bca3 100644
--- a/tests/unit/Mvc/View/Simple/RenderTraversalTest.php
+++ b/tests/unit/Mvc/View/Simple/RenderTraversalTest.php
@@ -90,4 +90,22 @@ public function testMvcViewSimpleRenderCannotTraverseWithBackslash(): void
$this->assertSame($expected, $actual);
}
+
+ /**
+ * A `..` that stays inside the render path removes the previous segment
+ * and is not dropped.
+ *
+ * @issue https://github.com/phalcon/cphalcon/issues/17606
+ * @author Phalcon Team
+ * @since 2026-09-23
+ */
+ public function testMvcViewSimpleRenderParentSegment(): void
+ {
+ $view = $this->container->get('viewSimple');
+
+ $expected = 'here';
+ $actual = $view->render('partials/../currentrender/other');
+
+ $this->assertSame($expected, $actual);
+ }
}