Issues (176)

src/LfmPath.php (1 issue)

1
<?php
2
3
namespace UniSharp\LaravelFilemanager;
4
5
use Illuminate\Container\Container;
6
use Intervention\Image\Facades\Image as InterventionImageV2;
7
use Intervention\Image\Laravel\Facades\Image as InterventionImageV3;
8
use Symfony\Component\HttpFoundation\File\UploadedFile;
9
use UniSharp\LaravelFilemanager\Events\FileIsUploading;
10
use UniSharp\LaravelFilemanager\Events\FileWasUploaded;
11
use UniSharp\LaravelFilemanager\Events\ImageIsUploading;
12
use UniSharp\LaravelFilemanager\Events\ImageWasUploaded;
13
use UniSharp\LaravelFilemanager\LfmUploadValidator;
14
15
class LfmPath
16
{
17
    private $working_dir;
18
    private $item_name;
19
    private $is_thumb = false;
20
21
    private $helper;
22
23
    public function __construct(Lfm $lfm)
24
    {
25
        $this->helper = $lfm;
26
    }
27
28
    public function __get($var_name)
29
    {
30
        if ($var_name == 'storage') {
31
            return $this->helper->getStorage($this->path('url'));
32
        }
33
    }
34
35
    public function __call($function_name, $arguments)
36
    {
37
        return $this->storage->$function_name(...$arguments);
38
    }
39
40
    public function dir($working_dir)
41
    {
42
        $this->working_dir = $working_dir;
43
44
        return $this;
45
    }
46
47
    public function thumb($is_thumb = true)
48
    {
49
        $this->is_thumb = $is_thumb;
50
51
        return $this;
52
    }
53
54
    public function setName($item_name)
55
    {
56
        $this->item_name = $item_name;
57
58
        return $this;
59
    }
60
61
    public function getName()
62
    {
63
        return $this->item_name;
64
    }
65
66
    public function path($type = 'storage')
67
    {
68
        if ($type == 'working_dir') {
69
            // working directory: /{user_slug}
70
            return $this->translateToLfmPath($this->normalizeWorkingDir());
71
        } elseif ($type == 'url') {
72
            // storage: files/{user_slug}
73
            // storage without folder: {user_slug}
74
            return $this->helper->getCategoryName() === '.'
75
                ? ltrim($this->path('working_dir'), '/')
76
                : $this->helper->getCategoryName() . $this->path('working_dir');
77
        } elseif ($type == 'storage') {
78
            // storage: files/{user_slug}
79
            // storage on windows: files\{user_slug}
80
            return str_replace(Lfm::DS, $this->helper->ds(), $this->path('url'));
81
        } else {
82
            // absolute: /var/www/html/project/storage/app/files/{user_slug}
83
            // absolute on windows: C:\project\storage\app\files\{user_slug}
84
            return $this->storage->rootPath() . $this->path('storage');
85
        }
86
    }
87
88
    public function translateToLfmPath($path)
89
    {
90
        return str_replace($this->helper->ds(), Lfm::DS, $path);
91
    }
92
93
    public function url()
94
    {
95
        return $this->storage->url($this->path('url'));
96
    }
97
98
    public function folders()
99
    {
100
        $all_folders = array_map(function ($directory_path) {
101
            return $this->pretty($directory_path, true);
102
        }, $this->storage->directories());
103
104
        $folders = array_filter($all_folders, function ($directory) {
105
            return $directory->name !== $this->helper->getThumbFolderName();
106
        });
107
108
        return $this->sortByColumn($folders);
109
    }
110
111
    public function files()
112
    {
113
        $files = array_map(function ($file_path) {
114
            return $this->pretty($file_path);
115
        }, $this->storage->files());
116
117
        return $this->sortByColumn($files);
118
    }
119
120
    public function pretty($item_path, $isDirectory = false)
121
    {
122
        return Container::getInstance()->makeWith(LfmItem::class, [
123
            'lfm' => (clone $this)->setName($this->helper->getNameFromPath($item_path)),
124
            'helper' => $this->helper,
125
            'isDirectory' => $isDirectory
126
        ]);
127
    }
128
129
    public function delete()
130
    {
131
        if ($this->isDirectory()) {
132
            return $this->storage->deleteDirectory();
133
        } else {
134
            return $this->storage->delete();
135
        }
136
    }
137
138
    /**
139
     * Create folder if not exist.
140
     *
141
     * @param  string  $path  Real path of a directory.
142
     * @return bool
143
     */
144
    public function createFolder()
145
    {
146
        if ($this->storage->exists($this)) {
147
            return false;
148
        }
149
150
        $this->storage->makeDirectory(0777, true, true);
151
    }
152
153
    public function isDirectory()
154
    {
155
        $working_dir = $this->path('working_dir');
156
        $parent_dir = substr($working_dir, 0, strrpos($working_dir, '/'));
157
158
        $parent_directories = array_map(function ($directory_path) {
159
            return app(static::class)->translateToLfmPath($directory_path);
160
        }, app(static::class)->dir($parent_dir)->directories());
161
162
        return in_array($this->path('url'), $parent_directories);
163
    }
164
165
    /**
166
     * Check a folder and its subfolders is empty or not.
167
     *
168
     * @param  string  $directory_path  Real path of a directory.
169
     * @return bool
170
     */
171
    public function directoryIsEmpty()
172
    {
173
        return count($this->storage->allFiles()) == 0;
174
    }
175
176
    public function normalizeWorkingDir()
177
    {
178
        $path = $this->working_dir
179
            ?: $this->helper->input('working_dir')
180
            ?: $this->helper->getRootFolder();
181
182
        if ($this->is_thumb) {
183
            // Prevent if working dir is "/" normalizeWorkingDir will add double "//" that breaks S3 functionality
184
            $path = rtrim($path, Lfm::DS) . Lfm::DS . $this->helper->getThumbFolderName();
185
        }
186
187
        if ($this->getName()) {
188
            // Prevent if working dir is "/" normalizeWorkingDir will add double "//" that breaks S3 functionality
189
            $path = rtrim($path, Lfm::DS) . Lfm::DS . $this->getName();
190
        }
191
192
        return $path;
193
    }
194
195
    /**
196
     * Sort files and directories.
197
     *
198
     * @param  mixed  $arr_items  Array of files or folders or both.
199
     * @return array of object
200
     */
201
    public function sortByColumn($arr_items)
202
    {
203
        $sort_by = $this->helper->input('sort_type');
204
        if (in_array($sort_by, ['name', 'time'])) {
205
            $key_to_sort = $sort_by;
206
        } else {
207
            $key_to_sort = 'name';
208
        }
209
210
        uasort($arr_items, function ($a, $b) use ($key_to_sort) {
211
            return strcasecmp($a->{$key_to_sort}, $b->{$key_to_sort});
212
        });
213
214
        return $arr_items;
215
    }
216
217
    public function error($error_type, $variables = [])
218
    {
219
        throw new \Exception($this->helper->error($error_type, $variables));
220
    }
221
222
    // Upload section
223
    public function upload($file)
224
    {
225
        $new_file_name = $this->getNewName($file);
226
        $new_file_path = $this->setName($new_file_name)->path('absolute');
227
228
        event(new FileIsUploading($new_file_path));
229
        event(new ImageIsUploading($new_file_path));
230
        try {
231
            $this->setName($new_file_name)->storage->save($file);
232
233
            $this->generateThumbnail($new_file_name);
234
        } catch (\Exception $e) {
235
            \Log::info($e);
236
            return $this->error('invalid');
237
        }
238
        event(new FileWasUploaded($new_file_path));
239
        event(new ImageWasUploaded($new_file_path));
240
241
        return $new_file_name;
242
    }
243
244
    public function validateUploadedFile($file)
245
    {
246
        $validator = new LfmUploadValidator($file);
247
248
        $validator->sizeLowerThanIniMaximum();
249
250
        $validator->uploadWasSuccessful();
251
252
        if (!config('lfm.over_write_on_duplicate')) {
253
            $validator->nameIsNotDuplicate($this->getNewName($file), $this);
254
        }
255
256
        $validator->mimetypeIsNotExcutable(config('lfm.disallowed_mimetypes', ['text/x-php', 'text/html', 'text/plain']));
257
258
        $validator->extensionIsNotExcutable();
259
260
        if (config('lfm.should_validate_mime', false)) {
261
            $validator->mimeTypeIsValid($this->helper->availableMimeTypes());
262
        }
263
264
        $validator->extensionIsValid(config('lfm.disallowed_extensions', []));
265
266
        if (config('lfm.should_validate_size', false)) {
267
            $validator->sizeIsLowerThanConfiguredMaximum($this->helper->maxUploadSize());
268
        }
269
270
        return true;
271
    }
272
273
    private function getNewName($file)
274
    {
275
        $new_file_name = $this->helper->translateFromUtf8(
276
            trim($this->helper->utf8Pathinfo($file->getClientOriginalName(), "filename"))
277
        );
278
279
        $extension = $file->getClientOriginalExtension();
280
281
        if (config('lfm.rename_file') === true) {
282
            $new_file_name = uniqid();
283
        } elseif (config('lfm.alphanumeric_filename') === true) {
284
            $new_file_name = preg_replace('/[^A-Za-z0-9\-\']/', '_', $new_file_name);
285
        }
286
287
        if ($extension) {
288
            $new_file_name_with_extention = $new_file_name . '.' . $extension;
289
        }
290
291
        if (config('lfm.rename_duplicates') === true) {
292
            $counter = 1;
293
            $file_name_without_extentions = $new_file_name;
294
            while ($this->setName(($extension) ? $new_file_name_with_extention : $new_file_name)->exists()) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $new_file_name_with_extention does not seem to be defined for all execution paths leading up to this point.
Loading history...
295
                if (config('lfm.alphanumeric_filename') === true) {
296
                    $suffix = '_'.$counter;
297
                } else {
298
                    $suffix = " ({$counter})";
299
                }
300
                $new_file_name = $file_name_without_extentions.$suffix;
301
302
                if ($extension) {
303
                    $new_file_name_with_extention = $new_file_name . '.' . $extension;
304
                }
305
                $counter++;
306
            }
307
        }
308
309
        return ($extension) ? $new_file_name_with_extention : $new_file_name;
310
    }
