PHP remove exif data from images - php

Is deleting the EXIF data from images using PHP enough to prevent malicious codes from being executed in a server?
I want to protect the server against the practices described in this blog post:
<?php
$img = imagecreatefromjpeg('malicious_codes.jpg');
$w = imagesx($img);
$h = imagesy($img);
$trans = imagecolortransparent($img);
if($trans >= 0) {
$rgb = imagecolorsforindex($img, $trans);
$oldimg = $img;
$img = imagecreatetruecolor($w,$h);
$color = imagecolorallocate($img,$rgb['red'],$rgb['green'],$rgb['blue']);
imagefilledrectangle($img,0,0,$w,$h,$color);
imagecopy($img,$oldimg,0,0,0,0,$w,$h);
}
imagejpeg($img,'safe_image.jpg');
?>

This will show you EXIF information from JPEG file in PHP.
$uploadfile = "uploaded/pic.jpg";
$exif = exif_read_data($uploadfile, 0, true);
echo "<b>Your file</b><br />\n";
foreach ($exif as $key => $section) {
foreach ($section as $name => $val) {
echo "$key.$name: $val<br />\n";
}
}
And this piece of code should delete all EXIF information
$img = new Imagick($uploadfile);
$img->stripImage();
$img->writeImage($uploadfile);
You can try it here:
https://iconnaut.com/exif.php

I think that if you manipulate the image of any way (resize for example), it lose some exif data.
At least in an example in java happened this.
HERE also has an example using ExifTool.
EDIT:
see this post: Remove EXIF data from JPG using PHP

Related

Google Cloud Vision save imagen after detect objects

I am trying to save a image in my database after detect objects with Google cloud vision. I am using php, framework laravel, this is my code,
function detect_object($imagen){
$path = $imagen->getRealPath();
$imageAnnotator = new ImageAnnotatorClient(['credentials' => base_path('credentials.json')]);
$output = imagecreatefromjpeg($path);
list($width, $height, $type, $attr) = getimagesize($path);
# annotate the image
$image = file_get_contents($path);
$response = $imageAnnotator->objectLocalization($image);
$objects = $response->getLocalizedObjectAnnotations();
foreach ($objects as $object) {
$name = $object->getName();
$score = $object->getScore();
$vertices = $object->getBoundingPoly()->getNormalizedVertices();
// printf('%s (confidence %f)):' . PHP_EOL, $name, $score);
// print('normalized bounding polygon vertices: ');
// foreach ($vertices as $vertex) {
// printf(' (%f, %f)', $vertex->getX(), $vertex->getY());
// }
// print(PHP_EOL);
$vertices_finales = [];
foreach ($vertices as $vertex) {
array_push($vertices_finales, ($vertex->getX() * $width));
array_push($vertices_finales, ($vertex->getY() * $height));
}
imagepolygon($output, $vertices_finales, (sizeof($vertices_finales) / 2), 0x00ff00);
imagestring($output, 5, ($vertices_finales[0] + 10), ($vertices_finales[1] + 10), $name, 0x00ff00);
}
header('Content-Type: image/jpeg');
imagejpeg($output);
imagedestroy($output);
$imageAnnotator->close();
}
Could you help me?
Thanks
I'm going to assume that you want to grab the raw binary generated by imagejpeg() after processing?
The only way i know how to do that is using output buffers.
instead of:
<?php
header('Content-Type: image/jpeg');
imagejpeg($output);
imagedestroy($output);
$imageAnnotator->close();
Do:
<?php
ob_start();
imagejpeg($output);
$imgData = ob_get_clean();
# Do what you want with imgData, like insert into a binary field in a db, write to disk, etc
imagedestroy($output);
$imageAnnotator->close();
If you also want to output the image to the browser, return $imgData from your detect_object() function and echo it to the browser
<?php
$imgData = detect_object($imagen);
header('Content-Type: image/jpeg');
echo $imgData

Making domdocument img search more lightweight

This grabs all images from a page, and is supposed to check if image has more width and height than 200. if so, grab the first of it. But its an expensive process, and im wondering if there are more lightweight approaches to this than using getimagesize. Does anyone know of a different approach without the use of external services like YQL etc?
if($ogimage!=''|| !empty($ogimage)){
$arrimg = $ogimage;
} else {
$imgarr = array();
foreach ($doc->getElementsByTagName('img') as $img) {
$arrimg_push = $img->getAttribute('src');
array_push($imgarr, $arrimg_push);
}
$i=0;
foreach($imgarr as $img){
list($width, $height, $type, $attr) = getimagesize($img);
if($width > 200 && $height > 200){
if($i > 0){
$arrimg = $img;
$i++;
}
}
}
}
ImageMagick's pingImage or pingImageFile will read as little of the image file as possible to get the basic attributes, which can then be accessed using getImageWidth and getImageHeight.

