]> git.mxchange.org Git - quix0rs-gnu-social.git/commitdiff
Relatively experimental change to store thumbnails in 'file/thumb/' (by default)
authorMikael Nordfeldth <mmn@hethane.se>
Mon, 7 Mar 2016 21:33:34 +0000 (22:33 +0100)
committerMikael Nordfeldth <mmn@hethane.se>
Mon, 7 Mar 2016 21:33:34 +0000 (22:33 +0100)
actions/attachment.php
actions/attachment_thumbnail.php
classes/File.php
classes/File_thumbnail.php
lib/attachmentlistitem.php
lib/default.php
lib/gnusocial.php
lib/imagefile.php
plugins/Oembed/OembedPlugin.php

index 1126759832a65799744a29c67c6c257d80a8ddb5..3ec837a511f804bcd1d82b764a0103ebc3912261 100644 (file)
@@ -96,7 +96,7 @@ class AttachmentAction extends ManagedAction
     {
         if (empty($this->attachment->filename)) {
             // if it's not a local file, gtfo
-            common_redirect($this->attachment->url, 303);
+            common_redirect($this->attachment->getUrl(), 303);
         }
 
         parent::showPage();
index 3b8eec3ca674b364d914f321b279cb3cb7db268e..cc1b0f09c6ba336f7d64da15f37e527b7bce00d6 100644 (file)
@@ -62,6 +62,6 @@ class Attachment_thumbnailAction extends AttachmentAction
             common_redirect($e->file->getUrl(), 302);
         }
 
-        common_redirect(File_thumbnail::url($thumbnail->filename), 302);
+        common_redirect(File_thumbnail::url($thumbnail->getFilename()), 302);
     }
 }
