3 namespace BookStack\Http\Controllers;
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;
11 use BookStack\Repos\PageRepo;
13 class ImageController extends Controller
19 * ImageController constructor.
23 public function __construct(Image $image, File $file)
25 $this->image = $image;
27 parent::__construct();
32 * Get all images, Paginated
34 * @return \Illuminate\Http\JsonResponse
36 public function getAll($page = 0)
39 $images = $this->image->orderBy('created_at', 'desc')
40 ->skip($page * $pageSize)->take($pageSize)->get();
41 foreach ($images as $image) {
42 $this->loadSizes($image);
44 $hasMore = $this->image->orderBy('created_at', 'desc')
45 ->skip(($page + 1) * $pageSize)->take($pageSize)->count() > 0;
46 return response()->json([
53 * Loads the standard thumbnail sizes for an image.
56 private function loadSizes(Image $image)
58 $image->thumbnail = $this->getThumbnail($image, 150, 150);
59 $image->display = $this->getThumbnail($image, 840, 0, true);
63 * Get the thumbnail for an image.
64 * If $keepRatio is true only the width will be used.
68 * @param bool $keepRatio
71 public function getThumbnail($image, $width = 220, $height = 220, $keepRatio = false)
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;
79 // Return the thumbnail url path if already exists
80 if (file_exists($thumbFilePath)) {
84 // Otherwise create the thumbnail
85 $thumb = ImageTool::make(public_path() . $image->url);
87 $thumb->resize($width, null, function ($constraint) {
88 $constraint->aspectRatio();
89 $constraint->upsize();
92 $thumb->fit($width, $height);
95 // Create thumbnail folder if it does not exist
96 if (!file_exists(dirname($thumbFilePath))) {
97 mkdir(dirname($thumbFilePath), 0775, true);
101 $thumb->save($thumbFilePath);
106 * Handles image uploads for use on pages.
107 * @param Request $request
108 * @return \Illuminate\Http\JsonResponse
110 public function upload(Request $request)
112 $this->checkPermission('image-create');
113 $this->validate($request, [
114 'file' => 'image|mimes:jpeg,gif,png'
116 $imageUpload = $request->file('file');
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;
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);
139 * Update image details
141 * @param Request $request
142 * @return \Illuminate\Http\JsonResponse
144 public function update($imageId, Request $request)
146 $this->checkPermission('image-update');
147 $this->validate($request, [
148 'name' => 'required|min:2|string'
150 $image = $this->image->findOrFail($imageId);
151 $image->fill($request->all());
153 $this->loadSizes($image);
154 return response()->json($this->image);
158 * Deletes an image and all thumbnail/image files
159 * @param PageRepo $pageRepo
160 * @param Request $request
162 * @return \Illuminate\Http\JsonResponse
164 public function destroy(PageRepo $pageRepo, Request $request, $id)
166 $this->checkPermission('image-delete');
167 $image = $this->image->findOrFail($id);
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);
177 $folder = public_path() . dirname($image->url);
178 $fileName = basename($image->url);
181 foreach (glob($folder . '/*') as $file) {
183 $thumbName = $file . '/' . $fileName;
184 if (file_exists($file)) {
187 // Remove thumb folder if empty
188 if (count(glob($file . '/*')) === 0) {
194 // Delete file and database entry
195 unlink($folder . '/' . $fileName);
198 // Delete parent folder if empty
199 if (count(glob($folder . '/*')) === 0) {
202 return response()->json('Image Deleted');