PHP - Get information about image (Height and Width) without loading it

Is it possible to get image information without loading the actual image with PHP? In my case I want the Height and Width.
I have this code to fetch images from a directory. I echo out the image's url and fetch it with JS.
<?php
$directory = "./images/photos/";
$sub_dirs = glob($directory . "*");
$i = 0;
$len = count($sub_dirs);
foreach($sub_dirs as $sub_dir)
{
$images = glob($sub_dir . '/*.jpg');
$j = 0;
$len_b = count($images);
foreach ($images as $image)
{
if ($j == $len_b - 1) {
echo $image;
} else {
echo $image . "|";
}
$j++;
}
if ($i == $len - 1) {
} else {
echo "|";
}
$i++;
}
?>
getImageSize() is the proper way to get this information in PHP
It does a minimal amount of work based on the type of image. For example, a GIF image's height/width are stored in a header. Very easy to access and read. So this is how the function most likely gets that information from the file. For a JPEG, it has to do a little more work, using the SOFn markers.
The fastest way to access this information would be to maintain a database of file dimensions every time a new one is uploaded.
Given your current situation. I recommend writing a PHP script that takes all of your current image files, gets the size with this function, and then inserts the info into a database for future use.
It depends what you mean by "without loading it".
The built-in getimagesize() does this.
list($w, $h) = getimagesize($filename);
You can programmatically get the image and check the dimensions using Javascript...
var img = new Image();
img.onload = function() {
alert(this.width + 'x' + this.height);
}
img.src = 'http://www.google.com/intl/en_ALL/images/logo.gif';
This can be useful if the image is not a part of the markup ;)
You can store the width'n'height information in a text file, and load it later on.
list($width, $height, $type, $attr) = getimagesize($_FILES["Artwork"]['tmp_name']);
Use this.

Remove EXIF data from JPG using PHP

Is there any way to remove the EXIF data from a JPG using PHP? I have heard of PEL, but I'm hoping there's a simpler way. I am uploading images that will be displayed online and would like the EXIF data removed.
Thanks!
EDIT: I don't/can't install ImageMagick.
Use gd to recreate the graphical part of the image in a new one, that you save with another name.
See PHP gd
edit 2017
Use the new Imagick feature.
Open Image:
<?php
$incoming_file = '/Users/John/Desktop/file_loco.jpg';
$img = new Imagick(realpath($incoming_file));
Be sure to keep any ICC profile in the image
$profiles = $img->getImageProfiles("icc", true);
then strip image, and put the profile back if any
$img->stripImage();
if(!empty($profiles)) {
$img->profileImage("icc", $profiles['icc']);
}
Comes from this PHP page, see comment from Max Eremin down the page.
A fast way to do it in PHP using ImageMagick (Assuming you have it installed and enabled).
<?php
$images = glob('*.jpg');
foreach($images as $image)
{
try
{
$img = new Imagick($image);
$img->stripImage();
$img->writeImage($image);
$img->clear();
$img->destroy();
echo "Removed EXIF data from $image. \n";
} catch(Exception $e) {
echo 'Exception caught: ', $e->getMessage(), "\n";
}
}
?>
I was looking for a solution to this as well. In the end I used PHP to rewrite the JPEG with ALL Exif data removed. I didn't need any of it for my purposes.
This option has several advantages...
The file is smaller because the EXIF data is gone.
There is no loss of image quality (because the image data is unchanged).
Also a note on using imagecreatefromjpeg: I tried this and my files got bigger. If you set quality to 100, your file will be LARGER, because the image has been resampled, and then stored in a lossless way. And if you don't use quality 100, you lose image quality. The ONLY way to avoid resampling is to not use imagecreatefromjpeg.
Here is my function...
/**
* Remove EXIF from a JPEG file.
* #param string $old Path to original jpeg file (input).
* #param string $new Path to new jpeg file (output).
*/
function removeExif($old, $new)
{
// Open the input file for binary reading
$f1 = fopen($old, 'rb');
// Open the output file for binary writing
$f2 = fopen($new, 'wb');
// Find EXIF marker
while (($s = fread($f1, 2))) {
$word = unpack('ni', $s)['i'];
if ($word == 0xFFE1) {
// Read length (includes the word used for the length)
$s = fread($f1, 2);
$len = unpack('ni', $s)['i'];
// Skip the EXIF info
fread($f1, $len - 2);
break;
} else {
fwrite($f2, $s, 2);
}
}
// Write the rest of the file
while (($s = fread($f1, 4096))) {
fwrite($f2, $s, strlen($s));
}
fclose($f1);
fclose($f2);
}
The code is pretty simple. It opens the input file for reading and the output file for writing, and then starts reading the input file. It data from one to the other. Once it reaches the EXIF marker, it reads the length of the EXIF record and skips over that number of bytes. It then continues by reading and writing the remaining data.
The following will remove all EXIF data of a jpeg file. This will make a copy of original file without EXIF and remove the old file. Use 100 quality not to loose any quality details of picture.
$path = "/image.jpg";
$img = imagecreatefromjpeg ($path);
imagejpeg ($img, $path, 100);
imagedestroy ($img);
(simple approximation to the graph can be found here)
function remove_exif($in, $out)
{
$buffer_len = 4096;
$fd_in = fopen($in, 'rb');
$fd_out = fopen($out, 'wb');
while (($buffer = fread($fd_in, $buffer_len)))
{
// \xFF\xE1\xHH\xLLExif\x00\x00 - Exif
// \xFF\xE1\xHH\xLLhttp:// - XMP
// \xFF\xE2\xHH\xLLICC_PROFILE - ICC
// \xFF\xED\xHH\xLLPhotoshop - PH
while (preg_match('/\xFF[\xE1\xE2\xED\xEE](.)(.)(exif|photoshop|http:|icc_profile|adobe)/si', $buffer, $match, PREG_OFFSET_CAPTURE))
{
echo "found: '{$match[3][0]}' marker\n";
$len = ord($match[1][0]) * 256 + ord($match[2][0]);
echo "length: {$len} bytes\n";
echo "write: {$match[0][1]} bytes to output file\n";
fwrite($fd_out, substr($buffer, 0, $match[0][1]));
$filepos = $match[0][1] + 2 + $len - strlen($buffer);
fseek($fd_in, $filepos, SEEK_CUR);
echo "seek to: ".ftell($fd_in)."\n";
$buffer = fread($fd_in, $buffer_len);
}
echo "write: ".strlen($buffer)." bytes to output file\n";
fwrite($fd_out, $buffer, strlen($buffer));
}
fclose($fd_out);
fclose($fd_in);
}
It is a prototype for a call from a command line.
this is the simplest way:
$images = glob($location.'/*.jpg');
foreach($images as $image) {
$img = imagecreatefromjpeg($image);
imagejpeg($img,$image,100);
}
I completely misunderstood your question.
You could use some command line tool to do this job. or write your own php extension to do it. have a look at this lib that would be useful: http://www.sno.phy.queensu.ca/~phil/exiftool/
Cheers,
vfn
I'm not pretty sure about it, but if its possible using GD o ImageMagick, the first thing that come to my mind is to create a new Image and add the old image to the new one.

