I am developing an API system for my uploading service (in PHP). At the current moment I support the option to send image data as binary data from file_get_contents, fread, etc, or by encoding it with 64 based system. I am attempting to determine the extension type of the image being uploaded to my service from this binary/base64 data. If it is base64 then I decode it and then process it.
I have the following at the moment:
// We need to figure it out ourselves
if ($type === "")
{
// Let's see if it is a base64 file
$base64 = $this->checkBase64Encoded($file_data);
// We got a 64 based file or binary
$type = $base64 === TRUE ? "base64" : "binary";
}
if ($type == "binary")
{
$im = imagecreatefromstring($file_data);
}
I want to see if it is possible to determine the image extension type for saving the file. What do you guys suggest? I read something about using getimagesize()? Although I am not sure about this. Is there no way to get around temporarily saving the file, processing it, and then renaming it?
I also planned to use this to test that the image was a valid image before i checked for extension but I wasn't exactly sure how to use the getimagesize() function:
try
{
// Get the width and height from the uploaded image
list($width, $height) = getimagesize($file['tmp_name']); // I'm not sure what to put here instead of $file['tmp_name']
}
catch (ErrorException $e)
{
// Ignore read errors
}
if (empty($width) OR empty($height))
{
// Cannot get image size, cannot validate
return FALSE;
}
Please feel free to ask for any clarifications if I was unclear. Thanks so much :)
You're looking for the fileinfo functions, particularly finfo_buffer().
Related
Iam getting base64 image in a json like below format
{
"profilepic":"iVBORw0KGgoAAAANSUhEUgAAAPAAAABGCAYAAADyxhn6AAAMYml..."
}
I have a PHP code like below, where i decode this base64 image and save it in server, i tried to run the code and am not able to see the image in particular folder location.
Can anyone help me to identify the problem here?
<?php
header("Access-Control-Allow-Origin: *");
$str_json = file_get_contents('php://input'); //($_POST doesn't work here)
$response = json_decode($str_json, true); // decoding received JSON to array
$photo = $response["profilepic"];
// Obtain the original content (usually binary data)
$bin = base64_decode($photo);
// Load GD resource from binary data
$im = imageCreateFromString($bin);
// Make sure that the GD library was able to load the image
// This is important, because you should not miss corrupted or unsupported images
if (!$im) {
die('Base64 value is not a valid image');
}
// Specify the location where you want to save the image
$img_file = 'test/'.uniqid().'.jpg';
// Save the GD resource as PNG in the best possible quality (no compression)
// This will strip any metadata or invalid contents (including, the PHP backdoor)
// To block any possible exploits, consider increasing the compression level
imagejpeg($im, $img_file, 80);
$imgPath = 'http://serverip/'.$img_file;
?>
Please help me to identify the issue
I've heard that the best way to handle uploaded images is to "re-process" them using the GD library and save the processed image. see: PHP image upload security check list
My question is how do this "re-processing" in GD? What this means exactly? I don't know the GD library very well and I'm afraid I will mess it up...
So if anyone who did this before could you give me an example for this?
(I know, another other option is to use ImageMagick. For ImageMagick I found an answer here: Remove EXIF data from JPG using PHP, but I can't use ImgMagick now. By the way.. removing EXIF data means completely recreate the image in this case?)
(I'm using Zend Framework if someone interested.)
If the user uploads a JPEG file, you could do something like this to reprocess it:
$newIm = #imagecreatefromjpeg($_FILES['file']['tmp_name']);
if (!$newIm) {
// gd could not create an image from the source
// most likely, the file was not a valid jpeg image
}
You could then discard the $newIm image using imagedestroy() and use the uploaded file from the user, or save out the image from GD and use that. There could be some issues with saving the GD image as it is not the original image.
Another simple method would be to check the header (first several bytes) of the image file to make sure it is correct; for example all JPEG files begin with 0xff 0xd8.
See also imagecreatefromstring(), and you can also use getimagesize() to run similar checks on the uploaded image.
function isvalidjpeg($file)
{
$finfo = finfo_open(FILEINFO_MIME_TYPE);
return is_resource($finfo) &&
(finfo_file($finfo, $file) === 'image/jpeg') &&
finfo_close($finfo);
}
if(isvalidjpeg($_FILES['file']['tmp_name'])) {
$newIm = #imagecreatefromjpeg($_FILES['file']['tmp_name']); .....
I'd like to check if an uploaded file is an image file (e.g png, jpg, jpeg, gif, bmp) or another file. The problem is that I'm using Uploadify to upload the files, which changes the mime type and gives a 'text/octal' or something as the mime type, no matter which file type you upload.
Is there a way to check if the uploaded file is an image apart from checking the file extension using PHP?
My thought about the subject is simple: all uploaded images are evil.
And not only because they can contain malicious codes, but particularly because of meta-tags. I'm aware about crawlers that browse the web to find some protected images using their hidden meta-tags, and then play with their copyright. Perhaps a bit paranoid, but as user-uploaded images are out of control over copyright issues, I take it seriousely into account.
To get rid of those issues, I systematically convert all uploaded images to png using gd. This have a lot of advantages: image is clean from eventual malicious codes and meta tags, I only have one format for all uploaded images, I can adjust the image size to fit with my standard, and... I immediately know if the image is valid or not! If the image can't be opened for conversion (using imagecreatefromstring which doesn't care about image format), then I consider the image as invalid.
A simple implementation could look like this:
function imageUploaded($source, $target)
{
// check for image size (see #DaveRandom's comment)
$size = getimagesize($source);
if ($size === false) {
throw new Exception("{$source}: Invalid image.");
}
if ($size[0] > 2000 || $size[1] > 2000) {
throw new Exception("{$source}: Too large.");
}
// loads it and convert it to png
$sourceImg = #imagecreatefromstring(#file_get_contents($source));
if ($sourceImg === false) {
throw new Exception("{$source}: Invalid image.");
}
$width = imagesx($sourceImg);
$height = imagesy($sourceImg);
$targetImg = imagecreatetruecolor($width, $height);
imagecopy($targetImg, $sourceImg, 0, 0, 0, 0, $width, $height);
imagedestroy($sourceImg);
imagepng($targetImg, $target);
imagedestroy($targetImg);
}
To test it:
header('Content-type: image/png');
imageUploaded('http://www.dogsdata.com/wp-content/uploads/2012/03/Companion-Yellow-dog.jpg', 'php://output');
This does not exactly answer your question as this is the same kind of hack than the accepted answer, but I give you my reasons to use it, at least :-)
You could use getimagesize() which returns zeros for size on non-images.
You can verify the image type by checking for magic numbers at the beginning of the file.
For example: Every JPEG file begins with a "FF D8 FF E0" block.
Here is more info on magic numbers
If Uploadify really changes the mime type - i would consider it a bug.
It doesn't make sense at all, because that blocks developers from working with
mime-type based functions in PHP:
finfo_open()
mime_content_type()
exif_imagetype().
This is a little helper function which returns the mime-type based on the first 6 bytes of a file.
/**
* Returns the image mime-type based on the first 6 bytes of a file
* It defaults to "application/octet-stream".
* It returns false, if problem with file or empty file.
*
* #param string $file
* #return string Mime-Type
*/
function isImage($file)
{
$fh = fopen($file,'rb');
if ($fh) {
$bytes = fread($fh, 6); // read 6 bytes
fclose($fh); // close file
if ($bytes === false) { // bytes there?
return false;
}
// ok, bytes there, lets compare....
if (substr($bytes,0,3) == "\xff\xd8\xff") {
return 'image/jpeg';
}
if ($bytes == "\x89PNG\x0d\x0a") {
return 'image/png';
}
if ($bytes == "GIF87a" or $bytes == "GIF89a") {
return 'image/gif';
}
return 'application/octet-stream';
}
return false;
}
You can check the first few bytes of the file for the magic number to figure out the image format.
Try using exif_imagetype to retrieve the actual type of the image. If the file is too small it will throw an error and if it can't find it it will return false
Is it not possible to interrogate the file with finfo_file?
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mimetype = finfo_file($finfo, $filename); //should contain mime-type
finfo_close($finfo);
This answer is untested but based on this forum discussion on the Uploadify forums.
I would also point out that finfo should "try to guess the content type and encoding of a file by looking for certain magic byte sequences at specific positions within the file" so in my mind this should still work even though Uploadify has specified the wrong mime type.
I need to make a website that will allow registered users to upload audio files.
I wonder is there any bullet proof practice regarding security.
The site is built in PHP
Check mime type of uploading file
mp3 -> audio/mpeg
More here: http://www.w3schools.com/media/media_mimeref.asp
You will want to check the file type carefully. This means not just doing a substring on the file name to get the extension. The extension is not a concrete indicator of what the file actually is.
As Danzan said, you will want to check the MIME type of the file, using some code like this:
if ($_FILES["audioUpload"]["type"] == "audio/mpeg") {
//proceed with upload procedure
} else {
echo "Only mp3's are allowed to be uploaded.";
}
This reduces the chances of a user uploading, say, malicious PHP code into your upload directory to basically zero.
Bullet-proof file type check is provided via combination of getimagesize, fileinfo extension and mime_content_type function (Nette Framework property):
// $file is absolute path to the uploaded file
$info = #getimagesize($file); // # - files smaller than 12 bytes causes read error
if (isset($info['mime'])) {
return $info['mime'];
} elseif (extension_loaded('fileinfo')) {
$type = preg_replace('#[\s;].*$#', '', finfo_file(finfo_open(FILEINFO_MIME), $file));
} elseif (function_exists('mime_content_type')) {
$type = mime_content_type($file);
}
return isset($type) && preg_match('#^\S+/\S+$#', $type)
? $type
: 'application/octet-stream';
You can not trust any data coming from the client, because they can be easily forged.
You can upload anything with PHP. Here's an example: http://www.tizag.com/phpT/fileupload.php
Regarding security, you have to verify that only certain people are allowed to upload stuff and that you verify the contents of what they're uploading (file size, file type, etc).
i am aware of the basics like what is a function, a class, a method etc. however i am totally confused on what exactly the below code does to read the image, i read it somewhere that we have to read the image in binary format first. i am confused on the process how the php reads the image and loads it for reading. i would like to know the function of each and every code in this class and what is actually happening with the code.
Code :
class Image {
function __construct($filename) {
//read the image file to a binary buffer
$fp = fopen($filename, 'rb') or die("Image $filename doesn't exist");
$buf = '';
while(!feof($fp))
$buf .= fgets($fp, 4096);
//create image
imagecreatefromstring($buf);
}
}
and when i instantiate the object image with the syntax $image = new Image("pic.jpg"); it does not print the image in html, what does the variable $image actually hold, if i want to print that image in html what should i be doing.
Update :
FYI : I understand PHP and HTML, as i was trying to learn OOP in PHP and i came across the article as this particular code was not understood clearly by me so i thought of asking you guys, i highly appreciate your response, i would be thankful if you could try and explain the code instead of asking me to try different code.
My concern is purely meant for learning purpose, i am not implementing it anywhere.
In HTML, all you need to do is refer to the file in an <img> tag.
<img src="/path/to/image/image.jpg" width="600" height="400" alt="Image Name" />
The source needs to be the URL of the image, relative to your webserver root directory.
As for the code, you put up. That would be completely unnecessary for HTML usage, and is also unnecessary for standard image use within PHP, as there are direct methods to load an image from a file, imagecreatefromjpeg() for instance for JPEG files.
As it stands, the constructor of your Image class takes a filename, opens that file and reads the entire contents as binary data in to the string $buf, 4096 bytes at a time. Then it calls imagecreatefromstring($buf) to convert the file data in to an image resource, which can then be used further within PHP with the PHP GD image handling functions.
As I say, none of this is particularly relevant if all you wish to do is display an existing image within HTML. Those commands are designed for image manipulation, inspection and creation.
Your $image would contain an instance of the Image Class.
Your constructor will try to open $filename. If that's not possible, the script will die/terminate with an error message. If $filename can be opened, the file will be read into the $buf variable and a GD image resource will be created.
The code is suboptimal for a number of reasons:
the GD resource created by imagecreatefromstring is not assigned to a property of the Image class. This means, the entire process is pointless, because the resource will be lost after it was created. The work done in the constructor is lost.
calling die will terminate the script. There is no way to get around this. It would be better to throw an Exception to let the developer decide whether s/he wants the script to terminate or catch and handle this situation.
reading a file with fopen and fread works, but file_get_contents is the preferred way to read the contents of a file into a string. It will use memory mapping techniques if supported by your OS to enhance performance.
You should not do work in the constructor. It is harmful to testability.
A better approach would be to use
class Image
{
protected $_gdResource;
public function loadFromFile($fileName)
{
$this->_gdResource = imagecreatefromstring(
file_get_contents($fileName)
);
if(FALSE === $this->_gdResource) {
throw new InvalidArgumentException(
'Could not create GD Resource from given filename. ' .
'Make sure filename is readable and contains an image type ' .
'supported by GD'
);
}
}
// other methods working with $_gdResource …
}
Then you can do
$image = new Image; // to create an empty Image instance
$image->loadFromFile('pic.jpg') // to load a GD resource
PHP's imagecreate* function return a resource. If you want to send it to the client, you'll have to set the appropriate headers and then send the raw image:
header('Content-Type: image/jpeg');
imagejpeg($img);
See the GD and Image Functions documentation for details.
class Image
{
public $source = '';
function __construct($filename)
{
$fp = fopen($filename, 'rb') or die("Image $filename doesn't exist");
$buf = '';
while(!feof($fp))
{
$buf .= fgets($fp, 4096);
}
$this->source = imagecreatefromstring($buf);
}
}
$image = new Image('image.jpg');
/* use $image->source for image processing */
header('Content-Type: image/jpeg');
imagejpeg($image->source);
If you just want to display the image, all of the above is irrelevant. You just need to write out an HTML image tag, e.g.
echo '<img src="pic.jpg" />';
That's it.
The code that you have given takes a very long and inconvenient way to load an image for manipulation using the GD library; that's almost certainly not what you wanted to do, but if you did, then you could use imagecreatefromjpeg instead.