Last active
April 2, 2024 18:40
-
-
Save jonataswalker/3c0c6b26eabb2e36bc90 to your computer and use it in GitHub Desktop.
Build a tree (array or json) from any directory.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
** | |
* Public Domain. | |
* @author Jonatas Walker | |
* Based in: http://kvz.io/blog/2007/10/03/convert-anything-to-tree-structures-in-php/ | |
* Usage: | |
* $root = '/home/www/'; | |
* $allow_ext = array('jpg','gif'); | |
* $exclude_dir = array('tilemill'); | |
* $prefix = 'small'; | |
* | |
* $tree = new buildTreeFromDirectory($root); | |
* $tree->setFilter($allow_ext, $prefix); | |
* $tree->saveJSON('/path/to/save', 'json-tree.json'); | |
* | |
*/ | |
class buildTreeFromDirectory { | |
public $root_dir, | |
$file_prefix, | |
$allowed_extensions, | |
$ignore_hidden, | |
$exclude_dir; | |
private $filter; | |
public function __construct($root_dir){ | |
$root_dir = realpath($root_dir); | |
if(!$root_dir) | |
die("This directory doesn't exist!"); | |
$this->root_dir = $root_dir; | |
$this->setFilter(); | |
date_default_timezone_set(@date_default_timezone_get()); | |
} | |
public function setFilter( | |
$allowed_extensions = array('*'), | |
$file_prefix = '', | |
$exclude_dir = array(), | |
$ignore_hidden = true | |
){ | |
$this->allowed_extensions = $allowed_extensions; | |
$this->file_prefix = $file_prefix; | |
$this->ignore_hidden = $ignore_hidden; | |
$this->exclude_dir = $exclude_dir; | |
} | |
public function buildTree(){ | |
$dir = new RecursiveDirectoryIterator( | |
$this->root_dir, FilesystemIterator::SKIP_DOTS); | |
$this->filter($dir); | |
$it = new RecursiveIteratorIterator( | |
$this->filter, | |
RecursiveIteratorIterator::SELF_FIRST, | |
RecursiveIteratorIterator::CATCH_GET_CHILD | |
); | |
$tree = array(); | |
foreach($it as $fileinfo) { | |
$name = $fileinfo->getFilename(); | |
$sub_path_name = $it->getSubPathName(); | |
$parts = explode(DIRECTORY_SEPARATOR, $sub_path_name); | |
array_pop($parts); | |
$parentArr = &$tree; | |
//go deep in the file|dir path | |
foreach ($parts as $part) { | |
$parentArr = &$parentArr['dirs'][$part]; | |
} | |
if ($fileinfo->isDir()) { | |
// Add the final part to the structure | |
$parentArr['dirs'][$name] = array('folder' => $name); | |
} else { | |
// Add some file info to the structure | |
if($fileinfo->isLink()){ | |
$realpath = $fileinfo->getRealPath(); | |
$filesize = filesize($realpath); | |
$filemtime = filemtime($realpath); | |
} else { | |
$filesize = $fileinfo->getSize(); | |
$filemtime = $fileinfo->getMTime(); | |
} | |
$parentArr['files'][] = array( | |
'filename' => $name, | |
'filesize' => $this->fileSizeConvert($filesize), | |
'date' => date("d-m-Y H:i", $filemtime), | |
'relative_path' => $it->getSubPath() | |
); | |
} | |
} | |
unset($parentArr); | |
$this->sortArray($tree); | |
return $tree; | |
} | |
private function sortArray(&$tree){ | |
foreach ($tree as &$value) { | |
if (is_array($value)) | |
$this->sortArray($value); | |
} | |
return ksort($tree); | |
} | |
public function saveJSON($path, $filename){ | |
$tree = $this->buildTree(); | |
$path = realpath($path); | |
if($path && is_writable($path)){ | |
$full = $path .DIRECTORY_SEPARATOR. $filename; | |
$write = file_put_contents($full, json_encode($tree)); | |
if($write) | |
echo 'Saved: ' . $full . "\n"; | |
else | |
echo 'Error trying to save: ' . $full . "\n"; | |
} | |
} | |
public function getJSON(){ | |
header('Content-Type: application/json'); | |
echo json_encode(array( | |
'tree' => $this->buildTree() | |
)); | |
} | |
private function filter($dir){ | |
$this->filter = new RecursiveCallbackFilterIterator($dir, | |
function($current, $key, $iterator){ | |
$filename = $current->getFilename(); | |
//ignore all hidden files/directories | |
if($this->ignore_hidden){ | |
if(substr($filename, 0, 1) == '.') | |
return false; | |
} | |
// Allow recursion | |
if($iterator->hasChildren() && | |
!in_array($filename, $this->exclude_dir)) { | |
return true; | |
} | |
if($current->isReadable() === false) | |
return false; | |
//filter by file extension | |
$path = $current->getPathname(); | |
$file_ext = pathinfo($path, PATHINFO_EXTENSION); | |
if($this->allowed_extensions[0] == '*'){ //no extension filter | |
$ext_allowed = true; | |
} else { | |
$ext_allowed = in_array($file_ext, $this->allowed_extensions); | |
} | |
if(!empty($this->file_prefix)){ | |
//filter by prefix and extension | |
if(strpos($filename, $this->file_prefix) === 0 && $ext_allowed) | |
return true; | |
else | |
return false; | |
} | |
//filter by extension | |
return $ext_allowed; | |
} | |
); | |
} | |
public function fileSizeConvert($bytes){ | |
$label = array('B', 'KB', 'MB', 'GB', 'TB', 'PB'); | |
for($i = 0; $bytes >= 1024 && $i < (count($label) -1); $bytes /= 1024, $i++); | |
return round($bytes, 2) . " " . $label[$i]; | |
} | |
} | |
//Usage: | |
$root = '/home/www/tests'; | |
$allow_ext = array('jpg','gif'); | |
$exclude_dir = array('tilemill'); | |
$prefix = 'small'; | |
$tree = new buildTreeFromDirectory($root); | |
$tree->setFilter($allow_ext, $prefix, $exclude_dir); | |
//$tree->getJSON(); //for ajax purpose | |
$tree_class->saveJSON('/path/to/save', 'json-tree.json'); | |
/** This is an example of the JSON structure | |
* you can see a beautified tree of this at http://codebeautify.org/jsonviewer/067c13 | |
{"tree":{"dirs":{"dir1":{"dirs":{"subdir1":{"dirs":{"sub-subdir1":{"folder":"sub-subdir1"}},"files":[{"date":"31-07-2015 12:53","filename":"small55ba1674dc59b.jpg","filesize":"15.25 KB","relative_path":"dir1/subdir1"}],"folder":"subdir1"}},"files":[{"date":"31-07-2015 12:46","filename":"small55ba1674dc59b.jpg","filesize":"15.25 KB","relative_path":"dir1"}],"folder":"dir1"},"dir2":{"dirs":{"subdir2.1":{"dirs":{"sub-subdir2.1":{"folder":"sub-subdir2.1"}},"folder":"subdir2.1"},"subdir2.2":{"dirs":{"sub-subdir2.2":{"folder":"sub-subdir2.2"}},"folder":"subdir2.2"},"subdir2.3":{"dirs":{"sub-subdir2.3":{"folder":"sub-subdir2.3"}},"folder":"subdir2.3"}},"files":[{"date":"31-07-2015 12:46","filename":"small55ba1674dc59b.jpg","filesize":"15.25 KB","relative_path":"dir2"}],"folder":"dir2"},"dir3":{"folder":"dir3"},"dir4":{"folder":"dir4"}},"files":[{"date":"30-07-2015 09:19","filename":"small55ba166fb2fe2.jpg","filesize":"36.91 KB","relative_path":""},{"date":"30-07-2015 09:20","filename":"small55ba1673846e8.jpg","filesize":"28.25 KB","relative_path":""},{"date":"30-07-2015 09:20","filename":"small55ba1674dc59b.jpg","filesize":"15.25 KB","relative_path":""},{"date":"30-07-2015 09:20","filename":"small55ba1671bd37b.jpg","filesize":"21.38 KB","relative_path":""},{"date":"30-07-2015 09:19","filename":"small55ba166e8b119.jpg","filesize":"31.82 KB","relative_path":""}]}} | |
*/ | |
/**And this is the Array structure - basically two entries for each directory: | |
* one for sub folders and other for files | |
Array | |
( | |
[dirs] => Array | |
( | |
[dir1] => Array | |
( | |
[dirs] => Array | |
( | |
[subdir1] => Array | |
( | |
[dirs] => Array | |
( | |
[sub-subdir1] => Array | |
( | |
[folder] => sub-subdir1 | |
) | |
) | |
[files] => Array | |
( | |
[0] => Array | |
( | |
[date] => 31-07-2015 12:53 | |
[filename] => small55ba1674dc59b.jpg | |
[filesize] => 15.25 KB | |
[relative_path] => dir1/subdir1 | |
) | |
) | |
[folder] => subdir1 | |
) | |
) | |
[files] => Array | |
( | |
[0] => Array | |
( | |
[date] => 31-07-2015 12:46 | |
[filename] => small55ba1674dc59b.jpg | |
[filesize] => 15.25 KB | |
[relative_path] => dir1 | |
) | |
) | |
[folder] => dir1 | |
) | |
[dir2] => Array | |
( | |
[dirs] => Array | |
( | |
[subdir2.1] => Array | |
( | |
[dirs] => Array | |
( | |
[sub-subdir2.1] => Array | |
( | |
[folder] => sub-subdir2.1 | |
) | |
) | |
[folder] => subdir2.1 | |
) | |
) | |
[files] => Array | |
( | |
[0] => Array | |
( | |
[date] => 31-07-2015 12:46 | |
[filename] => small55ba1674dc59b.jpg | |
[filesize] => 15.25 KB | |
[relative_path] => dir2 | |
) | |
) | |
[folder] => dir2 | |
) | |
) | |
[files] => Array | |
( | |
[0] => Array | |
( | |
[date] => 30-07-2015 09:19 | |
[filename] => small55ba166fb2fe2.jpg | |
[filesize] => 36.91 KB | |
[relative_path] => | |
) | |
) | |
) | |
*/ | |
?> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
FYI: you must supply an absolute path in the
buildTreeFromDirectory($root)
function as the$root
variable. If you pass a relative path the function will not build an accurate directory structure.