PHP recursive directory menu (different approaches) - php

I'm trying to create a PHP menu which displays the directories and files in each directory in a list, with links to each file in those directories (but not links to the directories themselves). The directories are numerical as years '2013', '2014', etc., and the files in these directories are PDFs.
In essence:
--- 2013 (not linked)
--------------- 01.pdf (linked)
--------------- 02.pdf (linked)
--------------- 03.pdf (linked)
--- 2014 (not linked)
--------------- 04.pdf (linked)
--------------- 05.pdf (linked)
--------------- 06.pdf (linked)
Currently, my code looks like this:
<?php
function read_dir_content($parent_dir, $depth = 0){
if ($handle = opendir($parent_dir))
{
while (false !== ($file = readdir($handle)))
{
if(in_array($file, array('.', '..'))) continue;
if( is_dir($parent_dir . "/" . $file) ){
$str_result .= "<li>" . read_dir_content($parent_dir . "/" . $file, $depth++) . "</li>";
}
$str_result .= "<li><a href='prs/{$file}'>{$file}</a></li>";
}
closedir($handle);
}
$str_result .= "</ul>";
return $str_result;
}
echo "<ul>".read_dir_content("prs/")."</ul>";
?>
However, this creates a complete mess when processed. (Unfortunately I cannot post an image as I am a new user, but if it's not too taboo, I will provide a sneaky link to it: http://i.stack.imgur.com/gmIFz.png)
My questions/requests for help on:
1. Why is the order reversed alphanumerically, i.e. why is 2013 at the bottom of the list and 2014 at the top?
2. How can I remove the links for the directories while keeping the links for the PDFs?
3. I'm confused over why there are empty list items at the end of each directory's list and why they are not logically/consistently spaced, i.e. why are the 01, 02, 03 PDFs not subordinate to the 2013 (see 'in essence' spacing above)?
N.B. I am new to programming and PHP, so please bear in mind that my obvious mistake/s might be very simple. Sorry in advance if they are.
edit: what would also be a massive bonus would be to get rid of the ".pdf"s on the end of the filenames, but that is probably an entirely different question/matter.

PHP5 has class called RecursiveDirectoryIterator
This code :
Sorts the list as you want (2013 first then 2014)
Does not show the links to the directories
Solves the formatting troubles
BONUS: removes the pdf extension
..
$myLinks = array();
$dirIterator = new RecursiveDirectoryIterator($parent_dir);
//iterates main prs directory
foreach ($dirIterator as $file) {
// If its a directory, it will iterate it's children (except if it's . or ..)
if ($file->isDir() && $file->getFilename() != '.' && $file->getFilename() != '..') {
$dir = new RecursiveDirectoryIterator($file->getRealPath());
$myLinks[$file->getFilename()] = array();
foreach ($dir as $subFile) {
//If it finds a file whose extension is pdf
if ($subFile->isFile() && $subFile->getExtension() == 'pdf') {
// Gets its filename and removes extension
$fname = str_replace('.pdf', '', $subFile->getFilename());
// adds the file information to an array
$myLinks[$file->getFilename()][$fname] = "prs/{$file->getFilename()}/{$subFile->getFilename()}";
}
}
}
}
//Sort our array alphabetically (and numerically) and recursively
ksort_recursive($myLinks);
function ksort_recursive(&$array)
{
if (!is_array($array)) return;
ksort($array);
foreach ($array as $k=>$v) {
ksort_recursive($array[$k]);
}
}
// now we print our links as a unordered list
print '<ul>';
foreach ($myLinks as $year => $val) {
print "<li>$year";
foreach ($val as $name => $link) {
print "<li><a href='$link'>$name</a></li>";
}
print '</li>';
}
print '</ul>';

First off I see this line in there
$str_result .= "</ul>";
but I don't see an opening ul tag. This is probably the source of the crazy looking result.
1) I would use scandir instead of readdir as it would let you set the sort order.
2,3) Get rid of $str_result .= "</ul>"; and try something like this in your inside your while loop to remove the dir links and get the order right: (NOTE: I have not run this)
if( ! in_array($file, array('.', '..')) ) {
if( is_dir($parent_dir . "/" . $file) ){
$str_result .= "<li>{$file}</li>";
$str_result .= "<ul>";
$str_result .= "<li>" . read_dir_content($parent_dir . "/" . $file, $depth++) . "</li>";
$str_result .= "</ul>";
} else {
$str_result .= "<li><a href='prs/{$file}'>{$file}</a></li>";
}
}

