How to sort a filelist array so that folders are first?


#1

I am fairly new to PHP and have been struggling for a few days on something that seems trivial. All I’m try to do is sort an array of files and folders so that the folders are listed first and then the files are alphabetically listed after. The files are coming from an FTP server and are being read into the array like this:

$backdir = substr($ftp_remote_dir, 0, strrpos $ftp_remote_dir, "/")); if($backdir == "") { $backdir = "/"; } $mylist = array(); $mylist = $newftp->get_file_list($mydir); rsort($mylist); // $files = $newftp->parse_ftp_rawlist($mylist);

The rsort puts the folders first but then sorts the files in to reverse size order. Please can someone put me out of my misery and tell me what I have to do to get them sorted so the folders are first then the files after all in alphabetical order

Many thanks. Ben. :cry:


#2

The same question was asked a few days ago.

http://phphelp.com/forums/viewtopic.php … ight=usort


#3

I read that post earlier and tried that and it didn’twork. Please can you spoon-feed me and type exactly what I have to type for it to work for my specific situation.

many thanks


#4

Try something out, I’ll correct errors and point you in the right direction. I don’t like spoon-feeding. Either that, or ask more specific questions. What is blocking you?


#5

I have tried adding the code that you helped the other guy with but this doesn’t appear to do what I need.

It is seperating the files from the folders but the files are still being listed in size order and not alphabetical order and the folders are being listed last.

This is the complete code listing for what I’m trying to do. I hope this is not too garbled for you to read:

[code]

<?php session_start(); //BS 20/10/06 //Code will assign the inputs from index.php to the SESSION Varibles. if ($_POST['Connect']) { foreach($_POST as $key => $value) { if ($key == "") { echo "All form fields are required."; exit(); } } $_SESSION['ftp_label'] = $_POST['ftp_label']; $_SESSION['ftp_server'] = $_POST['ftp_server']; $_SESSION['ftp_user_name'] = $_POST['ftp_user_name']; $_SESSION['ftp_user_pass'] = $_POST['ftp_user_pass']; $_SESSION['ftp_port'] = $_POST['ftp_port']; } //Assign SESSION varibles to name varibles for easy accessing. $ftp_label = $_SESSION['ftp_label']; $ftp_server = $_SESSION['ftp_server']; $ftp_user_name = $_SESSION['ftp_user_name']; $ftp_user_pass = $_SESSION['ftp_user_pass']; $ftp_port = $_SESSION['ftp_port']; //Adds the class page so that functions can be used require_once('classes/class.php'); //Puts the header on the top of the page require_once('includes/header.php'); //Establish new connection $newftp = new myftp; $result = $newftp->connect($ftp_server, $ftp_user_name, $ftp_user_pass, $ftp_port); $ftp_remote_dir = "/"; $backdir = substr($ftp_remote_dir, 0, strrpos($ftp_remote_dir, "/")); echo "

"; $v="_zip"; function cmp($a,$b) { if(is_dir($a) && is_dir($b)) return strcmp($a,$b); elseif(!is_dir($a) && !is_dir($b)) return strcmp($a,$b); elseif(is_dir($a)) return -1; else return 1; } //A set of nested IF statements to call functions from class.php which will respectively //Get a remote directory path, save a file (this section has been replaced), //delete entire directories, create directories, delete fies, and upload files. if (!$result){ $mydir = $newftp->get_dir(); if ($_GET['dir']) { $ftp_remote_dir = $_GET['dir']; $ftp_remote_dir = preg_replace('/(../)+/i', "/", $ftp_remote_dir); $mydir = $newftp->change_dir($ftp_remote_dir); $mydir = $ftp_remote_dir; } else { $ftp_remote_dir = $mydir; } if ($_GET['action'] == "save") { $fp = tmpfile(); fwrite($fp, $_POST['content']); rewind($fp); $uploadfile = $newftp->upload_open_file($_POST['file'], $fp); } if ($_GET['action'] == "rename") { $rename = $newftp->rename_file($_POST['oldname'], $_POST['newname']); } if ($_GET['action'] == "del_dir") { $deldirectory = $newftp->del_dir($_GET['delete']); } if ($_GET['action'] == "newdir") { $newdir = $newftp->new_dir($_POST['dir_name']); } if ($_GET['action'] == "delete") { $deletefile = $newftp->delete_file($file); } if ($_GET['action'] == "upload") { $destination_file = $_FILES['file']['name']; $source_file = $_FILES['file']['tmp_name']; $uploadfile = $newftp->upload_file($destination_file, $source_file, FTP_BINARY); } //Download files and folders to an array... $backdir = substr($ftp_remote_dir, 0, strrpos($ftp_remote_dir, "/")); if($backdir == "") { $backdir = "/"; } $mylist = array(); $mylist = $newftp->get_file_list($mydir); usort($mylist,cmp); $files = $newftp->parse_ftp_rawlist($mylist); $total = count($files)-1; $x = -1; echo "
You are curently in folder: /$ftp_user_name$mydir

