I am looking for a way to take a user uploaded image that is currently put in a temporary location ex: /tmp/jkhjkh78 and create a php image from it, autodetecting the format.
Is there a more clever way to do this than a bunch of try/catching with imagefromjpeg, imagefrompng, etc?
This is one of the functions of getimagesize. They probably should have called it "getimageinfo", but that's PHP for you.
//Image Processing
$cover = $_FILES['cover']['name'];
$cover_tmp_name = $_FILES['cover']['tmp_name'];
$cover_img_path = '/images/';
$type = exif_imagetype($cover_tmp_name);
if ($type == (IMAGETYPE_PNG || IMAGETYPE_JPEG || IMAGETYPE_GIF || IMAGETYPE_BMP)) {
$cover_pre_name = md5($cover); //Just to make a image name random and cool :D
/**
* #description : possible exif_imagetype() return values in $type
* 1 - gif image
* 2 - jpg image
* 3 - png image
* 6 - bmp image
*/
switch ($type) { #There are more type you can choose. Take a look in php manual -> http://www.php.net/manual/en/function.exif-imagetype.php
case '1' :
$cover_format = 'gif';
break;
case '2' :
$cover_format = 'jpg';
break;
case '3' :
$cover_format = 'png';
break;
case '6' :
$cover_format = 'bmp';
break;
default :
die('There is an error processing the image -> please try again with a new image');
break;
}
$cover_name = $cover_pre_name . '.' . $cover_format;
//Checks whether the uploaded file exist or not
if (file_exists($cover_img_path . $cover_name)) {
$extra = 1;
while (file_exists($cover_img_path . $cover_name)) {
$cover_name = md5($cover) . $extra . '.' . $cover_format;
$extra++;
}
}
//Image Processing Ends
this will make image name look cool and unique
Use exif_imagetype() if it's available ..:
http://www.php.net/manual/en/function.exif-imagetype.php
I'm pretty sure exif functions are available by default (i.e. you have to specifically exclude them rather than specifically include them) when you install php
You could try finfo_file(), apparently an improved version of mime_content_type().
Edit: OK, getimagesize() is better..
You can call a system command (if you're under linux/unix), file if you like:
kender#eira:~$ file a
a: JPEG image data, EXIF standard 2.2
This will help you to know the Extension as well as result based on condition
$image_file = 'http://foo.com/images.gif';
$extension = substr($image_file, -4); if($extension == ".jpg"){ echo 'Its a JPG Image.'; } else { echo 'Its not a JPG Image.'; }
People are recommending using getimagesize() but the documentation reads:
Caution This function expects filename to be a valid image file. If a
non-image file is supplied, it may be incorrectly detected as an image
and the function will return successfully, but the array may contain
nonsensical values.
Do not use getimagesize() to check that a given file is a valid image.
Use a purpose-built solution such as the Fileinfo extension instead.
The relevant function in the Fileinfo extension is finfo_file():
string finfo_file ( resource $finfo , string $file_name = NULL
[, int $options = FILEINFO_NONE [, resource $context = NULL ]] )
Returns a textual description of the contents of the file_name
argument, or FALSE if an error occurred.
Example return values given are: text/html, image/gif, application/vnd.ms-excel
However, comments on the official documentation page warn that this shouldn't be relied on for validation either.
Related
Is it possible to work with following kind of image urls?
http://product-images.barneys.com/is/image/Barneys/503230930_product_1
Currently I'm using following code to determine remote image formats. But I don't know how to handle the above mentioned example. Thats one example. Normally they do it for dynamic image resizing.
if($source['extension'] == 'png') {
$type = 'image/png';
}
<?php
$f = tempnam("./", "TMP0");
file_put_contents($f,file_get_contents("http://product-images.barneys.com/is/image/Barneys/503230930_product_1"));
if(getimagesize($f)){
$type = 'image/png';
}
$f file has now the image do whatever you want or delete it using unlink($f);
You could make use of finfo::file extension. You don't need to use cURL for this context.
<?php
$remoteImgTempName = 'someimg';
file_put_contents($remoteImgTempName,file_get_contents('http://product-images.barneys.com/is/image/Barneys/503230930_product_1'));
echo finfo_file(finfo_open(FILEINFO_MIME_TYPE), $remoteImgTempName);
OUTPUT :
image/jpeg
I've got a script and simple if check to see if a value is in a array. I can't seem to find out why the if tag runs when it's in the array.
else if (!in_array($type, $avatarformats)) {
$error .= '<div class="alert error">You\'re image is not a allowed format</div>';
unlink($_FILES['file']['tmp_name']);
}
When the script reads $type and $avatarformats it's = to the following.
$avatarformats = Array ( [0] => .jpg [1] => .jpeg [2] => .png )
$type = .png
The if tag runs when it should not because .png is in the array. Or am I no understaind what am doing.
I'm not sure how you determined the type, but typically the ['type'] that comes from $_FILES is the content type (e.g. 'image/jpeg'), rather than the extension of the filename itself.
To test for file extensions, you could use this code:
// get file extension (without leading period)
$ext = pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION);
// ...
elseif (!in_array($ext, array('png', 'jpg', 'jpeg'))) {
// error
}
Note: Use exif_imagetype(), please read http://www.php.net/manual/en/function.exif-imagetype.php
function image_allowed($imgfile) {
$types = array(IMAGETYPE_JPEG, IMAGETYPE_PNG);
return in_array(exif_imagetype($imgfile), $types);
}
Then in your code.
else if (!image_allowed($_FILES['file']['tmp_name'])) {
$error .= '<div class="alert error">You\'re image is not a allowed format</div>';
unlink($_FILES['file']['tmp_name']);
}
I suspect that in_array() is returning true because the statement !in_array($type, $avatarformats) is evaluating to true due to the full stop. It is evaluating the value of $type as an integer because of the decimal place.
That being said you have 2 options:
1) Try stripping the dot i.e. ".png" to "png" from the file extension before adding it to the array in the first place and then do the test.
2) or change your conditional to the following: else if (in_array($type, $avatarformats) == false) {
in_array() is a strange beast and I try to avoid it at the best of times. isset() is your friend and much faster than in_array under most conditions anyways.
How to verify whether the file (jpg, png, gif) is the picture in PHP?
I need function like this:
boolean isImage($url);
Or:
boolean isImage(binary_data_from_http_post);
I think second way is better, because works before saving file on disk.
I don't want to experiment with copying from random page found in google.
You can use finfo
http://de3.php.net/manual/en/function.finfo-file.php
Or get image size
http://de.php.net/getimagesize
You can use PHP's GD extension to check for a valid image:
function isImage($url) {
$buffer = file_get_contents($url);
$img = imagecreatefromstring($buffer);
return ($img !== false) ? true : false;
}
If you already have the potential image data you can use this instead:
function isImage($data) {
return (imagecreatefromstring($data) !== false) ? true : false;
}
Is it possible to find out the type of an image encoded as a base64 String in PHP?
I have no method of accessing the original image file, just the encoded string. From what I've seen, imagecreatefromstring() can create an image resource from a string representation (after it's been decoded from base64), but it automatically detects the image type and the image resource itself is a special PHP representation. In case I want to save the image as a file again, I would have no idea if the type I am saving it as corresponds to the original type from which the String representation was created.
FileInfo can do that for you:
$encoded_string = "....";
$imgdata = base64_decode($encoded_string);
$f = finfo_open();
$mime_type = finfo_buffer($f, $imgdata, FILEINFO_MIME_TYPE);
If you dont want to use these functions because of their dependencies you can use the first bytes of the data:
function getBytesFromHexString($hexdata)
{
for($count = 0; $count < strlen($hexdata); $count+=2)
$bytes[] = chr(hexdec(substr($hexdata, $count, 2)));
return implode($bytes);
}
function getImageMimeType($imagedata)
{
$imagemimetypes = array(
"jpeg" => "FFD8",
"png" => "89504E470D0A1A0A",
"gif" => "474946",
"bmp" => "424D",
"tiff" => "4949",
"tiff" => "4D4D"
);
foreach ($imagemimetypes as $mime => $hexbytes)
{
$bytes = getBytesFromHexString($hexbytes);
if (substr($imagedata, 0, strlen($bytes)) == $bytes)
return $mime;
}
return NULL;
}
$encoded_string = "....";
$imgdata = base64_decode($encoded_string);
$mimetype = getImageMimeType($imgdata);
references :- check here the list of file signatures
The solution given by #Marc B is the best one for me (if our php version is > 5.3.0 otherwise we can use the solution given by #Aaron Murgatroyd).
I would like to give a little addition to this solution.
To get the image type you can do it like this :
$split = explode( '/', $mime_type );
$type = $split[1];
In fact, (if you don't know it) the mime type for images is : image/type and type can be png or gif or jpeg or ...
Hope that can help someone and thanks to #Marc B for his solution.
For an exhaustive list of mime type you can look here :
http://www.sitepoint.com/web-foundations/mime-types-complete-list/
The way shown by #Marc B is the nicest.
Should FInfo not be available, the only other way I know is to store the data into a file, and run a getimagesize() on it.
Code below will get the image type from its mime type.
<?php
$base64 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKIAAAAxCAYAAABZAHL2AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAgfSURBVHhe7ZwxTBVLFIaH916wACstoDChEENhIxWYoJUmSqeJWkmiNkQS6TBBzSskUStNoNOCYCOJUKmJoVETY6WVjdJrow1UUvDyjfe/OYy7e+/ivbLknS/Z7N3ZndkzZ/45c3ZZ7RgeHt4MjrPD/FXbO86O4kJ0KoEL0akELkSnErgQnUrgQnQqQVuFODo6Go4dO1Y7cpx82ibEycnJMD09HW7cuBF6e3trpY6TTduEuLa2Fvfd3d3hzp078bfj5PH3gQMH/q39bikfPnwIg4ODMRru27cv7N27N7x796521nG20tKImOaDU1NTYX19Pf4+d+6c54tOLi2LiOSC4+PjoaenJ7x58yaW/fjxI3z8+DGcPn06Hg8NDYWVlZW6OB1HtCQisgQr2vGkPDs7G3NDeP/+fXj06FH87fmik0dLIuKXL19i/nfixInQ2dkZ80KiH9Hw+/fvni86DWlZjvj58+dw5syZuIf+/v4wNzcXBQieLzpFtPSpmZyQHJCohxCJjuSHX79+jdExzReXl5djnSpB1MZ2bHb+HNuOiOR7T58+DZcvX97ywpqod/v27XpeCLzYZtsN+SIThUi+m2G1IU9/+fJlePv2bSyjT/zWcdXYthB5KEGACBFBIjQrSAQ3MzNTX471EPPkyZOYMxJxHjx4EM+VhXZoz/kVRMgEJyXSA+NuYNtCRGB2+UIYEqTywmfPnoWrV6/WxUg5MxORXrx4sZ5PloV2eE3k/Mr58+drv0K4fv16mJiYqB1Vm20LEZHxcELUSwVJxGJDMOlDDFHz06dPdXE67eP169cxHdoNtOwfT7EkMBuPHDlSK/kJAmQ5xilXrlyJAm4UCRHwqVOn6ks91/OSXE4lz6Gd58+fx2POI2zyO+5PPcp4rcQ1qehpn+vYuObFixf1tkk12I4ePRqPBU/6HR0dsS8Wlj/1+9ChQ3GS0dfFxcV4/u7du6Grqyveh0krsJHVA1ZXV8P9+/e3tAWpbcDHJAcPHox1KKfP1KOP9NXWVz7OnpVI5WnfGvWBP1awAslOQZ2RkZHcciD9ajTe0PJ/xccgM5DqtMCpY2NjDSMhEZUBQng4BGiTJ1nq045NuHE+D0cMEGLhmGt4V6kndCKy7nvt2rXoKJxDJMfBtI3TcWaWELHn+PHjMc2wTmUA5+fnt+TGApGwLDKIsuPs2bPRNsAGbAEE+urVqygWbEmRbSBB0R/ub9GETH1PX/KESBt5983qw8mTJ+u+JBVT3205PqE9jilvhtJLM4ZjAAmxBGcdgvEMGE5XxAKiiQwt4tKlS1GEvHdkJrPRHmLSIALlOBQRAhESp+mJnYGjDhCJQVGbWYqouQd7hED9LPJECIhfA4HN3JcHMWDyMKmsD+y7U84LRIiNEgP20Rf9qZQJZq8HfM5E0j2xDRstnGMrAn/ovnl9IDoK2UEdOwHxEVCm9tROM5QWIqGbm+FUhMhs4jVBKk5EgygkSBu6i6BtKzjRSMQMhF3CgDqUyzE4Heeky2teulAkQpCwOKeJw14QRbBJObSiCiLS0oVvsBOxAW1gH/VoS4Opuhbs4nr2bKmPOMdWhNrFxrw+IES1LSEiUIt8YSeMFXAjSgtRg5qSipPlkxBNhFPO0QwMDJ1nYBB03v3yoI7dbLTmOBVrHogQZ9v6KTpnRcqApZFAwlcUUfQA/GL7SKqAD7Vtbv7MnKiXYidsKsJmUbtpW2kfdIwPQRNJ5RzjD50HIn2zFApRL0BtTobjWDZYPpg9GJIVLQAHM5gsYSKrTQuRk3tcuHAhChoxcy3CKBIF9yEyU8duZYUsaE9vBMiRisiK4KB720nIZFX0oG3Okc8K7muFqAhjB7gdFI0hqA8cY5MEzHgp4jPBZCe6KDM5/qntmwansymy2NCPcWwYg3MxmuMy7/wwXnmfYOAQ882bN7csG4J7IFSlANYBPLUWCTgP5Y30lVdRLOvpki40KCkSKHvyL6IG0T5LoII+qN6fJM9HsoXoho9BD1kIEAHTD1YwNvkiq29FbPs9YhYYjUARJ4Igb+GBIX1dUBY6hSi0HKRoYJVvWayDmaV5oknRwwv9oV2iU1pX97LRyi5P1hYbUYSErbcDQB38l7W1g2b7wF4PT+lEkq9s39ouRLu0ltmaheiXNTtxjJYAnGKXMznLOgI4tmXKP7U0CpbDtK5FD1qKBELORqB6ULN/P7eDwWDJTmBSKNpQrlwL+zThaJcopEj0O9h70w9shTJ9SPNrnSMqamyA47JRvaUR8XdBgCzBS0tLdaew8UROXqKogKBYBnAo5TiIgeSYZZSBY09+aUEM1KVt63SuR4x5MIjkxDa/AwSq3Ipy2lNOR7kihbCDih0WpRT4gHSCyUu/sYtN7W4Xm1aQZmArlOmDtR9brTDtOfu7WQo/A5OxIBHYsjJk1U+XGz4Jo+PMrj179oTDhw/HckRGzqaO81EtjuBVEh/e4jA6z+/9+/fHz9B423/v3r3A+0vK9SEu13E9EYD6Gxsb4fHjx2FhYSGe53pmsyKUoA735LwGzn72Rnt89obt3OPWrVvxegvt9vX1xWsePny45RM42Ui/1RZgB5NA9mMz9WgjFTPknbd9wi6dL9MHfnMNe+pYH3379q3eN0RPf8pQ+JcVu6T+bp4n2tGms/up1NLs/H9pOiK2A4+IjvCI6FQCF6JTCfw/c3cqgUdEpxK4EJ1K4EJ0KoEL0akELkSnErgQnUrgQnQqgQvRqQQuRKcSdPT39/tfVpwdp2NgYMCF6OwwIfwHN+rCnrjztp8AAAAASUVORK5CYII=";
$image_info = getimagesize($base64);
$extension = (isset($image_info["mime"]) ? explode('/', $image_info["mime"] )[1]: "");
echo $extension;
?>
If you know a minimal amount about the file format structure, you could theoretically look at the top bytes of the file until you could work out what type of file it is.
For example, a GIF image always starts with the following bytes GIF89a. If you can find that string at the begining of the file, you can be reasonably sure that it is a GIF image and absolutely certain it isn't any other image format. (it could still be a text file though, that just happens to start with 'GIF89a'; you'd have to parse more of the file to be absolutely certain)
Likewise, PNG files have the string PNG fairly near the start (it's not quite at the very begining; again, you'd need to research the file format specifics to help you determine how much you'd need to know to be certain).
JPEGs also contain recognisable strings in their headers, although these are more varied and complex. You might want to look out for the string Exif.
Getting the file format definitions would definitely give you more accuracy, but depending on how accurate you need to be, you might learn enough about the files formats just by opening some image files in a binary editor to see how they're structured.
These resources may help you:
http://www.w3.org/Graphics/JPEG/
http://www.w3.org/Graphics/PNG/
Follow PHP.NET Fileinfo :-
$finfo = finfo_open(FILEINFO_MIME_TYPE); // return mime type ala mimetype extension
foreach (glob("*") as $filename) {
echo finfo_file($finfo, $filename) . "\n";
}
finfo_close($finfo);
You can use magic numbers to detect a MIME type (check here the list of file signatures). However, file signatures are not 100% reliable and you can easily encounter false positives. Of course, there are tasks when a such solution is more than enough.
So if you have a Base64 string and want to identify its MIME type using file signatures you don't need to decode the Base64. A much faster way is to store the file signatures as Base64 and just check if input starts with one of them. A simple example:
<?php
function detectMimeType(string $base64)
{
$signaturesForBase64 = [
'JVBERi0' => "application/pdf",
'R0lGODdh' => "image/gif",
'R0lGODlh' => "image/gif",
'iVBORw0KGgo' => "image/png",
'/9j/' => "image/jpeg"
];
foreach($signaturesForBase64 as $sign => $mimeType)
{
if(strpos($base64, $sign) === 0) {
return $mimeType;
}
}
return false;
}
var_dump(detectMimeType('R0lGODdhAQABAPAAAP8AAAAAACwAAAAAAQABAAACAkQBADs=')); // image/gif
var_dump(detectMimeType('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAADElEQVR42mP4z8AAAAMBAQD3A0FDAAAAAElFTkSuQmCC')); // image/png
var_dump(detectMimeType('JVBERi0xLjUKJYCBgoMKMSAwIG9iago8PC9GaWx0ZXIvRmxhdGVEZWNvZGUvRmlyc3QgMTQxL04gMjAvTGVuZ3')); // application/pdf
var_dump(detectMimeType('/9j/4AAQSkZJRgABAQAAZABkAAD/2wCEABQQEBkSGScXFycyJh8mMi4mJiYmLj41NTU1NT5EQUFBQUFBRERERERERERE')); // image/jpeg
I got this solution from this Js Que-Answer
Additinally : this one is also works properly
I need to check whether a given image is a JPEG.
if ($_FILES["fname"]["error"] > 0) {
$imgData = "hyperlink/holder.jpg";
} else {
$imgData ="hyperlink/" . $_FILES["fname"]["name"];
}
// Only accept jpg images
// pjpeg is for Internet Explorer should be jpeg
if (!($_FILES["fname"]["type"] == "image/pjpeg") ) {
print "I only accept jpg files!";
exit(0);
}
When it goes to first statement in the first if statement it always gives I only accept jpg files!
How can I fix it?
Try the exif_imagetype image function.
Example:
if(exif_imagetype($filepath) != IMAGETYPE_JPEG){
echo 'Not a JPEG image';
}
PHP has such good image-type support, i wonder why you are restricting your app. In just a couple lines of code you can deal with any input format and convert to jpeg, if that is a requirement...
$im = imagecreatefrompng(input_filename)
imagejpeg($im, output_filename);
I believe the following works:
Also note that:
(exif_imagetype($ImagePathAndName) == IMAGETYPE_JPEG)
only reads the first few bytes looking for an image header so isn't really good enough to confirm if an image is corrupt.
Below I have it in a logical “and” statement i.e. both of these tests must be passed in order for the image to qualify as being valid and non-corrupt etc:
if ((exif_imagetype($ImagePathAndName) == IMAGETYPE_JPEG) && (imagecreatefromjpeg( $ImagePathAndName ) !== false ))
{
echo 'The picture is a valid jpg<br>';
}
Note: You need to place this line of code at the top of the php code in order to avoid seeing the warning messages from imagecreatefromjpeg( $ImagePathAndName ) when it encounters a fake/corrupt image file.
ini_set(‘gd.jpeg_ignore_warning’, 1);
Why don't you try creating an array of exceptions (the files you want the user to be able to upload).
// Hyperlink for your website
$hyperlink = "http://www.yourwebsitehere.com";
if($_FILES['fname']['error'] > 0)
{
$image= $hyperlink . "/holder.jpg";
}
else
{
$image = $hyperlink . "/" . $_FILES['fname']['name'];
}
// Only accept files of jpeg format
$exceptions = array("image/jpg", "image/jpeg", "image/pjpeg");
foreach($exceptions as $value)
{
if($_FILES['fname']['type'] != $value)
{
echo "I only accept jpeg images!";
break; // Or exit();
}
}
When using $_FILES, you are relying on informations sent by the client, which is not the best thing to do (you've seen it's not always the same, and, if I remember correctly, $_FILES['...']['type'] can be faked).
If you are using PHP >= 5.3 (or can install PECL packages), maybe you can give a look to the extension Fileinfo. If you are using an older version, what about mime_content_type?
And, as said by Scott, why allow only jpeg?
Looking about the code better : when you are in the first case (error > 0), you are assigning a default file to $imgData? Why the spaces around "hyperlink"?
And why do you always use to check the content-type, even if there was an error a couple of lines before?
To finish, did you have a look at the manual (Handling file uploads)?
Check the mime (Multipurpose Internet Mail Extensions) type of file with this code. And verify your desired type. You can also detect png,gif with this code.
if($_FILES["fname"]["type"] == "image/jpeg")
{
echo "File type is JPEG";
}