PHP - Simple script for image compression with pngquant - php

:) i found this 1 line of code in another post which successfully compresses the image using pngquant. the thing is, it outputs the optimised image with a different name (obviously to preserve the original).
im trying to find a way to:
a) add a minimum quality parameter of 60
b) use an if/else statement to to allow the user to choose to overwrite the existing file or output a new optimised image (of a user specified name)
thank you! ntlri - not to long read it
<?php system('pngquant --quality=85 image.png'); ?>
so what i have tried is the following.. for some reason the single quotes need to be double quotes to parse the variables correctly..
<?php
$min_quality = 60; $max_quality = 85;
$keep_original = 'dont_keep';
if ($keep_original == 'keep') {
$image_name = 'image.png';
$path_to_image = 'images/' . $image_name;
$new_file = 'image2.png';
$path_to_new_image = 'images/' . $new_file;
// don't know how to output to specified $new_file name
system("pngquant --quality=$min_quality-$max_quality $path_to_image");
} else {
$image_name = 'image.png';
$path_to_image = 'images/' . $image_name;
// don't know if you can overwrite file by same name as additional parameter
system("pngquant --quality=$min_quality-$max_quality $path_to_image");
// dont't know how you get the name of the new optimised image
$optimised_image = 'images/' . $whatever_the_optimised_image_is_called;
rename($optimised_image, $image_name);
unlink($optimised_image);
}
?>

from the docs of this program :
The output filename is the same as the input name except that\n\ it
ends in \"-fs8.png\", \"-or8.png\" or your custom extension
so , for this question:
// don't know how to output to specified $new_file name
system("pngquant --quality=$min_quality-$max_quality $path_to_image");
to choose a new name, assume you are compress image name.png :
--ext=_x.png
this will create new image called name_x.png
so , your $new_file would be just a suffix ,
$new_file = '_x.png'; // to choose new file name name_x.png
// don't know if you can overwrite file by same name as additional
parameter
as mentioned in the program docs , the new file name will be suffixed by either -fs8.png or -or8.png , so you may rename the file which will produced with this suffix , OR simply set the --ext option to : .png and this will append to the original file
--ext=.png
for more details, check the repository

i spoke to pornel whos the chappie that developed pngquant. its actually a lot simpler than all that i wrote that before...
! important - it is very important to use escapeshellarg() else people can take over your server by uploading a file with a special filename apparently.
$image_name = 'image.png';
$target_file = 'images/' . $image_name;
$existing_image = 'image.png'; // image already on server if applicable
$keep = 'keep';
$target_escaped = escapeshellarg($target_file);
if ($keep == 'keep') {
// process/change output file to image_compressed.png keeping both images
system("pngquant --force --quality=70 $target_escaped --ext=_compressed.png");
$remove_ext = substr($newFileName, 0 , (strrpos($newFileName, ".")));
// $new_image is just the name (image_compressed.png) if you need it
$new_image = $remove_ext . '_compressed.png';
// remove old file if different name
if ($existing_image != $newFileName) {
$removeOld = '../images/' . $existing_image;
unlink($removeOld);
} // comment out if you want to keep existing file
} else {
// overwrite if file has the same name
system("pngquant --force --quality=70 $target_escaped --ext=.png");
// remove old file if different name
if ($existing_image != $newFileName) {
$removeOld = '../images/' . $existing_image;
unlink($removeOld);
}
$new_image = $newFileName;
}

to override same name use this command
pngquant.exe --ext=.png --force input.png
so the output name will remain input.png

Related

PHP - Renaming a file to disallow duplicates

