mirror of
https://github.com/DirectoryLister/DirectoryLister.git
synced 2025-08-12 17:14:05 +02:00
Added the ability to specify files to be directly linked via the 'direct_links' configuration option
This commit is contained in:
@@ -62,6 +62,15 @@ return [
|
||||
*/
|
||||
'readmes_first' => env('READMES_FIRST', false),
|
||||
|
||||
/**
|
||||
* Comma separated list of file patterns to be directly linked. Directly
|
||||
* linked files will not be served by Directory Lister but handled by the
|
||||
* web server directly. This setting has no effect when FILES_PATH is set.
|
||||
*
|
||||
* Default value: null
|
||||
*/
|
||||
'direct_links' => env('DIRECT_LINKS', null),
|
||||
|
||||
/**
|
||||
* Enable downloading of directories as a zip archive.
|
||||
*
|
||||
|
@@ -4,23 +4,51 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\ViewFunctions;
|
||||
|
||||
use PHLAK\Splat\Glob;
|
||||
use PHLAK\Splat\Pattern;
|
||||
|
||||
class FileUrl extends Url
|
||||
{
|
||||
protected string $name = 'file_url';
|
||||
|
||||
/** Return the URL for a given path and action. */
|
||||
/** Direct links pattern cache. */
|
||||
private ?Pattern $pattern = null;
|
||||
|
||||
public function __invoke(string $path = '/'): string
|
||||
{
|
||||
if (is_file($path)) {
|
||||
return sprintf('?file=%s', $this->escape($this->normalizePath($path)));
|
||||
}
|
||||
$normalizedPath = $this->normalizePath($path);
|
||||
|
||||
$path = $this->normalizePath($path);
|
||||
|
||||
if ($path === '') {
|
||||
if ($normalizedPath === '') {
|
||||
return '';
|
||||
}
|
||||
|
||||
return sprintf('?dir=%s', $this->escape($path));
|
||||
$fullPath = $this->container->call('full_path', ['path' => $normalizedPath]);
|
||||
$escapedPath = $this->escape($normalizedPath);
|
||||
|
||||
if (is_file($fullPath)) {
|
||||
return $this->isDirectLink($fullPath) ? $escapedPath : sprintf('?file=%s', $escapedPath);
|
||||
}
|
||||
|
||||
return sprintf('?dir=%s', $escapedPath);
|
||||
}
|
||||
|
||||
/** Determine if a file should be directly linked. */
|
||||
private function isDirectLink(string $path): bool
|
||||
{
|
||||
if ($this->config->get('base_path') !== $this->config->get('files_path')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->config->get('direct_links') === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! $this->pattern instanceof Pattern) {
|
||||
$this->pattern = Pattern::make(sprintf('%s{%s}', Pattern::escape(
|
||||
$this->config->get('files_path') . DIRECTORY_SEPARATOR
|
||||
), $this->config->get('direct_links')));
|
||||
}
|
||||
|
||||
return Glob::matchStart($this->pattern, $path);
|
||||
}
|
||||
}
|
||||
|
@@ -6,6 +6,7 @@ namespace App\ViewFunctions;
|
||||
|
||||
use App\Config;
|
||||
use App\Support\Str;
|
||||
use DI\Container;
|
||||
|
||||
class Url extends ViewFunction
|
||||
{
|
||||
@@ -13,7 +14,8 @@ class Url extends ViewFunction
|
||||
|
||||
/** @param non-empty-string $directorySeparator */
|
||||
public function __construct(
|
||||
private Config $config,
|
||||
protected Container $container,
|
||||
protected Config $config,
|
||||
private string $directorySeparator = DIRECTORY_SEPARATOR
|
||||
) {}
|
||||
|
||||
|
@@ -8,7 +8,6 @@ class ZipUrl extends Url
|
||||
{
|
||||
protected string $name = 'zip_url';
|
||||
|
||||
/** Return the URL for a given path and action. */
|
||||
public function __invoke(string $path = '/'): string
|
||||
{
|
||||
$path = $this->normalizePath($path);
|
||||
|
@@ -15,10 +15,15 @@ class FileUrlTest extends TestCase
|
||||
#[Test]
|
||||
public function it_can_return_a_url(): void
|
||||
{
|
||||
$this->container->set('direct_links', '**/index.{htm,html},**/*.php');
|
||||
|
||||
$url = $this->container->get(FileUrl::class);
|
||||
|
||||
// Root
|
||||
$this->assertEquals('', $url('/'));
|
||||
$this->assertEquals('', $url('./'));
|
||||
|
||||
// Subdirectories
|
||||
$this->assertEquals('?dir=some/path', $url('some/path'));
|
||||
$this->assertEquals('?dir=some/path', $url('./some/path'));
|
||||
$this->assertEquals('?dir=some/path', $url('./some/path'));
|
||||
@@ -27,6 +32,16 @@ class FileUrlTest extends TestCase
|
||||
$this->assertEquals('?dir=0/path', $url('0/path'));
|
||||
$this->assertEquals('?dir=1/path', $url('1/path'));
|
||||
$this->assertEquals('?dir=0', $url('0'));
|
||||
|
||||
// Files
|
||||
$this->assertEquals('?file=subdir/alpha.scss', $url('subdir/alpha.scss'));
|
||||
$this->assertEquals('?file=subdir/bravo.js', $url('subdir/bravo.js'));
|
||||
$this->assertEquals('?file=subdir/charlie.bash', $url('subdir/charlie.bash'));
|
||||
|
||||
// Direct Links
|
||||
$this->assertEquals('direct_links/index.htm', $url('direct_links/index.htm'));
|
||||
$this->assertEquals('direct_links/index.html', $url('direct_links/index.html'));
|
||||
$this->assertEquals('direct_links/test.php', $url('direct_links/test.php'));
|
||||
}
|
||||
|
||||
#[Test]
|
||||
@@ -44,7 +59,8 @@ class FileUrlTest extends TestCase
|
||||
$this->assertEquals('?dir=1\path', $url('1\path'));
|
||||
}
|
||||
|
||||
public function test_url_segments_are_url_encoded(): void
|
||||
#[Test]
|
||||
public function url_segments_are_url_encoded(): void
|
||||
{
|
||||
$url = $this->container->get(FileUrl::class);
|
||||
|
||||
|
1
tests/_files/direct_links/index.htm
Normal file
1
tests/_files/direct_links/index.htm
Normal file
@@ -0,0 +1 @@
|
||||
<h1>Test file; please ignore</h1>
|
1
tests/_files/direct_links/index.html
Normal file
1
tests/_files/direct_links/index.html
Normal file
@@ -0,0 +1 @@
|
||||
<h1>Test file; please ignore</h1>
|
3
tests/_files/direct_links/test.php
Normal file
3
tests/_files/direct_links/test.php
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php
|
||||
|
||||
echo 'Test file; please ignore'
|
Reference in New Issue
Block a user