]> BookStack Code Mirror - bookstack/blob - app/Http/Controllers/ImageController.php
Added image name editing & deleting
[bookstack] / app / Http / Controllers / ImageController.php
1 <?php
2
3 namespace Oxbow\Http\Controllers;
4
5 use Illuminate\Filesystem\Filesystem as File;
6 use Illuminate\Http\Request;
7
8 use Illuminate\Support\Facades\Auth;
9 use Intervention\Image\Facades\Image as ImageTool;
10 use Illuminate\Support\Facades\DB;
11 use Oxbow\Http\Requests;
12 use Oxbow\Image;
13 use RecursiveDirectoryIterator;
14 use RecursiveIteratorIterator;
15 use RegexIterator;
16
17 class ImageController extends Controller
18 {
19     protected $image;
20     protected $file;
21
22     /**
23      * ImageController constructor.
24      * @param Image $image
25      * @param File $file
26      */
27     public function __construct(Image $image, File $file)
28     {
29         $this->image = $image;
30         $this->file = $file;
31     }
32
33     /**
34      * Returns an image from behind the public-facing application.
35      * @param Request $request
36      * @return \Illuminate\Http\Response
37      */
38     public function getImage(Request $request)
39     {
40         $cacheTime = 60*60*24;
41         $path = storage_path() . '/' . $request->path();
42         $modifiedTime = $this->file->lastModified($path);
43         $eTag = md5($modifiedTime . $path);
44         $headerLastModified = gmdate('r', $modifiedTime);
45         $headerExpires = gmdate('r', $modifiedTime + $cacheTime);
46
47         $headers = [
48             'Last-Modified' => $headerLastModified,
49             'Cache-Control' => 'must-revalidate',
50             'Pragma' => 'public',
51             'Expires' => $headerExpires,
52             'Etag' => $eTag
53         ];
54
55         $browserModifiedSince = $request->header('If-Modified-Since');
56         $browserNoneMatch = $request->header('If-None-Match');
57         if($browserModifiedSince !== null && file_exists($path) && ($browserModifiedSince == $headerLastModified || $browserNoneMatch == $eTag)) {
58             return response()->make('', 304, $headers);
59         }
60
61         if(file_exists($path)) {
62             return response()->make(file_get_contents($path), 200, array_merge($headers, [
63                 'Content-Type' => $this->file->mimeType($path),
64                 'Content-Length' => filesize($path),
65             ]));
66         }
67         abort(404);
68     }
69
70     /**
71      * Get all images, Paginated
72      * @param int $page
73      * @return \Illuminate\Http\JsonResponse
74      */
75     public function getAll($page = 0)
76     {
77         $pageSize = 30;
78         $images = DB::table('images')->orderBy('created_at', 'desc')
79             ->skip($page*$pageSize)->take($pageSize)->get();
80         foreach($images as $image) {
81             $image->thumbnail = $this->getThumbnail($image, 150, 150);
82         }
83         $hasMore = count(DB::table('images')->orderBy('created_at', 'desc')
84             ->skip(($page+1)*$pageSize)->take($pageSize)->get()) > 0;
85         return response()->json([
86             'images' => $images,
87             'hasMore' => $hasMore
88         ]);
89     }
90
91     /**
92      * Get the thumbnail for an image.
93      * @param $image
94      * @param int $width
95      * @param int $height
96      * @return string
97      */
98     public function getThumbnail($image, $width = 220, $height = 220)
99     {
100         $explodedPath = explode('/', $image->url);
101         array_splice($explodedPath, 4, 0, ['thumbs-' . $width . '-' . $height]);
102         $thumbPath = implode('/', $explodedPath);
103         $thumbFilePath = public_path() . $thumbPath;
104
105         // Return the thumbnail url path if already exists
106         if(file_exists($thumbFilePath)) {
107             return $thumbPath;
108         }
109
110         // Otherwise create the thumbnail
111         $thumb = ImageTool::make(public_path() . $image->url);
112         $thumb->fit($width, $height);
113
114         // Create thumbnail folder if it does not exist
115         if(!file_exists(dirname($thumbFilePath))) {
116             mkdir(dirname($thumbFilePath), 0775, true);
117         }
118
119         //Save Thumbnail
120         $thumb->save($thumbFilePath);
121         return $thumbPath;
122     }
123
124     /**
125      * Handles image uploads for use on pages.
126      * @param Request $request
127      * @return \Illuminate\Http\JsonResponse
128      */
129     public function upload(Request $request)
130     {
131         $imageUpload = $request->file('file');
132         $name = str_replace(' ', '-', $imageUpload->getClientOriginalName());
133         $storageName = substr(sha1(time()), 0, 10) . '-' . $name;
134         $imagePath = '/uploads/images/'.Date('Y-m-M').'/';
135         $storagePath = public_path(). $imagePath;
136         $fullPath = $storagePath . $storageName;
137         while(file_exists($fullPath)) {
138             $storageName = substr(sha1(rand()), 0, 3) . $storageName;
139             $fullPath = $storagePath . $storageName;
140         }
141         $imageUpload->move($storagePath, $storageName);
142         // Create and save image object
143         $this->image->name = $name;
144         $this->image->url = $imagePath . $storageName;
145         $this->image->created_by = Auth::user()->id;
146         $this->image->updated_by = Auth::user()->id;
147         $this->image->save();
148         $this->image->thumbnail = $this->getThumbnail($this->image, 150, 150);
149         return response()->json($this->image);
150     }
151
152     /**
153      * Update image details
154      * @param $imageId
155      * @param Request $request
156      * @return \Illuminate\Http\JsonResponse
157      */
158     public function update($imageId, Request $request)
159     {
160         $this->validate($request, [
161             'name' => 'required|min:2|string'
162         ]);
163         $image = $this->image->findOrFail($imageId);
164         $image->fill($request->all());
165         $image->save();
166         return response()->json($this->image);
167     }
168
169     /**
170      * Deletes an image and all thumbnail/image files
171      * @param $id
172      * @return \Illuminate\Http\JsonResponse
173      */
174     public function destroy($id)
175     {
176         $image = $this->image->findOrFail($id);
177
178         // Delete files
179         $folder = public_path() . dirname($image->url);
180         $pattern = '/' . preg_quote(basename($image->url)). '/';
181         $dir = new RecursiveDirectoryIterator($folder);
182         $ite = new RecursiveIteratorIterator($dir);
183         $files = new RegexIterator($ite, $pattern, RegexIterator::ALL_MATCHES);
184         foreach($files as $path => $file) {
185             unlink($path);
186         }
187         $image->delete();
188         return response()->json('Image Deleted');
189     }
190
191
192 }