"; echo ""; echo "
"; echo ""; foreach($files as $data) { $x+=1; if ($data['perms'] == "Attributes") { //Display the folders/files in a table with the actions that can be performed next to them echo ""; } elseif ($data['is_dir'] == TRUE) { if ($mydir == "/") { $target = $mydir.$data['name']; } else { $target = $mydir."/".$data[name]; } //The object is a folder so the folder options are diplayed echo ""; } elseif ($data['is_link']) { echo ""; } else { //The object is as file so the download option links to download.php and the size is displayed. echo ""; } } echo "
$data[name] $data[size] Added Select files to Download Delete?
$x $data[name] $data[date] DELETE?
$x $data[name] ".round($data['size'] / 1024)."Kb ($data[size] bytes) $data[date] DELETE?
$x "; $ext = strrchr($data[name],"."); $imagetype = $ext; if ($ext == ".jpg") { $imagetype = "jpg"; } elseif ($ext == ".bmp"){ $imagetype = "bmp"; } elseif ($ext == ".zip"){ $imagetype = "zip"; } elseif ($ext == ".mxd"){ $imagetype = "mxd"; } elseif ($ext == ".png"){ $imagetype = "png"; } elseif ($ext == ".gif"){ $imagetype = "gif"; } elseif ($ext == ".txt"){ $imagetype = "txt"; } elseif ($ext == ".xls"){ $imagetype = "xls"; } elseif ($ext == ".pdf"){ $imagetype = "pdf"; } elseif ($ext == ".PDF"){ $imagetype = "pdf"; } elseif ($ext == ".tif"){ $imagetype = "tif"; } elseif ($ext == ".tiff"){ $imagetype = "tif"; } elseif ($ext == ".ppt"){ $imagetype = "ppt"; } elseif ($ext == ".loc"){ $imagetype = "loc"; } elseif ($ext == ".htm"){ $imagetype = "htm"; } elseif ($ext == ".html"){ $imagetype = "htm"; } elseif ($ext == ".exe"){ $imagetype = "exe"; } elseif ($ext == ".mig"){ $imagetype = "mig"; } elseif ($ext == ".sgy"){ $imagetype = "sei"; } elseif ($ext == ".stk"){ $imagetype = "sei"; } elseif ($ext == ".las"){ $imagetype = "sei"; } elseif ($ext == ".tr2"){ $imagetype = "sei"; } elseif ($ext == ".spt"){ $imagetype = "spt"; } elseif ($ext == ".doc"){ $imagetype = "doc"; } elseif ($ext == ".jpeg"){ $imagetype = "jpg"; } elseif ($ext == ".shp"){ $imagetype = "shp"; } elseif ($ext == ".xml"){ $imagetype = "xml"; } elseif ($ext == ".mov"){ $imagetype = "mov"; } elseif ($ext == ".avi"){ $imagetype = "mov"; } else $imagetype = "unk"; echo" $data[name] "; $g=($data['size']); if ($g < 1024) {$z= $g.' Bytes'; } elseif ($g < 1024*1024) {$z= round(($g / 1024)). 'KB'; } elseif ($g < (1024*1024*1024)) {$z= round((($g/1024)/1024)).' MB'; } elseif ($g >(1024*1024*1024*1024)) {$z= round(((($g/1024)/1024)/1024)).' GB'; } else $z= $g.' Bytes'; echo" $z $data[date] DELETE?
"; echo ""; echo ""; echo "
"; echo "
Up one level Root Folder
"; // The upload to current folder link and create new folder are shown at the bottom. echo"

Please be patient while your file uploads.

"; echo "
Zip selected files for download


Upload file to Current Folder
Create a New Folder
"; // Once the code has been completed the link to the FTP server is disconnected $newftp->ftp_disconnect(); } else { echo "No Connection Established
"; } // The code that is written in footer.php is displayed require_once('includes/footer.php'); ?>[/code]

I’m sorry for dumping out all of the code for the page, but hopefully this will help you to see the problem and suggest a way I can resolve it?

Many thanks for you continued help and advice. Ben.


#6

Did you try using print_r() before and after the call to usort to see what it changed?


#7

The results are being diplayed on the page I’m viewing so I can see exactly what is changing. The array is going from being listed completely alphabetically (files mixed with folders) to folders being listed seperately at the end of the array with the files being listed in size order.