So I am using this script to upload a file to a directory and show it live.
<?php
function UploadImage($settings = false)
{
// Input allows you to change where your file is coming from so you can port this code easily
$inputname = (isset($settings['input']) && !empty($settings['input']))? $settings['input'] : "fileToUpload";
// Sets your document root for easy uploading reference
$root_dir = (isset($settings['root']) && !empty($settings['root']))? $settings['root'] : $_SERVER['DOCUMENT_ROOT'];
// Allows you to set a folder where your file will be dropped, good for porting elsewhere
$target_dir = (isset($settings['dir']) && !empty($settings['dir']))? $settings['dir'] : "/uploads/";
// Check the file is not empty (if you want to change the name of the file are uploading)
if(isset($settings['filename']) && !empty($settings['filename']))
$filename = $settings['filename'] . "sss";
// Use the default upload name
else
$filename = preg_replace('/[^a-zA-Z0-9\.\_\-]/',"",$_FILES[$inputname]["name"]);
// If empty name, just return false and end the process
if(empty($filename))
return false;
// Check if the upload spot is a real folder
if(!is_dir($root_dir.$target_dir))
// If not, create the folder recursively
mkdir($root_dir.$target_dir,0755,true);
// Create a root-based upload path
$target_file = $root_dir.$target_dir.$filename;
// If the file is uploaded successfully...
if(move_uploaded_file($_FILES[$inputname]["tmp_name"],$target_file)) {
// Save out all the stats of the upload
$stats['filename'] = $filename;
$stats['fullpath'] = $target_file;
$stats['localpath'] = $target_dir.$filename;
$stats['filesize'] = filesize($target_file);
// Return the stats
return $stats;
}
// Return false
return false;
}
?>
<?php
// Make sure the above function is included...
// Check file is uploaded
if(isset($_FILES["fileToUpload"]["name"]) && !empty($_FILES["fileToUpload"]["name"])) {
// Process and return results
$file = UploadImage();
// If success, show image
if($file != false) { ?>
<img src="<?php echo $file['localpath']; ?>" />
<?php
}
}
?>
The thing I am worried about is that if a person uploads a file with the same name as another person, it will overwrite it. How would I go along scraping the filename from the url and just adding a random string in place of the file name.
Explanation: When someone uploads a picture, it currently shows up as
www.example.com/%filename%.png.
I would like it to show up as
www.example.com/randomstring.png
to make it almost impossible for images to overwrite each other.
Thank you for the help,
A php noob
As contributed in the comments, I added a timestamp to the end of the filename like so:
if(isset($settings['filename']) && !empty($settings['filename']))
$filename = $settings['filename'] . "sss";
// Use the default upload name
else
$filename = preg_replace('/[^a-zA-Z0-9\.\_\-]/',"",$_FILES[$inputname]["name"]) . date('YmdHis');
Thank you for the help

Get extension of a image and append it to filename and send headers accordingly

I have a file picviwer.php that loads a pic as following:
<img src="http://www.example.com/loadimage?uid=$id&view=pic" id="ppic" />
It sends a GET request to a another file loadimage.php with the id of the photo to be loaded.
Below is the code for loadimage.php
if(isset($_GET['uid'])){
$uid = $_GET['uid'];
$remoteImage = "http://www.example.com/user-pics/".$uid.".png";
$img = file_get_contents($remoteImage);
header('Content-Type: image/x-png'); //or whatever
readfile($remoteImage);
}
Right now the above code deals only for png image and I wish to extend for images of all types(.jpg,.gif etc.). For this I want to get the extension of the image and then send headers accordingly. Also append the correct extension with the filename(uid).How can I do that?
i hope it will help you . it would be little long but surly will work and can add more extension in else if condtion .
if(file_exists("http://www.example.com/user-pics/".$uid.".png")) {
$remoteImage = "http://www.example.com/user-pics/".$uid.".png";
}elseif( file_exists("http://www.example.com/user-pics/".$uid.".jpg") ){
$remoteImage = "http://www.example.com/user-pics/".$uid.".jpg";
}
and so on
I would recommend not accessing the files via the full domain name but by the path they are on your server. This would eliminate the server load it takes to form a internal HTTP request to check the file existence and read the content.
You could find the exiting extensions as follows:
if(isset($_GET['uid'])){
$uid = $_GET['uid'];
$imagesPath = '/path/to/images/'; //REPLACE with the correct server path
$existingImage = '';
foreach (glob($imagesPath . $uid . ".*") as $filename) {
// this matches all files with name $uid and an existing extension. If you have preferred extensions handle them here.
$existingImage = $filename;
break; // We only need one if we have no extension preference
}
if ('' === $existingImage) {
// No images are found that have the required filename. Handle this exception here
}
$finfo = finfo_open(FILEINFO_MIME_TYPE); // return mime type ala mimetype
$imgMimeType = finfo_file($finfo, $existingImage);
finfo_close($finfo);
header('Content-Type: ' . $imgMimeType);
readfile($existingImage );
}
You can grab the extension for a file using:
$extension = pathinfo($imagePath, PATHINFO_EXTENSION);
To get the correct mime-type for the header use exif_imagetype() to get the imagetype which can be converted to the correct mime-type.
(provided you will only use images).
$imageType = exif_imagetype($imagePath);
$headerString = 'Content-Type:'. image_type_to_mime_type ($imageType);
header($headerString);

