Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <?php
- /**
- * Table of Contents HTML Generator
- *
- * File: toc.php
- * Created: 2019-03-19
- * Updated: 2019-03-23 RDOS
- * Time: 09:09 EDT
- */
- // namespace
- /**
- * Table of Contents HTML Generator Class
- *
- * Generates a generic table of contents from the directory structure starting
- * at the root of the directory at which it is pointed. Limited to a certain
- * depth, a certain number of files and a printed file length (all set in
- * options). Only picks up HTML files (options).
- */
- class TocGenerator
- {
- /** Options */
- protected $opts = [
- 'page' => [
- 'title' => 'Table of Contents',
- 'lang' => 'en-CA',
- 'robots' => false,
- 'cols' => 3,
- ],
- 'max' => [
- 'depth' => 4,
- 'files' => [
- 'd0' => 7,
- 'd1' => 72,
- 'd2' => 12,
- 'd3' => 14,
- ],
- ],
- 'dir' => [
- 'cache' => '/a',
- 'meta' => '/a/0',
- 'toc' => '/a/0/toc',
- ],
- 'security' => [ 'file' => '.security', ],
- 'file' => [
- 'ext' => '.html',
- 'name' => '/article.html',
- 'print' => true,
- 'display' => true,
- 'size' => [ 'max' => 10000 ],
- ],
- 'toc' => [ 'file' => '/default.html' ],
- 'class' => [
- 'div' => 'toc',
- 'list' => '',
- ],
- 'debug' => true,
- ];
- /**
- * Initialize the Class
- *
- * @return void
- */
- public function init()
- {
- $security = $this->check();
- if ( $security )
- {
- $this->run();
- }
- // else do nothing (no hints).
- }
- /**
- * Security Check
- *
- * Check for a hidden file on the server. Only run if this is present. This
- * is to prevent unintended or intentional but malevolent execution of this
- * script. This isn't desirable as it runs through the entire cached directory
- * and could get quite large. This file may be a good candidate for a daily
- * or weekly cron job (turn off if no changes over prolonged periods). Could
- * provide a hint to this effect in the page displayed if calling this file
- * directly. The security file should be empty. It does not need to contain
- * anything, it just needs to be there.
- */
- private function check()
- {
- $file = $this->opts['security']['file'];
- if( file_exists( __DIR__ . '/' . $file ) )
- {
- return true;
- }
- else
- {
- return false;
- }
- }
- /**
- * Run the Class
- *
- * Uses a hook and chain approach (Top Down)
- */
- private function run()
- {
- // Get the paths needed for this work.
- $paths = $this->getPaths();
- //Initialize
- $arr = [];
- // Check to ensure that $paths is an array and not empty.
- if( is_array( $paths ) && count( $paths ) > 0 )
- {
- // Iterate through the directories.
- $arr = $this->itrDir00( $paths['cache'] );
- // Create the div to hold the contents.
- $html = $this->getDivHtml( $paths, $arr );
- // Check to make sure we have what we need.
- if( is_string( $html ) && strlen( $html ) > 0 )
- {
- // Get the page meta to describe what the page is about.
- $meta = $this->getPageMeta();
- // Add the page meta to the _end_ of the HTML just generated.
- $html = $html . $meta;
- // Wrap the HTML just generated in Page HTML
- $page = $this->getPageHtml( $html );
- // Build the file path and name we need to print it to a file.
- $file = $paths['toc'] . $this->opts['toc']['file'];
- // Print the file and obtain the response.
- $resp = $this->printHTML( $file, $page );
- pre_dump( $resp );
- }
- else
- {
- 'No HTML';
- }
- }
- }
- /**
- * Build the TOC portion of the HTML page
- *
- * Note: No closing tag is needed on the list element (ref).
- */
- private function getDivHtml( $paths, $list )
- {
- // Check to ensure it is an array and that it is not empty
- if ( is_string( $list ) && strlen( $list ) > 0 )
- {
- // Initialize
- $str = '';
- // Get the class for the top level div.
- $class = $this->getClass( $this->opts['class']['div'] );
- $str .= '<style>' . PHP_EOL;
- $str .= '.toc ul { list-style: none; }' . PHP_EOL;
- $str .= '.toc section {' . PHP_EOL;
- $str .= ' margin: 15px 0;' . PHP_EOL;
- $str .= sprintf( ' columns: %s;', $this->opts['page']['cols'] );
- $str .= '}' . PHP_EOL;
- $str .= '</style>' . PHP_EOL;
- // Create the title elements
- $str .= sprintf( '<h1>%s</h1>%s', $this->opts['page']['title'], PHP_EOL );
- // open the div
- $str .= sprintf( '<div%s>%s', $class, PHP_EOL );
- $str .= $list;
- // Close the div
- $str .= '</div>' . PHP_EOL;
- return $str;
- }
- else
- {
- return false;
- }
- }
- /**
- * Get the List UL
- *
- * @param $arr Array containing the items from which to generate list
- *
- * @return string Unordered list
- */
- private function getListHtml( $paths, $arr )
- {
- // Initialize
- $str = '';
- $cnt = 0;
- // Open the list element (<ul>), and leave room for adding classes.
- $str .= sprintf( '<ul>%s', PHP_EOL );
- // This loop calls the containing function if the value encountered is an array.
- foreach( $arr as $val )
- {
- if ( is_array( $val ) )
- {
- // Trailing </li> removed...
- if( 0 == $cnt )
- {
- $str .= '<li>' . getListUL( $val, $str );
- }
- else
- {
- $str .= PHP_EOL . '<li>' . getListUL( $val, $str );
- }
- }
- else
- {
- $str .= sprintf( '<li><a href="%s">%s</a>%s', $val, $val, PHP_EOL );
- }
- $cnt++;
- }
- $str .= '</ul>' . PHP_EOL;
- return $str;
- }
- /**
- * Get the Class
- *
- * Get the class, or return empty if none available
- *
- * @param string $class
- *
- * @return string String containing 'class="class"'.
- */
- private function getClass( $class )
- {
- // Initialize
- $str = '';
- // build the class string (simple).
- if ( is_string( $class ) && strlen( $class ) > 0 ) {
- $str .= sprintf( ' class="%s"', $class );
- }
- return $str;
- }
- /**
- * Scan Directory (Simple)
- *
- */
- function scanDirToList( $path ) {
- $arr = [];
- $arrDir = scandir( $path );
- // Initilize
- $str = '';
- $str .= '<ul>' . PHP_EOL;
- foreach ( $arrDir as $key => $value )
- {
- if ( ! in_array( $value, array( '.', '..' ) ) )
- {
- if ( is_dir( $dir . '/' . $value ) )
- {
- $result[$value] = scanDirToList( $dir . '/' . $value );
- }
- else
- {
- $result[] = $value;
- }
- }
- }
- return $result;
- }
- /**
- * Iterate Directory 00
- *
- * Use the basic Directory Iterator class to scan just the directory in which
- * it is, then manually detemine if it has discovered a directory. Create
- * the list item HTML as we go along.
- *
- * '.': Current directory
- * '..': Parent directory
- *
- * @param array $paths
- *
- * @return string
- */
- private function itrDir00( $path0 )
- {
- // Initialize.
- $str = '';
- // Set the count to 0.
- $cnt = 0;
- // Set the max depth allowed.
- $max['depth'] = $this->opts['max']['depth'];
- // Set the max files allowed for depth 0 (root of cache).
- $max['files'] = $this->opts['max']['files']['d0'];
- // Set the number of columns.
- $cols = $this->opts['page']['cols'];
- // Wrap the list in a section, with a class.
- $str .= '<section class="list columns">' . PHP_EOL;
- // Open the list element.
- $str .= '<ul>' . PHP_EOL;
- // Scan just the directory given, via the full path.
- $files = scandir( $path0 );
- // Loop through the files obtained.
- foreach ( $files as $file )
- {
- // Check the file (pass it through a filter).
- if ( $file = $this->chkFile00( $file ) )
- {
- // Make sure the limit has not been exceeded.
- if ( $cnt < $max['files'] )
- {
- // Check to see if this is a directory.
- if( is_dir( $path0 . '/' . $file ) )
- {
- // Obtain just the slug (for the link).
- $slug = $this->opts['dir']['cache'] . '/' . $file;
- // Create the list item. Add an id for a bookmark.
- $str .= sprintf( '<li><a id="%s" href="%s/">%s</a></li>%s',
- $file, $slug, ucfirst( $file ), PHP_EOL );
- // Create the path for the next level.
- $path1 = $path0 . '/' . $file;
- // Create a nav item after the fact to attach to the top of the str.
- $arrNav[$cnt]['dir'] = $this->opts['dir']['cache'];
- $arrNav[$cnt]['file'] = $file;
- $arrNav[$cnt]['base'] = $this->opts['dir']['toc'];
- $arrNav[$cnt]['slug'] = $slug;
- $arrNav[$cnt]['path'] = $path1;
- $arrNav[$cnt]['title'] = ucfirst( $file );
- // Scan the next path given to see if it is not empty.
- $files1 = scandir( $path1 );
- // Check to see if it is not empty.
- if( count( $files1 ) > 2 )
- {
- // Create the HTML from the next path.
- $strDir1 = $this->itrDir01( $slug, $path1 );
- if ( $strDir1 )
- {
- $str .= $strDir1;
- }
- }
- // Increment the counter.
- $cnt++;
- } // Continue to the next item.
- }
- else
- {
- // Maximum files reached for this level. Break.
- break;
- }
- } // Continue to the next item.
- } // Done the loop.
- // Close the list element.
- $str .= '</ul>' . PHP_EOL;
- // Close the section.
- $str .= '</section>' . PHP_EOL;
- // Build the nav HTML
- $strNav = $this->getNavHtml( $arrNav );
- // Attach the Nav HTML to the TOP of the string built so far.
- $str = $strNav . $str;
- // Return the string.
- return $str;
- }
- /**
- * Iterate Directory 01
- *
- * Scan the Second Level Directories.
- *
- * '.': Current directory
- * '..': Parent directory
- *
- * @param array $paths
- *
- * @return string
- */
- private function itrDir01( $slug0, $path1 )
- {
- if ( is_string( $path1 ) && strlen( $path1 ) > 0 )
- {
- // Initialize.
- $str = '';
- // Set the count to 0.
- $cnt = 0;
- // Set the max depth allowed.
- $max['depth'] = $this->opts['max']['depth'];
- // Set the max files allowed.
- $max['files'] = $this->opts['max']['files']['d1'];
- // Open the list element.
- $str .= '<ul>' . PHP_EOL;
- // Scan just the directory given
- $files = scandir( $path1 );
- $itrDir1 = new DirectoryIterator( $path1 );
- // Loop through the files obtained.
- foreach ( $files as $file )
- {
- // Check the file (pass it through a filter).
- if ( $file = $this->chkFile01( $file ) )
- {
- // Make sure the limit has not been exceeded.
- if ( $cnt < $max['files'] )
- {
- // Check to see if this is a directory.
- if( is_dir( $path1 . '/' . $file ) )
- {
- // Obtain just the slug (for the link).
- $slug1 = $slug0 . '/' . $file;
- // Create the file name to check if it exists in current directory
- $isFile = $path1 . '/' . $file . $this->opts['file']['name'];
- $star = $this->isStarred( $isFile );
- // Create the list item
- $str .= sprintf( '<li><a href="%s/">%s%s</a></li>%s',
- $slug1, ucfirst( $file ), $star, PHP_EOL );
- // Now this directory needs to be checked for subdirectories.
- // $dir2 = scandir( $file );
- // Increment the counter.
- $cnt++;
- } // Continue to the next item.
- }
- else
- {
- // Maximum files reached for this level. Break.
- break;
- }
- } // Continue to the next item.
- } // Done the loop.
- // Close the list element.
- $str .= '</ul>' . PHP_EOL;
- // Return the string.
- return $str;
- }
- else
- {
- return false;
- }
- }
- /**
- * Check if file Exists to Star or Not
- *
- * Check if a specific file exists to determine whether or not to give it a
- * "star" (*). The star (*) indicates the presence of readable content.
- *
- * @param string $file
- *
- * @return string star (*) or empty string ''.
- */
- private function isStarred( $file )
- {
- // Initialize
- $star = '';
- // Check to ensure the file given is a string and of reasonable length.
- if ( is_string( $file ) && strlen( $file ) > 2 )
- {
- // If it exists, set the star variable to '*';
- if( file_exists( $file ) )
- {
- $star = '*';
- }
- }
- // Return the star.
- return $star;
- }
- /**
- * Iterate Directory 01
- *
- * Scan the Second Level Directories.
- *
- * '.': Current directory
- * '..': Parent directory
- *
- * @param array $paths
- *
- * @return string
- */
- private function itrDir02( $slug1, $dir2 )
- {
- if ( is_string( $dir1 ) && strlen( $dir1 ) > 0 )
- {
- // Initialize.
- $str = '';
- // Set the count to 0.
- $cnt = 0;
- // Set the max depth allowed.
- $max['depth'] = $this->opts['max']['depth'];
- // Set the max files allowed.
- $max['files'] = $this->opts['max']['files']['d1'];
- // Open the list element.
- $str .= '<ul>' . PHP_EOL;
- // Scan just the directory given
- $files = scandir( $dir1 );
- $itrDir1 = new DirectoryIterator( $dir1 );
- // Loop through the files obtained.
- foreach ( $files as $file )
- {
- // Check the file (pass it through a filter).
- if ( $file = $this->chkFile01( $file ) )
- {
- // Make sure the limit has not been exceeded.
- if ( $cnt < $max['files'] )
- {
- // Check to see if this is a directory.
- if( is_dir( $dir1 . '/' . $file ) )
- {
- // Obtain just the slug (for the link).
- $slug = $slug0 . '/' . $file;
- // Create the list item
- $str .= sprintf( '<li><a href="%s/">%s</a></li>%s', $slug, ucfirst( $file ), PHP_EOL );
- // Now this directory needs to be checked for subdirectories.
- // $dir2 = scandir( $file );
- // Increment the counter.
- $cnt++;
- } // Continue to the next item.
- }
- else
- {
- // Maximum files reached for this level. Break.
- break;
- }
- } // Continue to the next item.
- } // Done the loop.
- // Close the list element.
- $str .= '</ul>' . PHP_EOL;
- // Return the string.
- return $str;
- }
- else
- {
- return false;
- }
- }
- /**
- * Check Files in the Top Level Directory
- *
- * Return only files that are three characters long (for this level).
- * Exclude files that are not wanted that are three characters long.
- *
- * @param string $file
- *
- * @return string [$file]
- */
- private function chkFile00( $file )
- {
- // Basic check
- if ( is_string( $file ) && strlen( $file ) > 0 )
- {
- // automatically rejects single and double dots, and 1 letter directories.
- if ( strlen( $file ) > 2 && strlen( $file ) < 4 )
- {
- // Get excluded directories.
- $exclude = $this->getExc00();
- // Return the file, having passed through this filter (Made it!!!)
- if ( ! in_array( $file, $exclude ) )
- {
- return $file;
- }
- else
- {
- return false;
- }
- }
- else
- {
- return false;
- }
- }
- else
- {
- return false;
- }
- }
- /**
- * Check Files in the Second Level Directory
- *
- *
- * @param string $file
- *
- * @return string [$file]
- */
- private function chkFile01( $file )
- {
- // Basic check
- if ( is_string( $file ) && strlen( $file ) > 0 )
- {
- // automatically rejects single and double dots, and 1 letter directories.
- if ( strlen( $file ) > 3 && strlen( $file ) < 5 )
- {
- // Get excluded directories.
- $exclude = $this->getExc01();
- // Return the file, having passed through this filter (Made it!!!)
- if ( ! in_array( $file, $exclude ) )
- {
- return $file;
- }
- else
- {
- return false;
- }
- }
- else
- {
- return false;
- }
- }
- else
- {
- return false;
- }
- }
- /**
- * Get Excluded Directories
- */
- private function getExc00()
- {
- $arr = [ '.', '..', 'cmn', 'mem', 'wki' ];
- return $arr;
- }
- /**
- * Get Excluded Directories
- */
- private function getExc01()
- {
- $arr = [ '.', '..', 'cmn', 'mem', ];
- return $arr;
- }
- /**
- * Get the Paths
- *
- * @return string
- */
- private function getPaths()
- {
- // Initialize.
- $paths = [];
- // Path to the root of the site
- $paths['root'] = null;
- // Path to the cache (i.e. SITE_ROOT_PATH . '/a')
- $paths['cache'] = null;
- // Path to the toc (i.e. SITE_CACHE_PATH . '/0/toc')
- $paths['toc'] = null;
- // Determine the root path by removing the trailing part.
- $paths['root'] = str_replace( $this->opts['dir']['toc'], '', __DIR__ );
- // Create the path to the cache by adding the cache directory to the root.
- $paths['cache'] = $paths['root'] . $this->opts['dir']['cache'];
- // Create the path to the TOC by adding the TOC directory to the root.
- $paths['toc'] = $paths['root'] . $this->opts['dir']['toc'];
- return $paths;
- }
- /**
- * Get the Page Meta
- *
- * Information to describe what the page is about.
- *
- * @return string
- */
- private function getPageMeta()
- {
- // Initialize.
- $str = '';
- $str .= '<section class="meta">' . PHP_EOL;
- $str .= '<h2>About this Page</h2>' . PHP_EOL;
- $str .= '<p>The page is automatically generated. It uses a script to iterate' . PHP_EOL;
- $str .= ' through the directory structure created. This is different than' . PHP_EOL;
- $str .= ' generating it from a database. A directory structure is part of' . PHP_EOL;
- $str .= ' the file system of an operating system (OS) and so is more robust' . PHP_EOL;
- $str .= ' than that created from a database. It is also easier to work with' . PHP_EOL;
- $str .= ' and can be set up by anyone used to folders on common operating' . PHP_EOL;
- $str .= ' systems (i.e. Mac, Windows or Linux).' . PHP_EOL;
- $str .= '</section>' . PHP_EOL;
- return $str;
- }
- /**
- * Build the Complete HTML Page
- *
- * @param $html
- *
- * @return string
- */
- private function getPageHtml( $html )
- {
- $str = '<!DOCTYPE html>' . PHP_EOL;
- $str .= sprintf( '<html lang="%s">%s', $this->opts['page']['lang'], PHP_EOL );
- $str .= '<head>' . PHP_EOL;
- $str .= '<meta charset="UTF-8">' . PHP_EOL;
- $str .= '<meta name="viewport" content="width=device-width, initial-scale=1"/>' . PHP_EOL;
- $str .= sprintf( '<title>%s</title>%s', $this->opts['page']['title'], PHP_EOL );
- $str .= $this->opts['page']['robots'] ? '<meta name="robots" content="noindex,nofollow" />' . PHP_EOL : '';
- $str .= sprintf( '<link rel=stylesheet href="/style.min.css">%s', PHP_EOL);
- $str .= '</head>' . PHP_EOL;
- $str .= '<body>' . PHP_EOL;
- $str .= '<main>' . PHP_EOL;
- // open the article element
- $str .= '<article>' . PHP_EOL;
- $str .= $html;
- // close the article element
- $str .= '</article>' . PHP_EOL;
- $str .= '</main>' . PHP_EOL;
- $str .= '<nav class="nav-up"><a href="../" title="Go up one directory">^</a></nav>' . PHP_EOL;
- $str .= '</html>' . PHP_EOL;
- return $str;
- }
- /**
- * Nav HTML
- *
- * Builds the Nav HTML from the top level directories
- * #arrNav[]['dir'] = $dir0;
- * $arrNav[]['file'] = $file;
- * $arrNav[]['slug'] = $slug;
- * $arrNav[]['path'] = $path1;
- * $arrNav[]['title'] = ucfirst( $file );
- *
- * @param array $nav
- *
- * @return string
- */
- private function getNavHtml( $arr )
- {
- // Check to see if it is an array and that it is not empty.
- if ( is_array( $arr ) && count( $arr ) > 0 )
- {
- // Initialize the string
- $str = '';
- // Open the nav element.
- $str .= '<nav>' . PHP_EOL;
- // Loop through the array items
- foreach ( $arr as $item )
- {
- $str .= sprintf( '<a href="%s/#%s" title="%s">%s</a> ',
- $item['base'], $item['file'], $item['title'], $item['title'] );
- }
- // Close the nav element.
- $str .= '</nav>' . PHP_EOL;
- }
- // Return the string.
- return $str;
- }
- /**
- * Print the HTML to a File
- *
- * Checks the length of the string
- *
- * file['path']: path to the file
- * file['stub']: first part of the file name
- * file['ext']: extension (if needed)
- * file['name']: first and second part of the file name.
- * file['title']: file stub exploded and capitalized as needed.
- * file['size']: file size
- * file['date']['created']: file created date
- * file['date']['updated']: file last updated
- * file['author]['initials']: author initials (may be in article meta info).
- *
- */
- private function printHTML( $file, $html )
- {
- // Initialize.
- $resp = null;
- if (
- $this->opts['file']['print']
- && strlen( $html ) > 0
- && strlen( $html ) < $this->opts['file']['size']['max']
- )
- {
- $resp = file_put_contents( $file, $html );
- }
- return $resp;
- }
- } // end class
- if( ! function_exists( 'pre_dump' ) ) {
- function pre_dump( $arr ) {
- if ( isset( $_GET['display'] ) )
- {
- echo '<pre>';
- var_dump( $arr );
- echo '</pre>';
- }
- }
- }
- /**
- * Table of Contents Generator public function
- *
- * Instantiates a new class, then calls the init function in it.
- *
- * @return void
- */
- function toc_generator()
- {
- $toc = new TocGenerator();
- $toc->init();
- }
- toc_generator();
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement