Related
I am in the lengthy process of modernizing a lot of code on my website to make it php 8.x compliant. I have never really gotten the hang of user defined functions, so the following code was not created by me.
I am trying to change create_function, which has been removed as of php 8.0, to an anonymous function.
I removed the security lines as they were irrelevant.
Any hints as to how I should proceed?
Code:
print_r($_FILES)
##produces
$_FILES is Array ( [pix] => Array ( [name] => christmas every day.jpg [type] => image/jpeg [tmp_name] => /tmp/phpWPefKh [error] => 0 [size] => 91284 ) )
Here is the outdated code:
Code:
<?php
$end=substr($_FILES['pix']['name'],-3,3);
$end=strtolower($end);
if($end=="jpg"||$end=="peg"||$end=="gif"||$end=="png") {}
else {echo"<script type=\"text/javascript\">
window.location = \"http://www.animeviews.com\"
</script>";
exit;
}
function or_f($a, $b) {
return $a || $b;
}
function file_has_extension($fn, $ext) {
if(is_array($ext))
return array_reduce(array_map(create_function('$a', 'return file_has_extension(\'' . $fn . '\', $a);'), $ext), 'or_f', false);
else
return stripos($fn, '.' . strtolower($ext)) === strlen($fn) - strlen($ext) + 1;
}
$image_extensions = array(
'png',
'jpg',
'jpeg',
'gif'
);
if(!isset($_POST['Upload']) and !isset($_POST['Overwrite']))
{
include("picform.php");
} # endif
else
{
if($_FILES['pix']['tmp_name'] == "none")
{
echo "<b>File did not successfully upload. Check the
file size. File must be less than 500K.<br>";
include("picform.php");
exit();
}
if(file_has_extension($_FILES['pix']['name'], $image_extensions))
{
echo "<b>File is not a picture. Please try another
file.</b><br>";
include("picform.php");
exit();
}
else
{
$destination = $_FILES['pix']['name'];
$destination = strtolower($destination);
$temp_file = $_FILES['pix']['tmp_name'];
if (file_exists($destination) and $_POST['Overwrite']!="Overwrite") {
echo "The file $destination already exists.";exit();
}
#########
move_uploaded_file($temp_file,$destination);
echo "<p><b>The file has successfully uploaded:</b>
{$destination}
({$_FILES['pix']['size']})</p>";
$img="http://www.animeviews.com/images/$destination";
$img = $destination;
$width = "180px";
$height = "";
// Get new dimensions
list($width1, $height1) = getimagesize($img);
if ($width =="") {$j=$height/$height1; $width = $width1 * $j;}
if ($height=="") {$j=$width/$width1; $height = $height1 * $j;}
$new_width = $width;
$new_height = $height;
// Resample
$image_p = imagecreatetruecolor($width, $height);
$image = imagecreatefromjpeg($img);
imagecopyresampled($image_p, $image, 0, 0, 0, 0, $new_width, $new_height, $width1, $height1);
// Output
$img=preg_replace('/h.*\//','',$img);
$img=strtolower($img);
$dest="thumbs/$img";
imagejpeg($image_p,$dest);
}
}
?>
The purpose was to make sure that only images are uploaded, so create_function() or function() are not really needed. In fact, all I really needed was the following code snippet:
Code:
$end=substr($_FILES['pix']['type'], 0, 6);
$end=strtolower($end);
In short, the following code will check to see if the image being uploaded is an image. Not displayed is the code to be sure the user of the script is me. The script will overwrite the image if the same filename already exists and Overwrite was selected. A thumbnail is created and, lastly, a message is displayed saying that the file was successfully uploaded with the size.
Here is the full code:
Code:
<?php
$end=substr($_FILES['pix']['type'], 0, 6);
$end=strtolower($end);
if($end=="image/") {}
else {echo"<script type=\"text/javascript\">
window.location = \"http://www.animeviews.com/images/picform.php\"
</script>";
exit;
}
if(!isset($_POST['Upload']) and !isset($_POST['Overwrite']))
{
include("picform.php");
} # endif
else
{
if($_FILES['pix']['tmp_name'] == "none")
{
echo "<b>File did not successfully upload. Check the
file size. File must be less than 500K.<br>";
include("picform.php");
exit();
}
$destination = $_FILES['pix']['name'];
$destination = strtolower($destination);
$temp_file = $_FILES['pix']['tmp_name'];
if (file_exists($destination) and $_POST['Overwrite']!="Overwrite") {
echo "The file $destination already exists.";exit();
}
#########
move_uploaded_file($temp_file,$destination);
echo "<p><b>The file has successfully uploaded:</b>
{$destination}
({$_FILES['pix']['size']})</p>";
$img="http://www.animeviews.com/images/$destination";
$img = $destination;
$width = "180";
##$height = "";
// Get new dimensions
list($width1, $height1) = getimagesize($img);
if (!isset($width)) {$j=$height/$height1; $width = $width1 * $j;}
if (!isset($height)) {$j=$width/$width1; $height = $height1 * $j;}
$new_width = $width;
$new_height = $height;
// Resample
$image_p = imagecreatetruecolor($width, $height);
$image = imagecreatefromjpeg($img);
imagecopyresampled($image_p, $image, 0, 0, 0, 0, $new_width, $new_height, $width1, $height1);
// Output
$img=preg_replace('/h.*\//','',$img);
$img=strtolower($img);
$dest="thumbs/$img";
imagejpeg($image_p,$dest);
}
i'll try to describe the solution:
Legacy code: create_function('$a', 'return file_has_extension(\'' . $fn . '\', $a);')
Perfect code: function ($a) use ($fn) { return file_has_extension ($fn, $a); }
Explanation: in the first case, you can see the removed function named create_function, which creates a new closure (example of simple closue: function ($args) use ($extraArg - here is extra vars. which you need into the closure, 'use' - construction can be ummitted) { return ...$args }. Closure is equals type callable, you can read this documentation and see, that the first argument of previous function (it's array_map) will be the callable type, all you need pass the same type with the same behavior).
In the second case, you can see some strange construction like this use ($fn), it's necessary, because the closure|callable type has the own variable scope (more here).
More, about Closure and him scope here.
Rewritten file_has_extension function:
function file_has_extension($fn, $ext) {
if (is_array($ext)){
return array_reduce(
array_map(
function ($a) use ($fn) {
return file_has_extension($fn, $a);
},
$ext
),
function ($a, $b) {
return $a || $b;
},
false
);
}
return stripos($fn, '.' . strtolower($ext)) === strlen($fn) - strlen($ext) + 1;
}
i wanted to create a thumbnail with specific custom width & height. The function am using only create a thumbnail with a maximum set width/height.
How do i tweak the below function to give me a defined width/height e.g 50x50, 75x75, 100x100.
$original_photo = "photos/photo.extension";
$newcopy = "photos/thumbnails/photo.extension";
$copy_w = 50;
$copy_h = 50;
$extension = explode('.', 'photo.extension');
$extension = end($extension);
function create_thumbnail($original_photo, $newcopy, $copy_w, $copy_h, $extension) {
list($original_w, $original_h) = getimagesize($original_photo);
$scale_ratio = $original_w / $original_h;
if (($copy_w / $copy_h) > $scale_ratio) {
$copy_w = $copy_h * $scale_ratio;
} else {
$copy_h = $copy_w / $scale_ratio;
}
$img = '';
if ($extension == 'gif') {
$img = imagecreatefromgif($original_photo);
} elseif ($extension == 'png') {
$img = imagecreatefrompng($original_photo);
} else {
$img = imagecreatefromjpeg($original_photo);
}
$true_color = imagecreatetruecolor($copy_w, $copy_h);
imagecopyresampled($true_color, $img, 0, 0, 0, 0, $copy_w, $copy_h, $original_w, $original_h);
if (imagejpeg($true_color, $newcopy, 80) == true) {
return true;
} else {
return false;
}
}
Working with images in PHP/GD can be a pain. There are a lot of edge cases, particularly when transparent PNG/GIFs are manipulated.
If possible, I shamelessly recommend a library I wrote to handle things like this: SimpleImage 3.0
Using SimpleImage, you can achieve the desired effect with the following code:
// Load the image from image.jpg
$image = new \claviska\SimpleImage('image.jpg');
// Create a 50x50 thumbnail, convert to PNG, and write to thumbnail.png
$image->thumbnail(50, 50)->toFile('thumbnail.png', 'image/png');
See this page for more details on how the thumbnail method works and available arguments.
I have a function that uploads files up to 8MB but now I also want to compress or at least rescale larger images, so my output image won't be any bigger than 100-200 KB and 1000x1000px resolution. How can I implement compress and rescale (proportional) in my function?
function uploadFile($file, $file_restrictions = '', $user_id, $sub_folder = '') {
global $path_app;
$new_file_name = generateRandomString(20);
if($sub_folder != '') {
if(!file_exists('media/'.$user_id.'/'.$sub_folder.'/')) {
mkdir('media/'.$user_id.'/'.$sub_folder, 0777);
}
$sub_folder = $sub_folder.'/';
}
else {
$sub_folder = '';
}
$uploadDir = 'media/'.$user_id.'/'.$sub_folder;
$uploadDirO = 'media/'.$user_id.'/'.$sub_folder;
$finalDir = $path_app.'/media/'.$user_id.'/'.$sub_folder;
$fileExt = explode(".", basename($file['name']));
$uploadExt = $fileExt[count($fileExt) - 1];
$uploadName = $new_file_name.'_cache.'.$uploadExt;
$uploadDir = $uploadDir.$uploadName;
$restriction_ok = true;
if(!empty($file_restrictions)) {
if(strpos($file_restrictions, $uploadExt) === false) {
$restriction_ok = false;
}
}
if($restriction_ok == false) {
return '';
}
else {
if(move_uploaded_file($file['tmp_name'], $uploadDir)) {
$image_info = getimagesize($uploadDir);
$image_width = $image_info[0];
$image_height = $image_info[1];
if($file['size'] > 8000000) {
unlink($uploadDir);
return '';
}
else {
$finalUploadName = $new_file_name.'.'.$uploadExt;
rename($uploadDirO.$uploadName, $uploadDirO.$finalUploadName);
return $finalDir.$finalUploadName;
}
}
else {
return '';
}
}
}
For the rescaling I use a function like this:
function dimensions($width,$height,$maxWidth,$maxHeight)
// given maximum dimensions this tries to fill that as best as possible
{
// get new sizes
if ($width > $maxWidth) {
$height = Round($maxWidth*$height/$width);
$width = $maxWidth;
}
if ($height > $maxHeight) {
$width = Round($maxHeight*$width/$height);
$height = $maxHeight;
}
// return array with new size
return array('width' => $width,'height' => $height);
}
The compression is done by a PHP function:
// set limits
$maxWidth = 1000;
$maxHeight = 1000;
// read source
$source = imagecreatefromjpeg($originalImageFile);
// get the possible dimensions of destination and extract
$dims = dimensions(imagesx($source),imagesy($source),$maxWidth,$maxHeight);
// prepare destination
$dest = imagecreatetruecolor($dims['width'],$dims['height']);
// copy in high-quality
imagecopyresampled($dest,$source,0,0,0,0,
$width,$height,imagesx($source),imagesy($source));
// save file
imagejpeg($dest,$destinationImageFile,85);
// clear both copies from memory
imagedestroy($source);
imagedestroy($dest);
You will have to supply $originalImageFile and $destinationImageFile. This stuff comes from a class I use, so I edited it quite a lot, but the basic functionality is there. I left out any error checking, so you still need to add that. Note that the 85 in imagejpeg() denotes the amount of compression.
you can use a simple one line solution through imagemagic library the command will like this
$image="path to image";
$res="option to resize"; i.e 25% small , 50% small or anything else
exec("convert ".$image." -resize ".$res." ".$image);
with this you can rotate resize and many other image customization
Take a look on imagecopyresampled(), There is also a example that how to implement it, For compression take a look on imagejpeg() the third parameter helps to set quality of the image, 100 means (best quality, biggest file) and if you skip the last option then default quality is 75 which is good and compress it.
So, I have this class that's half-working.
Somehow I'm not being able to copy a re-sized sample of the uploaded image, only a black "square" with the "correct" dimensions (screw the dimensions, as long as the thumb comes up clear. one step at the time).
I'm sorry for the WOT but it's driving me cray-cray.
Thanks in advance.
<?php
class Upload {
#function from http://stackoverflow.com/a/10666106/587811
public function resize_values($origWidth,$origHeight,$maxWidth = 200,$maxHeight = 200){
#check for longest side, we'll be seeing that to the max value above
if($origHeight > $origWidth){ #if height is more than width
$newWidth = ($maxHeight * $origWidth) / $origHeight;
$retval = array(width => $newWidth, height => $maxHeight);
}
else{
$newHeight= ($maxWidth * $origHeight) / $origWidth;
$retval = array(width => $origWidth, height => $newHeight);
}
return $retval;
}
public function image($picurl, $file, $path="images/uploaded/") {
echo "function chamada!";
if ($picurl) {
$picFileName=rand(1,9999).$_SESSION['id'];
$picExt=substr(strstr($picurl,'.'),1,3);
$picExt=strtolower($picExt);
$allowed = array("jpg","png","gif","bmp");
if (in_array($picExt,$allowed)) {
if (getimagesize($file)) {
$picNewName=str_replace(" ","_",$picFileName.'.'.$picExt);
$picWhereTo=$path.$picNewName;
$copy=move_uploaded_file($file, $picWhereTo);
if ($copy) {
list($width, $height) = getimagesize($picWhereTo);
$size = $this->resize_values($width,$height,250,250);
$thumb = imagecreatetruecolor($size['width'],$size['height']);
imagealphablending($thumb, false);
$source = imagecreatefromjpeg($picWhereTo);
imagecopyresized($thumb,$source,0,0,0,0,$size['width'],$size['height'],$width,$height);
$picNewName=$picFileName.'_thumb.'.$picExt;
imagejpeg($thumb,$path.$picNewName);
$picinfo['where']=$picWhereTo;
$picinfo['name']=$picNewName;
return $picinfo;
}
else return false;
}
else return false;
}
else return false;
}
}
}
?>
I've ran into a similar problem like this. This has to do with png's with transparency.
Give this a shot after you create $thumb using imagecreatetruecolor();
imagealphablending($thumb, false);
I'm not entirely certain this is the solution - but I think its along the right track. Your true color supports alpha blending - and it is blending in the background from the jpeg - and it might be confused by the lack of information.
If this doesn't work, please describe the exact image format you are uploading so we can try it out and see what happens.
Change your
$source = imagecreatefromjpeg($file);
to
$source = imagecreatefromjpeg($picWhereTo);
And this is how you call the function
$objoflclass->image($_FILES['img']['name'],$_FILES['img']['tmp_name'],'');
where $_FILES['img'] is the name of the image upload field and i believe from this u can understand what was the problem
Idea
I have a function that checks to see if a thumbnail exists in cache folder for a particular image. If it does, it returns the path to that thumbnail. If it does not, it goes ahead and generates the thumbnail for the image, saves it in the cache folder and returns the path to it instead.
Problem
Let's say I have 10 images but only 7 of them have their thumbnails in the cache folder. Therefore, the function goes to generation of thumbnails for the rest 3 images. But while it does that, all I see is a blank, white loading page. The idea is to display the thumbnails that are already generated and then generate the ones that do not exist.
Code
$images = array(
"http://i49.tinypic.com/4t9a9w.jpg",
"http://i.imgur.com/p2S1n.jpg",
"http://i49.tinypic.com/l9tow.jpg",
"http://i45.tinypic.com/10di4q1.jpg",
"http://i.imgur.com/PnefW.jpg",
"http://i.imgur.com/EqakI.jpg",
"http://i46.tinypic.com/102tl09.jpg",
"http://i47.tinypic.com/2rnx6ic.jpg",
"http://i50.tinypic.com/2ykc2gn.jpg",
"http://i50.tinypic.com/2eewr3p.jpg"
);
function get_name($source) {
$name = explode("/", $source);
$name = end($name);
return $name;
}
function get_thumbnail($image) {
$image_name = get_name($image);
if(file_exists("cache/{$image_name}")) {
return "cache/{$image_name}";
} else {
list($width, $height) = getimagesize($image);
$thumb = imagecreatefromjpeg($image);
if($width > $height) {
$y = 0;
$x = ($width - $height) / 2;
$smallest_side = $height;
} else {
$x = 0;
$y = ($height - $width) / 2;
$smallest_side = $width;
}
$thumb_size = 200;
$thumb_image = imagecreatetruecolor($thumb_size, $thumb_size);
imagecopyresampled($thumb_image, $thumb, 0, 0, $x, $y, $thumb_size, $thumb_size, $smallest_side, $smallest_side);
imagejpeg($thumb_image, "cache/{$image_name}");
return "cache/{$image_name}";
}
}
foreach($images as $image) {
echo "<img src='" . get_thumbnail($image) . "' />";
}
To elaborate on #DCoder's comment, what you could do is;
If the thumb exists in the cache, return the URL just as you do now. This will make sure that thumbs that are in the cache will load quickly.
If the thumb does not exist in the cache, return an URL similar to /cache/generatethumb.php?http://i49.tinypic.com/4t9a9w.jpg where the script generatethumb.php generates the thumbnail, saves it in the cache and returns the thumbnail. Next time, it will be in the cache and the URL won't go through the PHP script.