Here is an output of the array using print_r before the sort:
Array ( [0] => total 41819 [1] => drwxrw-rw- 1 root root 0 Jan 12 10:09 . [2] => drwxrw-rw- 1 root root 0 Jan 12 10:09 … [3] => -rwxrw-rw- 1 root root 20480 Jan 12 09:56 desc.doc [4] => -rwxrw-rw- 1 root root 334961 Jan 12 09:53 DSCF0100.JPG [5] => -rwxrw-rw- 1 root root 162785 Jan 12 10:09 FTPtoPHP.pdf [6] => -rwxrw-rw- 1 root root 447107 Jan 9 17:24 SO84-202.gif [7] => drwxrw-rw- 1 root root 0 Jan 12 09:55 Text_files [8] => -rwxrw-rw- 1 root root 1397222 Jan 9 17:26 whirl2560x1024.png [9] => -rwxrw-rw- 1 root root 19045881 Jan 11 09:55 wpc54gv2_driver_utility_v2[1].02.zip )

and here is an output after the sort:
Array ( [0] => -rwxrw-rw- 1 root root 20480 Jan 12 09:56 desc.doc [1] => -rwxrw-rw- 1 root root 162785 Jan 12 10:09 FTPtoPHP.pdf [2] => -rwxrw-rw- 1 root root 334961 Jan 12 09:53 DSCF0100.JPG [3] => -rwxrw-rw- 1 root root 447107 Jan 9 17:24 SO84-202.gif [4] => -rwxrw-rw- 1 root root 1397222 Jan 9 17:26 whirl2560x1024.png [5] => -rwxrw-rw- 1 root root 19045881 Jan 11 09:55 wpc54gv2_driver_utility_v2[1].02.zip [6] => drwxrw-rw- 1 root root 0 Jan 12 09:55 Text_files [7] => drwxrw-rw- 1 root root 0 Jan 12 10:09 . [8] => drwxrw-rw- 1 root root 0 Jan 12 10:09 … [9] => total 41819 )

All I need to do is sort the array so that the folders are first in alphabetical order and the files then follow after also in alphabetical order, why does this trivial problem seem to be causing so much grief :-?

Many thanks for you continued help. Ben.


#8

Oh, sorry about misleading you. I didn’t know you received the information in that format.

You need to compare using only the last portion of the string for the filename and check the first character to know if it’s a directory. The function will become something like:

[php]
function cmp($a,$b) {
$aIsDir = ( $a{0} == ‘d’ );
$aIsDir = ( $b{0} == ‘d’ );

// Double check these
$a = substr( $a, strrpos($a, ' ') );
$b = substr( $b, strrpos($b, ' ') );

if($aIsDir && $bIsDir) return strcmp($a,$b); 
elseif(!$aIsDir && !$bIsDir) return strcmp($a,$b); 
elseif($aIsDir) return -1; 
else return 1; 

}
[/php]

Note that I did not have time to test it, so it might not work out of the box.


#9
:) They are kinda alphabetical but not quite. They are not sorted on date modified, date created or files contained within. This is what some test folders look like:

[ul]254
About
Office Docs
New Folder
New Folder2
Images
ZZz
apple
image
zz[/ul]

All I want to be able to do now is list the files in alphabetical order not caring whether the filename begins with a capital or not and sort the directories.

Hopefully you will have seen this kind of thing before and will have an easy fix to help solve my problem entirely.

Once again many thanks for your continued support. Ben.


#10

Very simple, the strcmp() function uses the ASCII values for the comparison. You can simply replace it when a more appropriate one.

strcasecmp() will do it in a case insensitive way.
strnatcasecmp() will do in insensitive, but will also place 10foo and 100foo in a logical way (at least, to humans).


#11

My files and folders are now separated with the folders first and the files are in alphabetical order. MANY THANKS BANE!!! :wink: They are being listed like this:
[ul]Alpha
Office Docs
New Folder
Total[/ul]

Do you have any ideas as to what may be going on? Or how to resolve this?
I’m pretty sure I need to edit this line:[php]
elseif($aIsDir) return -1;
[/php]But I’m not too sure what to change it to?

Many thanks for all your help, Ben.


#12

I have figured out what is causing this wierd sorting order and have since tested the files sorting as well and they are doing the same thing.

What is happening is that the sorting is being made on the first letter of the last word in the filename or directory name and not the first letter of the entire name.

Is there a way that this can be built in to the cmp function?
OR
Is there a way to automatically change ‘spaces’ to ‘underscores’ when reading the filelist array? I know you can use:
[php]str_replace(" ", “_”, trim($str));[/php]
to replace the spaces with underscores on a single variable but in the array it doesn’t seem to work. :-?

Many thanks for helping Bane. Ben Sayers.


#13

Many thanks for all of your help Bane, I have developed a work around for the sorting issue. I am automatically replacing ‘spaces’ with ‘underscores’ when files are uploaded so therefore the sorting on the final word in the filename is not an issue any more.

Anyone else reading this wishing to remove spaces on file upload, here is the code I used:
[php]if ($_GET[‘action’] == “upload”) {
$destination_file = $FILES[‘file’][‘name’];
$destin = str_replace(" ", "
", trim($destination_file));
$source_file = $_FILES[‘file’][‘tmp_name’];
$uploadfile = $newftp->upload_file($destin, $source_file, FTP_BINARY);
}
[/php]

Thanks. Ben. :D