How to copy a file without overwriting the destination file? - php

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 );

Related

Unable to Rename the latest file in a folder with PHP

I want to rename the latest added file from a folder, but somehow my code isn't working. Could please help!
For example, if the latest file is "file_0202.json"
And I want to Change it to "file.json"
Here is my Code
<?php
$files = scandir('content/myfiles', SCANDIR_SORT_DESCENDING);
$selected_file = $files[0];
$new_filename = preg_replace('/_[^_.]*\./', '.', $selected_file);
if(rename($selected_file, $new_filename, ))
{
echo 'renamed';
}
else {
echo 'can not rename';
}
?>
It's better if you use glob(). glob() returns the path and filename used.
Then you have to sort by the file that was last changed. You can use usort and filemtime for that.
$files = glob('content/myfiles/*.*');
usort($files,function($a,$b){return filemtime($b) <=> filemtime($a);});
$selected_file = $files[0];
$new_filename = preg_replace('/_[^_.]*\./', '.', $selected_file);
if(rename($selected_file, $new_filename))
{
echo 'renamed';
}
else {
echo 'can not rename';
}
Instead of *.* you can restrict the searched files if necessary. As an example *.json . Be careful with your regular expression so that it doesn't change a path.

file_exists() not working in php5 inside while loop

file_exists isn't working. I've looked at a few examples and still no go. Program does not detect the file. The path of my file is /var/www/osbs/PHPAPI/recording.mp3 and the website root is inside osbs. The location of this file is inside PHPAPI that is why I do not put full path in file_put_contents. The program is able to make the original recording.mp3 but not any appended versions of it.
<?php
$actual_name = pathinfo("PHPAPI/recording.mp3",PATHINFO_FILENAME);
$original_name = $actual_name;
$extension = pathinfo("PHPAPI/recording.mp3",PATHINFO_EXTENSION);
if ($_GET["RecordingUrl"]) {
if (file_exists("/var/www/osbs/PHPAPI/".$actual_name.".".$extension)) {
$actual_name = find_new_name($original_name, $extension);
}
else {
$actual_name = $original_name;
}
$name = $actual_name.".".$extension;
file_put_contents($name, file_get_contents($_GET["RecordingUrl"]));
}
function find_new_name ( $file, $extension ) {
$name = $file.".".$extension;
$i = 0;
while(file_exists("/var/www/osbs/PHPAPI/".$name)){
$new_name = $file.$i;
$name = $new_name.".".$extension;
$i++;
}
return $new_name;
}
?>
Your issue is with the file_put_contents. You need to specify a full path, and you only specify a file name. Try echoing $name just before using it, you'll see it's not a path, just a filename.
I would recommend you to set a constant at the begining of the file with the path instead of sometimes relying on relative paths and sometimes relying on absolute paths.
<?php
const SAVE_PATH = "/var/www/osbs/";
$actual_name = pathinfo(SAVE_PATH."PHPAPI/recording.mp3",PATHINFO_FILENAME);
$original_name = $actual_name;
$extension = pathinfo(SAVE_PATH."PHPAPI/recording.mp3",PATHINFO_EXTENSION);
if (isset($_GET["RecordingUrl"]) && $_GET["RecordingUrl"]) {
if (file_exists(SAVE_PATH."PHPAPI/".$actual_name.".".$extension)) {
$actual_name = find_new_name($original_name, $extension);
}
else {
$actual_name = $original_name;
}
$name = $actual_name.".".$extension;
file_put_contents(SAVE_PATH.'PHPAPI/'.$name, file_get_contents($_GET["RecordingUrl"]));
}
function find_new_name ( $file, $extension ) {
$name = $file.".".$extension;
$i = 0;
while(file_exists(SAVE_PATH."PHPAPI/".$name)){
$new_name = $file.$i;
$name = $new_name.".".$extension;
$i++;
}
return $new_name;
}
?>
What I changed:
Defined a const SAVE_PATH = "/var/www/osbs/";
Use the new constant everywhere. No more relative sometimes and absolute sometimes, it's all absolute.
Used the constant in file_put_contents (THIS IS THE ACTUAL FIX, YOU NEED A FULL PATH HERE)
Added an additional check to make sure RecordingUrl isset, otherwise you get a PHP warning when it's not set.
The problem seems to be in the first line of your script:
$actual_name = pathinfo("PHPAPI/recording.mp3", PATHINFO_FILENAME);
This will assign recording.mp3 to $actual_filename. You are then checking for recording.mp3.mp3 by concatenating the extension to the filename. I think you want to use PATHINFO_BASENAME which will return the filename sans extension.
Are you sure about the path? /PHPAPI looks for the file inside /PHPAPI, not the expected /var/www/osbs/PHPAPI/. You should check for PHPAPI/$filename instead.
You have to put your all logical in the find_new_name() function. That would made your code clearer
if ($_GET["RecordingUrl"]) {
$name = find_new_name("PHPAPI/recording.mp3");
file_put_contents($name, file_get_contents($_GET["RecordingUrl"]));
}
function find_new_name($name) {
$info = pathinfo($name);
$name = $info['basename'];
$i = 0;
while (file_exists("$info[dirname]/$name")) {
$name = sprintf('%s%d.%s', $info['filename'], ++$i, $info['extension']);
}
return "$info[dirname]/$name";
}
You forgot the path with the file_put_contents().
It should be:
file_put_contents("PHPAPI/".$name, file_get_contents($_GET["RecordingUrl"]));
Or:
file_put_contents("/var/www/osbs/PHPAPI/".$name, file_get_contents($_GET["RecordingUrl"]));
You are confused between URL of a file and its PATH
Your httdoc(or public_html ) root is /var/www/osbs/PHPAPI
But Your filesystem root is '/'
Try
file_put_contents( __DIR__.'/'.$name, file_get_contents($_GET["RecordingUrl"]));
there are lots of bad practices in your code
'file_exists' and a few other file calls like fstat are cached by php. This is documented in the manual for file_exists. Your first call when the file does not exists is saved and returned in subsequent calls. Use 'clearstatcache()' between calls to clear the cache.
A "little" refactoring:
Absolute path everywhere
Transparent function, more self-explanatory name, simpler use of argument
Protection against malicious input ($_POST really doesn't cut it)
Why file_put_contents() when you want to actually copy()
<?php
define("SRC_PATH", "/var/www/osbs/whereverYourSrcIs/");
define("SAVE_PATH", "/var/www/osbs/PHPAPI/");
function findAvailableName($name) {
$i = 1;
$pathinfo = pathinfo($name);
while(file_exists($name)) {
$name = $pathinfo['dirname'] . '/' . $pathinfo['filename'] . "." . $i++ . "." . $pathinfo['extension'];
}
return $name;
}
if (isset($_GET["RecordingUrl"]) && $_GET["RecordingUrl"]) {
if (strpos('/' . $_GET['RecordingUrl'] . '/', '/../') !== false) {
die("invalid input, don't be evil");
}
copy(SRC_PATH . $_GET["RecordingUrl"], findAvailableName(SAVE_PATH . "recording.mp3"));
}

PHP - Simple script for image compression with pngquant

:) 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

