Passed
Push — master ( e779bf...8d157f )
by Gabriel
03:58
created

FileDisk::download()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
c 0
b 0
f 0
nc 1
nop 3
dl 0
loc 3
rs 10
ccs 2
cts 2
cp 1
crap 1
1
<?php
2
3
namespace Nip\Filesystem;
4
5
use League\Flysystem\Adapter\Local as LocalAdapter;
6
use League\Flysystem\AwsS3v3\AwsS3Adapter;
7
use League\Flysystem\Cached\CachedAdapter;
8
use League\Flysystem\Filesystem as Flysystem;
9
use Nip\Utility\Str;
10
use RuntimeException;
11
use Symfony\Component\HttpFoundation\File\UploadedFile;
12
13
//use League\Flysystem\AwsS3v3\AwsS3Adapter;
14
15
/**
16
 * Class FlysystemAdapter
17
 * @package Nip\Filesystem
18
 */
19
class FileDisk extends Flysystem
20
{
21
22
    /**
23
     * Store the uploaded file on the disk with a given name.
24
     *
25
     * @param string $path
26
     * @param UploadedFile $file
27
     * @param string $name
28
     * @param array $options
29
     * @return string|false
30
     */
31
    public function putFileAs($path, $file, $name, $options = [])
32
    {
33
        $stream = fopen($file->getRealPath(), 'r+');
34
35
        // Next, we will format the path of the file and store the file using a stream since
36
        // they provide better performance than alternatives. Once we write the file this
37
        // stream will get closed automatically by us so the developer doesn't have to.
38
        $result = $this->put(
39
            $path = trim($path . '/' . $name, '/'),
40
            $stream,
41
            $options
42
        );
43
44
        if (is_resource($stream)) {
45
            fclose($stream);
46
        }
47
        return $result ? $path : false;
48
    }
49
50
    /**
51
     * Get the URL for the file at the given path.
52
     *
53
     * @param string $path
54
     * @return string
55
     */
56
    public function getUrl($path)
57
    {
58
        $adapter = $this->getAdapter();
59
60
        if ($adapter instanceof CachedAdapter) {
61
            $adapter = $adapter->getAdapter();
62
        }
63
64
        if (method_exists($adapter, 'getUrl')) {
65
            return $adapter->getUrl($path);
66
        } elseif ($adapter instanceof AwsS3Adapter) {
67
            $path = ltrim($path,'/');
68
            return $this->getAwsUrl($adapter, $path);
69
        } elseif ($adapter instanceof LocalAdapter) {
70
            return $this->getLocalUrl($path);
71
        } else {
72
            throw new RuntimeException('This driver does not support retrieving URLs.');
73
        }
74
    }
75
76
    /**
77
     * Get the URL for the file at the given path.
78
     *
79
     * @param string $path
80
     * @return string
81
     */
82
    protected function getLocalUrl($path)
83
    {
84
        $config = $this->getConfig();
85
86
        // If an explicit base URL has been set on the disk configuration then we will use
87
        // it as the base URL instead of the default path. This allows the developer to
88
        // have full control over the base path for this filesystem's generated URLs.
89
        if ($config->has('url')) {
90
            return $this->concatPathToUrl($config->get('url'), $path);
91
        }
92
        $path = '/storage/' . $path;
93
        // If the path contains "storage/public", it probably means the developer is using
94
        // the default disk to generate the path instead of the "public" disk like they
95
        // are really supposed to use. We will remove the public from this path here.
96
        if (Str::contains($path, '/storage/public/')) {
97
            return Str::replaceFirst('/public/', '/', $path);
98
        } else {
99
            return $path;
100
        }
101
    }
102
103
    /**
104
     * Get the URL for the file at the given path.
105
     *
106
     * @param \League\Flysystem\AwsS3v3\AwsS3Adapter $adapter
107
     * @param string $path
108
     * @return string
109
     */
110
    protected function getAwsUrl($adapter, $path)
111
    {
112
        // If an explicit base URL has been set on the disk configuration then we will use
113
        // it as the base URL instead of the default path. This allows the developer to
114
        // have full control over the base path for this filesystem's generated URLs.
115
        if (!is_null($url = $this->getConfig()->get('url'))) {
116
            return $this->concatPathToUrl($url, $adapter->getPathPrefix() . $path);
117
        }
118
119
        return $adapter->getClient()->getObjectUrl(
120
            $adapter->getBucket(),
121
            $adapter->getPathPrefix() . $path
122
        );
123
    }
124
125
    /**
126
     * Concatenate a path to a URL.
127
     *
128
     * @param string $url
129
     * @param string $path
130
     * @return string
131
     */
132
    protected function concatPathToUrl($url, $path)
133
    {
134
        return rtrim($url, '/') . '/' . ltrim($path, '/');
135
    }
136
137
138
139
    /**
140
     * Create a streamed response for a given file.
141
     *
142
     * @param  string  $path
143
     * @param  string|null  $name
144
     * @param  array|null  $headers
145
     * @param  string|null  $disposition
146
     * @return \Symfony\Component\HttpFoundation\StreamedResponse
147
     */
148 2
    public function response($path, $name = null, array $headers = [], $disposition = 'inline')
149
    {
150 2
        $response = new \Symfony\Component\HttpFoundation\StreamedResponse;
151
152 2
        $filename = $name ?? basename($path);
153
154 2
        $disposition = $response->headers->makeDisposition(
155 2
            $disposition, $filename, $this->fallbackName($filename)
156
        );
157
158 2
        $response->headers->replace($headers + [
159 2
                'Content-Type' => $this->getMimetype($path),
160 2
                'Content-Length' => $this->getSize($path),
161 2
                'Content-Disposition' => $disposition,
162
            ]);
163
164
        $response->setCallback(function () use ($path) {
165 1
            $stream = $this->readStream($path);
166 1
            fpassthru($stream);
0 ignored issues
show
Bug introduced by
It seems like $stream can also be of type false; however, parameter $handle of fpassthru() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

166
            fpassthru(/** @scrutinizer ignore-type */ $stream);
Loading history...
167 1
            fclose($stream);
0 ignored issues
show
Bug introduced by
It seems like $stream can also be of type false; however, parameter $handle of fclose() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

167
            fclose(/** @scrutinizer ignore-type */ $stream);
Loading history...
168 2
        });
169
170 2
        return $response;
171
    }
172
173
    /**
174
     * Create a streamed download response for a given file.
175
     *
176
     * @param  string  $path
177
     * @param  string|null  $name
178
     * @param  array|null  $headers
179
     * @return \Symfony\Component\HttpFoundation\StreamedResponse
180
     */
181 1
    public function download($path, $name = null, array $headers = [])
182
    {
183 1
        return $this->response($path, $name, $headers, 'attachment');
184
    }
185
186
    /**
187
     * Convert the string to ASCII characters that are equivalent to the given name.
188
     *
189
     * @param  string  $name
190
     * @return string
191
     */
192 2
    protected function fallbackName($name)
193
    {
194 2
        return str_replace('%', '', Str::ascii($name));
195
    }
196
}
197