]> BookStack Code Mirror - bookstack/blob - app/Services/AttachmentService.php
Added Italian language
[bookstack] / app / Services / AttachmentService.php
1 <?php namespace BookStack\Services;
2
3 use BookStack\Exceptions\FileUploadException;
4 use BookStack\Attachment;
5 use Exception;
6 use Symfony\Component\HttpFoundation\File\UploadedFile;
7
8 class AttachmentService extends UploadService
9 {
10
11     /**
12      * Get an attachment from storage.
13      * @param Attachment $attachment
14      * @return string
15      */
16     public function getAttachmentFromStorage(Attachment $attachment)
17     {
18         $attachmentPath = $this->getStorageBasePath() . $attachment->path;
19         return $this->getStorage()->get($attachmentPath);
20     }
21
22     /**
23      * Store a new attachment upon user upload.
24      * @param UploadedFile $uploadedFile
25      * @param int $page_id
26      * @return Attachment
27      * @throws FileUploadException
28      */
29     public function saveNewUpload(UploadedFile $uploadedFile, $page_id)
30     {
31         $attachmentName = $uploadedFile->getClientOriginalName();
32         $attachmentPath = $this->putFileInStorage($attachmentName, $uploadedFile);
33         $largestExistingOrder = Attachment::where('uploaded_to', '=', $page_id)->max('order');
34
35         $attachment = Attachment::forceCreate([
36             'name' => $attachmentName,
37             'path' => $attachmentPath,
38             'extension' => $uploadedFile->getClientOriginalExtension(),
39             'uploaded_to' => $page_id,
40             'created_by' => user()->id,
41             'updated_by' => user()->id,
42             'order' => $largestExistingOrder + 1
43         ]);
44
45         return $attachment;
46     }
47
48     /**
49      * Store a upload, saving to a file and deleting any existing uploads
50      * attached to that file.
51      * @param UploadedFile $uploadedFile
52      * @param Attachment $attachment
53      * @return Attachment
54      * @throws FileUploadException
55      */
56     public function saveUpdatedUpload(UploadedFile $uploadedFile, Attachment $attachment)
57     {
58         if (!$attachment->external) {
59             $this->deleteFileInStorage($attachment);
60         }
61
62         $attachmentName = $uploadedFile->getClientOriginalName();
63         $attachmentPath = $this->putFileInStorage($attachmentName, $uploadedFile);
64
65         $attachment->name = $attachmentName;
66         $attachment->path = $attachmentPath;
67         $attachment->external = false;
68         $attachment->extension = $uploadedFile->getClientOriginalExtension();
69         $attachment->save();
70         return $attachment;
71     }
72
73     /**
74      * Save a new File attachment from a given link and name.
75      * @param string $name
76      * @param string $link
77      * @param int $page_id
78      * @return Attachment
79      */
80     public function saveNewFromLink($name, $link, $page_id)
81     {
82         $largestExistingOrder = Attachment::where('uploaded_to', '=', $page_id)->max('order');
83         return Attachment::forceCreate([
84             'name' => $name,
85             'path' => $link,
86             'external' => true,
87             'extension' => '',
88             'uploaded_to' => $page_id,
89             'created_by' => user()->id,
90             'updated_by' => user()->id,
91             'order' => $largestExistingOrder + 1
92         ]);
93     }
94
95     /**
96      * Get the file storage base path, amended for storage type.
97      * This allows us to keep a generic path in the database.
98      * @return string
99      */
100     private function getStorageBasePath()
101     {
102         return $this->isLocal() ? 'storage/' : '';
103     }
104
105     /**
106      * Updates the file ordering for a listing of attached files.
107      * @param array $attachmentList
108      * @param $pageId
109      */
110     public function updateFileOrderWithinPage($attachmentList, $pageId)
111     {
112         foreach ($attachmentList as $index => $attachment) {
113             Attachment::where('uploaded_to', '=', $pageId)->where('id', '=', $attachment['id'])->update(['order' => $index]);
114         }
115     }
116
117
118     /**
119      * Update the details of a file.
120      * @param Attachment $attachment
121      * @param $requestData
122      * @return Attachment
123      */
124     public function updateFile(Attachment $attachment, $requestData)
125     {
126         $attachment->name = $requestData['name'];
127         if (isset($requestData['link']) && trim($requestData['link']) !== '') {
128             $attachment->path = $requestData['link'];
129             if (!$attachment->external) {
130                 $this->deleteFileInStorage($attachment);
131                 $attachment->external = true;
132             }
133         }
134         $attachment->save();
135         return $attachment;
136     }
137
138     /**
139      * Delete a File from the database and storage.
140      * @param Attachment $attachment
141      */
142     public function deleteFile(Attachment $attachment)
143     {
144         if ($attachment->external) {
145             $attachment->delete();
146             return;
147         }
148         
149         $this->deleteFileInStorage($attachment);
150         $attachment->delete();
151     }
152
153     /**
154      * Delete a file from the filesystem it sits on.
155      * Cleans any empty leftover folders.
156      * @param Attachment $attachment
157      */
158     protected function deleteFileInStorage(Attachment $attachment)
159     {
160         $storedFilePath = $this->getStorageBasePath() . $attachment->path;
161         $storage = $this->getStorage();
162         $dirPath = dirname($storedFilePath);
163
164         $storage->delete($storedFilePath);
165         if (count($storage->allFiles($dirPath)) === 0) {
166             $storage->deleteDirectory($dirPath);
167         }
168     }
169
170     /**
171      * Store a file in storage with the given filename
172      * @param $attachmentName
173      * @param UploadedFile $uploadedFile
174      * @return string
175      * @throws FileUploadException
176      */
177     protected function putFileInStorage($attachmentName, UploadedFile $uploadedFile)
178     {
179         $attachmentData = file_get_contents($uploadedFile->getRealPath());
180
181         $storage = $this->getStorage();
182         $attachmentBasePath = 'uploads/files/' . Date('Y-m-M') . '/';
183         $storageBasePath = $this->getStorageBasePath() . $attachmentBasePath;
184
185         $uploadFileName = $attachmentName;
186         while ($storage->exists($storageBasePath . $uploadFileName)) {
187             $uploadFileName = str_random(3) . $uploadFileName;
188         }
189
190         $attachmentPath = $attachmentBasePath . $uploadFileName;
191         $attachmentStoragePath = $this->getStorageBasePath() . $attachmentPath;
192
193         try {
194             $storage->put($attachmentStoragePath, $attachmentData);
195         } catch (Exception $e) {
196             throw new FileUploadException(trans('errors.path_not_writable', ['filePath' => $attachmentStoragePath]));
197         }
198         return $attachmentPath;
199     }
200
201 }