diff --git a/core/src/Support/ChunkFileStore.php b/core/src/Support/ChunkFileStore.php index d8f3f726dd..6021dff554 100644 --- a/core/src/Support/ChunkFileStore.php +++ b/core/src/Support/ChunkFileStore.php @@ -54,7 +54,7 @@ public function __construct(array $formats, string $directory) public static function make(): self { $formats = []; - $directory = EVO_BASE_PATH . 'views/chunks/'; + $directory = self::basePath() . 'views/chunks/'; if (function_exists('config')) { try { @@ -68,6 +68,19 @@ public static function make(): self return new self($formats, $directory); } + /** + * The installation root, with a fallback for processes that run without the + * bootstrap constants (the cache refresh worker, tests). + * + * @since 3.5.8 + */ + protected static function basePath(): string + { + $base = defined('EVO_BASE_PATH') ? (string) EVO_BASE_PATH : dirname(__DIR__, 3) . '/'; + + return rtrim(str_replace(chr(92), '/', $base), '/') . '/'; + } + /** * @return array */ @@ -416,8 +429,10 @@ public function ensureDirectory(): bool return false; } + // both dialects: a bare 2.2 directive is a 500 on Apache 2.4 without mod_access_compat foreach ([ - '.htaccess' => "order deny,allow\ndeny from all\n", + '.htaccess' => "\n Require all denied\n\n" + . "\n Order deny,allow\n Deny from all\n\n", 'index.html' => "

Unauthorized access

\nYou're not allowed to access file folder", ] as $guard => $body) { if (!file_exists($this->directory . '/' . $guard)) { @@ -431,7 +446,7 @@ public function ensureDirectory(): bool /** Relative to the installation: an absolute server path is nobody's business. */ public function displayDirectory(): string { - $base = rtrim(str_replace(chr(92), '/', EVO_BASE_PATH), '/') . '/'; + $base = self::basePath(); $directory = $this->directory . '/'; return strpos($directory, $base) === 0 ? substr($directory, strlen($base)) : $directory; diff --git a/core/tests/Unit/Manager/ChunkFileStoreGuardsTest.php b/core/tests/Unit/Manager/ChunkFileStoreGuardsTest.php new file mode 100644 index 0000000000..2377aa0888 --- /dev/null +++ b/core/tests/Unit/Manager/ChunkFileStoreGuardsTest.php @@ -0,0 +1,40 @@ + 'HTML'], $dir); + + expect($store->ensureDirectory())->toBeTrue(); + + $htaccess = (string) file_get_contents($dir . '/.htaccess'); + expect($htaccess) + ->toContain('') + ->toContain('Require all denied') + ->toContain('') + ->and(preg_match('/^\s*(Order|Deny from)\b/mi', preg_replace('/.*?<\/IfModule>/s', '', $htaccess))) + ->toBe(0) + ->and($htaccess)->toBe((string) file_get_contents(dirname(__DIR__, 4) . '/views/chunks/.htaccess')); + + unlink($dir . '/.htaccess'); + unlink($dir . '/index.html'); + rmdir($dir); +}); + +it('resolves the installation root without the bootstrap constants', function () { + // A separate PHP process: constants defined by other tests must not leak in. + $probe = tempnam(sys_get_temp_dir(), 'evo_chunk_probe_'); + file_put_contents($probe, 'displayDirectory();'); + $out = trim((string) shell_exec(escapeshellarg(PHP_BINARY) . ' ' . escapeshellarg($probe) . ' 2>&1')); + unlink($probe); + + expect($out)->toBe('views/chunks/'); +}); diff --git a/views/chunks/.htaccess b/views/chunks/.htaccess index ff2beb844b..fb1de45bdb 100644 --- a/views/chunks/.htaccess +++ b/views/chunks/.htaccess @@ -1,2 +1,7 @@ -order deny,allow -deny from all + + Require all denied + + + Order deny,allow + Deny from all +