<?php

declare(strict_types=1);

/**
 * 本文件属于 DBErp 进销存系统。
 *
 * 版权所有 © 2026 北京珑大钜商科技有限公司。保留所有权利。
 *
 * 未经官方授权，不得删除、篡改或隐藏本文件中的版权声明、产品标识与来源信息。
 * 商业授权、官方更新与技术支持服务，请以珑大官方支持中心记录为准。
 *
 * @link https://support.loongdom.cn
 * @see  https://www.dberp.com.cn
 */

namespace App\Support\Filesystem;

use Throwable;

/**
 * 在 open_basedir 等受限环境下安全探测路径，避免文件系统警告升级为异常并中断页面渲染。
 */
class SafeFilesystemProbe
{
    public function safeIsFile(string $path): bool
    {
        if ($path === '') {
            return false;
        }

        if (! $this->isPathAllowedByOpenBasedir($path)) {
            return false;
        }

        try {
            return @is_file($path) === true;
        } catch (Throwable) {
            return false;
        }
    }

    public function safeIsExecutable(string $path): bool
    {
        if ($path === '') {
            return false;
        }

        if (! $this->isPathAllowedByOpenBasedir($path)) {
            return false;
        }

        try {
            return @is_executable($path) === true;
        } catch (Throwable) {
            return false;
        }
    }

    public function isPathAllowedByOpenBasedir(string $path, ?string $restriction = null): bool
    {
        if ($path === '') {
            return false;
        }

        $restriction = trim($restriction ?? (string) ini_get('open_basedir'));

        if ($restriction === '') {
            return true;
        }

        $normalizedPath = $this->normalizePath($path);
        $roots = preg_split('/[:;]/', str_replace('\\', '/', $restriction)) ?: [];

        foreach ($roots as $root) {
            $normalizedRoot = $this->normalizeOpenBasedirRoot($root);

            if ($normalizedRoot === '') {
                continue;
            }

            if ($normalizedPath === $normalizedRoot || str_starts_with($normalizedPath.'/', $normalizedRoot.'/')) {
                return true;
            }
        }

        return false;
    }

    /**
     * 对可能落在 open_basedir 外的路径尝试 realpath；不可访问时返回 null，不抛异常。
     */
    public function safeRealpath(string $path): ?string
    {
        if ($path === '') {
            return null;
        }

        if (! $this->isPathAllowedByOpenBasedir($path)) {
            return null;
        }

        try {
            $resolved = @realpath($path);

            return is_string($resolved) && $resolved !== '' ? $resolved : null;
        } catch (Throwable) {
            return null;
        }
    }

    private function normalizePath(string $path): string
    {
        $normalized = str_replace('\\', '/', $path);
        $normalized = preg_replace('#/+#', '/', $normalized) ?? $normalized;

        return rtrim($normalized, '/');
    }

    private function normalizeOpenBasedirRoot(string $root): string
    {
        $root = trim($root);

        if ($root === '') {
            return '';
        }

        $normalized = $this->normalizePath($root);

        // open_basedir 根目录本身通常可访问；失败时回退为字符串规范化结果。
        try {
            $resolved = @realpath($normalized);

            if (is_string($resolved) && $resolved !== '') {
                return $this->normalizePath($resolved);
            }
        } catch (Throwable) {
            // 保持字符串规范化结果
        }

        return $normalized;
    }
}
