Is there a speedy and efficient way to scan through a directory and generate markup based on files found?
I wrote this block of code and what it does is set path variables depending on information pulled from the database. Then it searches through directories and pulls out files that I want to insert into my page.
I use the Smarty template engine, my problem is that even though this works to the extent I want it to. It runs really slow and takes a while to scan through the directories pull the files and make the markup before the whole page is loaded.
// Load variables based on if the user has a custom theme applied or a default one
$theme_name = $default->get_theme('theme_dir_name', 'dash');
if($users->get_settings('theme_is_custom', $auth->session->get('user_id')) == 1)
{
$css_path = "/".$auth->session->get("user_name")."/css";
$theme_dir = dirname(__FILE__) . "/assets/users/".$users->get_user_id($_GET['user'])."/themes/".$theme_name."/tpl/";
$s->assign("css_dir", $css_path."/".$theme_name);
$s->assign("js_dir" , "/".$_GET['user']."/js/".$theme_name);
}else{
$css_path = "/css";
$theme_dir = dirname(__FILE__) . "/assets/default/themes/".$theme_name."/tpl/";
$s->assign("css_dir", $css_path."/".$theme_name);
$s->assign("js_dir" , "/js/".$theme_name);
}
// Load modules
foreach($users->get_active_module($auth->session->get('user_id')) as $m)
{
if(@$m['module_is_custom'] == 1)
{
$path = "/".$auth->session->get("user_id")."/modules/".$m['module_folder_name']."/index.php";
$dir = "/".$auth->session->get("user_id")."/modules/".$m['module_folder_name'];
}else{
$path = dirname(__FILE__)."/assets/default/modules/".$m['module_folder_name']."/index.php";
$dir = dirname(__FILE__)."/assets/default/modules/".$m['module_folder_name'];
$js = "/modules/default/".$m['module_folder_name']."/js/";
$css = "/modules/default/".$m['module_folder_name']."/css/";
}
$css_module = "开发者_C百科";
$js_module = "";
$module = $s->fetch($path);
if($handle = opendir($dir."/css/"))
{
while(false !== ($file = readdir($handle)))
{
if($file != "." && $file != ".."){
$css_module .= '<link rel="stylesheet" href="'.$css.$file.'" />';
}
}
closedir($handle);
}
if($handle = opendir($dir."/js/"))
{
while(false !== ($file = readdir($handle)))
{
if($file != "." && $file != "..")
{
$js_module .= '<script type="text/javascript" src="'.$js.$file.'"></script>';
}
}
closedir($handle);
}
$s->assign($m['module_folder_name']."_module", $css_module."\n".$js_module."\n".$module);
}
EDIT:
function getFileList($dir)
{
$retval = array();
if(substr($dir, -1) != "/")
$dir .= "/";
$d = @dir($dir) or die("getFileList: Failed opening directory $dir for reading");
while(false !== ($entry = $d->read()))
{
if($entry[0] == ".")
continue;
if(is_dir("$dir$entry"))
{
$retval[] = array( "name" => "$dir$entry/", "type" => filetype("$dir$entry"), "size" => 0, "lastmod" => filemtime("$dir$entry") );
}elseif(is_readable("$dir$entry")){
$retval[] = array( "name" => "$dir$entry", "type" => mime_content_type("$dir$entry"), "size" => filesize("$dir$entry"), "lastmod" => filemtime("$dir$entry") );
}
echo basename("$dir$entry")."<br />";
}
$d->close(); return $retval;
}
If you're on PHP 5.3 or later I'd suggest using the SPL FilesystemIterator
as an elegant solution for this.
One of the nice things about this approach is that you can make this recursive by swapping the iterator to RecursiveIteratorIterator
and RecursiveDirectoryIterator
.
You can also use the fileinfo
class instead of the deprecated mime_content_type()
.
Here's a drop-in replacement for Oliver's answer:
function getFileList($dir, $recursive = false)
{
$finfo = new finfo(FILEINFO_MIME);
$retval = array();
if ($recursive)
{
// Note: If RecursiveIteratorIterator::SELF_FIRST is removed it will use the default
// RecursiveIteratorIterator::LEAVES_ONLY and therefore ignore directories.
$iter = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir),
RecursiveIteratorIterator::SELF_FIRST);
}
else
{
$iter = new FilesystemIterator($dir);
}
foreach ($iter as $path => $info)
{
$filename = $info->getFilename();
if ("." === $filename[0])
{
// ignore hidden files on unix for compatability with the Oliver's function
// note that the default constructor flag FilesystemIterator::SKIP_DOTS will have skipped the . and .. files anyway.
continue;
}
$val = array("name" => $path,
"type" => $info->getType(),
"size" => $info->getSize(),
"lastmod" => $info->getMTime());
if ($info->isFile())
{
$fulltype = $finfo->file($path);
// $finfo->file() returns something like "application/octet-stream; charset=binary"
// the first part matches what mime_content_type() returns, ignore the rest for compatability with Oliver's function
$ftypeparts = explode(";", $fulltype, 2);
$val ["type"] = $ftypeparts[0];
}
$retval[] = $val;
}
return $retval;
}
SPL DirectoryIterator
on PHP 5.2 or later will do most of this as well, though you'll need to use mime_content_type()
.
use this function, I wrote it myself and use it in several projects
function getFileList($dir) {
$retval = array();
if(substr($dir, -1) != "/") $dir .= "/";
$d = @dir($dir) or die("getFileList: Failed opening directory $dir for reading");
while(false !== ($entry = $d->read())) {
if($entry[0] == ".") continue;
if(is_dir("$dir$entry")) {
$retval[] = array( "name" => "$dir$entry/", "type" => filetype("$dir$entry"), "size" => 0, "lastmod" => filemtime("$dir$entry") );
} elseif(is_readable("$dir$entry")) {
$retval[] = array( "name" => "$dir$entry", "type" => mime_content_type("$dir$entry"), "size" => filesize("$dir$entry"), "lastmod" => filemtime("$dir$entry") );
}
}
$d->close();
return $retval;
}
Please note the function I Posted above... other then that, do load first any data which you are going to use in arrays and then process the markup all in one go after you gathered all the data.
精彩评论