Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get image mimetype from resource in PHP/GD?

Tags:

php

image

ftp

gd

I'm trying to find the mime type of an image. PHP has the function getimagesize but that only takes a filename, whereas I have an image "resource" instead - i.e. an image created from imagecreatefromstring.

I found the functions imagesx and imagesy which return the width/height from a resource but I can't find any function that tell me the mime type from a resource. Anyone know of a way to do this?

Note: Due to a weird server set up, we can't read/write files from the server normally, only through an FTP layer (which is where I read the image data from).

like image 920
DisgruntledGoat Avatar asked Feb 05 '10 12:02

DisgruntledGoat


People also ask

Which type of pictures can be created by using GD library?

GD is used for creating PNG, JPEG and GIF images and is commonly used to generate charts, graphics, thumbnails on the fly.

What is mime type in PHP?

The mime_content_type() function is an inbuilt function in PHP which is used to get the MIME content-type of a file. Syntax: string mime_content_type( $file ) Parameters: This function accepts single parameter $file which specifies the path of the file which MIME details to be find.

What is image function PHP?

Image create ( ) function is another inbuilt PHP function mainly used to create a new image. The function returns the given image in a specific size. We need to define the width and height of the required image.

What is a GD extension?

Before you can start generating images with PHP, you need to check that you actually have image-generation capabilities in your PHP installation. In this chapter we'll discuss using the GD extension, which allows PHP to use the open source GD graphics library available from http://www.boutell.com/gd/.


2 Answers

An image created using imagecreatefromstring has no MIME type any more, it is decoded from its native format and stored in GD's internal format.

The same question was asked a while back with the same result.

The only way to go is to catch the image before it gets imagecreatefromstringed, and somehow catch the size information from it.

You say that you can't do file read/write operations on your system, so just writing out the file is out of the question.

The fact that getimagesize() can't read from variables is known and lamented: http://bugs.php.net/bug.php?id=44239

The guy there mentions a nifty workaround: Registering a new stream wrapper that allows file operations on variables.

Is this an option on your server setup?

like image 143
Pekka Avatar answered Sep 22 '22 01:09

Pekka


If you've got access to the binary data of the image (as the use of imagecreatefromstring() suggests), you can detect the file-type "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];
}

Abusing a stream wrapper gets a bit more complicated. At least if we don't want to fiddle with global variables.


// 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);
like image 30
fireweasel Avatar answered Sep 20 '22 01:09

fireweasel