PHP/HTML/CSS - Script to scan a directoy recursively with filters and/or ingore list


/ Published in: PHP
Save to your folder(s)

There seems to be many scan directory systems but I could not find one that works the way I needed. I added in functionality for a search filter and an ignore list. The search filter and ignore list can ignore by extension, file (case-sensitive file name), and directory. I also added in the ability to have a max depth for the scan.

The HTML and CSS that are in the script is to preview in the browser the output. If you scan a directory that is outside the webroot then the links will not be built properly. I did not care to resolve this issue as it was not a problem for me.

I tested the script in Strict mode and have no errors, warnings, or notices. Pasting this here for a few friends and the community. If you can improve the script, please let me know as I always enjoy learning new techniques.

Thanks,
SoN9ne


Copy this code and paste it in your HTML
  1. <?php
  2. /**
  3.  * Scans a directory recursively
  4.  * Can filter the directory to show only desired file extensions
  5.  *
  6.  * @author Jeremy Simkins <SoN9ne>
  7.  */
  8.  
  9. /**
  10.  * Prepare filters
  11.  * - Do not edit unless you know what you are doing!
  12.  * - Look below (Look for BEGIN) to edit the filters
  13.  */
  14. # Define search Filters
  15. $searchFilter = array();
  16. $searchFilter['file'] = array();
  17. $searchFilter['extension'] = array();
  18. $searchFilter['directory'] = array();
  19.  
  20. # Define ignore Filters
  21. $ignore = array();
  22. $ignore['file'] = array();
  23. $ignore['extension'] = array();
  24. $ignore['directory'] = array();
  25. //--> End Prepare filters
  26.  
  27.  
  28. //-----[ BEGIN - Edit this data as you see fit ]-----------------------------------\\
  29. /**
  30.  * Directory to scan
  31.  * @var string
  32.  */
  33. $directory = "../"; // up one directory to get all the files of the system
  34.  
  35.  
  36. /**
  37.  * Set the maximum depth for the scan
  38.  *
  39.  * @var mixed - NULL|int - NULL will have no depth limitation, int is the number of levels deep to step into
  40.  */
  41. define('MAX_SCAN_DEPTH', NULL);
  42.  
  43. /**
  44.  * Custom search filters
  45.  * - You can add any type of filter to limit the search.
  46.  *
  47.  * Notes:
  48.  * - Extension and directory filters should be all lowercase
  49.  * - File filters should include the extension and are case-sensitive
  50.  */
  51. # Define search extension filters
  52. //$searchFilter['extension'][] = 'php';
  53.  
  54.  
  55. # Define search file filters
  56. //$searchFilter['file'][] = '';
  57.  
  58.  
  59. # Define search directory filters
  60. //$searchFilter['directory'][] = '';
  61. //--> End search filters
  62.  
  63.  
  64. /**
  65.  * Edit the ignore filters
  66.  */
  67. # Define ignore extension filters
  68. $ignore['extension'][] = 'buildpath'; // ZDE file
  69. $ignore['extension'][] = 'ds_store'; // Desktop Services Store file
  70. $ignore['extension'][] = 'project'; // ZDE file
  71.  
  72.  
  73. # Define ignore file filters
  74. //$ignore['file'][] = '';
  75.  
  76.  
  77. # Define ignore directory filters
  78. $ignore['directory'][] = '.svn'; // Do not scan svn directories
  79. $ignore['directory'][] = '.settings'; // Do not scan ZDE .setting folder
  80. $ignore['directory'][] = '__sessions'; // Do not scan custom sessions storage folder
  81. //--> End ignore filters
  82. //-----[ STOP - Edit this data as you see fit ]-----------------------------------\\
  83.  
  84.  
  85. /**
  86.  * Do Not edit below unless you know what you are doing
  87.  */
  88. # Set timezone
  89. date_default_timezone_set('America/New_York');
  90.  
  91. # Total files flag
  92. $totalFiles = 0;
  93. $totalDirectories = 0;
  94.  
  95. # Define direcoty tree array
  96. $directory_tree = array();
  97.  
  98. # Scan the directory
  99. $directory_tree = customScanDir($directory, $searchFilter, $ignore);
  100.  
  101. # Sort the array
  102. array_sort($directory_tree, 'name');
  103.  
  104. //echo '<pre>';
  105. //print_r($directory_tree);
  106. //echo '</pre>';
  107. //die();
  108.  
  109.  
  110. # Start output buffering
  111.  
  112. # Display the content
  113. displayDirRecursively($directory_tree, $totalFiles, $totalDirectories);
  114.  
  115. # Save output to a var
  116. $tmp = ob_get_contents();
  117.  
  118. # Delete the output buffer
  119.  
  120. # Output the page
  121. ?>
  122. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  123. <html xmlns="http://www.w3.org/1999/xhtml">
  124. <head>
  125. <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  126. <title>Scanner</title>
  127. <style>
  128. body {
  129. margin: 0;
  130. padding: 0;
  131. font: normal 14px Arial;
  132. color: #666;
  133. background: #efefef;
  134. }
  135.  
  136. ul,ol {
  137. background: #fff;
  138. border: 4px solid #fff;
  139. }
  140.  
  141. .dirList {
  142. margin: 5px auto;
  143. width: 60%;
  144. overflow: hidden;
  145. -moz-box-shadow: 0 0 20px #b5b5b5;
  146. }
  147.  
  148. #detail-container {
  149. margin: 5px auto;
  150. width: 60%;
  151. }
  152.  
  153. #details,#legend {
  154. margin: 5px auto;
  155. -moz-box-shadow: 0 0 20px #b5b5b5;
  156. }
  157.  
  158. #details {
  159. float: left;
  160. width: 70%;
  161. list-style: none;
  162. }
  163.  
  164. #legend {
  165. display: inline-block;
  166. float: right;
  167. width: 20%;
  168. }
  169.  
  170. .clear {
  171. clear: both;
  172. }
  173.  
  174. li {
  175. line-height: 1.8em;
  176. margin: 0 5px;
  177. padding-left: 2em;
  178. text-indent: -2em;
  179. width: 100%;
  180. }
  181.  
  182. ol.legend:first-child {
  183. background: maroon;
  184. }
  185.  
  186. .dirList li:nth-child(even) {
  187. background: #fff;
  188. }
  189.  
  190. .dirList li:nth-child(odd) {
  191. background: #ecf3fe;
  192. }
  193.  
  194. .dirList li:hover {
  195. background: yellow;
  196. }
  197.  
  198. .dirList ul {
  199. margin-left: -30px;
  200. }
  201.  
  202. #details .title,#legend .title {
  203. list-style: none;
  204. font-weight: bold;
  205. border-bottom: 1px solid #ccc;
  206. margin: 0 0 0 -38px;
  207. }
  208.  
  209. .folder {
  210. list-style: circle;
  211. }
  212.  
  213. .file {
  214. list-style: square;
  215. }
  216.  
  217. h3,h4 {
  218. padding: 10px;
  219. margin: 0px;
  220. font: normal 20px 'Trebuchet MS';
  221. text-align: center;
  222. }
  223.  
  224. h4 {
  225. font: normal 15px 'Trebuchet MS';
  226. }
  227.  
  228. a {
  229. color: #0079e0;
  230. }
  231.  
  232. a:visited {
  233. color: purple;
  234. }
  235. </style>
  236. </head>
  237. <body>
  238. <div id="detail-container">
  239. <ol id="details">
  240. <li class="title">Details:</li>
  241. <li>Total Directories Scanned: <strong><?php echo $totalDirectories; ?></strong></li>
  242. <li>Total Files Located: <strong><?php echo $totalFiles; ?></strong></li>
  243. </ol>
  244. <ol id="legend">
  245. <li class="title">Legend:</li>
  246. <li class="folder">Folder</li>
  247. <li class="file">File</li>
  248. </ol>
  249. <div class="clear"></div>
  250. </div>
  251. <hr />
  252.  
  253. <?php
  254. # Output the buffer
  255. echo $tmp;
  256. ?>
  257.  
  258. </body>
  259. </html>
  260. <?php
  261.  
  262. /**
  263.  * Recursively scans the directory
  264.  *
  265.  * @param string $directory - Directory to scan
  266.  * @param array $searchFilter - Array of serch data
  267.  * @param array $ignore - Array of data to ignore
  268.  * @param int $depth - Flag for knowing the depth of the scan
  269.  * @throws Exception
  270.  */
  271. function customScanDir($directory = '.', $searchFilter = NULL, $ignore = NULL, $depth = 0) {
  272.  
  273. if ( MAX_SCAN_DEPTH && $depth > MAX_SCAN_DEPTH ) return array();
  274.  
  275. if ( substr($directory, -1) == '/' ) {
  276. $directory = substr($directory, 0, -1);
  277. }
  278.  
  279. try {
  280. try {
  281. $directory_tree = array(); // Define output array
  282. foreach (new DirectoryIterator($directory) as $fileInfo) {
  283. if ( $fileInfo->isDot() ) continue;
  284.  
  285. $subdirectories = explode('/', $fileInfo->getPathname());
  286. $tmpName = end($subdirectories);
  287.  
  288. if ( $fileInfo->isDir() && !empty($ignore['directory']) && !in_array($tmpName, $ignore['directory']) ) {
  289. $directory_tree['directory'][] = array('path'=>$fileInfo->getPathname(), 'name'=>$tmpName, 'kind'=>'directory', 'content'=>array_sort(customScanDir($fileInfo->getPathname(), $searchFilter, $ignore, $depth + 1), 'name'));
  290. } else if ( $fileInfo->isFile() ) {
  291. $tmpExtension = strtolower(end(explode('.', $tmpName)));
  292.  
  293. # Ignored files and extensions
  294. if ( !empty($ignore['extension']) && in_array($tmpExtension, $ignore['extension']) || !empty($ignore['file']) && in_array(strtolower($tmpName), $ignore['file']) || !empty($searchFilter['extension']) && !in_array($tmpExtension, $searchFilter['extension']) ) {
  295. continue;
  296. }
  297.  
  298. # Add the file to the tree if it is searched or we are displaying the entire directory
  299. if ( empty($searchFilter['file']) || !empty($searchFilter['file']) && in_array(strtolower($tmpName), $searchFilter['file']) ) {
  300. $directory_tree['file'][] = array('name'=>$tmpName, 'extension'=>$tmpExtension, 'path'=>$fileInfo->getPathname(), 'lastModified'=>date('M d Y h:i:s a', $fileInfo->getMTime()), 'kind'=>'file');
  301. }
  302. }
  303. }
  304.  
  305. unset($tmpName, $tmpExtension); // Free tmp vars
  306. return $directory_tree;
  307. } catch ( UnexpectedValueException $e ) {
  308. throw new Exception(sprintf("Directory [%s/] contained a directory that cannot be stepped into", $directory), E_USER_WARNING);
  309. return array(); // Return an empty array
  310. }
  311. } catch ( Exception $e ) {
  312. die($e->getMessage()); // Show the error
  313. }
  314. }
  315.  
  316. /**
  317.  * Steps throught the directory array and displays
  318.  *
  319.  * @param array $fileSystem - Array of file system
  320.  * @param int $totalFiles - Flag to count the total files found
  321.  * @param int $totalDirectories - Flag to count the total directories scanned
  322.  * @param int $depth - Flag to know the depth of the display
  323.  */
  324. function displayDirRecursively($fileSystem = array(), & $totalFiles = 0, & $totalDirectories = 0, $depth = 0) {
  325. echo '<ul class="' . (($depth) ? "sub-depth-{$depth}" : 'dirList') . '">';
  326. foreach ($fileSystem as $fsType=>$fsData) {
  327. foreach ($fsData as $item) {
  328. if ( $fsType === 'directory' ) {
  329. ++$totalDirectories;
  330.  
  331. echo '<li class="folder">';
  332. echo $item['name'];
  333.  
  334. if ( isset($item['content']) && is_array($item['content']) && !empty($item['content']) ) {
  335. displayDirRecursively($item['content'], $totalFiles, $totalDirectories, $depth + 1);
  336. }
  337. $deep = 0;
  338. echo '</li>';
  339. } else if ( $fsType === 'file' ) {
  340. ++$totalFiles;
  341.  
  342. echo '<li class="file">';
  343. echo sprintf('<a href="%s" target="_blank" title="%s">%s</a>', $item['path'], $item['path'], $item['name']);
  344. echo '</li>';
  345. }
  346. }
  347. }
  348. echo '</ul>';
  349. }
  350.  
  351. /**
  352.  * Sorts an array by key
  353.  *
  354.  * @param array $array
  355.  * @param mixed $on - string||int
  356.  * @param bool $sortASC - TRUE sort ASC, FALSE sort DESC
  357.  * @return array
  358.  */
  359. function array_sort($array, $on, $sortASC = TRUE) {
  360. $new_array = array();
  361. $sortable_array = array();
  362.  
  363. if ( count($array) > 0 ) {
  364. foreach ($array as $k=>$v) {
  365. if ( is_array($v) ) {
  366. foreach ($v as $k2=>$v2) {
  367. if ( $k2 == $on ) {
  368. $sortable_array[$k] = $v2;
  369. }
  370. }
  371. } else {
  372. $sortable_array[$k] = $v;
  373. }
  374. }
  375.  
  376. if ( $sortASC ) {
  377. asort($sortable_array);
  378. } else {
  379. arsort($sortable_array);
  380. }
  381.  
  382. foreach ($sortable_array as $k=>$v) {
  383. $new_array[$k] = $array[$k];
  384. }
  385. }
  386.  
  387. return $new_array;
  388. }

Report this snippet


Comments

RSS Icon Subscribe to comments

You need to login to post a comment.