OSDN Git Service

CHANGE: Media/MediaObjectクラスにリサンプリング用メソッド・メンバーを追加
authorsakamocchi <o-takashi@sakamocchi.jp>
Sat, 19 May 2012 14:47:47 +0000 (23:47 +0900)
committersakamocchi <o-takashi@sakamocchi.jp>
Sat, 19 May 2012 14:47:57 +0000 (23:47 +0900)
追加:
Media::$thumbdir
Media::$algorism
Media::$image_mime
Media::responseResampledImage()
Media::storeResampledImage()
Media::sort_media_by_filename()

変更:
sort_media()をMedia::sort_media_by_timestamp()に

MediaObjectは下位互換性を考慮しつつ書きなおした。

nucleus/libs/MEDIA.php

index 0195d2d..9e6128a 100644 (file)
@@ -14,7 +14,7 @@
  *\r
  * @license http://nucleuscms.org/license.txt GNU General Public License\r
  * @copyright Copyright (C) 2002-2012 The Nucleus Group\r
- * @version $Id: MEDIA.php 1864 2012-05-19 11:39:44Z sakamocchi $
+ * @version $Id: MEDIA.php 1864 2012-05-19 11:39:44Z sakamocchi $\r
  */\r
 \r
 define('PRIVATE_COLLECTION',           'Private Collection');\r
