1 | <?php |
||
2 | |||
3 | namespace Nip\Filesystem; |
||
4 | |||
5 | use League\Flysystem\Config; |
||
6 | use League\Flysystem\FilesystemAdapter; |
||
7 | use League\Flysystem\Local\LocalFilesystemAdapter as LocalAdapter; |
||
8 | use League\Flysystem\AwsS3v3\AwsS3V3Adapter; |
||
9 | use League\Flysystem\Filesystem as Flysystem; |
||
10 | use League\Flysystem\PathNormalizer; |
||
11 | use League\Flysystem\WhitespacePathNormalizer; |
||
12 | use Nip\Utility\Str; |
||
13 | use RuntimeException; |
||
14 | use Symfony\Component\HttpFoundation\File\UploadedFile; |
||
15 | |||
16 | /** |
||
17 | * Class FlysystemAdapter |
||
18 | * @package Nip\Filesystem |
||
19 | */ |
||
20 | class FileDisk extends Flysystem |
||
21 | { |
||
22 | protected $adapter; |
||
23 | |||
24 | public function __construct( |
||
25 | FilesystemAdapter $adapter, |
||
26 | array $config = [], |
||
27 | PathNormalizer $pathNormalizer = null |
||
28 | ) { |
||
29 | $this->adapter = $adapter; |
||
30 | parent::__construct($adapter, $config, $pathNormalizer); |
||
31 | } |
||
32 | |||
33 | public function getAdapter() |
||
34 | { |
||
35 | return $this->adapter; |
||
36 | } |
||
37 | |||
38 | /** |
||
39 | * Store the uploaded file on the disk with a given name. |
||
40 | * |
||
41 | * @param string $path |
||
42 | * @param UploadedFile $file |
||
43 | * @param string $name |
||
44 | * @param array $options |
||
45 | * @return string|false |
||
46 | */ |
||
47 | public function putFileAs($path, $file, $name, $options = []) |
||
48 | { |
||
49 | $stream = fopen($file->getRealPath(), 'r+'); |
||
50 | |||
51 | // Next, we will format the path of the file and store the file using a stream since |
||
52 | // they provide better performance than alternatives. Once we write the file this |
||
53 | // stream will get closed automatically by us so the developer doesn't have to. |
||
54 | $result = $this->put( |
||
55 | $path = trim($path . '/' . $name, '/'), |
||
56 | $stream, |
||
57 | $options |
||
58 | ); |
||
59 | |||
60 | if (is_resource($stream)) { |
||
61 | fclose($stream); |
||
62 | } |
||
63 | return $result ? $path : false; |
||
64 | } |
||
65 | |||
66 | /** |
||
67 | * Get the URL for the file at the given path. |
||
68 | * |
||
69 | * @param string $path |
||
70 | * @return string |
||
71 | */ |
||
72 | public function getUrl($path) |
||
73 | { |
||
74 | $path = str_replace('\\','/', $path); |
||
75 | $path = str_replace('//','/', $path); |
||
76 | |||
77 | $adapter = $this->getAdapter(); |
||
78 | |||
79 | if (method_exists($adapter, 'getUrl')) { |
||
80 | return $adapter->getUrl($path); |
||
81 | } elseif ($adapter instanceof AwsS3V3Adapter) { |
||
82 | $path = ltrim($path,'/'); |
||
83 | return $this->getAwsUrl($adapter, $path); |
||
84 | } elseif ($adapter instanceof LocalAdapter) { |
||
85 | return $this->getLocalUrl($path); |
||
86 | } else { |
||
87 | throw new RuntimeException('This driver does not support retrieving URLs.'); |
||
88 | } |
||
89 | } |
||
90 | |||
91 | /** |
||
92 | * Get the URL for the file at the given path. |
||
93 | * |
||
94 | * @param string $path |
||
95 | * @return string |
||
96 | */ |
||
97 | protected function getLocalUrl($path) |
||
98 | { |
||
99 | $config = $this->getConfig(); |
||
100 | |||
101 | // If an explicit base URL has been set on the disk configuration then we will use |
||
102 | // it as the base URL instead of the default path. This allows the developer to |
||
103 | // have full control over the base path for this filesystem's generated URLs. |
||
104 | if ($config->has('url')) { |
||
105 | return $this->concatPathToUrl($config->get('url'), $path); |
||
106 | } |
||
107 | $path = '/storage/' . $path; |
||
108 | // If the path contains "storage/public", it probably means the developer is using |
||
109 | // the default disk to generate the path instead of the "public" disk like they |
||
110 | // are really supposed to use. We will remove the public from this path here. |
||
111 | if (Str::contains($path, '/storage/public/')) { |
||
112 | return Str::replaceFirst('/public/', '/', $path); |
||
113 | } else { |
||
114 | return $path; |
||
115 | } |
||
116 | } |
||
117 | |||
118 | /** |
||
119 | * Get the URL for the file at the given path. |
||
120 | * |
||
121 | * @param \League\Flysystem\AwsS3v3\AwsS3Adapter $adapter |
||
122 | * @param string $path |
||
123 | * @return string |
||
124 | */ |
||
125 | protected function getAwsUrl($adapter, $path) |
||
126 | { |
||
127 | // If an explicit base URL has been set on the disk configuration then we will use |
||
128 | // it as the base URL instead of the default path. This allows the developer to |
||
129 | // have full control over the base path for this filesystem's generated URLs. |
||
130 | if (!is_null($url = $this->getConfig()->get('url'))) { |
||
131 | return $this->concatPathToUrl($url, $adapter->getPathPrefix() . $path); |
||
132 | } |
||
133 | |||
134 | return $adapter->getClient()->getObjectUrl( |
||
135 | $adapter->getBucket(), |
||
136 | $adapter->getPathPrefix() . $path |
||
137 | ); |
||
138 | } |
||
139 | |||
140 | /** |
||
141 | * Concatenate a path to a URL. |
||
142 | * |
||
143 | * @param string $url |
||
144 | * @param string $path |
||
145 | * @return string |
||
146 | */ |
||
147 | protected function concatPathToUrl($url, $path) |
||
148 | 2 | { |
|
149 | return rtrim($url, '/') . '/' . ltrim($path, '/'); |
||
150 | 2 | } |
|
151 | |||
152 | 2 | ||
153 | |||
154 | 2 | /** |
|
155 | 2 | * Create a streamed response for a given file. |
|
156 | * |
||
157 | * @param string $path |
||
158 | 2 | * @param string|null $name |
|
159 | 2 | * @param array|null $headers |
|
160 | 2 | * @param string|null $disposition |
|
161 | 2 | * @return \Symfony\Component\HttpFoundation\StreamedResponse |
|
162 | */ |
||
163 | public function response($path, $name = null, array $headers = [], $disposition = 'inline') |
||
164 | { |
||
165 | 1 | $response = new \Symfony\Component\HttpFoundation\StreamedResponse; |
|
166 | 1 | ||
167 | 1 | $filename = $name ?? basename($path); |
|
168 | 2 | ||
169 | $disposition = $response->headers->makeDisposition( |
||
170 | 2 | $disposition, $filename, $this->fallbackName($filename) |
|
0 ignored issues
–
show
Bug
introduced
by
![]() |
|||
171 | ); |
||
172 | |||
173 | $response->headers->replace($headers + [ |
||
174 | 'Content-Type' => $this->mimeType($path), |
||
175 | 'Content-Length' => $this->fileSize($path), |
||
176 | 'Content-Disposition' => $disposition, |
||
177 | ]); |
||
178 | |||
179 | $response->setCallback(function () use ($path) { |
||
180 | $stream = $this->readStream($path); |
||
181 | 1 | fpassthru($stream); |
|
182 | fclose($stream); |
||
183 | 1 | }); |
|
184 | |||
185 | return $response; |
||
186 | } |
||
187 | |||
188 | /** |
||
189 | * Create a streamed download response for a given file. |
||
190 | * |
||
191 | * @param string $path |
||
192 | 2 | * @param string|null $name |
|
193 | * @param array|null $headers |
||
194 | 2 | * @return \Symfony\Component\HttpFoundation\StreamedResponse |
|
195 | */ |
||
196 | public function download($path, $name = null, array $headers = []) |
||
197 | { |
||
198 | return $this->response($path, $name, $headers, 'attachment'); |
||
199 | } |
||
200 | |||
201 | /** |
||
202 | * Convert the string to ASCII characters that are equivalent to the given name. |
||
203 | * |
||
204 | * @param string $name |
||
205 | * @return string |
||
206 | */ |
||
207 | protected function fallbackName($name) |
||
208 | { |
||
209 | return str_replace('%', '', Str::ascii($name)); |
||
210 | } |
||
211 | |||
212 | /** |
||
213 | * @deprecated use mimeType |
||
214 | */ |
||
215 | public function getMimetype(string $path): string |
||
216 | { |
||
217 | return $this->mimeType($path); |
||
218 | } |
||
219 | |||
220 | /** |
||
221 | * @deprecated use fileSize |
||
222 | */ |
||
223 | public function getSize(string $path): int |
||
224 | { |
||
225 | return $this->fileSize($path); |
||
226 | } |
||
227 | |||
228 | /** |
||
229 | * @deprecated use deleteDirectory |
||
230 | */ |
||
231 | public function deleteDir(string $location): void |
||
232 | { |
||
233 | $this->deleteDirectory($location); |
||
234 | } |
||
235 | } |
||
236 |