index 20e1bc8344156f9c73372e72f876f89222be353a..a1a2f78906e7056605a05bc80c757639d33174fb 100644 (file)
@@ -500,7 +500,7 @@ class File extends Managed_DataObject
     {
         if ($prefer_local && !empty($this->filename)) {
             // A locally stored file, so let's generate a URL for our instance.
-            return self::url($this->filename);
+            return self::url($this->getFilename());
         }
 
         // No local filename available, return the URL we have stored
index e028409f0f0f62b4cdd278cf0a26bd244c1a7b1d..925a3b24295ab057ca30db27e0d1a234ac385de5 100644 (file)
@@ -129,23 +129,76 @@ class File_thumbnail extends Managed_DataObject
 
     static function path($filename)
     {
-        // TODO: Store thumbnails in their own directory and don't use File::path here
-        return File::path($filename);
+        if (!File::validFilename($filename)) {
+            // TRANS: Client exception thrown if a file upload does not have a valid name.
+            throw new ClientException(_('Invalid filename.'));
+        }
+
+        $dir = common_config('thumbnail', 'dir') ?: File::path('thumb');
+
+        if (!in_array($dir[mb_strlen($dir)-1], ['/', '\\'])) {
+            $dir .= DIRECTORY_SEPARATOR;
+        }
+
+        return $dir . $filename;
     }
 
     static function url($filename)
     {
-        // TODO: Store thumbnails in their own directory and don't use File::url here
-        return File::url($filename);
+        if (!File::validFilename($filename)) {
+            // TRANS: Client exception thrown if a file upload does not have a valid name.
+            throw new ClientException(_('Invalid filename.'));
+        }
+
+        // FIXME: private site thumbnails?
+
+        $path = common_config('thumbnail', 'path');
+        if (empty($path)) {
+            return File::url('thumb')."/{$filename}";
+        }
+
+        $protocol = (GNUsocial::useHTTPS() ? 'https' : 'http');
+        $server = common_config('thumbnail', 'server') ?: common_config('site', 'server');
+
+        if ($path[mb_strlen($path)-1] != '/') {
+            $path .= '/';
+        }
+        if ($path[0] != '/') {
+            $path = '/'.$path;
+        }
+
+        return $protocol.'://'.$server.$path.$filename;
+    }
+
+    public function getFilename()
+    {
+        if (!File::validFilename($this->filename)) {
+            // TRANS: Client exception thrown if a file upload does not have a valid name.
+            throw new ClientException(_("Invalid filename."));
+        }
+        return $this->filename;
     }
 
     public function getPath()
     {
-        $filepath = self::path($this->filename);
-        if (!file_exists($filepath)) {
-            throw new FileNotFoundException($filepath);
+        $oldpath = File::path($this->getFilename());
+        $thumbpath = self::path($this->getFilename());
+
+        // If we have a file in our old thumbnail storage path, move it to the new one
+        if (file_exists($oldpath) && !file_exists($thumbpath)) {
+            if ($this->getFilename() === $this->getFile()->filename) {
+                // special case where thumbnail file exactly matches stored File
+                common_debug('File filename and File_thumbnail filename match on '.$this->file_id);
+            } elseif (!rename($oldpath, $thumbpath)) {
+                common_log(LOG_ERR, 'Could not move thumbnail from '._ve($oldpath).' to '._ve($thumbpath));
+                throw new ServerException('Could not move thumbnail from old path to new path.');
+            } else {
+                common_log(LOG_DEBUG, 'Moved thumbnail '.$this->file_id.' from '._ve($oldpath).' to '._ve($thumbpath));
+            }
+        } elseif (!file_exists($thumbpath)) {
+            throw new FileNotFoundException($thumbpath);
         }
-        return $filepath;
+        return $thumbpath;
     }
 
     public function getUrl()
@@ -188,10 +241,14 @@ class File_thumbnail extends Managed_DataObject
 
     public function delete($useWhere=false)
     {
-        if (!empty($this->filename) && file_exists(File_thumbnail::path($this->filename))) {
-            $deleted = @unlink(self::path($this->filename));
-            if (!$deleted) {
-                common_log(LOG_ERR, sprintf('Could not unlink existing file: "%s"', self::path($this->filename)));
+        if (!empty($this->filename)) {
+            try {
+                $deleted = @unlink($this->getPath());
+                if (!$deleted) {
+                    common_log(LOG_ERR, 'Could not unlink existing thumbnail file: '._ve($this->getPath()));
+                }
+            } catch (FileNotFoundException $e) {
+                common_log(LOG_INFO, 'Thumbnail already gone from '._ve($e->path));
             }
         }
 
index e6163ecc9265372d627c6caa446be96983032c32..6ee3c7087b43d5d573489974693ed89c8bfcf9fb 100644 (file)
@@ -204,11 +204,7 @@ class AttachmentListItem extends Widget
      */
     protected function scrubHtmlFile(File $attachment)
     {
-        $path = File::path($attachment->filename);
-        if (!file_exists($path) || !is_readable($path)) {
-            common_log(LOG_ERR, "Missing local HTML attachment $path");
-            return false;
-        }
+        $path = $attachment->getPath();
         $raw = file_get_contents($path);
 
         // Normalize...
index d8b291b3444309084335d642763b49c846eb73ae..bf2d37d7739e01e984b50ced81d9b626c2029202 100644 (file)
@@ -271,13 +271,18 @@ $default =
                     'exe' => false,  // this would deny any uploads to keep the "exe" file extension
                 ],
               ),
-        'thumbnail' =>
-        array('crop' => false,      // overridden to true if thumb height === null
+        'thumbnail' => [
+              'dir' => null,    // falls back to File::path('thumb') (equivalent to ['attachments']['dir'] .  '/thumb/')
+              'path' => null,   // falls back to generating a URL with File::url('thumb/$filename') (equivalent to ['attachments']['path'] . '/thumb/')
+              'server' => null, // Only used if ['thumbnail']['path'] is NOT empty, and then it falls back to ['site']['server'], schema is decided from GNUsocial::useHTTPS()
+
+              'crop' => false,      // overridden to true if thumb height === null
               'maxsize' => 1000,     // thumbs with an edge larger than this will not be generated
               'width' => 450,
               'height' => 600,
               'upscale' => false,
-              'animated' => false), // null="UseFileAsThumbnail", false="can use still frame". true requires ImageMagickPlugin
+              'animated' => false, // null="UseFileAsThumbnail", false="can use still frame". true requires ImageMagickPlugin
+            ],
         'application' =>
         array('desclimit' => null),
         'group' =>
index aecebe2556440788fa2fd1e7f0c1bd3a76d7e557..f07d2c24468e46d34fa1e67ac695b4f04fb851c8 100644 (file)
@@ -429,10 +429,28 @@ class GNUsocial
      */
     static function verifyLoadedConfig()
     {
+        $mkdirs = [];
+
         if (common_config('htmlpurifier', 'Cache.DefinitionImpl') === 'Serializer'
                 && !is_dir(common_config('htmlpurifier', 'Cache.SerializerPath'))) {
-            if (!mkdir(common_config('htmlpurifier', 'Cache.SerializerPath'))) {
-                throw new ConfigException('Could not create HTMLPurifier cache dir: '._ve(common_config('htmlpurifier', 'Cache.SerializerPath')));
+            $mkdirs[common_config('htmlpurifier', 'Cache.SerializerPath')] = 'HTMLPurifier Serializer cache';
+        }
+
+        // go through our configurable storage directories
+        foreach (['attachments', 'thumbnail'] as $dirtype) {
+            $dir = common_config($dirtype, 'dir');
+            if (!empty($dir) && !is_dir($dir)) {
+                $mkdirs[$dir] = $dirtype;
+            }
+        }
+
+        // try to create those that are not directories
+        foreach ($mkdirs as $dir=>$description) {
+            if (is_file($dir)) {
+                throw new ConfigException('Expected directory for '._ve($description).' is a file!');
+            }
+            if (!mkdir($dir)) {
+                throw new ConfigException('Could not create directory for '._ve($description).': '._ve($dir));
             }
         }
 
index 9f870ae290bf44ae61e2132996d18bcc087c96f2..c707208af6eef0c917ab28ee4acdc66c4718dd15 100644 (file)
@@ -153,8 +153,14 @@ class ImageFile
             $image = new ImageFile($file->getID(), $imgPath);
         } catch (UnsupportedMediaException $e) {
             // Avoid deleting the original
-            if ($imgPath != $file->getPath()) {
-                unlink($imgPath);
+            try {
+                if ($imgPath !== $file->getPath()) {
+                    @unlink($imgPath);
+                }
+            } catch (FileNotFoundException $e) {
+                // File reported (via getPath) that the original file
+                // doesn't exist anyway, so it's safe to delete $imgPath
+                @unlink($imgPath);
             }
             throw $e;
         }
@@ -607,10 +613,15 @@ class ImageFile
         // Perform resize and store into file
         $this->resizeTo($outpath, $box);
 
-        // Avoid deleting the original
-        if ($this->getPath() != File_thumbnail::path($this->filename)) {
-            $this->unlink();
+        try {
+            // Avoid deleting the original
+            if (!in_array($this->getPath(), [File::path($this->filename), File_thumbnail::path($this->filename)])) {
+                $this->unlink();
+            }
+        } catch (FileNotFoundException $e) {
+            // $this->getPath() says the file doesn't exist anyway, so no point in trying to delete it!
         }
+
         return File_thumbnail::saveThumbnail($this->fileRecord->getID(),
                                       null, // no url since we generated it ourselves and can dynamically generate the url
                                       $width, $height,
index 196b07d75d0d57fa2a5bfc8f98204b8587ef565e..cb59bb21e59e0af676f945520bad3956739872fe 100644 (file)
@@ -328,7 +328,7 @@ class OembedPlugin extends Plugin
         $ext = File::guessMimeExtension($info['mime']);
 
         // We'll trust sha256 (File::FILEHASH_ALG) not to have collision issues any time soon :)
-        $filename = hash(File::FILEHASH_ALG, $imgData) . ".{$ext}";
+        $filename = 'oembed-'.hash(File::FILEHASH_ALG, $imgData) . ".{$ext}";
         $fullpath = File_thumbnail::path($filename);
         // Write the file to disk. Throw Exception on failure
         if (!file_exists($fullpath) && file_put_contents($fullpath, $imgData) === false) {