311
312
    public function generateThumbnail($file_name)
313
    {
314
        $original_image = $this->pretty($file_name);
315
316
        if (!$original_image->shouldCreateThumb()) {
317
            return;
318
        }
319
320
        // create folder for thumbnails
321
        $this->setName(null)->thumb(true)->createFolder();
322
323
        // generate cropped image content
324
        $this->setName($file_name)->thumb(true);
325
        $thumbWidth = $this->helper->shouldCreateCategoryThumb() && $this->helper->categoryThumbWidth() ? $this->helper->categoryThumbWidth() : config('lfm.thumb_img_width', 200);
326
        $thumbHeight = $this->helper->shouldCreateCategoryThumb() && $this->helper->categoryThumbHeight() ? $this->helper->categoryThumbHeight() : config('lfm.thumb_img_height', 200);
327
328
        if (class_exists(InterventionImageV2::class)) {
329
            $encoded_image = InterventionImageV2::make($original_image->get())
330
                ->fit($thumbWidth, $thumbHeight)
331
                ->stream()
332
                ->detach();
333
        } else {
334
            $encoded_image = InterventionImageV3::read($original_image->get())
335
                ->cover($thumbWidth, $thumbHeight)
336
                ->encodeByMediaType();
337
        }
338
339
340
        $this->storage->put($encoded_image, 'public');
341
    }
342
}
343