Related

PHP function error in generating directory tree as a nested html list [duplicate]

This question already has answers here:
RecursiveIteratorIterator and RecursiveDirectoryIterator to nested html lists
(2 answers)
Closed 4 years ago.
I have a directory that has a depth of at least 3 or 4 levels. I'm trying to recurse through the directory tree as deep and generate a HTML unordered nested list.
The code I'm using creates a nested HTML list but it is not in the correct directory depth order. This is what it is currently producing which is not correct.
This is what I am trying to achieve
My current code is below. Which part do I need to modify to make this work?
<?php
function read_dir_tree($parent_dir, $depth = 0){
$str_result = "";
$str_result .= "<li>". dirname($parent_dir) ."</li>";
$str_result .= "<ul>";
if ($handle = opendir($parent_dir))
{
while (false !== ($file = readdir($handle)))
{
if(in_array($file, array('.', '..'))) continue;
if( is_dir($parent_dir . "/" . $file) ){
$str_result .= "<li>" . read_dir_tree($parent_dir . "/" . $file, $depth++) . "</li>";
}
$str_result .= "<li>{$file}</li>";
}
closedir($handle);
}
$str_result .= "</ul>";
return $str_result;
}
function read_dir($tp){
$link = ($tp);
echo "<ul>".read_dir_tree($link)."</ul>";
}
?>
I call this PHP from HTML using:
<?php
read_dir("media");
?>
max514, this has already been answered here with a full working example.
RecursiveIteratorIterator and RecursiveDirectoryIterator to nested html lists

php loop through files in subfolders in folder and get file paths

Im really new to PHP i searched google to find a correct script that loops through all subfolders in a folder and get all files path in that subfolder
<?php
$di = new RecursiveDirectoryIterator('posts');
foreach (new RecursiveIteratorIterator($di) as $filename => $file) {
echo $filename. '<br/>';
}
?>
So i have folder 'posts' in which i have subfolder 'post001' in which i have two files
controls.png
text.txt
And the code above echos this
posts\.
posts\..
posts\post001\.
posts\post001\..
posts\post001\controls.png
posts\post001\text.txt
But i want to echo only the file paths inside these subfolders like this
posts\post001\controls.png
posts\post001\text.txt
The whole point of this is that i want to dynamically create divs for each subfolder and inside this div i put img with src and some h3 and p html tags with text equal to the .txt file so is this proper way of doing that and how to remake my php script so that i get just the file paths
So I can see the answers and they are all correct but now my point was that i need something like that
foreach( glob( 'posts/*/*' ) as $filePath ){
//create div with javascript
foreach( glob( 'posts/$filePath/*' ) as $file ){
//append img and h3 and p html tags to the div via javascript
}
//append the created div somewhere in the html again via javascript
}
So whats the correct syntax of doing these two foreach loops in php im really getting the basics now
See if this works :)
$di = new RecursiveDirectoryIterator('posts');
foreach (new RecursiveIteratorIterator($di) as $filename => $file) {
if ((substr($file, -1) != '.') && (substr($file, -2) != '..')) {
echo $file . '<br/>';
}
}
<h1>Directory Listing</h1>
<?php
/**
* Recursive function to append the full path of all files in a
* given directory $dirpath to an array $context
*/
function getFilelist($dirpath, &$context){
$fileArray = scandir($dirpath);
if (count($fileArray) > 2) {
/* Remove the . (current directory) and .. (parent directory) */
array_shift($fileArray);
array_shift($fileArray);
foreach ($fileArray as $f) {
$full_path = $dirpath . DIRECTORY_SEPARATOR . $f;
/* If the file is a directory, call the function recursively */
if (is_dir($full_path)) {
getFilelist($full_path, $context);
} else {
/* else, append the full path of the file to the context array */
$context[] = $full_path;
}
}
}
}
/* $d is the root directory that you want to list */
$d = '/Users/Shared';
/* Allocate the array to store of file paths of all children */
$result = array();
getFilelist($d, $result);
$display_length = false;
if ($display_length) {
echo 'length = ' . count($result) . '<br>';
}
function FormatArrayAsUnorderedList($context) {
$ul = '<ul>';
foreach ($context as $c) {
$ul .= '<li>' . $c . '</li>';
}
$ul .= '</ul>';
return $ul;
}
$html_list = FormatArrayAsUnorderedList($result);
echo $html_list;
?>
Take a look at this:
<?php
$filename[] = 'posts\.';
$filename[] = 'posts\..';
$filename[] = 'posts\post001\.';
$filename[] = 'posts\post001\..';
$filename[] = 'posts\post001\controls.png';
$filename[] = 'posts\post001\text.txt';
foreach ($filename as $file) {
if (substr($file, -4, 1) === ".") {
echo $file."<br>";
}
}
?>
Result:
posts\post001\controls.png
posts\post001\text.txt
What this does is checking if the 4th last digit is a dot. If so, its an extension of three letters and it should be a file. You could also check for specific extensions.
$ext = substr($file, -4, 4);
if ($ext === ".gif" || $ext === ".jpg" || $ext === ".png" || $ext === ".txt") {
echo $file."<br>";
}