Downscale/resize?

How do I resize/downscale the images that gets uploaded with my upload script down to 350x100 if they are over 350x100?
My script:
$allowed_filetypes = array('.png','.PNG');
$filename = $_FILES['strUpload']['name'];
$ext = substr($filename, strpos($filename,'.'), strlen($filename)-1);
if(in_array($ext,$allowed_filetypes))
{
list($width, $height, $type, $attr) = getimagesize($_FILES['strUpload']['tmp_name']);
if ($width > 350 || $height > 100)
{
echo "That file dimensions are not allowed. Only 350x100 is allowed";
exit();
}
if ($_FILES['strUpload']['size'] > 2097152 )
{
echo "ERROR: Large File Size. Only less than 2mb accepted";
exit();
}
$imagename = uniqid('ff') . ".png";
move_uploaded_file ( $_FILES['strUpload']['tmp_name'], $imagename );
print ( "<script type=\"text/javascript\">" );
if(file_exists($imagename) && $_FILES['strUpload']['name'] != '')
{
print ( "self.opener.SetImageFile(\"" . $imagename . "\");" );
echo "\n";
print ( "self.opener.setInputFile(\"" . $imagename . "\");" );
}
echo "\n";
print ( "window.close();" );
echo "\n";
print ( "</script>" );
$open = new dbconnect();
$open->callDB("localhost","pema2201_william","lindberg","pema2201_siggen");
$ip = $_SERVER['REMOTE_ADDR'];
$dattum = date('Y-m-d H:i:s', time());
mysql_query("INSERT INTO piclist (ip,pic,datum) VALUES('$ip','$imagename','$dattum')") or die(mysql_error());
}
else
{
echo "WRONG FILE TYPE ONLY PNG ALLOWED"
}
PHP has several image handling libraries. The GD library has shipped since PHP 4.3 so I suggest using that. Just read the docs to find what you need.
Use imagecopyresized - there's a good example of how to use it on the PHP manual page.
Have a look at this question someone else asked a few days ago.
That not only explains how it's done, but also how it's done in an efficient way. (ImageMagick should be used over the GD library)
Hope that helps.
The general gist is to create a new "canvas" of the desired dimensions for the image to go in.
Take your uploaded image and copy it onto the new canvas giving setting a source width x height (take all of the source image) and destination width x height (use all of the destination canvas), offsets are available to shift the image around a bit if you need to.
Then finally save it where you need it to go, or insert it into a database field, (this will replace your move_uploaded_file call).

Categories