代码之家  ›  专栏  ›  技术社区  ›  DisgruntledGoat

从php/gd中的资源获取图像mimetype?

  •  9
  • DisgruntledGoat  · 技术社区  · 15 年前

    我想找一个图像的哑剧类型。php有函数 getimagesize 但这只需要一个文件名,而我有一个图像“资源”,也就是从 imagecreatefromstring .

    我找到了功能 imagesx imagesy 它从资源返回宽度/高度,但我找不到任何函数来告诉我资源的mime类型。有人知道怎么做吗?

    注意:由于设置了一个奇怪的服务器,我们 无法读取/写入文件 通常只通过一个ftp层从服务器读取图像数据。

    4 回复  |  直到 11 年前
        1
  •  8
  •   riverinyo    11 年前

    我知道这很古老,但万一有人像我一样看到这篇文章…

    从php 5.4.0中发布的一个更好的选项是: getimagesizefromstring

    这个新函数与getImageSize完全相同,但允许您从流中检索信息。

        2
  •  12
  •   fireweasel    13 年前

    如果您有权访问图像的二进制数据(如使用imageCreateFromString()所建议的那样),则可以检测文件类型“manually”(手动):

    
    function image_file_type_from_binary($binary) {
        if (
            !preg_match(
                '/\A(?:(\xff\xd8\xff)|(GIF8[79]a)|(\x89PNG\x0d\x0a)|(BM)|(\x49\x49(?:\x2a\x00|\x00\x4a))|(FORM.{4}ILBM))/',
                $binary, $hits
            )
        ) {
            return 'application/octet-stream';
        }
        static $type = array (
            1 => 'image/jpeg',
            2 => 'image/gif',
            3 => 'image/png',
            4 => 'image/x-windows-bmp',
            5 => 'image/tiff',
            6 => 'image/x-ilbm',
        );
        return $type[count($hits) - 1];
    }
    

    滥用流包装器会变得更加复杂。 至少如果我们不想摆弄全局变量。

    
    // getimagesize() from string
    class GisFromString {
        const proto_default = 'gisfromstring';
        protected static $proto = null;
        protected static $imgdata = null;
    
        static function getImageSize($imgdata) {
            if (null === self::$proto) {
                self::register();
            }
            self::$imgdata = $imgdata;
            // note: @ suppresses "Read error!" notices if $imgdata isn't valid
            return @getimagesize(self::$proto . '://');
        }
    
        static function getMimeType($imgdata) {
            return is_array($gis = self::getImageSize($imgdata))
                ? $gis['mime']
                : $gis;
        }
    
        // streamwrapper helper:
    
        const unregister = null;
    
        // register|unregister wrapper for the given protocol|scheme
        // return registered protocol or null
        static function register(
            $proto = self::proto_default // protocol or scheme
        ) {
            if (self::unregister === $proto) { // unregister if possible
                if (null === self::$proto) {
                    return null;
                }
                if (!stream_wrapper_unregister(self::$proto)) {
                    return null;
                }
                $return = self::$proto;
                self::$proto = null;
                return $return;
            }
            if (!preg_match('/\A([a-zA-Z][a-zA-Z0-9.+\-]*)(:([\/\x5c]{0,3}))?/', $proto, $h)) {
                throw new Exception(
                    sprintf('could not register invalid scheme or protocol name "%s" as streamwrapper', $proto)
                );
            }
            if (!stream_wrapper_register($proto = $h[1], __CLASS__)) {
                throw new Exception(
                    sprintf('protocol "%s" already registered as streamwrapper', $proto)
                );
            }
            return self::$proto = $proto;
        }
    
        // streamwrapper API:
    
        function stream_open($path, $mode) {
            $this->str = (string) self::$imgdata;
            $this->fsize = strlen($this->str);
            $this->fpos = 0;
            return true;
        }
    
        function stream_close() {
            self::$imgdata = null;
        }
    
        function stream_read($num_bytes) {
            if (!is_numeric($num_bytes) || $num_bytes < 1) {
                return false;
            }
            /* uncomment this if needed
            if ($this->fpos + $num_bytes > 65540 * 4) {
                // prevent getimagesize() from scanning the whole file
                // 65_540 is the maximum possible bytesize of a JPEG segment
                return false;
            }
            */
            if ($this->fpos + $num_bytes > $this->fsize) {
                $num_bytes = $this->fsize - $this->fpos;
            }
            $read = substr($this->str, $this->fpos, $num_bytes);
            $this->fpos += strlen($read);
            return $read;
        }
    
        function stream_eof() {
            return $this->fpos >= $this->fsize;
        }
    
        function stream_tell() {
            return $this->fpos;
        }
    
        function stream_seek($off, $whence = SEEK_SET) {
            if (SEEK_CUR === $whence) {
                $off = $this->fpos + $off;
            }
            elseif (SEEK_END === $whence) {
                $off = $this->fsize + $off;
            }
            if ($off < 0 || $off > $this->fsize) {
                return false;
            }
            $this->fpos = $off;
            return true;
        }
    }
    
    
    // usage:
    //$imgdata = file_get_contents('path/lenna.jpg');
    
    
    // if the default protocol is already registered
    //GisFromString::register('other');
    
    var_dump(GisFromString::getImageSize($imgdata));
    
    echo GisFromString::getMimeType($imgdata);
    
        3
  •  10
  •   Community CDub    8 年前

    使用创建的图像 imagecreatefromstring 不再有mime类型,它从其本机格式解码并存储在gd的内部格式中。

    同样的问题是 asked a while back 结果相同。

    唯一的方法是在图像被 图像创建自字符串 Ed,不知何故从中获取尺寸信息。

    你说你不能在你的系统上做文件读/写操作,所以仅仅写文件是不可能的。

    GetImageSize()无法从变量中读取这一事实是众所周知的,令人遗憾的是: http://bugs.php.net/bug.php?id=44239

    那里的人提到了一个漂亮的解决方案: Registering a new stream wrapper that allows file operations on variables .

    这是服务器设置中的一个选项吗?

        4
  •  0
  •   matiasf    15 年前

    您可以使用php fileinfo函数。

    $image_buffer = SomeFunctionToGetStringBufferFromGD();
    
    $fileinfo = finfo_open();
    
    $type = finfo_buffer($fileinfo, $image_buffer);
    

    它使用 magic numbers (与unix文件命令相同)以标识文件类型。