I am looking for this PHP function:
- List a directory, recursive
- The functionallity to navigate through folders
- No javascript
- Navigation via web adress, "?p=2|1" or something like that
- Sorted by type then names
I am looking for this PHP function:
<?php
class DirTree
{
protected $root;
protected $active;
const URL_KEY = 'el';
public function __construct($root, $active = null) {
$this->root = realpath($root);
if ($active !== null) {
$this->active = realpath($this->root . '/' . $active);
}
}
public function isActive($element) {
return substr($this->active, 0, strlen($element->getPathname())) === $element->getPathname();
}
public function getLink($element) {
return '?' . http_build_query(array(
self::URL_KEY => substr($element->getPathname(), strlen($this->root))
));
}
protected function _get(Iterator $it) {
$result = array();
$dirs = $files = array();
foreach ($it as $entry) {
if ($entry->isDir()) {
$data = (object)array(
'type' => 'dir',
'name' => $entry->getBasename(),
'object' => $entry
);
if ($this->isActive($entry)) {
$data->children = $this->_get($it->getChildren());
$data->active = true;
}
$dirs[$entry->getBasename()] = $data;
}
else {
$files[$entry->getFilename()] = (object)array(
'type' => 'file',
'name' => $entry->getFilename(),
'object' => $entry,
'active' => $this->isActive($entry)
);
}
}
uksort($dirs, 'strnatcmp');
uksort($files, 'strnatcmp');
return array_values(array_merge($dirs, $files));
}
public function get() {
return $this->_get(
new RecursiveDirectoryIterator($this->root)
);
}
public function outputUl($dirTree = null) {
if ($dirTree === null) {
$dirTree = $this->get();
}
echo '<ul>';
foreach ($dirTree as $element) {
$classes = array($element->type);
if ($element->type === 'dir') {
if ($element->active) {
$classes[] = 'active';
}
echo '<li class="', implode(' ', $classes), '">';
echo '<a href="', $this->getLink($element->object),'">';
echo $element->name;
echo '</a>';
if (sizeof($element->children) > 0) {
$this->outputUl($element->children);
}
echo '</li>';
}
else {
if ($element->active) {
$classes[] = 'active';
}
echo '<li class="', implode(' ', $classes), '">';
echo '<a href="', $this->getLink($element->object),'">';
echo $element->name;
echo '</a>';
echo '</li>';
}
}
echo '</ul>';
}
}
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>DirTree</title>
<style type="text/css">
#dirTree a {
text-decoration: none;
color: #171717;
}
#dirTree .file a {
color: #999999;
}
#dirTree .active > a {
font-weight: bold;
}
</style>
</head>
<body>
<div id="dirTree">
<?php
$dirTree = new DirTree(
'.',
isset($_GET[DirTree::URL_KEY]) ? $_GET[DirTree::URL_KEY] : null
);
$dirTree->outputUl();
?>
</div>
</body>
</html>
I recently had to make something like it, so here is a function that does exactly that. Optionally, you can add classnames to files and folders to style them with CSS. All folders are displayed 'opened', although with a little JS you can make a function to add some 'open-close' behaviour to the list.
<?php
/**
* function makeDirectoryTree
* iterates recursively through a directory
* and lists it in an unordered list
*
* usage: echo makeDirectoryTree(relative/path/to/directory);
*
* @param string $pathname
* @return string
*/
function makeDirectoryTree($pathname){
$path = realpath($pathname);
if(!is_dir($path)){
return "Path does not exist!";
}
$foldertree = new DOMDocument();
/*
* the rootelement of the tree
*/
$ul[""] = $foldertree->createElement('ul');
$ul[""]->setAttribute('id', 'foldertree_root');
$foldertree->appendChild($ul[""]);
/*
* Files in rootfolder
* if not iterated separately, these files will appear alphabetically between the folders
* instead of on top of the list
*
*/
$iterator = new DirectoryIterator($path);
foreach ($iterator as $fileinfo) {
if ($fileinfo->isFile()) {
/*
* the random id could be useful if you want to manipulate an element with JS
* for instance to 'open' or 'close' the folders
* also, add an optional classname to files and folders, so you can
* do some markup with CSS, for instance:
* .folder {color: #f00; list-style-image: url('path/to/images/folder.png');}
* .file {color: #999; list-style-image: url('path/to/images/file.png');}
*/
$random_id = md5(microtime());
$li_element = $foldertree->createElement('li', $fileinfo->getFilename());
$li_element->setAttribute('id', 'li_' . str_ireplace(' ', '', $random_id));
$li_element->setAttribute('class', 'file'); //optional classname
$ul[""]->appendChild($li_element);
}
}
/*
* iterate through the other folders
*/
$objects = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path), RecursiveIteratorIterator::SELF_FIRST);
foreach($objects as $name=>$value){
if($value->isDir()){
$relative_path = str_ireplace($path . DIRECTORY_SEPARATOR, "", $value->getPathname());
$path_array = explode(DIRECTORY_SEPARATOR, $relative_path);
$new_dir = array_pop($path_array);
$directory_up = implode(DIRECTORY_SEPARATOR, $path_array);
$random_id = md5(microtime());
$li[$relative_path] = $foldertree->createElement('li', $new_dir);
$li[$relative_path]->setAttribute('id', 'li_' . str_ireplace(' ', '', $random_id));
$li[$relative_path]->setAttribute('class', 'folder'); //optional classname
$ul[$relative_path] = $foldertree->createElement('ul');
$ul[$relative_path]->setAttribute('id', 'ul_' . str_ireplace(' ', '', $random_id));
$li[$relative_path]->appendChild($ul[$relative_path]);
$ul[$directory_up]->appendChild($li[$relative_path]);
$iterator = new DirectoryIterator($value->getPathname());
foreach ($iterator as $fileinfo) {
if ($fileinfo->isFile()) {
$random_id = md5(microtime());
$li_element = $foldertree->createElement('li', $fileinfo->getFilename());
$li_element->setAttribute('id', 'li_' . str_ireplace(' ', '', $random_id));
$li_element->setAttribute('class', 'file'); //optional classname
$ul[$relative_path]->appendChild($li_element);
}
}
}
}
return $foldertree->saveHTML();
}
?>