1

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: https://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.

Tom
  • 89
  • 8
  • 1
    Check this out: http://stackoverflow.com/questions/2183486/php-get-file-name-without-file-extension and also play with the examples on php.net regarding basename(), pathinfo() and glob(). – Ryan Nov 09 '13 at 06:24
  • Thanks, Ryan - Tivie kindly addressed this bonus question, but good to have a link to this documentation. Cheers. – Tom Nov 09 '13 at 06:37

2 Answers2

3

PHP5 has class called RecursiveDirectoryIterator

This code :

  1. Sorts the list as you want (2013 first then 2014)
  2. Does not show the links to the directories
  3. Solves the formatting troubles
  4. 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>';
Tivie
  • 18,864
  • 5
  • 58
  • 77
  • Here's the result when I added the line "$parent_dir = "prs/";" at the top (since I was getting an error otherwise): http://i.imgur.com/Ea7CxHH.png 1) The code is sorted into 2013, then 2014, but the numbers are not ordered. Do I have to re-run ksort on each group separately? 2) It's great that this iterates the children and not the directors (insofar as not making the directories links), but how can I make them appear but not as links (like I tried to illustrate in the first blockquote of my question). – Tom Nov 09 '13 at 05:59
  • @Tom Check my edited answer. Also, try to understand the bit of code I gave you. You shouldn't trust any code you get in the internet without understanding it. If you have any questions, I will gladly answer – Tivie Nov 09 '13 at 23:00
  • Thanks, Tivie. To get the folder names, can I add something like: $myDirs = array(); foreach ($dir as $folder) { $myDirs[$folder->getDirname()] = array(); ? But then, how do I make the PDFs subordinate? I think I need some sort of loop but how can I make new arrays each time which are specific to each directory? Do I create a loop around this current iterator loop which goes something like above? $myDirs = ... – Tom Nov 10 '13 at 02:43
  • Sorry, ignore that! I figured it out with your code. I edited the last section to be: print '
      '; foreach ($myLinks as $year => $val) { print "
    • $year
      • "; foreach ($val as $name => $link) { print "
      • $name
      • "; } print '
      '; } print '
    ';
    – Tom Nov 10 '13 at 02:56
1

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>";
    }

}
Gabriel Littman
  • 552
  • 3
  • 13
  • Thanks, Gabriel - especially for pointing out that obvious line! Good to be able to know (at least partly) where I went wrong. And scandir seems great, too! – Tom Nov 09 '13 at 06:39