Skip to content

Instantly share code, notes, and snippets.

@nothrem
Last active June 7, 2016 12:02
Show Gist options
  • Save nothrem/44e31e5f84c3f16fdd9d1be2ffa3f906 to your computer and use it in GitHub Desktop.
Save nothrem/44e31e5f84c3f16fdd9d1be2ffa3f906 to your computer and use it in GitHub Desktop.
/* Use as standalone function or static method of any object.
* Set default $shardLevel to a value relevant for your usercase (e.g. +3 for MD5 filenames, -2 for ID filenames, etc.)
*/
/**
* Creates subfolders for storing files to prevent folder overloading by too many files.
*
* @param mixed $filename (required) Basic filename without extension. Can be anything convertable to string valid for filenaming.
* @param string $root (optional, default: '/') Where to start creating the subfolders. Set false to skip folder creation.
* @param string $ext (optional, default: none) Extension for the file.
* @param number $shardLevel (optional, default: -3) Maximum number of subfolders to create.
* For positive numbers will use letters from the beginning of the $filename, for negative numbers will use letters from the end of the $filename.
* Zero disables sharding and will only ensure $root folder exists and will create filepath from $root, $filename and $ext.
* Use PHP_INT_MAX or -PHP_INT_MAX for unlimited number of folders. Recommended maximum is 64 or less (based on OS limits).
* @return array
* shards Created subfolders in $root from member id (e.g. '5/4/3/' for ID 12345).
* filename Filename with extension from member id
* filepath Path of shards and filename
* rootpath Full path including root
* root Content of $root (so you don't need to keep it separately)
* @throws Exception When filename is empty.
*/
function shardFilename($filename, $root = '/', $ext = '', $shardLevel = 3) {
$filename = '' . $filename; //convert to string
if (empty($filename)) {
throw new Exception('Missing filename for sharding.');
}
$len = strlen($filename);
$path = '';
for ($i = 0; $i < abs($shardLevel); ++$i) {
if (($len - $i) < 2) { //do not shard for last letter
break; //e.g. 3/2/123.tmp for short name but 5/4/3/12345.tmp for longer
}
$path .= $filename[$shardLevel > 0 ? $i : $len - $i - 1] . '/';
}
if (false !== $root && !is_dir($root . $path)) {
$umask = umask(0); //allow to create folder with all rights
mkdir($root . $path, 0777, true);
umask($umask); //return previous limits
}
return array(
'root' => $root,
'shards' => $path,
'filename' => $filename . $ext,
'rootpath' => $root . $path . $filename . $ext,
'filepath' => $path . $filename . $ext,
);
}
/* EXAMPLE:
file_put_contents(shardFilename('12345', UPLOAD_PATH, '.tmp', 3)['rootpath'], $data); //will save to '/upload/1/2/3/12345.tmp'
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment