File size: 3,158 Bytes
6773345
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
<?php

namespace App\Domain\Files;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\URL;

class SignedFileUrlFactory
{
    public function temporaryFileDownloadUrl(string $routeName, string $fileId, ?Carbon $expiresAt = null): array
    {
        return $this->temporaryFileUrl($routeName, $fileId, $expiresAt);
    }

    public function temporaryFileStreamUrl(string $routeName, string $fileId, ?Carbon $expiresAt = null): array
    {
        return $this->temporaryFileUrl($routeName, $fileId, $expiresAt);
    }

    private function temporaryFileUrl(string $routeName, string $fileId, ?Carbon $expiresAt = null): array
    {
        $expiresAt ??= Carbon::now()->addMinutes(10);
        $signedRelativeUrl = URL::temporarySignedRoute($routeName, $expiresAt, [
            'fileId' => $fileId,
        ], false);

        $relativePath = parse_url($signedRelativeUrl, PHP_URL_PATH) ?: $signedRelativeUrl;
        $queryString = (string) (parse_url($signedRelativeUrl, PHP_URL_QUERY) ?: '');
        $publicPath = $this->publicPathFor($relativePath);

        return [
            'url' => rtrim($this->publicOrigin(), '/').$publicPath.($queryString === '' ? '' : '?'.$queryString),
            'expires_at' => $expiresAt,
        ];
    }

    private function publicPathFor(string $relativePath): string
    {
        $publicBase = $this->publicApiBaseUrl();
        $basePath = rtrim((string) (parse_url($publicBase, PHP_URL_PATH) ?: ''), '/');

        if ($basePath === '') {
            return $relativePath;
        }

        if (str_starts_with($relativePath, $basePath.'/')) {
            return $relativePath;
        }

        if (str_ends_with($basePath, '/api/v1') && str_starts_with($relativePath, '/api/v1/')) {
            return $basePath.substr($relativePath, strlen('/api/v1'));
        }

        return $relativePath;
    }

    private function publicOrigin(): string
    {
        $publicBase = $this->publicApiBaseUrl();
        $basePath = rtrim((string) (parse_url($publicBase, PHP_URL_PATH) ?: ''), '/');

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

        return preg_replace('#'.preg_quote($basePath, '#').'$#', '', $publicBase) ?: $publicBase;
    }

    private function publicApiBaseUrl(): string
    {
        $configured = trim((string) (config('app.public_api_base_url') ?: config('platform.backend_api_base_url')));
        if ($configured !== '') {
            return rtrim($configured, '/');
        }

        $request = request();
        $origin = $request->getSchemeAndHttpHost();
        $baseUrl = rtrim($request->getBaseUrl(), '/');

        if ($origin !== '' && $baseUrl !== '') {
            return $origin.$baseUrl.'/api/v1';
        }

        $requestPath = (string) (parse_url($request->getRequestUri(), PHP_URL_PATH) ?: '');
        $apiPrefixPosition = strpos($requestPath, '/api/v1');

        if ($origin !== '' && $apiPrefixPosition !== false) {
            $publicPrefix = rtrim(substr($requestPath, 0, $apiPrefixPosition), '/');

            return $origin.$publicPrefix.'/api/v1';
        }

        return rtrim((string) config('app.url'), '/');
    }
}