On creating zip file by php I get two files instead of one

I'm struggling around with a simple PHP functionality: Creating a ZIP Archive with some files in.
The problem is, it does not create only one file called filename.zip but two files called filename.zip.a07600 and filename.zip.b07600. Pls. see the following screenshot:
The two files are perfect in size and I even can rename each of them to filename.zip and extract it without any problems.
Can anybody tell me what is going wrong???
function zipFilesAndDownload_Defect($archive_file_name, $archiveDir, $file_path = array(), $files_array = array()) {
// Archive File Name
$archive_file = $archiveDir."/".$archive_file_name;
// Time-to-live
$archiveTTL = 86400; // 1 day
// Delete old zip file
#unlink($archive_file);
// Create the object
$zip = new ZipArchive();
// Create the file and throw the error if unsuccessful
if ($zip->open($archive_file, ZIPARCHIVE::CREATE) !== TRUE) {
$response->res = "Cannot open '$archive_file'";
return $response;
}
// Add each file of $file_name array to archive
$i = 0;
foreach($files_array as $value){
$expl = explode("/", $value);
$file = $expl[(count($expl)-1)];
$path_file = $file_path[$i] . "/" . $file;
$size = round((filesize ($path_file) / 1024), 0);
if(file_exists($path_file)){
$zip->addFile($path_file, $file);
}
$i++;
}
$zip->close();
// Then send the headers to redirect to the ZIP file
header("HTTP/1.1 303 See Other"); // 303 is technically correct for this type of redirect
header("Location: $archive_file");
exit;
}
The code which calls the function is a file with a switch-case... it is called itself by an ajax-call:
case "zdl":
$files_array = array();
$file_path = array();
foreach ($dbh->query("select GUID, DIRECTORY, BASENAME, ELEMENTID from SMDMS where ELEMENTID = ".$osguid." and PROJECTID = ".$osproject.";") as $subrow) {
$archive_file_name = $subrow['ELEMENTID'].".zip";
$archiveDir = "../".$subrow['DIRECTORY'];
$files_array[] = $archiveDir.DIR_SEPARATOR.$subrow['BASENAME'];
$file_path[] = $archiveDir;
}
zipFilesAndDownload_Defect($archive_file_name, $archiveDir, $file_path, $files_array);
break;
One more code... I tried to rename the latest 123456.zip.a01234 file to 123456.zip and then unlink the old 123456.zip.a01234 (and all prior added .a01234 files) with this function:
function zip_file_exists($pathfile){
$arr = array();
$dir = dirname($pathfile);
$renamed = 0;
foreach(glob($pathfile.'.*') as $file) {
$path_parts = pathinfo($file);
$dirname = $path_parts['dirname'];
$basename = $path_parts['basename'];
$extension = $path_parts['extension'];
$filename = $path_parts['filename'];
if($renamed == 0){
$old_name = $file;
$new_name = str_replace(".".$extension, "", $file);
#copy($old_name, $new_name);
#unlink($old_name);
$renamed = 1;
//file_put_contents($dir."/test.txt", "old_name: ".$old_name." - new_name: ".$new_name." - dirname: ".$dirname." - basename: ".$basename." - extension: ".$extension." - filename: ".$filename." - test: ".$test);
}else{
#unlink($file);
}
}
}
In short: copy works, rename didn't work and "unlink"-doesn't work at all... I'm out of ideas now... :(
ONE MORE TRY: I placed the output of $zip->getStatusString() in a variable and wrote it to a log file... the log entry it produced is: Renaming temporary file failed: No such file or directory.
But as you can see in the graphic above the file 43051221.zip.a07200 is located in the directory where the zip-lib opens it temporarily.
Thank you in advance for your help!
So, after struggling around for days... It was so simple:
Actually I work ONLY on *nix Servers so in my scripts I created the folders dynamically with 0777 Perms. I didn't know that IIS doesn't accept this permissions format at all!
So I remoted to the server, right clicked on the folder Documents (the hierarchically most upper folder of all dynamically added files and folders) and gave full control to all users I found.
Now it works perfect!!! The only thing that would be interesting now is: is this dangerous of any reason???
Thanks for your good will answers...
My suspicion is that your script is hitting the PHP script timeout. PHP zip creates a temporary file to zip in to where the filename is yourfilename.zip.some_random_number. This file is renamed to yourfilename.zip when the zip file is closed. If the script times out it will probably just get left there.
Try reducing the number of files to zip, or increasing the script timeout with set_time_limit()
http://php.net/manual/en/function.set-time-limit.php

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);

Categories