@@ -22,12 +22,21 @@ define('READ_ONLY_MEDIA_FOLDER',    '(Read Only)');
 \r
 class Media\r
 {\r
+       static public $thumbdir = '.thumb';\r
+       static public $algorism = 'md5';\r
+       static public $image_mime = array(\r
+               'image/jpeg'    => '.jpeg',\r
+               'image/png'             => '.png',\r
+               'image/gif'             => '.gif',\r
+       );\r
+       \r
        /**\r
         * Media::getCollectionList()\r
         * Gets the list of collections available to the currently logged\r
         * in member\r
-        *\r
-        * @returns array of dirname => display name\r
+        * \r
+        * @param       boolean $exceptReadOnly\r
+        * @return array        dirname => display name\r
         */\r
        static public function getCollectionList($exceptReadOnly = FALSE)\r
        {\r
@@ -51,7 +60,7 @@ class Media
                        if ( @is_dir($DIR_MEDIA . $dirname) &&\r
                                ($dirname != '.') &&\r
                                ($dirname != '..') &&\r
-                               ($dirname != 'CVS') &&\r
+                               ($dirname != self::$thumbdir) &&\r
                                (!is_numeric($dirname)) )\r
                                {\r
                                if ( @is_writable($DIR_MEDIA . $dirname) )\r
@@ -98,13 +107,20 @@ class Media
                        // only add files that match the filter\r
                        if ( !@is_dir($filename) && self::checkFilter($filename, $filter) )\r
                        {\r
-                               array_push($filelist, new MediaObject($collection, $filename, filemtime($mediadir . $filename)));\r
+                               array_push($filelist, new MediaObject($collection, $filename, $DIR_MEDIA));\r
                        }\r
                }\r
                closedir($dirhandle);\r
                \r
-               // sort array so newer files are shown first\r
-               usort($filelist,  array(__CLASS__, 'sort_media'));\r
+               /* sort array */\r
+               if ( !$CONF['MediaPrefix'] )\r
+               {\r
+                       usort($filelist,  array(__CLASS__, 'sort_media_by_timestamp'));\r
+               }\r
+               else\r
+               {\r
+                       usort($filelist,  array(__CLASS__, 'sort_media_by_filename'));\r
+               }\r
                \r
                return $filelist;\r
        }\r
@@ -329,42 +345,427 @@ class Media
        }\r
        \r
        /**\r
-        * Media::sort_media()\r
+        * Media::responseResampledImage()\r
+        * send resampled image via HTTP\r
+        * \r
+        * @param       Object  $medium         Medium Object\r
+        * @exit\r
+        */\r
+       static public function responseResampledImage($medium, $maxwidth=0, $maxheight=0)\r
+       {\r
+               if ( get_class($medium) !== 'Medium' )\r
+               {\r
+                       header("HTTP/1.1 503 Service Unavailable");\r
+                       exit('Nucleus CMS: Fail to generate resampled image');\r
+                       return;\r
+               }\r
+               \r
+               $resampledimage = $medium->getResampledBinary($maxwidth, $maxheight);\r
+               if ( $resampledimage === FALSE )\r
+               {\r
+                       unset($resampledimage);\r
+                       header("HTTP/1.1 503 Service Unavailable");\r
+                       exit('Nucleus CMS: Fail to generate resampled image');\r
+                       return;\r
+               }\r
+               \r
+               header("Content-type: {$medium->mime}");\r
+               echo $resampledimage;\r
+               \r
+               unset($resampledimage);\r
+               \r
+               exit;\r
+       }\r
+       \r
+       /**\r
+        * Media::storeResampledImage()\r
+        * Store resampled image binary to filesystem as file\r
+        * \r
+        * @param       object  $medium         medium Object\r
+        * @param       integer $maxwidth       maximum width\r
+        * @param       integer $maxheight      maximum height\r
+        * @param       string  $path           directory path for destination\r
+        * @param       string  $name           file name for destination\r
+        * @return      boolean\r
+        */\r
+       static public function storeResampledImage($medium, $maxwidth=0, $maxheight=0, $path='', $name='')\r
+       {\r
+               global $DIR_MEDIA;\r
+               \r
+               if ( get_class($medium) !== 'Medium' )\r
+               {\r
+                       return FALSE;\r
+               }\r
+               \r
+               if ( $path !== '' )\r
+               {\r
+                       $path = realpath($path);\r
+                       if ( !file_exists($path)\r
+                         || strpos($path, $DIR_MEDIA) !== 0 )\r
+                       {\r
+                               return FALSE;\r
+                       }\r
+               }\r
+               else\r
+               {\r
+                       $path = '$DIR_MEDIA/' . self::$thumbdir;\r
+               }\r
+               \r
+               if ( $name === '' )\r
+               {\r
+                       $name = $this->getHashedname();\r
+               }\r
+               \r
+               $resampledimage = $medium->getResampledBinary($maxwidth, $maxheight);\r
+               if ( !$resampledimage )\r
+               {\r
+                       unset($resampledimage);\r
+                       return FALSE;\r
+               }\r
+               \r
+               $handle = @fopen("{$path}/{$name}", 'w');\r
+               if ( !$handle )\r
+               {\r
+                       unset ($resampledimage);\r
+                       return FALSE;\r
+               }\r
+               \r
+               if ( !@fwrite($handle, $resampledimage) )\r
+               {\r
+                       unset($resampledimage);\r
+                       @unlink("{$path}/{$name}");\r
+                       return FALSE;\r
+               }\r
+               \r
+               unset($resampledimage);\r
+               fclose($handle);\r
+               \r
+               if ( !@chmod("{$path}/{$name}", 0774) )\r
+               {\r
+                       @unlink("{$path}/{$name}");\r
+                       return FALSE;\r
+               }\r
+               \r
+               return TRUE;\r
+       }\r
+       \r
+       /**\r
+        * Media::sort_media_by_timestamp()\r
         * User-defined sort method to sort an array of MediaObjects\r
         * \r
         * @param       object  $a\r
         * @param       object  $b\r
         * @return      boolean\r
         */\r
-       static private function sort_media($a, $b)\r
+       static private function sort_media_by_timestamp($a, $b)\r
        {\r
                if ($a->timestamp == $b->timestamp) return 0;\r
                return ($a->timestamp > $b->timestamp) ? -1 : 1;\r
        }\r