PHP Delete file

I am trying to develop a user page for a forum and I'm kinda struggling with the image upload.
The problem is that I would like to limit the user to only be able to upload one single image, but be able to change it anytime. so basically, I would like to either overwrite the existing file either delete the old picture and add a new one instead.
At this point I have a piece of code that adds a timestamp at the end of the file (which I don't really need actually).
CODE:
if(isset($_POST['upload']))
{
$extension=strstr($_FILES['uploadedfile']['name'], ".");
$filename = "_/userfiles/userpics/".basename($_FILES['uploadedfile']['name'],
$extension);
$target = "_/userfiles/userpics/".basename($_FILES['uploadedfile']['name']);
$valid = true;
if(file_exists($target))
{
$filename = $filename . time();
$target = $filename . $extension;
}
if($valid)
{
// move the file into the folder of our choise
move_uploaded_file($_FILES['uploadedfile']['tmp_name'], $target);
$img_sql = "INSERT INTO sp_userimage (imageid, path, id) value ('', '".$target."', '".$_SESSION['userid']."')";
$img_result = mysql_query($img_sql);
echo "upload sucessfull";
}
Make use of unlink() in PHP Manual.
if(file_exists($target))
{
unlink($target); // deletes file
//$filename = $filename . time();
//$target = $filename . $extension;
}
I think this might be a bit better suited for you. You might have to edit it a tad.
if($valid)
{
// Check if user has a file.
$img_check = mysql_query("SELECT * FROM sp_userimage WHERE id = " . (int) $_SESION['user_id']);
if( mysql_num_rows($img_check) > 0 ){
$row = mysql_fetch_object($img_check);
// Delete the file.
unlink($row->path);
}
// move the file into the folder of our choise
move_uploaded_file($_FILES['uploadedfile']['tmp_name'], $target);
$img_sql = "INSERT INTO sp_userimage (imageid, path, id) value ('', '".$target."', '".$_SESSION['userid']."')";
$img_result = mysql_query($img_sql);
echo "upload sucessfull";
}
It might be easier to normalize the image type (e.g. only jpegs) and then name the file as the userid. For example:
$target = 'userpics' . DIRECTORY_SEPARATOR . $_SESSION['userid'];
move_uploaded_file($_FILES['uploadedfile']['tmp_name'], $target);
This will simply overwrite the old picture with the new one. Given that this type of filename is deterministic, you also don't need to store the filename in the database.
Use unlink() function
read more here PHP unlink
okay ,if u want to delete the file for that particular user only.
then store the filename vs user in some MapTable in db.
mysql_query("CREATE TABLE t_usr_file_map(
usr_id INT NOT NULL ,
file_name VARCHAR(100),
)")
or die(mysql_error());
and at the time of reupload , fetch the filename from the table for that user , unlink it and reupload the fresh one again.
OR,
or u can use PHP file_rename function at the time of upload. rename filename to the userid
rename ( string $oldname , string $newname [, resource $context ] )
and u can always do unlink based on user-id
Its very simple by unlink()
as:
unlink(dirname(__FILE__) . "/../../public_files/" . $filename);
if (file_exists($path))
{
$filename= rand(1,99).$filename;
unlink($oldfile);
}
move_uploaded_file($_FILES['file']['tmp_name'],$filename);

How to copy a file without overwriting the destination file?

The script I made is.
<?php
$source_file = 'http://www.domain.tld/directory/img.png';
$dest_file = '/home/user/public_html/directory/directory/img.png';
copy($source_file, $dest_file);
?>
I need that image to not be delete and reuploaded every time the script is running. I would either want it to be img1.png, img2.png, img3.png, etc. Or img(Date,Time).png, img(Date,Time).png, etc. Is this possible and if so, how do I do this?
If you're concerned with overwriting a file, you could just drop in a timestamp to ensure uniqueness:
$dest_file = '/home/user/public_html/directory/directory/img.png';
// /home/user/public_html/directory/directory/img1354386279.png
$dest_file = preg_replace("/\.[^\.]{3,4}$/i", time() . "$0", $dest_file);
Of if you wanted simpler numbers, you could take a slightly more tasking route and change the destination file name as long as a file with that name already exists:
$file = "http://i.imgur.com/Z92wU.png";
$dest = "nine-guy.png";
while (file_exists($dest)) {
$dest = preg_replace_callback("/(\d+)?(\.[^\.]+)$/", function ($m) {
return ($m[1] + 1) . $m[2];
}, $dest);
}
copy($file, $dest);
You may need to be using a later version of PHP for the anonymous function callback; I tested with 5.3.10 and everything worked just fine.
<?php
$source_file = 'http://www.domain.tld/directory/img.png';
$dest_file = '/home/user/public_html/directory/directory/img.png';
if(!is_file($dest_file)){
copy($source_file, $dest_file);
}
else{
$fname = end(explode('/',$dest_file));
$fname = time().'-'.$fname;
$dest_file = dirname($dest_file).'/'.$fname;
copy($source_file,$dest_file);
}
?>
use this code
This will add time before filename
$source_file = 'http://www.domain.tld/directory/img.png';
$dest_file = '/home/user/public_html/directory/directory/img'.uniqid().'.png';
copy($source_file, $dest_file);
uniquid gives you a unique Id which is rarely possible to overwrite...
also i would make folders for each month or related to the id of the image
like
mkdir(ceil($imgId / 1000), 0777);
You can use rename().
For Example:
rename ("/var/www/files/file.txt", "/var/www/sites/file1.txt");
Or
You can also use copy
$source_file = 'http://www.domain.tld/directory/img.png';
$dest_file = '/home/user/public_html/directory/directory/img.png';
if(!is_file($dest_file)){
copy($source_file, $dest_file);
}
Or if you want to add time it ,you can try like this.
$source="http://www.domain.tld/directory/";
$destn ="/home/user/public_html/directory/directory/";
$filename="image.png";
$ex_name = explode('.',$filename));
$newname = $ex_name[0].'-'.time().$ex_name[1]; //where $ex_name[0] is filename and $ex_name[1] is extension.
copy($source.filename,$destn.$newname );

PHP dynamic zip file creation crashes with non-image filetypes. (wp)

I have a function that takes uploaded files (WORDPRESS) and adds them to a (newly created) zip file.
every new file is added to the zip (if is not yet created - the first file will create one ) and also to a comment with the list of the files.
function Ob99_generate_zip_file($meta) {
// we always need post_id , right ?
if( isset($_GET['post_id']) ) {
$post_id = $_GET['post_id'];
} elseif( isset($_POST['post_id']) ) {
$post_id = $_POST['post_id'];
}
//setting some more variables.
$file = wp_upload_dir();// take array
$file2 = wp_upload_dir();//debug
$zipname = $file['path'].'file.zip'; // set zip file name
$file = trailingslashit($file['basedir']).$meta['file'];// construct real path
// Without this next condition the function dies. WHY ??
list($orig_w, $orig_h, $orig_type) = #getimagesize($file); // not help to comment
if (!$orig_type == IMAGETYPE_GIF || !$orig_type == IMAGETYPE_PNG|| !$orig_type == IMAGETYPE_JPEG) {
//why other filetypes not working ??
return ;
}
$zip = new ZipArchive; // initiatte class
$zip->open($zipname , ZipArchive::CREATE); // open buffer
$new_filename = substr($file,strrpos($file,'/') + 1); //we do not need nested folders
$zip->addFile($file,$sitename.'/'.$new_filename); // we add the file to the zip
if (file_exists($zipname)){
$comment = $zip->getArchiveComment(); // if the file already exist read the comment
}
else { // if not - let´s give it a cool retro header
$comment_head = '*********************************'. PHP_EOL ;
$comment_head .= '****** <<< FILE CONTENT >>> *****'. PHP_EOL ;
$comment_head .= '*********************************'. PHP_EOL ;
}
$comment = $comment_head . $comment ;// add header before comment
$comment = $comment . PHP_EOL . PHP_EOL . $meta['file'] ; // add new file name
$zip->setArchiveComment($comment); // and comment
$zip->addFromString('filelist.txt', $comment); // create txt file with the same list
$zip->close()or die('can not create zip file'.$file.print_r($meta).'---- DEBUG SEPERATOR ---- '.print_r($file2)); // FINISHED or DIE with debug
}
My problem : if I try to upload any file other than an image - the function will DIE .
I have added a condition for checking imagetype - but I would like to know why it is crashing and how to make it work without said condition ...
Does the zip function have any problems with PDF , doc or anyother ? is that a wordpress problem ?
The problem section seems to be where you're asking PDFs, etc. their image size. Why don't you try:
$image_size = getimagesize($file);
if($image_size===false)
{
// This is not an image
// Do what you want to PDFs, etc.
}
else
{
// This is an image
// Find out image type, dimensions, etc.
}

Categories