Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 18 additions & 3 deletions core/src/Support/ChunkFileStore.php
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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<string, string>
*/
Expand Down Expand Up @@ -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' => "<IfModule mod_authz_core.c>\n Require all denied\n</IfModule>\n"
. "<IfModule !mod_authz_core.c>\n Order deny,allow\n Deny from all\n</IfModule>\n",
'index.html' => "<h2>Unauthorized access</h2>\nYou're not allowed to access file folder",
] as $guard => $body) {
if (!file_exists($this->directory . '/' . $guard)) {
Expand All @@ -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;
Expand Down
40 changes: 40 additions & 0 deletions core/tests/Unit/Manager/ChunkFileStoreGuardsTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

use EvolutionCMS\Support\ChunkFileStore;

/**
* The chunk directory is guarded by an .htaccess the store writes itself, and the
* store is also built by processes that never ran the bootstrap - the cache refresh
* worker among them - so neither may depend on Apache 2.2 nor on EVO_BASE_PATH.
*/

it('writes the directory guard in both the 2.2 and the 2.4 dialect', function () {
$dir = sys_get_temp_dir() . '/evo_chunk_guard_' . uniqid();
$store = new ChunkFileStore(['html' => 'HTML'], $dir);

expect($store->ensureDirectory())->toBeTrue();

$htaccess = (string) file_get_contents($dir . '/.htaccess');
expect($htaccess)
->toContain('<IfModule mod_authz_core.c>')
->toContain('Require all denied')
->toContain('<IfModule !mod_authz_core.c>')
->and(preg_match('/^\s*(Order|Deny from)\b/mi', preg_replace('/<IfModule !mod_authz_core\.c>.*?<\/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, '<?php require ' . var_export(dirname(__DIR__, 3) . '/vendor/autoload.php', true) . ';'
. 'echo defined("EVO_BASE_PATH") ? "defined" : \EvolutionCMS\Support\ChunkFileStore::make()->displayDirectory();');
$out = trim((string) shell_exec(escapeshellarg(PHP_BINARY) . ' ' . escapeshellarg($probe) . ' 2>&1'));
unlink($probe);

expect($out)->toBe('views/chunks/');
});
9 changes: 7 additions & 2 deletions views/chunks/.htaccess
Original file line number Diff line number Diff line change
@@ -1,2 +1,7 @@
order deny,allow
deny from all
<IfModule mod_authz_core.c>
Require all denied
</IfModule>
<IfModule !mod_authz_core.c>
Order deny,allow
Deny from all
</IfModule>
Loading