+       \r
+       /**\r
+        * Media::sort_media_by_filename()\r
+        * User-defined sort method to sort an array of MediaObjects\r
+        * \r
+        * @param       object  $a\r
+        * @param       object  $b\r
+        * @return      boolean\r
+        */\r
+       static private function sort_media_by_filename($a, $b)\r
+       {\r
+               if ($a->filename == $b->filename) return 0;\r
+               return ($a->filename > $b->filename) ? -1 : 1;\r
+       }\r
 }\r
 \r
-/**\r
- * Represents the characteristics of one single media-object\r
- *\r
- * Description of properties:\r
- *  - filename: filename, without paths\r
- *  - timestamp: last modification (unix timestamp)\r
- *  - collection: collection to which the file belongs (can also be a owner ID, for private collections)\r
- *  - private: true if the media belongs to a private member collection\r
- */\r
 class MediaObject\r
 {\r
+       public $mime = '';\r
+       \r
+       public $root = '';\r
+       public $path = '';\r
        public $private;\r
        public $collection;\r
-       public $filename;\r
-       public $timestamp;\r
+       public $filename = '';\r
+       \r
+       public $prefix = '';\r
+       public $name = '';\r
+       public $suffix = '';\r
        \r
-       public function __construct($collection, $filename, $timestamp)\r
+       public $timestamp = 0;\r
+       public $size = 0;\r
+       \r
+       public $width = 0;\r
+       public $height = 0;\r
+       public $resampledwidth = 0;\r
+       public $resampledheight = 0;\r
+       \r
+       /**\r
+        * MediaObject::__construct()\r
+        * \r
+        * @param       string          $collection     \r
+        * @param       string          $filename       \r
+        * @param       string          $root           fullpath to media directory\r
+        */\r
+       public function __construct($collection, $filename, $root)\r
        {\r
-               $this->private = is_numeric($collection);\r
+               global $CONF, $DIR_MEDIA;\r
+               \r
+               $root = preg_replace('#/*$#', '', $DIR_MEDIA);\r
+               if ( $root == '' || $collection == '' )\r
+               {\r
+                       return FALSE;\r
+               }\r
+               \r
+               /* get and validate fullpath for the medium */\r
+               if ( !file_exists($root)\r
+                 || FALSE === ($fullpath = realpath("{$root}/{$collection}/{$filename}"))\r
+                 || strpos($fullpath, $root) !== 0\r
+                 || !file_exists($fullpath) )\r
+               {\r
+                       return FALSE;\r
+               }\r
+               \r
+               /* store fundamentals */\r
+               $this->root = $root;\r
+               $this->private = (integer) $collection;\r
                $this->collection = $collection;\r
-               $this->filename = $filename;\r
-               $this->timestamp = $timestamp;\r
+               $this->filename = basename($fullpath);\r
+               $this->timestamp = @filemtime($fullpath);\r
+               $this->size = ceil(filesize($fullpath) / 1000);\r
+               \r
+               /* store relative directory path from root directory for media */\r
+               $this->path = preg_replace(array("#{$this->root}/#", "#/{$this->name}#"), '', $fullpath);\r
+               if ( $this->path === $this->name )\r
+               {\r
+                       $this->path = ''; \r
+               }\r
+               \r
+               /* get width and height if this is image binary */\r
+               if ( FALSE === ($info = @getimagesize ($fullpath)) )\r
+               {\r
+                       $this->mime = 'application/octet-stream';\r
+                       $this->width = 0;\r
+                       $this->height = 0;\r
+               }\r
+               else\r
+               {\r
+                       $this->mime = $info['mime'];\r
+                       $this->width = $info[0];\r
+                       $this->height = $info[1];\r
+               }\r
+               \r
+               /* utilise Fileinfo subsystem if available */\r
+               if ( defined('FILEINFO_MIME_TYPE') && function_exists ('finfo_open')\r
+                 && (FALSE !== ($info = finfo_open(FILEINFO_MIME_TYPE))) )\r
+               {\r
+                       $this->mime = finfo_file($info, $fullpath);\r
+               }\r
+               \r
+               /* store data with parsed filename */\r
+               if ( preg_match('#^(.*)\.([a-zA-Z0-9]{2,})$#', $this->filename, $info) === 1 )\r
+               {\r
+                       $this->name = $info[1];\r
+                       $this->suffix = $info[2];\r
+                       \r
+                       if ( $CONF['MediaPrefix'] && preg_match('#^([0-9]{8})\-(.*)$#', $this->name, $info) == 1 )\r
+                       {\r
+                               $this->prefix = preg_replace('#^([0-9]{4})([0-9]{2})([0-9]{2})$#', '$1/$2/$3', $info[1]);\r
+                               $this->name = $info[2];\r
+                       }\r
+               }\r
+               \r
                return;\r
        }\r
+       \r
+       /**\r
+        * MediaObject::setResampledSize()\r
+        * Set resampled size\r
+        * \r
+        * @param       integer $maxwidth\r
+        * @param       integer $maxheight\r
+        * @return      boolean\r
+        */\r
+       public function setResampledSize($maxwidth=0, $maxheight=0)\r
+       {\r
+               if ( ($maxwidth == 0) && ($maxheight == 0) )\r
+               {\r
+                       return FALSE;\r
+               }\r
+               else if ( $this->width == 0 || $this->height  == 0 )\r
+               {\r
+                       return FALSE;\r
+               }\r
+               else if ($this->width < $maxwidth && $this->height < $maxheight )\r
+               {\r
+                       $this->resampledwidth = $this->width;\r
+                       $this->resampledheight = $this->height;\r
+               }\r
+               else if ( $maxheight == 0 || $this->width > $this->height )\r
+               {\r
+                       $this->resampledheight = intval ($this->height * $maxwidth / $this->width);\r
+                       $this->resampledwidth = $maxwidth;\r
+               }\r
+               else if ( $maxwidth == 0 || $this->width <= $this->height )\r
+               {\r
+                       $this->resampledwidth = intval ($this->width * $maxheight / $this->height);\r
+                       $this->resampledheight = $maxheight;\r
+               }\r
+               return TRUE;\r
+       }\r
+       \r
+       /**\r
+        * MediaObject::getResampledBinary()\r
+        * Return resampled image binary\r
+        * \r
+        * @param       void\r
+        * @return      mixed   binary if success, FALSE if failed\r
+        */\r
+       public function getResampledBinary($maxwidth=0, $maxheight=0)\r
+       {\r
+               static $gdinfo = array();\r
+               static $original;\r
+               static $resampledimage;\r
+               \r
+               if ( !$this->setResampledSize($maxwidth, $maxheight) )\r
+               {\r
+                       return FALSE;\r
+               }\r
+               \r
+               if ( $gdinfo = array() )\r
+               {\r
+                       $gdinfo = gd_info();\r
+               }\r
+               \r
+               if ( $this->path !== '' )\r
+               {\r
+                       $fullpath = "{$this->root}/{$this->path}/{$this->name}";\r
+               }\r
+               else\r
+               {\r
+                       $fullpath = "{$this->root}/{$this->name}";\r
+               }\r
+               if ( !file_exists($fullpath) )\r
+               {\r
+                       return FALSE;\r
+               }\r
+               \r
+               if ( !array_key_exists($this->mime, Media::$image_mime)\r
+                 || $this->width == 0\r
+                 || $this->height == 0\r
+                 || $this->resampledwidth == 0\r
+                 || $this->resampledheight == 0 )\r
+               {\r
+                       return FALSE;\r
+               }\r
+               \r
+               /* check current available memory */\r
+               $memorymax = trim(ini_get("memory_limit"));\r
+               switch ( strtolower ($memorymax[strlen($memorymax)-1]) )\r
+               {\r
+                       case 'g':\r
+                               $memorymax *= 1024;\r
+                       case 'm':\r
+                               $memorymax *= 1024;\r
+                       case 'k':\r
+                               $memorymax *= 1024;\r
+               }\r
+               \r
+               /*\r
+                * this code is based on analyze if gd.c in php source code\r
+                * if you can read C/C++, please check these elements and notify us if you have some ideas\r
+                */\r
+               if ( (memory_get_usage()\r
+                  + ($this->resampledwidth * $this->resampledheight * 5 + $this->resampledheight * 24 + 10000)\r
+                  + ($this->width * $this->height * 5 + $this->height * 24 + 10000))\r
+                 > $memorymax )\r
+               {\r
+                       return FALSE;\r
+               }\r
+               \r
+               switch ( $this->mime )\r
+               {\r
+                       case 'image/gif':\r
+                               if ( (!array_key_exists('GIF Read Support', $gdinfo) || !isset($gdinfo['GIF Read Support']))\r
+                                 || (!array_key_exists('GIF Create Support', $gdinfo) || !isset($gdinfo['GIF Create Support'])) )\r
+                               {\r
+                                       return FALSE;\r
+                               }\r
+                               $function = 'imagecreatefromgif';\r
+                               break;\r
+                       case 'image/jpeg':\r
+                               if ( (!array_key_exists('JPEG Support', $gdinfo) || !isset($gdinfo['JPEG Support']))\r
+                                 && (!array_key_exists('JPG Support', $gdinfo) || !isset($gdinfo['JPG Support'])) )\r
+                               {\r
+                                       return FALSE;\r
+                               }\r
+                               $function = 'imagecreatefromjpeg';\r
+                               break;\r
+                       case 'image/png':\r
+                               if ( !array_key_exists('PNG Support', $gdinfo) || !isset($gdinfo['PNG Support']) )\r
+                               {\r
+                                       return FALSE;\r
+                               }\r
+                               $function = 'imagecreatefrompng';\r
+                               break;\r
+                       default:\r
+                               return FALSE;\r
+               }\r
+               \r
+               if ( !is_callable($function) )\r
+               {\r
+                       return FALSE;\r
+               }\r
+               \r
+               $original = call_user_func_array($function, array(&$fullpath));\r
+               if ( !$original )\r
+               {\r
+                       return FALSE;\r
+               }\r
+               \r
+               $resampledimage = imagecreatetruecolor($this->resampledwidth, $this->resampledheight);\r
+               if ( !$resampledimage )\r
+               {\r
+                       imagedestroy($original);\r
+                       return FALSE;\r
+               }\r
+               \r
+               @set_time_limit(ini_get('max_execution_time'));\r
+               if ( !ImageCopyResampled($resampledimage, $original, 0, 0, 0, 0, $this->resampledwidth, $this->resampledheight, $this->width, $this->height) )\r
+               {\r
+                       return FALSE;\r
+               }\r
+               \r
+               imagedestroy($original);\r
+               \r
+               ob_start();\r
+               \r
+               switch ( $this->mime )\r
+               {\r
+                       case 'image/gif':\r
+                               imagegif($resampledimage);\r
+                               break;\r
+                       case 'image/jpeg':\r
+                               imagejpeg($resampledimage);\r
+                               break;\r
+                       case 'image/png':\r
+                               imagepng($resampledimage);\r
+                               break;\r
+                       case 'image/bmp':\r
+                       case 'image/x-ms-bmp':\r
+                               imagepng($resampledimage);\r
+                               break;\r
+                       default:\r
+                               return FALSE;\r
+               }\r
+               \r
+               imagedestroy($resampledimage);\r
+               \r
+               return ob_get_clean();\r
+       }\r
+       \r
+       public function getHashedName()\r
+       {\r
+               return (string) hash(Media::$algorism, "{$this->path}/{$this->name}", FALSE);\r
+       }\r
 }\r