Organise & Name Uploaded Files - php

What's the best way to ogranise and name uploaded files?
I maybe wrong on this, but I feel it's not good practice to save all files in one directory, as this will result in slowness of the filesystem if the file ever needed to be browsed?
All thoughts and idea's welcome
Cheers

i use a function like this to generate a 3-level folder's tree for uploaded files:
function get_1000_path($id)
{
$id = strval($id);
$id = str_repeat("0", 9 - strlen($id)).$id;
$path = substr($id, 0, 3)."/".substr($id, 3, 3)."/".substr($id, 6, 3)."/";
return $path;
}
so max count of files in one subfolder is 1000, filesystem will work well

It depends on how your application is working.
If it's something like users galleries, I would simply create one folder for every user, then a year -> month structure.
If files are commonly shared by all the users, I would organize them in different directories based on time (year -> month -> week -> day). If your site is not expecting a lot of traffic, a year -> month division should be enough.
I would use uniqid() function to rename the uploaded files so that there will be no need to check for overwrite or duplicates.

I think it depends on your system/site or needs, ie. for a user portal it could be better like this user_images/USER-ID/filename-unid_id.jpg. For example, this could be usefull uploads/news_images/YYYY/MM/DD/filename-unid_id.jpg type for a news site. At this point it won't need large unid_id's like md5 or something else and you can use php hash like: $unid_id = hash('crc32b', microtime()). Cos there are hard line collution possibilities.
// in your upload file
$dir = "uploads/news_images/". date("Y-m-d");
if (!is_dir($dir)) {
mkdir($dir, 0777, true);
if (!is_writable($dir)) chmod($dir, 0777); // try again changing mod
}
But, both two example, you need to store file name/path of each file. In this way, you use this method to store data (personally I use json format when storing many data togather and if I don't need to search on);
// table "news_images"
id | file_name | file_data
--------------------------
1 | blue fish | {"path":"2012/12/12", "slug":"blue-fish-9834a12b", "ext":"jpg" ...
Good lucks..

Related

PHP Sequentially naming game ids in a dynamic list of game names

Ever time I make a game of a certain type, say cricket, I have to name it BTAG-n, where n is the number of games made for that type,
eg cricket BTAG-0, cricket BTAG-1, hockey BTAG-0, soccer BTAG-0
I cannot use a database for this, as the the number of different types of games will change with time. So I tried using files.
$filename = '/game_data/'.$name.'.txt';
$count = '0';
if (!file_exists($filename)){
file_put_contents($filename, $count);
}else{
$count = ((int)file_get_contents($filename))+1;
file_put_contents($filename, $count);
}
$randNumber = "BTAG-".$count;
But $count is always 0, I assume because file_put_contents and file_get_contents don't work, and I can't find how to enable errors or change permissions as there is no php.ini file in my cpanel (I inherited this project from another person I have no contact with, maybe he deleted it).
Any help appreciated.
You're trying to write to the root folder of our server, which is most likely not writeable by your PHP process, try to remove the "/" at the beginning of your file path, it will attempt to write the file at the same location of your script.
You might also need the folder "game_data" created there.

PHP Script for Monitoring Folder Creation

I want to write one PHP script that will tell me how many folders getting created today( not modified one !! ).
Ex. Suppose if gave the path ( like c:\Data ) so my script must be continuously checking that
give path for if it is new entry of any folder. I have used http://php.net/manual/en/function.date-diff.php. But getting result for modified folders as well.
Quote from #Alin Purcaru:
Use filectime. For Windows it will return the creation time, and for Unix the change time which is the best you can get because on Unix there is no creation time (in most filesystems).
Using a reference file to compare the files age allows you to detect new files whidout using a database.
// Path to the reference file.
// All files newer than this will be treated as new
$referenceFile="c:\Data\ref";
// Location to search for new folders
$dirsLocation="c:\Data\*";
// Get modification date of reference file
if (file_exists($referenceFile))
$referenceTime = fileatime($referenceFile);
else
$referenceTime = 0;
// Compare each directory with the reference file
foreach(glob($dirsLocation, GLOB_ONLYDIR) as $dir) {
if (filectime($dir) > $referenceTime)
echo $dir . " is new!";
}
// Update modification date of the reference file
touch($referenceFile);
Another solution could be to use a database. Any folders that are not in the database are new. This ensures to not catch modified folders.
You might want to try getting your script launched with cron like every one minute and check the difference between directory lists (from before and current I mean), not the dates. It's not a perfect solution, but it will work.
Check directories arays with:
$dirs = array_filter(glob('*'), 'is_dir');
Compare them later with array_diff

php move/copy image files to new directory/folder structure in linux

I have a php/mysql website where users create listings and upload multiple images (3 image sizes for each). I made the mistake of storing the images in folders as below :
images/listings/listing_id/image-name.jpg
images/listings/listing_id/thumbs/image-name.jpg
images/listings/listing_id/large/image-name.jpg
Unfortuantely now I have come across the problem where the maximum number of sub directories is 30,000 and my code breaks.
I want to now change my folder structure to the one below :
images/listings/yyyy/mm/dd/listing_id/image-name.jpg
images/listings/yyyy/mm/dd/listing_id/thumbs/image-name.jpg
images/listings/yyyy/mm/dd/listing_id/large/image-name.jpg
I decided the best way forward would be to create a php script to loop around all directories in the 'images/listings/' folder, and copy every image in to a new directory as specified above. or each 'listing_id' folder, I would need to lookup using mysql the listing_id, and get the created_date and then split the date to get the yyyy mm dd.
I'm totally lost in creating the php script, would it be possible to rename the existing directory structure without copying and deleting the old images, or would I need to copy the old images, create the new directories, move them and then delete the old folders?
So long as you don't have any listing_ids that are the same as a 4-digit year you should be able to create the new folder structure alongside the existing one.
You seem to already have a plan for how to do it, you should try actually writing some code.
Hint: rename() is the same as 'move'. Don't do "copy and delete" unless you want it to take 10x longer.
Lastly, as a rule of thumb you should try to avoid having any folder with more than about 1000 entries if possible. If there are a lot of filesystem operations that have to use the directory index for a folder that large it can drastically reduce filesystem performance.
You can use
$origin = "images/listings";
$final = "images/final";
$start = strlen($origin) + 1;
$di = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($origin, RecursiveDirectoryIterator::SKIP_DOTS));
foreach ( $di as $file ) {
if ($file->isFile()) {
$mtime = $file->getMTime();
$date = sprintf("%d/%d/%d", date("Y", $mtime), date("m", $mtime), date("d", $mtime));
$new = sprintf("%s/%s/%s", $final, $date, substr($file, $start));
$dir = dirname($new);
is_dir($dir) or mkdir($dir, null, true);
rename($file, $new);
}
}
For the moving of image,you can use the rename() Function of php.
For example
rename("../app/temp/natural.jpeg","../public/public_photo/natural.jpeg");
Above given code natural.jpeg from the folder /aap/temp/ has moved to the folder /public/public_photo/

Directory structure for large number of files

I made one site... where i am storing user uploaded files in separate directories like
user_id = 1
so
img/upload_docs/1/1324026061_1.txt
img/upload_docs/1/1324026056_1.txt
Same way if
user_id = 2
so
img/upload_docs/2/1324026061_2.txt
img/upload_docs/2/1324026056_2.txt
...
n
So now if in future if I will get 100000 users then in my upload_docs folder I will have 100000 folders.
And there is no restriction on user upload so it can be 1000 files for 1 user or 10 files any number of files...
so is this proper way?
Or if not then can anyone suggest me how to store this files in this kind of structure???
What I would do is name the images UUIDs and create subfolders based on the names of the files. You can do this pretty easily with chunk_split. For example, if you create a folder every 4 characters you would end up with a structure like this:
img/upload_docs/1/1324/0260/61_1.txt
img/upload_docs/1/1324/0260/56_1.txt
By storing the image name 1324026056_1.txt you could then very easily determine where it belongs or where to fetch it using chunk_split.
This is a similar method to how git stores objects.
As code, it could look something like this.
// pass filename ('123456789.txt' from db)
function get_path_from_filename($filename) {
$path = 'img/upload_docs';
list($filename, $ext) = explode('.', $filename); //remove extension
$folders = chunk_split($filename, 4, '/'); // becomes 1234/5678/9
// now we store it here
$newpath = $path.'/'.$folders.'/'.$ext;
return $newpath;
}
Now when you search for the file to deliver it to the user, use a function using these steps to recreate where the file is (based on the filename which is still stored as '123456789.txt' in the DB).
Now to deliver or store the file, use get_path_from_filename.
img/upload_docs/1/0/10000/1324026056_2.txt
img/upload_docs/9/7/97555/1324026056_2.txt
img/upload_docs/2/3/23/1324026056_2.txt

Auto create directories after uploading with PHP

I'm creating a php site where a company will upload a lot of images. I'd like one folder to contain upto 500-1000 files and PHP automatically creates a new one if previous contains more that 1000 files.
For example, px300 has folder dir1 which stores 500 files, then a new one dir2 will be created.
Are there any existed a solutions?
This task is simple enough not to require an existing solution. You can make use of scandir to count the number of files in a directory, and then mkdir to make a directory.
// Make sure we don't count . and .. as proper directories
if (count(scandir("dir")) - 2 > 1000) {
mkdir("newdir");
}
A common approach is to create one-letter directories based on the file name. This works particularly well if you assign random names to files (and random names are good to avoid name conflicts in user uploads):
/files/a/c/acbd18db4cc2f85cedef654fccc4a4d8
/files/3/7/37b51d194a7513e45b56f6524f2d51f2
In this way:
if ($h = opendir('/dir')) {
$files = 0;
while (false !== ($file = readdir($h))) {
$files++
}
if($files > 1000){
//create dir
mkdir('/newdir')
}
}
You could use the glob function. It will return an array matching your pattern, which you could count for the amount of files.

Categories