I looked at a few other questions mentioning tempnam() in the context of unique file naming.
I was left a bit unclear on whether the file names will be truly unique.
Let's say that we have a file upload script, that moves and renames the files to a permanent directory.
What I want to ask, is: Will the file name always be unique, when used like this:
$tmp_name = tempnam($dir, '');
unlink($tmp_name);
copy($uploaded_file, "$tmp_name.$ext");
As cantsay suggested, I made a php script to look for identical values.
function tempnam_tst() {
for ($i=0; $i < 250000 ; $i++) {
$tmp_name = tempnam('/tmp/', '');
unlink($tmp_name);
$arr[$i] = $tmp_name;
}
return array_intersect($arr, array_unique(array_diff_key($arr, array_unique($arr))));
}
$arr = array();
do {
$arr = tempnam_tst();
} while ( empty($arr) );
echo 'Matching items (case-sensitive):<br>';
echo '<pre>';
print_r($arr);
echo '</pre>';
Result:
Matching items (case-sensitive):
Array
(
[59996] => /tmp/8wB6RI
[92722] => /tmp/KnFtJa
[130990] => /tmp/KnFtJa
[173696] => /tmp/8wB6RI
)
From what I can see, tempnam() does not always generate an unique name.
Try this->
$uploadPath = "/upload/";
$fileName = time().$_FILES['file_name']['name'];
$tempName = $_FILES['file_name']['tmp_name'];
move_uploaded_file($tempName,$uploadPath.$fileName);
This will upload unique file in upload folder.
Related
So I have a bit of an issue. I'm trying to create something that once ran will check if the file it's trying to save as exists, if it exists then it renames the existing file its number +1, and what it's suppose to do is if that file exists then rename that file.
So basically
1(A) 2(B) 3(C)
Save file X as 1
1(X) 2(A) 3(B) 4(C)
But currently instead of that it's moving the first file being renamed to the last number and I'm unsure how to fix it.
What it's doing
1(A) 2(B) 3(C)
Save file X as 1
1(X) 2(B) 3(C) 4(A)
<?php
ob_start(); ?>
<html>
All HTML here
</html>
<?php
$path = "cache/home-".$imputnum.".html";
?>
<?php
if (file_exists($path)) {
$i=$imputnum;
$new_path=$path;
while (file_exists($new_path))
{
$extension = "html";
$filename = "home";
$directory = "cache";
$new_path = $directory . '/' . $filename . '-' . $i . '.' . $extension;
$i++;
}
if(!rename($path, $new_path)){
echo 'error renaming file';
}
}
?>
<?php
$fp = fopen("cache/home-".$imputnum.".html", 'w');
fwrite($fp, ob_get_contents());
ob_end_flush();
?>
If there are already 3 files, you'll need to rename all 3 of them.. For instance
x-3.ext -> x-4.ext
x-2.ext -> x-3.ext
x-1.ext -> x-2.ext
(from last to first). So, the rename must be inside a loop.
Here's an example:
function save_file( $name, $ext, $content ) {
$f = "$name.$ext";
$i = 0;
while ( file_exists( $f ) )
$f = "$name-".++$i.".$ext";
while ( $i > 0 )
rename( $name.(--$i==0?"":"-$i").".$ext", "$name-".($i+1).".$ext" );
file_put_contents( "$name.$ext", $content );
}
save_file( "home", "html", "A" );
save_file( "home", "html", "AB" );
save_file( "home", "html", "ABC" );
save_file( "home", "html", "ABCD" );
After this is run, we have:
home.html: "ABCD"
home-1.html: "ABC"
home-2.html: "AB"
home-3.html: "A"
here's a snippet of how i did it
// Get a unique filename
$filename = "$IMAGES_DIR/UploadedImg.$ext";
while(file_exists($filename)){
$chunks = explode(".", $filename);
$extention = array_pop($chunks);
$basename = implode(".", $chunks);
$num = isset($num) ? ($num+1) : 0;
$filename = "$basename$num.$extention";
if(file_exists($filename)) $filename = "$basename.$extention";
}
What you are trying to do sounds like a job for array_unshift which prepends to an array. See http://php.net/manual/en/function.array-unshift.php
After inserting the base file name without numbers into the array, I would loop through the array and append/prepend the index like so:
$filenames = $exising_filenames;
array_unshift($filenames, $new_filename);
foreach($filenames as $index => &$filename {
// Do some operation to remove the numbers from filename here.
// Now add back the number using the array's index.
$filename = ($index+1).$filename;
// You may rename the existing files using the filenames.
}
// Insert the new file with filename using $filenames[0]
This question already has answers here:
How to generate a random, unique, alphanumeric string?
(31 answers)
Closed 9 years ago.
How would I go about creating a random string of text for use with file names?
I am uploading photos and renaming them upon completion. All photos are going to be stored in one directory so their filenames need to be unique.
Is there a standard way of doing this?
Is there a way to check if the filename already exists before trying to overwrite?
This is for a single user environment (myself) to show my personal photos on my website however I would like to automate it a little. I don't need to worry about two users trying to upload and generating the same filename at the same time but I do want to check if it exists already.
I know how to upload the file, and I know how to generate random strings, but I want to know if there is a standard way of doing it.
The proper way to do this is to use PHP's tempnam() function. It creates a file in the specified directory with a guaranteed unique name, so you don't have to worry about randomness or overwriting an existing file:
$filename = tempnam('/path/to/storage/directory', '');
unlink($filename);
move_uploaded_file($_FILES['file']['tmp_name'], $filename);
function random_string($length) {
$key = '';
$keys = array_merge(range(0, 9), range('a', 'z'));
for ($i = 0; $i < $length; $i++) {
$key .= $keys[array_rand($keys)];
}
return $key;
}
echo random_string(50);
Example output:
zsd16xzv3jsytnp87tk7ygv73k8zmr0ekh6ly7mxaeyeh46oe8
EDIT
Make this unique in a directory, changes to function here:
function random_filename($length, $directory = '', $extension = '')
{
// default to this files directory if empty...
$dir = !empty($directory) && is_dir($directory) ? $directory : dirname(__FILE__);
do {
$key = '';
$keys = array_merge(range(0, 9), range('a', 'z'));
for ($i = 0; $i < $length; $i++) {
$key .= $keys[array_rand($keys)];
}
} while (file_exists($dir . '/' . $key . (!empty($extension) ? '.' . $extension : '')));
return $key . (!empty($extension) ? '.' . $extension : '');
}
// Checks in the directory of where this file is located.
echo random_filename(50);
// Checks in a user-supplied directory...
echo random_filename(50, '/ServerRoot/mysite/myfiles');
// Checks in current directory of php file, with zip extension...
echo random_filename(50, '', 'zip');
Hope this is what you are looking for:-
<?php
function generateFileName()
{
$chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789_";
$name = "";
for($i=0; $i<12; $i++)
$name.= $chars[rand(0,strlen($chars))];
return $name;
}
//get a random name of the file here
$fileName = generateName();
//what we need to do is scan the directory for existence of the current filename
$files = scandir(dirname(__FILE__).'/images');//assumed images are stored in images directory of the current directory
$temp = $fileName.'.'.$_FILES['assumed']['type'];//add extension to randomly generated image name
for($i = 0; $i<count($files); $i++)
if($temp==$files[$i] && !is_dir($files[$i]))
{
$fileName .= "_1.".$_FILES['assumed']['type'];
break;
}
unset($temp);
unset($files);
//now you can upload an image in the directory with a random unique file name as you required
move_uploaded_file($_FILES['assumed']['tmp_name'],"images/".$fileName);
unset($fileName);
?>
The following code is meant to iterate through a directory of images and rename them.
I had it working well, but what I would like to add is a 'static' token at the beginning of the file that once renamed, it will then in future ignore.
For example, let's say that we have a directory of 100 files.
The first 20 of which go by the name "image-JTzkT1RYWnCqd3m1VXYcmfZ2nhMOCCunucvRhuaR5.jpg"
The last 80 go by the name "FejVQ881qPO5t92KmItkNYpny.jpg" where this could be absolutely anything.
I would like to ignore the files that have already been renamed (denoted by the 'image-" at the beginning of the file name)
How can I do this?
<?php
function crypto_rand_secure($min, $max) {
$range = $max - $min;
if ($range < 0) return $min; // not so random...
$log = log($range, 2);
$bytes = (int) ($log / 8) + 1; // length in bytes
$bits = (int) $log + 1; // length in bits
$filter = (int) (1 << $bits) - 1; // set all lower bits to 1
do {
$rnd = hexdec(bin2hex(openssl_random_pseudo_bytes($bytes)));
$rnd = $rnd & $filter; // discard irrelevant bits
} while ($rnd >= $range);
return $min + $rnd;
}
function getToken($length){
$token = "";
$codeAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
$codeAlphabet.= "abcdefghijklmnopqrstuvwxyz";
$codeAlphabet.= "0123456789";
for($i=0;$i<$length;$i++){
$token .= $codeAlphabet[crypto_rand_secure(0,strlen($codeAlphabet))];
}
return $token;
}
$dir = "/path/to/images";
if ( $handle = opendir ( $dir)) {
echo "Directory Handle = $handles<br />" ;
echo "Files: <br />" ;
while ( false !== ($file = readdir($handle))) {
if ( $file != "." && $file != ".." ) {
$isdir = is_dir ( $file ) ;
if ( $isdir == "1" ) {} // if its a directory do nothing
else {
$file_array[] = "$file" ; // get all the file names and put them in an array
//echo "$file<br />" ;
} // closes else
} // closes directory check
} // closes while
} // closes opendir
//Lets go through the array
$arr_count = count( $file_array ) ; // find out how many files we have found so we can initiliase the counter
for ( $counter=1; $counter<$arr_count; $counter++ ) {
echo "Array = $file_array[$counter] - " ; // tell me how many files there are
//$new = str_replace ( "C", "CIMG", $file_array[$counter] ) ; // now create the new file name
$new =getToken(50);
//if (substr($file_array[$counter]), 0, 3) == "gallery_image")
//{
//}
//else
//{
$ren = rename ( "$dir/$file_array[$counter]" , "image-$dir/$new.jpg" ) ; // now do the actual file rename
echo "$new<br />" ; // print out the new file name
//}
}
closedir ( $handle ) ;
?>
It seems like you're doing a lot of unnecessary work for something that should be quite trivial.
As far as I understand you want to get a list of the files from a directory and rename all of the ones not already pre-pended with image-.
You can do that with the following piece of code:
$dir = "/path/to/dir/"; //Trailing slash is necessary or you would have to change $dir.$newname to $dir.'/'.$newname further down the code
if(is_dir($dir)){
$dirHandle = opendir($dir);
while($file = readdir($dirHandle)){
if(is_file($dir.$file) === TRUE){
if(strpos($file, 'image-') === 0)
continue; //Skip if the image- is apready prepended
while(TRUE){
$cryptname = md5(mt_rand(1,10000).$file.mt_rand(1,10000)); //Create random string
$newname = 'image-'.$cryptname.'.jpg'; //Compile new file name
if(is_file($dir.$newname) === FALSE) //Check file name doesn't exist
break; //Exit loop if it doesn't
}
rename($dir.$file, $dir.$newname); //Rename file with new name
}
}
}
If you want to use your own function then you can the change the line:
$cryptname = md5(mt_rand(1,10000).$file.mt_rand(1,10000));
To use your function instead of md5. Like:
$cryptname = getToken(50);
I suggest that you should also check that the file name doesn't already exist otherwise - unlikely as it may be - you run the risk of overwriting files.
/images/ vs ./images/
Firstly, when dealing with the web you have to understand that there are effectively two root directories.
The web root and the document root. Take the example url http://www.mysite.com/images/myimage.jpg as far as the web root is concerned the path name is /images/myimage.jpg however, from php you have yo use the document root which would actually be something like: /home/mysite/pubic_html/images/myimage.jpg
So when you type / in php it thinks that you mean the directory which home is located in.
./images/ works because the ./ means this directory i.e. the one that the script/php is in.
In your case you probably have a file structure like:
>/
>home
>public_html
>images
image-243.jpg
image-243.jpg
index.php
So because index.php is in the same folder as images: ./images/ is equal to /home/public_html/images/. / on the other hand means the parent directory of home which has no images folder let alone the one you're targeting.
If you're more used to windows think of it like this: in php / means the document root directory (on windows that would be something like C:\).
You have the 'image-' in front of the directory portion of your file name:
$ren = rename ( "$dir/$file_array[$counter]" , "image-$dir/$new.jpg" )
should be
$ren = rename ( "$dir/$file_array[$counter]" , "$dir/image-$new.jpg" )
Sorry to bother you with this. I'm running mkdir to replicate directories that I have stored in a DB.
If I display the data on a php page the directories look like this:
element1/Content/EPAC/PROD
element1/Content/EPAC/TEST
element1/Content/EPAC_SG/PROD
element1/Content/EU/PROD
element1/Content/EU/TEST
The above is a subset of the data. What is happening with the above subset when I loop through it, it creates the directory element1/Content/EPAC/PROD but ignores element1/Content/EPAC/TEST and element1/Content/EPAC_SG/PROD, Then it creates element1/Content/EU/PROD but ignores element1/Content/EU/TEST etc and continues through the loop like that. The code I'm using is:
foreach($NSRarray as $value)
{
mkdir("ftpfolders/$value", 0700, true);
}
*the $value variable above is the 'element1/Content/EPAC/PROD' record taken from the DB.
Any ideas? Thanks in advance, Ste
I would split this into generating directories one at a time.
Transform your array into sth. like
$dics=array(
'element1' => array(
'Content' => array(
'EPAC' => array('PROD', 'TEST'),
'EPAC_SG' => array('PROD')
'EU' => array('PROD', 'TEST')
)
)
);
Then loop over it, starting with array_keys($dics) and create the directory if not existing.
Continue with array_keys($dics['element1']) and then repeat it until your reach the inner childs.
Hope this helps.
use this code, this will gives you proper folder structure as per your requirement
<?php
$NSRarray = array('element1/Content/EPAC/PROD', 'element1/Content/EPAC/TEST', 'element1/Content/EPAC_SG/PROD','element1/Content/EU/PROD','element1/Content/EU/TEST');
foreach($NSRarray as $value)
{
$getFolders = explode('/' , $value);
$mainFoldername = "ftpfolders";
$countfolder = 0;
$countfolder = count($getFolders);
$tempName = "";
$i = 0;
for($i == 0; $i < $countfolder; $i++){
$tempName .= $getFolders[$i];
if (!file_exists("$mainFoldername/$tempName")) {
mkdir("$mainFoldername/$tempName", 0700, true);
}
$tempName .= '/';
}
}
?>
I would like to script in php code that will search a specific folder for a recently added file with a .zip file extension and add it to a variable to be manipulated later.
Use scandir to look for files in the specific folder, then isolate zip files using some strpos() or regexp on the retrieved filenames.
If needed, test the last modification time of the zip files found.
Edit: Using glob() will even be faster to match *.zip files.
[Edit]
Managed to come up with this code but i think i coded dirty. Any way to clean this up?
$show = 2; // Change to 0 for listing all found file types
$dir = ''; // Blank if the folder/directory to be scanned is the current one (with the script)
if($dir) chdir($dir);
$files = glob( '*.zip');
usort( $files, 'filemtime_compare' );
function filemtime_compare( $a, $b )
{
return filemtime( $b ) - filemtime( $a );
}
$i = 0;
foreach ( $files as $file )
{
++$i;
if ( $i == $show ) break;
$value = $file;
}
echo "This is the file name in the variable: " . $value;
?>