fix: link old
This commit is contained in:
@@ -261,19 +261,16 @@ class PhotoPreview
|
|||||||
private function resolveBinary(string $name): ?string
|
private function resolveBinary(string $name): ?string
|
||||||
{
|
{
|
||||||
$candidates = match ($name) {
|
$candidates = match ($name) {
|
||||||
'magick' => [base_path('bin/magick'), 'magick', '/opt/homebrew/bin/magick', '/usr/local/bin/magick', '/usr/bin/magick'],
|
'magick' => [base_path('bin/magick'), '/opt/homebrew/bin/magick', '/usr/local/bin/magick', '/usr/bin/magick', 'magick'],
|
||||||
'convert' => ['convert', '/usr/bin/convert'],
|
'convert' => [base_path('bin/convert'), '/usr/bin/convert', 'convert'],
|
||||||
'heif-convert' => [base_path('bin/heif-convert'), 'heif-convert', '/usr/bin/heif-convert', '/usr/local/bin/heif-convert'],
|
'heif-convert' => [base_path('bin/heif-convert'), '/usr/bin/heif-convert', '/usr/local/bin/heif-convert', 'heif-convert'],
|
||||||
'heif-dec' => [base_path('bin/heif-dec'), 'heif-dec', '/usr/bin/heif-dec', '/usr/local/bin/heif-dec'],
|
'heif-dec' => [base_path('bin/heif-dec'), '/usr/bin/heif-dec', '/usr/local/bin/heif-dec', 'heif-dec'],
|
||||||
default => [$name],
|
default => [$name],
|
||||||
};
|
};
|
||||||
|
$outside = null;
|
||||||
$bare = null;
|
$bare = null;
|
||||||
foreach ($candidates as $bin) {
|
foreach ($candidates as $bin) {
|
||||||
if (! str_contains($bin, DIRECTORY_SEPARATOR)) {
|
if (! str_contains($bin, DIRECTORY_SEPARATOR)) {
|
||||||
$found = $this->which($bin);
|
|
||||||
if ($found !== null) {
|
|
||||||
return $found;
|
|
||||||
}
|
|
||||||
$bare ??= $bin;
|
$bare ??= $bin;
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
@@ -281,26 +278,13 @@ class PhotoPreview
|
|||||||
if ($this->isSafeExecutable($bin)) {
|
if ($this->isSafeExecutable($bin)) {
|
||||||
return $bin;
|
return $bin;
|
||||||
}
|
}
|
||||||
}
|
// Panel open_basedir blocks PHP from stat() /usr/bin, but proc_open can still run it.
|
||||||
|
if (! $this->isPathInsideOpenBasedir($bin)) {
|
||||||
// exec() is often allowed when is_executable() is not; let Process try PATH.
|
$outside ??= $bin;
|
||||||
return $bare;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function which(string $name): ?string
|
|
||||||
{
|
|
||||||
$path = getenv('PATH');
|
|
||||||
if (! is_string($path) || $path === '') {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
foreach (explode(PATH_SEPARATOR, $path) as $dir) {
|
|
||||||
$candidate = rtrim($dir, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR.$name;
|
|
||||||
if ($this->isSafeExecutable($candidate)) {
|
|
||||||
return $candidate;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return $outside ?? $bare;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function isSafeExecutable(string $path): bool
|
private function isSafeExecutable(string $path): bool
|
||||||
@@ -318,14 +302,30 @@ class PhotoPreview
|
|||||||
if ($basedir === '') {
|
if ($basedir === '') {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
$real = realpath($path);
|
$roots = [];
|
||||||
$check = $real !== false ? $real : $path;
|
|
||||||
foreach (explode(PATH_SEPARATOR, $basedir) as $root) {
|
foreach (explode(PATH_SEPARATOR, $basedir) as $root) {
|
||||||
$root = rtrim($root, DIRECTORY_SEPARATOR);
|
$root = rtrim($root, DIRECTORY_SEPARATOR);
|
||||||
if ($root === '') {
|
if ($root !== '') {
|
||||||
continue;
|
$roots[] = $root;
|
||||||
}
|
}
|
||||||
if ($check === $root || str_starts_with($check, $root.DIRECTORY_SEPARATOR)) {
|
}
|
||||||
|
if ($this->pathPrefixedByRoot($path, $roots)) {
|
||||||
|
$real = @realpath($path);
|
||||||
|
$check = is_string($real) && $real !== '' ? $real : $path;
|
||||||
|
|
||||||
|
return $this->pathPrefixedByRoot($check, $roots);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param list<string> $roots
|
||||||
|
*/
|
||||||
|
private function pathPrefixedByRoot(string $path, array $roots): bool
|
||||||
|
{
|
||||||
|
foreach ($roots as $root) {
|
||||||
|
if ($path === $root || str_starts_with($path, $root.DIRECTORY_SEPARATOR)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,18 @@ use Tests\TestCase;
|
|||||||
|
|
||||||
class PhotoPreviewTest extends TestCase
|
class PhotoPreviewTest extends TestCase
|
||||||
{
|
{
|
||||||
|
#[Test]
|
||||||
|
public function basedir_probe_does_not_realpath_system_bins(): void
|
||||||
|
{
|
||||||
|
$preview = new PhotoPreview;
|
||||||
|
$ref = new \ReflectionMethod(PhotoPreview::class, 'isPathInsideOpenBasedir');
|
||||||
|
$this->assertFalse($ref->invoke($preview, '/usr/bin/heif-convert')
|
||||||
|
&& (string) ini_get('open_basedir') !== ''
|
||||||
|
&& ! str_contains((string) ini_get('open_basedir'), '/usr/bin'));
|
||||||
|
$resolved = (new \ReflectionMethod(PhotoPreview::class, 'resolveBinary'))->invoke($preview, 'heif-convert');
|
||||||
|
$this->assertNotNull($resolved);
|
||||||
|
}
|
||||||
|
|
||||||
#[Test]
|
#[Test]
|
||||||
public function detects_heic_ftyp_header(): void
|
public function detects_heic_ftyp_header(): void
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user