(new Soapbox())->shout(array_map('strtoupper', $opinions)); //Shaun's blog


Me, elsewhere

GitHub
parseword
Miscellaneous public code

Twitter
@parseword
I don't tweet much

XMPP chat
xmpp@shaunc.com
(Pidgin, Miranda, Swift, etc.)


Perfect is the enemy of good enough.

Getting directory contents by date in PHP

Posted April 15, 2017 by shaun

When working with directory contents, sometimes it's useful to list the files by age, either newest or oldest first. For example, you might want to display the 10 most recently uploaded photos in a directory, or delete the oldest files from a temp directory. PHP provides an easy way to get a directory's file listing, scandir(), but it sorts the file list alphabetically. What if you'd rather sort by date?

To build a date-ordered file list, it's necessary to read the directory contents manually with opendir() and readdir(). As each file is discovered, it can be added to an array using its modification time as the array key. Finally, the resulting array can be sorted (or reverse-sorted) by key, producing a list of files that's ordered by date, from oldest to newest (or vice versa).

Here's a function, scandir_chrono(), that implements this logic with a few extra features:

/**
 * Return an array of file paths representing the contents of the target
 * directory, ordered by date instead of by filename.
 * 
 * @param string $path The target directory path
 * @param bool $reverse Whether to sort in reverse date order (oldest first)
 * @param array $exts If set, only find files with these extensions
 * @return array A sorted array of absolute filesystem paths
 */
function scandir_chrono(string $path, bool $reverse = false, ?array $exts = []): array {

    /* Fail if the directory can't be opened */
    if (!(is_dir($path) && $dir = opendir($path))) {
        return [];
    }

    /* An array to hold the results */
    $files = [];

    while (($file = readdir($dir)) !== false) {
        /* Skip anything that's not a regular file */
        if (filetype($path . '/' . $file) !== 'file') {
            continue;
        }
        /* If extensions were provided and this file doesn't match, skip it */
        if (!empty($exts) && !in_array(pathinfo($path . '/' . $file,
                                PATHINFO_EXTENSION), $exts)) {
            continue;
        }
        /* Add this file to the array with its modification time as the key */
        $files[filemtime($path . '/' . $file)] = $file;
    }
    closedir($dir);

    /* Sort and return the array */
    $fn = $reverse ? 'krsort' : 'ksort';
    $fn($files);
    return $files;
}

This function takes a directory path and returns an array of absolute, fully-qualified paths to each file. By default, the files are sorted from oldest to newest; to sort in the opposite direction, pass true for the $reverse parameter. Optionally, you can specify an array of file extensions you're interested in, and the returned array will only contain matching files.

For example, to get a list of all files in /tmp ordered newest first:

$files = scandir_chrono('/tmp', true);

To get a list of only txt and log files in the temp directory, sorted with the oldest files first:

$files = scandir_chrono('/tmp', false, ['txt', 'log']);

When specifying extensions, note that the dot shouldn't be included.



Recent articles

📰 Undeliverable as addressed: A massive broken spam campaign?

📰 Using WITH_META_MODE and ccache for FreeBSD build boosts

📰 Resolving subversion error E000013: Unable to create pristine install stream

📰 Enhancements to SmokePing's AnotherDNS probe

📰 Generating vanity DNSSEC key tags

📰 DDoS involving forged packets from 23.225.141.70

📰 Website integrity monitoring through version control

📰 SpamAssassin 3.4.2 fixes security problems, adds HashBL and phishing plugins

📰 Bug or turf war? ICQ via Pidgin now fails with "startOSCARSession: Request Timeout"

📰 🎂

📰 SFSQuery, a PHP class to query the StopForumSpam API and DNSBL

📰 Resolving portmaster error "pkg-static: automake-1.16.1 conflicts with automake-wrapper-20131203"

📰 Resolving LibreNMS error "RuntimeException: The only supported ciphers are AES-128-CBC and AES-256-CBC with the correct key lengths"

📰 1.1.1.1: Fast, but not so accurate (yet)

📰 autodiscover.xml as an Indicator of Attack

▲ Back to top | Permalink to this page