{"id":71,"date":"2007-04-18T23:48:43","date_gmt":"2007-04-18T22:48:43","guid":{"rendered":"http:\/\/pgregg.com\/wp\/2007\/04\/code-release-preg-find-a-recursive-file-listing-tool-for-php\/"},"modified":"2020-05-17T20:42:11","modified_gmt":"2020-05-17T19:42:11","slug":"code-release-preg-find-a-recursive-file-listing-tool-for-php","status":"publish","type":"post","link":"https:\/\/blog.pgregg.com\/blog\/2007\/04\/code-release-preg-find-a-recursive-file-listing-tool-for-php\/","title":{"rendered":"Code release: preg_find() &#8211; A recursive file listing tool for PHP"},"content":{"rendered":"<p>Updated for Version 2.4, May 17, 2020.<\/p>\n<p>I originally wrote this a few (16) years ago in 2004 and never really promoted it beyond the realms of the #php IRC channel on EfNet.\u00a0 However, it has managed to find its way into applications such as WordPress and many other PHP apps.\u00a0 It is gratifying to know that others are finding it useful.<\/p>\n<p>So what is preg_find() anyway? A short summary for those who have never encountered it: Imaging a recursive capable glob() with the ability to filter the results with a regex (PCRE) and various arguments to modify the results to bring back additional data.<\/p>\n<p>Well today (18 April 2007) I thought I would add one commonly requested feature. Sorting.\u00a0 Using the power of PHP&#8217;s anonymous (lambda-style) functions, preg_find() now creates a custom sort routine based on the arguments passed in, filename, dir+filename, last modified, file size, disk usage (yes those last 2 are different) in either ascending or descending order.<\/p>\n<p><a href=\"http:\/\/www.pgregg.com\/projects\/php\/preg_find\/preg_find.phps\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Download preg_find.phps<\/a><br \/>\n<a href=\"http:\/\/www.pgregg.com\/projects\/php\/preg_find\/preg_find.php.txt\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Download preg_find.php in plain text format<\/a><\/p>\n<hr \/>\n<p>A simple example to get started &#8211; we&#8217;ll work on my PHP miscellaneous code directory:<\/p>\n<p>Example 1: List the files (no directories):<\/p>\n<table style=\"width: 95%;\" cellspacing=\"4\" cellpadding=\"6\" align=\"center\">\n<tbody>\n<tr>\n<td class=\"punquote\"><span class=\"puntext\"><b>Code:<\/b><\/span><\/p>\n<pre>include 'preg_find.php';\n$files = preg_find('\/.\/', '..\/code');\nforeach($files as $file) printf(\"&lt;br&gt;%sn\", $file);<\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><span class=\"puntext\">You can <a href=\"http:\/\/www.pgregg.com\/projects\/php\/preg_find\/preg_find_ex.php#1\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">see the result here<\/a><\/span><\/p>\n<hr \/>\n<p>Now let us look at a recursive search &#8211; this is easy, just pass in the PREG_FIND_RECURSIVE argument.<br \/>\nExample 2: List the files, recursively:<\/p>\n<table style=\"width: 95%;\" cellspacing=\"4\" cellpadding=\"6\" align=\"center\">\n<tbody>\n<tr>\n<td class=\"punquote\"><span class=\"puntext\"><b>Code:<\/b><\/span><\/p>\n<pre>$files = preg_find('\/.\/', '..\/code', PREG_FIND_RECURSIVE);\nforeach($files as $file) printf(\"&lt;br&gt;%sn\", $file);<\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><span class=\"puntext\">You can <a href=\"http:\/\/www.pgregg.com\/projects\/php\/preg_find\/preg_find_ex.php#2\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">see the result here<\/a><\/span><\/p>\n<hr \/>\n<p>Lets go further, this time we don&#8217;t want to see any files &#8211; only a directory structure.<br \/>\nExample 3: List the directory tree:<\/p>\n<table style=\"width: 95%;\" cellspacing=\"4\" cellpadding=\"6\" align=\"center\">\n<tbody>\n<tr>\n<td class=\"punquote\"><span class=\"puntext\"><b>Code:<\/b><\/span><\/p>\n<pre>$files = preg_find('\/.\/', '..\/code', PREG_FIND_DIRONLY|PREG_FIND_RECURSIVE);\nforeach($files as $file) printf(\"&lt;br&gt;%sn\", $file);<\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><span class=\"puntext\">You can <a href=\"http:\/\/www.pgregg.com\/projects\/php\/preg_find\/preg_find_ex.php#3\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">see the result here<\/a><\/span><\/p>\n<p>It should be obvious by now that we are using constants as our modifier arguments. What might not be immediately obvious is that these constants are &#8220;bit&#8221; values (.e.g. 1, 2, 4, 8, 16, &#8230;, 1024, etc) and using PHP&#8217;s <strong>Bitwise Or<\/strong> operator &#8220;<strong>|<\/strong>&#8221; we can combine modifiers to pass multiple modifiers into the function.<\/p>\n<hr \/>\n<p>How about a regex? Files starting with str_ and ending in .php<br \/>\nExample 4: Using a regex on the same code as example 1:<\/p>\n<table style=\"width: 95%;\" cellspacing=\"4\" cellpadding=\"6\" align=\"center\">\n<tbody>\n<tr>\n<td class=\"punquote\"><span class=\"puntext\"><b>Code:<\/b><\/span><\/p>\n<pre>$files = preg_find('\/^str_.*?.php$\/D', '..\/code');\nforeach($files as $file) printf(\"&lt;br&gt;%sn\", $file);<\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><span class=\"puntext\">You can <a href=\"http:\/\/www.pgregg.com\/projects\/php\/preg_find\/preg_find_ex.php#4\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">see the result here<\/a><\/span><\/p>\n<hr \/>\n<p>What about that funky PREG_FIND_RETURNASSOC modifier?<br \/>\nThis will change the output dramatically from a simple file\/directory array to an associative array where the key is the filename, and the value is lots of information about that file.<\/p>\n<p>Example5: Use of PREG_FIND_RETURNASSOC<\/p>\n<table style=\"width: 95%;\" cellspacing=\"4\" cellpadding=\"6\" align=\"center\">\n<tbody>\n<tr>\n<td class=\"punquote\"><span class=\"puntext\"><b>Code:<\/b><\/span><\/p>\n<pre>$files = preg_find('\/^str_.*?.php$\/D', '..\/code', PREG_FIND_RETURNASSOC);\nforeach($files as $file) printf(\"&lt;br&gt;%sn\", $file);<\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><span class=\"puntext\">You can <a href=\"http:\/\/www.pgregg.com\/projects\/php\/preg_find\/preg_find_ex.php#5\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">see the result here<\/a><\/span><\/p>\n<hr \/>\n<p>As I mentioned earlier, I added sorting capability to the results, so let us look at some examples of that.<\/p>\n<p>Example 6. Sorting the results (of example 1)<\/p>\n<table style=\"width: 95%;\" cellspacing=\"4\" cellpadding=\"6\" align=\"center\">\n<tbody>\n<tr>\n<td class=\"punquote\"><span class=\"puntext\"><b>Code:<\/b><\/span><\/p>\n<pre>$files = preg_find('\/.\/', '..\/code', PREG_FIND_SORTKEYS);\nforeach($files as $file) printf(\"&lt;br&gt;%sn\", $file);<\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><span class=\"puntext\">You can <a href=\"http:\/\/www.pgregg.com\/projects\/php\/preg_find\/preg_find_ex.php#6\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">see the result here<\/a><\/span><\/p>\n<hr \/>\n<p>Example 7. And reverse sort.<\/p>\n<table style=\"width: 95%;\" cellspacing=\"4\" cellpadding=\"6\" align=\"center\">\n<tbody>\n<tr>\n<td class=\"punquote\"><span class=\"puntext\"><b>Code:<\/b><\/span><\/p>\n<pre>$files = preg_find('\/.\/', '..\/code', PREG_FIND_SORTKEYS|PREG_FIND_SORTDESC);\nforeach($files as $file) printf(\"&lt;br&gt;%sn\", $file);<\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><span class=\"puntext\">You can <a href=\"http:\/\/www.pgregg.com\/projects\/php\/preg_find\/preg_find_ex.php#7\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">see the result here<\/a><\/span><\/p>\n<hr \/>\n<p>Ok, thats all well and good, what about something more interesting?<\/p>\n<p>Example 8. Finding the largest 5 files in the tree, sorted by filesize, descending.<\/p>\n<table style=\"width: 95%;\" cellspacing=\"4\" cellpadding=\"6\" align=\"center\">\n<tbody>\n<tr>\n<td class=\"punquote\"><span class=\"puntext\"><b>Code:<\/b><\/span><\/p>\n<pre>$files = preg_find('\/.\/', '..\/code', PREG_FIND_RECURSIVE|PREG_FIND_RETURNASSOC|PREG_FIND_SORTFILESIZE|PREG_FIND_SORTDESC);\n\n$i=1;\nforeach($files as $file =&gt; $stats) {\n  printf('&lt;br&gt;%d) %d %s', $i, $stats['stat']['size'], $file);\n  $i++;\n  if ($i &gt; 5) break;\n}<\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><span class=\"puntext\">You can <a href=\"http:\/\/www.pgregg.com\/projects\/php\/preg_find\/preg_find_ex.php#8\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">see the result here<\/a>.<\/span><\/p>\n<hr \/>\n<p>Or what about the 10 most recently modified files?<\/p>\n<p>Example 9.<\/p>\n<table style=\"width: 95%;\" cellspacing=\"4\" cellpadding=\"6\" align=\"center\">\n<tbody>\n<tr>\n<td class=\"punquote\"><span class=\"puntext\"><b>Code:<\/b><\/span><\/p>\n<pre>$files = preg_find('\/.\/', '..\/code',\n  PREG_FIND_RECURSIVE|PREG_FIND_RETURNASSOC|PREG_FIND_SORTMODIFIED|PREG_FIND_SORTDESC);\n$i=1;\nforeach($files as $file =&gt; $stats) {\n  printf('&lt;br&gt;%d) %s - %d bytes - %s', $i,\n    date('Y-m-d H:i:s', $stats['stat']['mtime']), $stats['stat']['size'], $file);\n  $i++;\n  if ($i &gt; 10) break;\n}<\/pre>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><span class=\"puntext\">You can <a href=\"http:\/\/www.pgregg.com\/projects\/php\/preg_find\/preg_find_ex.php#9\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">see the result here<\/a>.<\/span><\/p>\n<hr \/>\n<p>I am keen to receive feedback on what you think of this function.\u00a0 \u00a0If you have used it in some other application &#8211; great, I would love to know.\u00a0 Suggestions, improvements, criticisms are also always welcome.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Updated for Version 2.4, May 17, 2020. I originally wrote this a few (16) years ago in 2004 and never really promoted it beyond the realms of the #php IRC channel on EfNet.\u00a0 However, it has managed to find its way into applications such as WordPress and many other PHP apps.\u00a0 It is gratifying to &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/blog.pgregg.com\/blog\/2007\/04\/code-release-preg-find-a-recursive-file-listing-tool-for-php\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Code release: preg_find() &#8211; A recursive file listing tool for PHP&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"1","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[10],"tags":[14,81,82],"class_list":["post-71","post","type-post","status-publish","format-standard","hentry","category-php","tag-algorithms","tag-php-2","tag-preg_find"],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/pbQOUu-19","jetpack-related-posts":[],"_links":{"self":[{"href":"https:\/\/blog.pgregg.com\/blog\/wp-json\/wp\/v2\/posts\/71","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.pgregg.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.pgregg.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.pgregg.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.pgregg.com\/blog\/wp-json\/wp\/v2\/comments?post=71"}],"version-history":[{"count":2,"href":"https:\/\/blog.pgregg.com\/blog\/wp-json\/wp\/v2\/posts\/71\/revisions"}],"predecessor-version":[{"id":861,"href":"https:\/\/blog.pgregg.com\/blog\/wp-json\/wp\/v2\/posts\/71\/revisions\/861"}],"wp:attachment":[{"href":"https:\/\/blog.pgregg.com\/blog\/wp-json\/wp\/v2\/media?parent=71"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.pgregg.com\/blog\/wp-json\/wp\/v2\/categories?post=71"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.pgregg.com\/blog\/wp-json\/wp\/v2\/tags?post=71"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}