]> BookStack Code Mirror - bookstack/blob - app/Http/Controllers/ImageController.php
fd790157034dc3e3800742abaf8b139c77903ab6
[bookstack] / app / Http / Controllers / ImageController.php
1 <?php
2
3 namespace BookStack\Http\Controllers;
4
5 use Illuminate\Filesystem\Filesystem as File;
6 use Illuminate\Http\Request;
7 use Illuminate\Support\Facades\Auth;
8 use Intervention\Image\Facades\Image as ImageTool;
9 use Illuminate\Support\Facades\DB;
10 use BookStack\Image;
11 use BookStack\Repos\PageRepo;
12
13 class ImageController extends Controller
14 {
15     protected $image;
16     protected $file;
17
18     /**
19      * ImageController constructor.
20      * @param Image $image
21      * @param File  $file
22      */
23     public function __construct(Image $image, File $file)
24     {
25         $this->image = $image;
26         $this->file = $file;
27         parent::__construct();
28     }
29
30
31     /**
32      * Get all images, Paginated
33      * @param int $page
34      * @return \Illuminate\Http\JsonResponse
35      */
36     public function getAll($page = 0)
37     {
38         $pageSize = 30;
39         $images = $this->image->orderBy('created_at', 'desc')
40             ->skip($page * $pageSize)->take($pageSize)->get();
41         foreach ($images as $image) {
42             $this->loadSizes($image);
43         }
44         $hasMore = $this->image->orderBy('created_at', 'desc')
45                 ->skip(($page + 1) * $pageSize)->take($pageSize)->count() > 0;
46         return response()->json([
47             'images' => $images,
48             'hasMore' => $hasMore
49         ]);
50     }
51
52     /**
53      * Loads the standard thumbnail sizes for an image.
54      * @param Image $image
55      */
56     private function loadSizes(Image $image)
57     {
58         $image->thumbnail = $this->getThumbnail($image, 150, 150);
59         $image->display = $this->getThumbnail($image, 840, 0, true);
60     }
61
62     /**
63      * Get the thumbnail for an image.
64      * If $keepRatio is true only the width will be used.
65      * @param      $image
66      * @param int  $width
67      * @param int  $height
68      * @param bool $keepRatio
69      * @return string
70      */
71     public function getThumbnail($image, $width = 220, $height = 220, $keepRatio = false)
72     {
73         $explodedPath = explode('/', $image->url);
74         $dirPrefix = $keepRatio ? 'scaled-' : 'thumbs-';
75         array_splice($explodedPath, 4, 0, [$dirPrefix . $width . '-' . $height]);
76         $thumbPath = implode('/', $explodedPath);
77         $thumbFilePath = public_path() . $thumbPath;
78
79         // Return the thumbnail url path if already exists
80         if (file_exists($thumbFilePath)) {
81             return $thumbPath;
82         }
83
84         // Otherwise create the thumbnail
85         $thumb = ImageTool::make(public_path() . $image->url);
86         if($keepRatio) {
87             $thumb->resize($width, null, function ($constraint) {
88                 $constraint->aspectRatio();
89                 $constraint->upsize();
90             });
91         } else {
92             $thumb->fit($width, $height);
93         }
94
95         // Create thumbnail folder if it does not exist
96         if (!file_exists(dirname($thumbFilePath))) {
97             mkdir(dirname($thumbFilePath), 0775, true);
98         }
99
100         //Save Thumbnail
101         $thumb->save($thumbFilePath);
102         return $thumbPath;
103     }
104
105     /**
106      * Handles image uploads for use on pages.
107      * @param Request $request
108      * @return \Illuminate\Http\JsonResponse
109      */
110     public function upload(Request $request)
111     {
112         $this->checkPermission('image-create');
113         $this->validate($request, [
114             'file' => 'image|mimes:jpeg,gif,png'
115         ]);
116         $imageUpload = $request->file('file');
117
118         $name = str_replace(' ', '-', $imageUpload->getClientOriginalName());
119         $storageName = substr(sha1(time()), 0, 10) . '-' . $name;
120         $imagePath = '/uploads/images/' . Date('Y-m-M') . '/';
121         $storagePath = public_path() . $imagePath;
122         $fullPath = $storagePath . $storageName;
123         while (file_exists($fullPath)) {
124             $storageName = substr(sha1(rand()), 0, 3) . $storageName;
125             $fullPath = $storagePath . $storageName;
126         }
127         $imageUpload->move($storagePath, $storageName);
128         // Create and save image object
129         $this->image->name = $name;
130         $this->image->url = $imagePath . $storageName;
131         $this->image->created_by = auth()->user()->id;
132         $this->image->updated_by = auth()->user()->id;
133         $this->image->save();
134         $this->loadSizes($this->image);
135         return response()->json($this->image);
136     }
137
138     /**
139      * Update image details
140      * @param         $imageId
141      * @param Request $request
142      * @return \Illuminate\Http\JsonResponse
143      */
144     public function update($imageId, Request $request)
145     {
146         $this->checkPermission('image-update');
147         $this->validate($request, [
148             'name' => 'required|min:2|string'
149         ]);
150         $image = $this->image->findOrFail($imageId);
151         $image->fill($request->all());
152         $image->save();
153         $this->loadSizes($image);
154         return response()->json($this->image);
155     }
156
157     /**
158      * Deletes an image and all thumbnail/image files
159      * @param PageRepo $pageRepo
160      * @param Request  $request
161      * @param int      $id
162      * @return \Illuminate\Http\JsonResponse
163      */
164     public function destroy(PageRepo $pageRepo, Request $request, $id)
165     {
166         $this->checkPermission('image-delete');
167         $image = $this->image->findOrFail($id);
168
169         // Check if this image is used on any pages
170         $pageSearch = $pageRepo->searchForImage($image->url);
171         $isForced = ($request->has('force') && ($request->get('force') === 'true') || $request->get('force') === true);
172         if ($pageSearch !== false && !$isForced) {
173             return response()->json($pageSearch, 400);
174         }
175
176         // Delete files
177         $folder = public_path() . dirname($image->url);
178         $fileName = basename($image->url);
179
180         // Delete thumbnails
181         foreach (glob($folder . '/*') as $file) {
182             if (is_dir($file)) {
183                 $thumbName = $file . '/' . $fileName;
184                 if (file_exists($file)) {
185                     unlink($thumbName);
186                 }
187                 // Remove thumb folder if empty
188                 if (count(glob($file . '/*')) === 0) {
189                     rmdir($file);
190                 }
191             }
192         }
193
194         // Delete file and database entry
195         unlink($folder . '/' . $fileName);
196         $image->delete();
197
198         // Delete parent folder if empty
199         if (count(glob($folder . '/*')) === 0) {
200             rmdir($folder);
201         }
202         return response()->json('Image Deleted');
203     }
204
205
206 }