php scandir sort first single files then folders and subfolders

I have the following files and folders inside my '/templates' folder:
/templates/folder/contact.html
/templates/folder/index.html
/templates/folder/search.html
/templates/index.html
/templates/music.html
/templates/path/index.html
/templates/path/test.html
/templates/video.html
Now I want to get the list sorting first the single files,
and then the folders and subfolders, I mean:
/index.html
/music.html
/video.html
/folder/contact.html
/folder/index.html
/folder/search.html
/path/index.html
/path/test.html
And I am using this code, but I can't figure out how to sort them in that order.. Please help
<?php
function listFolderFiles($dir, $parent = ''){
$ffs = scandir($dir);
echo '<ol style="padding:0;">';
foreach($ffs as $ff){
if($ff != '.' && $ff != '..'){
echo '<li>'.$parent.'/'.$ff;
if(is_dir($dir.'/'.$ff)){
listFolderFiles($dir.'/'.$ff, $ff );
}
echo '</li>';
}
}
echo '</ol>';
}
listFolderFiles('templates');
?>
Please Note: also actually this code outputs the subfolders one time as "empty", e.g. /folder
and the content inside the subfolders without the initial slash: folder/contact.html
but I need to have the initial slash like: /folder/contact.html
and remove the "empty" subfolders
If you do not need to have another alphabetical sorting there, you can go with storing directories (instead of recursive call) into an array and call listFolderFiles for all the elements in that array at the end of function.
If you want to stick with your original recursive approach - without filename sorting (as outlined by #peter-vančo):
function listFolderFiles($dir, $parent = '')
{
$ffs = scandir($dir);
$subfolders = array();
echo '<ol style="padding:0;">';
foreach($ffs as $ff)
{
if (!is_dir($dir . '/' . $ff))
{
echo '<li>'.$parent.'/'.$ff . '</li>';
}
else if($ff != '.' && $ff != '..')
{
$subfolders[$ff] = $dir.'/'.$ff;
}
}
foreach($subfolders as $ff => $subfolderDir)
{
listFolderFiles($subfolderDir, '/' . $ff);
}
echo '</ol>';
}
Here is a simple Recursive iterator which one split Every items to: Folders and Files:
$MójFolder = __DIR__;
$Pliki = array('Pliki'=>array(), 'Foldery'=>array());
$Foldery = [];
$SkanerKatalogówIPlików = new RecursiveDirectoryIterator($MójFolder, RecursiveDirectoryIterator::SKIP_DOTS);
$SkanujWszystkiePodkatalogi = new RecursiveIteratorIterator($SkanerKatalogówIPlików, RecursiveIteratorIterator::SELF_FIRST);
foreach($SkanujWszystkiePodkatalogi as $WszystkiePlikiIFoldery){
$Ścieżka = str_replace($MójFolder, '', $WszystkiePlikiIFoldery);
if($WszystkiePlikiIFoldery->isDir()){
$Pliki['Foldery'][] = '.' . $Ścieżka .'/';
natcasesort($Pliki['Foldery']);
}elseif($WszystkiePlikiIFoldery->isFile()){
$Pliki['Pliki'][] = $Ścieżka ;
}
}

Print out questions in sequential order in PHP

Problem:
I have a zip file that contains 13 xml files. Each file, except for the first one, contain a quiz question and several answers. When I upload the file to the below script it prints out the questions and the answers correctly, but NOT in order. The order of questions randomly shift each time I upload the zip-file.
Question:
Is there a way I can utilize the file names to tell the script to print out the questions in sequential order every time?
Zip-file contain:
imsmanifest.xml
item101008.xml
item101009.xml
item101010.xml
item101011.xml
item101012.xml
item101013.xml
item101014.xml
item101015.xml
item101016.xml
item101017.xml
item101018.xml
item101019.xml
PHP-script (warning, long script):
<?php
//Initialize counter
$i = 0;
//Go through each file
while (($file = readdir($dh)) !== false)
{
//Skipt the first loop
if ($i > 1)
{
//Ignore misc file
if ($file != 'imsmanifest.xml')
{
//Create new DOM document
$dom= new DOMDocument();
//Load XML file
$dom->load('uploads/' . $file);
//Do not preserve white space
$dom->preserveWhiteSpace = false;
//Check if correct answers should be displayed
if (isset($_POST['XMLAnswers']))
{
//Get correct answer
$correct = $dom->getElementsByTagName( "correctResponse" )->item(0)->nodeValue;
//Get question
$questions = $dom->getElementsByTagName('p')->item(0)->nodeValue;
//Print out question
echo '<h4>' . htmlspecialchars($questions) . '</h4>' . "\n";
//Get answers
$domTable = $dom->getElementsByTagName("simpleChoice");
//Loop through each answer
foreach ($domTable as $answers)
{
//Delete potential unnecessary tags
$pattern = array(
'<p xmlns="http://www.imsglobal.org/xsd/imsqti_v2p1">',
'</p>'
);
//Check if answer is correct one
if ($correct == $answers->getAttribute('identifier'))
{
//Print out correct answer
echo '<span style="color:red;">' . utf8_decode(str_replace($pattern, '', innerHTML($answers))) . '</span><br />' . "\n";
}
else
{
//Print out answer
echo utf8_decode(str_replace($pattern, '', innerHTML($answers))) . '<br />' . "\n";
}
}
}
}
}
//Increment counter
$i++;
}
?>
Rather than using opendir/readdir, use scandir. See http://www.php.net/manual/en/function.scandir.php. scandir returns you a sorted array of files in the directory. You should be able to drop this in and have your code work with minimal changes, other than replacing the outer while readdir loop with:
$files = scandir($dir);
foreach ($files as $file) {
//your current code
}

PHP Directories

Can someone please xplain this code. Im reading larry ullmans book on php and i dont get this part. Thanks in advance!!
$search_dir = '.';
$contents = scandir($search_dir);
print '<h2>Directories</h2>
<ul>';
foreach ($contents as $item) {
if ( (is_dir($search_dir . '/' . $item)) AND (substr($item, 0, 1) != '.') ) {
print "<li>$item</li>\n";
}
}
print '</ul>';
It shows you list of all directories in current directory
I'll repost your code with comments to exaplain what each line does.
$search_dir = '.'; //Set the directory to search. "." means the current one.
$contents = scandir($search_dir); //scan the directory and return its results into $contents
print '<h2>Directories</h2>
<ul>';
foreach($contents as $item) { //Iterate through the array and for each item...
//If the item is a directory AND it doesn't start with a . (which means the current one)...
if ((is_dir($search_dir.'/'.$item)) AND(substr($item, 0, 1) != '.')) {
print "<li>$item</li>\n"; //Print it
}
}
print '</ul>';
In short, it prints out an output of the directories inside the directory the script is running in.

Categories