]> BookStack Code Mirror - bookstack/blobdiff - app/Services/ImageService.php
Update PageRepo.php
[bookstack] / app / Services / ImageService.php
index e6ee4cf0be3f083d6e2e41b6c9b02b97137b738b..47c27cd0a2930f08fedba74127d9c76548d99de0 100644 (file)
@@ -1,6 +1,10 @@
 <?php namespace BookStack\Services;
 
+use BookStack\Exceptions\ImageUploadException;
 use BookStack\Image;
+use BookStack\User;
+use Exception;
+use Intervention\Image\Exception\NotSupportedException;
 use Intervention\Image\ImageManager;
 use Illuminate\Contracts\Filesystem\Factory as FileSystem;
 use Illuminate\Contracts\Filesystem\Filesystem as FileSystemInstance;
@@ -34,11 +38,49 @@ class ImageService
         $this->cache = $cache;
     }
 
-    public function saveNew(Image $image, UploadedFile $uploadedFile, $type)
+    /**
+     * Saves a new image from an upload.
+     * @param UploadedFile $uploadedFile
+     * @param  string      $type
+     * @return mixed
+     */
+    public function saveNewFromUpload(UploadedFile $uploadedFile, $type)
+    {
+        $imageName = $uploadedFile->getClientOriginalName();
+        $imageData = file_get_contents($uploadedFile->getRealPath());
+        return $this->saveNew($imageName, $imageData, $type);
+    }
+
+
+    /**
+     * Gets an image from url and saves it to the database.
+     * @param             $url
+     * @param string      $type
+     * @param bool|string $imageName
+     * @return mixed
+     * @throws \Exception
+     */
+    private function saveNewFromUrl($url, $type, $imageName = false)
+    {
+        $imageName = $imageName ? $imageName : basename($url);
+        $imageData = file_get_contents($url);
+        if($imageData === false) throw new \Exception('Cannot get image from ' . $url);
+        return $this->saveNew($imageName, $imageData, $type);
+    }
+
+    /**
+     * Saves a new image
+     * @param string $imageName
+     * @param string $imageData
+     * @param string $type
+     * @return Image
+     * @throws ImageUploadException
+     */
+    private function saveNew($imageName, $imageData, $type)
     {
         $storage = $this->getStorage();
         $secureUploads = Setting::get('app-secure-images');
-        $imageName = str_replace(' ', '-', $uploadedFile->getClientOriginalName());
+        $imageName = str_replace(' ', '-', $imageName);
 
         if ($secureUploads) $imageName = str_random(16) . '-' . $imageName;
 
@@ -48,17 +90,26 @@ class ImageService
         }
         $fullPath = $imagePath . $imageName;
 
-        $storage->put($fullPath, file_get_contents($uploadedFile->getRealPath()));
+        try {
+            $storage->put($fullPath, $imageData);
+        } catch (Exception $e) {
+            throw new ImageUploadException('Image Path ' . $fullPath . ' is not writable by the server.');
+        }
+
+        $imageDetails = [
+            'name'       => $imageName,
+            'path'       => $fullPath,
+            'url'        => $this->getPublicUrl($fullPath),
+            'type'       => $type
+        ];
+
+        if (auth()->user() && auth()->user()->id !== 0) {
+            $userId = auth()->user()->id;
+            $imageDetails['created_by'] = $userId;
+            $imageDetails['updated_by'] = $userId;
+        }
 
-        $userId = auth()->user()->id;
-        $image = $image->forceCreate([
-            'name' => $imageName,
-            'path' => $fullPath,
-            'url' => $this->getPublicUrl($fullPath),
-            'type' => $type,
-            'created_by' => $userId,
-            'updated_by' => $userId
-        ]);
+        $image = Image::forceCreate($imageDetails);
 
         return $image;
     }
@@ -69,10 +120,12 @@ class ImageService
      * Checks the cache then storage to avoid creating / accessing the filesystem on every check.
      *
      * @param Image $image
-     * @param int   $width
-     * @param int   $height
-     * @param bool  $keepRatio
+     * @param int $width
+     * @param int $height
+     * @param bool $keepRatio
      * @return string
+     * @throws Exception
+     * @throws ImageUploadException
      */
     public function getThumbnail(Image $image, $width = 220, $height = 220, $keepRatio = false)
     {
@@ -89,8 +142,16 @@ class ImageService
             return $this->getPublicUrl($thumbFilePath);
         }
 
-        // Otherwise create the thumbnail
-        $thumb = $this->imageTool->make($storage->get($image->path));
+        try {
+            $thumb = $this->imageTool->make($storage->get($image->path));
+        } catch (Exception $e) {
+            if ($e instanceof \ErrorException || $e instanceof NotSupportedException) {
+                throw new ImageUploadException('The server cannot create thumbnails. Please check you have the GD PHP extension installed.');
+            } else {
+                throw $e;
+            }
+        }
+
         if ($keepRatio) {
             $thumb->resize($width, null, function ($constraint) {
                 $constraint->aspectRatio();
@@ -137,6 +198,24 @@ class ImageService
         return true;
     }
 
+    /**
+     * Save a gravatar image and set a the profile image for a user.
+     * @param User $user
+     * @param int  $size
+     * @return mixed
+     */
+    public function saveUserGravatar(User $user, $size = 500)
+    {
+        $emailHash = md5(strtolower(trim($user->email)));
+        $url = 'http://www.gravatar.com/avatar/' . $emailHash . '?s=' . $size . '&d=identicon';
+        $imageName = str_replace(' ', '-', $user->name . '-gravatar.png');
+        $image = $this->saveNewFromUrl($url, 'user', $imageName);
+        $image->created_by = $user->id;
+        $image->updated_by = $user->id;
+        $image->save();
+        return $image;
+    }
+
     /**
      * Get the storage that will be used for storing images.
      * @return FileSystemInstance
@@ -145,7 +224,7 @@ class ImageService
     {
         if ($this->storageInstance !== null) return $this->storageInstance;
 
-        $storageType = env('STORAGE_TYPE');
+        $storageType = config('filesystems.default');
         $this->storageInstance = $this->fileSystem->disk($storageType);
 
         return $this->storageInstance;
@@ -171,10 +250,10 @@ class ImageService
     private function getPublicUrl($filePath)
     {
         if ($this->storageUrl === null) {
-            $storageUrl = env('STORAGE_URL');
+            $storageUrl = config('filesystems.url');
 
             // Get the standard public s3 url if s3 is set as storage type
-            if ($storageUrl == false && env('STORAGE_TYPE') === 's3') {
+            if ($storageUrl == false && config('filesystems.default') === 's3') {
                 $storageDetails = config('filesystems.disks.s3');
                 $storageUrl = 'https://s3-' . $storageDetails['region'] . '.amazonaws.com/' . $storageDetails['bucket'];
             }