Location: PHPKode > scripts > DirContent > dircontent/DirContent/Sort.php
<?php
/**
 * Class for sorting files and folders in some directory.
 *
 * Files and folders can be sorted by name, type or size.
 *
 * @subpackage DirContent
 * @author Nikola Posa <hide@address.com>
 * @license GNU General Public License
 */
class DirContent_Sort
{
	/**
	 * Path to directory which content is being sorted.
	 *
	 * @var string
	 */
	protected static $basePath;
	
	/**
	 * Files in some directory that are being sorted.
	 *
	 * @var array
	 */
	protected $files;

	/**
	 * Sorting type. It can be either string or array with type and 
	 * order by as key - value pairs.
	 *
	 * @var mixed
	 */
	protected static $sortBy;
	
	/**
	 * Prefix of sorting methods that are used as callbacks of 
	 * uasort() function.
	 *
	 * @var string
	 */
	protected $methodPrefix = 'sortBy';
	
	const ORDER_ASC  = 'asc';
    const ORDER_DESC = 'desc';
	
	/**
	 * Constructor.
	 *
	 * @param string Path to directory.
	 * @param array Files in that directory.
	 * @param mixed Sorting type.
	 * @return void
	 */
	public function __construct($basePath, $files, $sortBy)
	{
		$this->setBasePath($basePath);
		
		$this->setFiles($files);
		
		$this->setSortBy($sortBy);
	}
	
	/**
	 * Sets path to directory which is being proccessed.
	 *
	 * @param string Path to directory.
	 * @return void
	 */
	public function setBasePath($basePath)
	{
		if (!is_string($basePath)) {
			throw new Exception ('Invalid base path.');
		}
		
		self::$basePath = $basePath;
	}
	
	/**
	 * Stores array with file/folder names.
	 *
	 * @param array Files.
	 * @return void
	 */
	public function setFiles($files)
	{
		if (!is_array($files)) {
			throw new Exception ('File list parameter must be array.');
		}
		
		$this->files = $files;
	}
	
	/**
	 * Sets sorting type.
	 *
	 * @param mixed Sorting type.
	 * @return void
	 */
	public function setSortBy($sortBy)
	{
		if (!is_string($sortBy) && !is_array($sortBy)) {
			throw new Exception ('Sort by options parameter must be either string or array.');
		}
		elseif (is_array($sortBy)) {
			$order = current($sortBy);
			if ($order != self::ORDER_ASC && $order != self::ORDER_DESC) { 
				throw new Exception ('Unexisting option for sorting order supplied.');
			}
		}
		
		self::$sortBy = $sortBy;
	}
	
	/**
	 * Function that represents factory for calling sorting methods, 
	 * depending of passed sorting type.
	 *
	 * @param mixed Sorting type.
	 * @return void
	 */
	public static function sort($basePath, $files, $sortBy)
	{
		$DCSort = new self($basePath, $files, $sortBy);
		
		if (is_array($sortBy)) { //Array with type and order by as key - value pairs.
			$option = key($sortBy);
		}
		elseif (is_string($sortBy)) {
			$option = $sortBy; 
		}
		
		//Generating name of sorting method that'll be called.
		$method = $DCSort->methodPrefix . ucfirst($option);
		
		uasort($DCSort->files, array('DirContent_Sort', $method));
		
		return $DCSort->files;
	}
	
	/**
	 * Callback function for sorting files/folders by name.
	 *
	 * @param string First value to compare.
	 * @param string Second value to compare.
	 * @return int
	 */
	protected static function sortByName($a, $b)
	{
		$typesValues = array('dir' => 1, 'file' => 2);
		
		//Folder or file? Converting type to integer value, due to easier comparison.
		$aType = $typesValues[filetype(self::$basePath . '/' . $a)];
		$bType = $typesValues[filetype(self::$basePath . '/' . $b)];
		
		if ($aType == $bType) { //Same types (file/folder)? Do name comparison.
			if (self::$sortBy['name'] == self::ORDER_DESC) { //In descending order?
				return strnatcasecmp($b, $a);
			}
			else {
				return strnatcasecmp($a, $b);
			}
		}
		
		//Otherwise, compare types.
		if (self::$sortBy['name'] == self::ORDER_DESC) {
			return ($aType > $bType) ? -1 : 1;
		}
		else {
			return ($aType < $bType) ? -1 : 1;
		}
	}
	
	/**
	 * Callback function for sorting files/folders by type.
	 *
	 * @param string First value to compare.
	 * @param string Second value to compare.
	 * @return int
	 */
	protected static function sortByType($a, $b)
	{
		$typesValues = array('dir' => 1, 'file' => 2);
		
		//Folder or file? Converting type to integer value, due to easier comparison.
		$aType = $typesValues[filetype(self::$basePath . '/' . $a)];
		$bType = $typesValues[filetype(self::$basePath . '/' . $b)];
		
		if ($aType == $bType) { //Same types (file/folder)?
			if ($aType == 2) { //File?
				//Getting file extensions.
				$aExt = substr($a, strrpos($a, '.')+1);
				$bExt = substr($b, strrpos($b, '.')+1);
				
				if ($aExt == $bExt) { //Same extension? Compare by file name.
					$params = array($a, $b);
				}
				else { //Extension is different, compare by extension.	
					$params = array($aExt, $bExt);
				}
			}
			else { //... folder.
				$params = array($a, $b);
			}
			
			if (self::$sortBy['type'] == self::ORDER_DESC) { //In descending order?
				$first = $params[1];
				$second = $params[0];
			}
			else {
				$first = $params[0];
				$second = $params[1];
			}
			
			//File/folder name comparison.
			return strnatcasecmp($first, $second);
		}
			
		//Otherwise, compare types.
		if (self::$sortBy['type'] == self::ORDER_DESC) {
			return ($aType > $bType) ? -1 : 1;
		}
		else {
			return ($aType < $bType) ? -1 : 1;
		}
	}
	
	/**
	 * Callback function for sorting files/folders by size.
	 *
	 * @param string First value to compare.
	 * @param string Second value to compare.
	 * @return int
	 */
	protected static function sortBySize($a, $b)
	{
		//Getting file/folder size.
		$a = filesize(self::$basePath . '/' . $a);
		$b = filesize(self::$basePath . '/' . $b);
		
		if ($a == $b) { //Same sizes?
			return 0;
		}
		
		if (self::$sortBy['size'] == self::ORDER_DESC) { //In descending order?
			return ($a > $b) ? -1 : 1;
		}
		else {
			return ($a < $b) ? -1 : 1;
		}
	}
}
?>
Return current item: DirContent