Last active
September 26, 2019 15:36
-
-
Save earth3300/78bcdff46e6891caff28ffd6c020212c to your computer and use it in GitHub Desktop.
Converts a CSS file or files to an array and saves as a PHP file or files.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* EC01 Converts CSS to a PHP Data Array | |
* | |
* Converts valid CSS to a PHP data array and saves as a file. | |
* | |
* @package Earth3300\EC01 | |
* @since 1.0.0 | |
* @author Clarence J. Bos <cbos@tnoep.ca> | |
* @copyright Copyright (c) 2018, Clarence J. Bos | |
* @license https://www.gnu.org/licenses/gpl-3.0.en.html GPL v3.0 | |
* @link https://gist.github.com/earth3300/78bcdff46e6891caff28ffd6c020212c | |
* | |
* File: printer.css-to-dat.php | |
* Created: 2019-09-19 | |
* Updated: 2019-09-23 | |
* Time: 19:56 EDT | |
* ID: ENG-ON-001 | |
*/ | |
namespace Earth3300\EC01; | |
if( ! defined( 'NDA' ) ) | |
{ | |
define('NDA',true); | |
} | |
/** | |
* Prints a CSS file. | |
*/ | |
class CssPrinter | |
{ | |
/** @var array Default options. */ | |
protected $opts = [ | |
// Development Status. | |
'dev' => 0, | |
'dev0' => 0, | |
'dev1' => 0, | |
'dev2' => 0, | |
'dev3' => 0, | |
'dev4' => 0, | |
'this' => [ | |
'file' => 'printer.css-to-dat.php', | |
'title' => 'EC01 CSS to Data Printer', | |
'date' => [ | |
'created' => '2019-09-19', | |
], | |
], | |
'page' => [ | |
'title' => 'EC01 CSS to Data Printed', | |
], | |
'dir' => [ | |
'input' => '/0/t/css/src', | |
'output' => '/0/t/css/dat', | |
], | |
'file' => [ | |
'overwrite' => 1, | |
], | |
'files' => [ | |
'exclude' => [ | |
'00-header.css', | |
], | |
], | |
'max' => [ | |
'len' => 3000000, // Bytes | |
'files' => 1, | |
], | |
'write' => [ | |
'root' => 0, | |
], | |
'message' => [ | |
'na' => 'Not available.', | |
'write' => [ | |
'denied' => 'Write permission denied.' , | |
'success' => 'Write operation succeeded.', | |
'failure' => 'Write operation failed.', | |
], | |
], | |
]; | |
function __construct() | |
{ | |
} | |
/** | |
* Init | |
*/ | |
public function init() | |
{ | |
if( $this->security() ) | |
{ | |
$this->authorize(); | |
} | |
} | |
/** | |
* Security | |
*/ | |
private function security() | |
{ | |
if ( '127.0.0.1' == $_SERVER['REMOTE_ADDR'] | |
&& file_exists( __DIR__ . '/.security' ) ) | |
{ | |
return true; | |
} | |
else | |
{ | |
return false; | |
} | |
} | |
/** | |
* Authorize | |
*/ | |
private function authorize() | |
{ | |
if( isset( $_GET['unlock'] ) ) | |
{ | |
echo $this->run(); | |
} | |
else | |
{ | |
echo '<pre>Unauthorized.</pre>' . PHP_EOL; | |
} | |
} | |
/** | |
* Run | |
* | |
* Run, if authorized. | |
* | |
* @return string $html | |
*/ | |
private function run() | |
{ | |
if( isset( $_GET['run'] ) ) | |
{ | |
$file = []; | |
$file['text']['resp'] = ''; | |
$file = $this->getDesc( $file ); | |
$file = $this->getPaths( $file ); | |
$file = $this->getFiles( $file ); | |
$file = $this->getInfo( $file ); | |
foreach( $file['files'] as $cnt => $name ) | |
{ | |
$item = []; | |
$item = $this->preProcess( $file, $item, $name ); | |
if ( $this->opts['dev'] && $cnt >= $this->opts['max']['files'] ) | |
{ | |
break; | |
} | |
$item = $this->process( $file, $item ); | |
$file = $this->postProcess( $file, $item ); | |
} | |
$html = $this->getPageHTML( $file ); | |
return $html; | |
} | |
else | |
{ | |
echo '<pre>You wish to run the script?</pre>' . PHP_EOL; | |
} | |
} | |
/** | |
* Get the Description (Purpose) of This File | |
* | |
* @param array $file | |
* | |
* @return array | |
*/ | |
private function getDesc( $file ) | |
{ | |
$file['text']['desc'] = ''; | |
$file['text']['desc'] = '<div class="description">'; | |
$file['text']['desc'] .= '<p>Converts valid CSS to a PHP data array and <br>'; | |
$file['text']['desc'] .= ' saves it as a file.</p>'; | |
$file['text']['desc'] .= '</div>' . PHP_EOL; | |
$file['text']['desc'] .= '<div class="clear"></div>' . PHP_EOL; | |
$file['text']['desc'] .= PHP_EOL; | |
return $file; | |
} | |
/** | |
* Get the Paths to the Files to Process. | |
* | |
* @param array $file | |
* | |
* @return array | |
*/ | |
private function getPaths( $file ) | |
{ | |
if( is_array( $file ) ) | |
{ | |
$file['root'] = rtrim( $_SERVER['DOCUMENT_ROOT'], '/' ); | |
$file['path']['input'] = $file['root']; | |
$file['path']['input'] .= $this->opts['dir']['input']; | |
$file['path']['output'] = $file['root']; | |
$file['path']['output'] .= $this->opts['dir']['output']; | |
} | |
return $file; | |
} | |
/** | |
* Get the Files. | |
* | |
* @param array $file | |
* | |
* @return array | |
*/ | |
private function getFiles( $file ) | |
{ | |
$file['files'] = null; | |
if( isset( $file['path']['input'] ) ) | |
{ | |
$match = $file['path']['input'] . '/*.css'; | |
// $file['files'][0], $file['files'][1], $file['files'][2], etc... | |
$file['files'] = glob( $match ); | |
} | |
return $file; | |
} | |
/** | |
* Get Info | |
* | |
* @param array $file | |
* | |
* @return array | |
*/ | |
private function getInfo( $file ) | |
{ | |
$file['text']['info'] = null; | |
$str = ''; | |
if( is_array( $file ) ) | |
{ | |
// Input path | |
$str .= isset( $file['path']['input'] ) ? | |
sprintf( '<br>Input Path: %s<br>%s', $file['path']['input'], PHP_EOL ) : ''; | |
// Count of the files. | |
$str .= isset( $file['cnt'] ) ? | |
sprintf( '<br>Files: %s<br>%s', $file['cnt'], PHP_EOL ) : ''; | |
// Output path | |
$str .= isset( $file['path']['output'] ) ? | |
sprintf( '<br>Output Path: %s<br><br>%s', $file['path']['output'], PHP_EOL ) : ''; | |
} | |
$file['text']['info'] = $str; | |
return $file; | |
} | |
/** | |
* Pre Process | |
* | |
* @param array $file | |
* @param array $item | |
* @param string $name Full path to file, including the name | |
* | |
* @return array | |
*/ | |
private function preProcess( $file, $item, $name ) | |
{ | |
if( is_array( $item ) ) | |
{ | |
$item['error'] = ''; | |
$item['file']['input'] = $name; | |
$item = $this->getFileInfo( $file, $item ); | |
} | |
return $item; | |
} | |
/** | |
* Process | |
* | |
* @param array $file | |
* @param array $item | |
* | |
* @return array | |
*/ | |
private function process( $file, $item ) | |
{ | |
if( is_array( $item ) ) | |
{ | |
$item['error'] = ''; | |
$item['php'] = ''; | |
$item = $this->getFile( $file, $item ); | |
$item = $this->clnFile( $file, $item ); | |
$item = $this->addQuoFile( $file, $item ); | |
$item = $this->repBrkFile( $file, $item ); | |
$item = $this->genFncName( $file, $item ); | |
$item = $this->genFile( $file, $item ); | |
} | |
return $item; | |
} | |
/** | |
* Post Process | |
* | |
* @param array $file | |
* @param array $item | |
* | |
* @return array | |
*/ | |
private function postProcess( $file, $item ) | |
{ | |
if ( is_array( $item ) ) | |
{ | |
$item['file']['output'] = str_replace( '.css', '.php', $item['file']['output'] ); | |
$file['text']['resp'] .= $this->printFile( $file, $item ); | |
} | |
return $file; | |
} | |
/** | |
* Get File Info | |
* | |
* @param array $file | |
* @param array $item | |
* | |
* @return array | |
*/ | |
private function getFileInfo( $file, $item ) | |
{ | |
$item['file']['name'] = null; | |
$item['file']['base'] = null; | |
if( isset( $item['file']['input'] ) ) | |
{ | |
// Start with the path. | |
$item['file']['output'] = $file['path']['output']; | |
// Get the file name using pathinfo(). | |
$item['file']['output'] .= '/' . pathinfo( $item['file']['input'], PATHINFO_BASENAME ); | |
// Convert .css to .php | |
$item['file']['output'] = str_replace( '.css', '.php', $item['file']['output'] ); | |
// Get the file name from pathinfo() | |
$item['file']['name'] = pathinfo( $item['file']['input'], PATHINFO_BASENAME ); | |
// Replace the .css with .php | |
$item['file']['name'] = str_replace( '.css', '.php', $item['file']['name'] ); | |
// Get the base name (no extension), using pathinfo(). | |
$item['file']['base'] = pathinfo( $item['file']['input'], PATHINFO_FILENAME ); | |
} | |
return $item; | |
} | |
/** | |
* Get File | |
* | |
* Gets the file as an array | |
* | |
* @example file( 'style.css', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES ); | |
* | |
* @param array $file | |
* @param array $item | |
* | |
* @return array | |
*/ | |
private function getFile( $file, $item ) | |
{ | |
if( isset( $item['file']['input'] ) ) | |
{ | |
if( file_exists( $item['file']['input'] ) ) | |
{ | |
$item['text']['lines'] = file( $item['file']['input'], FILE_SKIP_EMPTY_LINES ); | |
} | |
} | |
return $item; | |
} | |
/** | |
* Clean the File (Return as a String) | |
* | |
* Remove all comments and extra line breaks to leave clean, | |
* well formatted CSS. This can then be processed by replacing | |
* the { with => [, the } with ], and then... placing quotes | |
* around all selectors and attributes. This may require a third | |
* step once the cleaning is finished. | |
* | |
* @param array $file | |
* @param array $item | |
* | |
* @return $item Converted from lines to a single string. | |
*/ | |
private function clnFile( $file, $item ) | |
{ | |
$text = ''; | |
$max = 36; | |
$skip = 0; | |
if( isset( $item['text']['lines'] ) ) | |
{ | |
foreach( $item['text']['lines'] as $cnt => $line ) | |
{ | |
// Remove extra line returns. | |
$line = str_replace( "\n\n", '\n', $line ); | |
if( $this->opts['dev'] && $cnt == $max ) | |
{ | |
break; | |
} | |
// Comment start. | |
if( $this->iss( $line, '/*' ) || $skip ) | |
{ | |
$skip = 1; | |
} | |
// Comment end. | |
if( $this->iss( $line, '*/' ) && ! $skip ) | |
{ | |
$skip = 0; | |
} | |
// Skip single line comment. | |
if( $this->iss( $line, '/*' ) && $this->iss( $line, '*/' ) ) | |
{ | |
continue; | |
} | |
// Process only lines containing valid CSS. | |
if( ! $this->isCSS( $line ) ) | |
{ | |
continue; | |
} | |
// Skip empty lines. | |
if( empty( $line ) ) | |
{ | |
continue; | |
} | |
$this->opts['dev'] ? printf( '<pre>' . $cnt . ': ' . $line . '<br>' ) : ''; | |
$text .= $line; | |
} // Loop | |
$item['text']['input'] = $text; | |
} // if | |
if( $this->opts['dev0'] ) | |
{ | |
pre_dump( $item['text']['input'], 0 ); | |
} | |
return $item; | |
} | |
/** | |
* Process the File | |
* | |
* Convert. | |
* | |
* @param array $file | |
* @param array $item | |
* | |
* @return array | |
*/ | |
/* | |
$node[0] = null; | |
$pair[0] = null; | |
$node[1] = null; | |
$pair[1] = null; | |
$node[2] = null; | |
$pair[2] = null; | |
// first forward bracket bumps node from null to 0 | |
@media all { | |
$node[0] = true; | |
$pair[0] = false; | |
// second forward bracket with no pair bumps node to 1 | |
body { | |
$node[0] = true; | |
$pair[0] = false; | |
// first pairing bumps pair to true (same level as node). | |
font: 12pt/1.5 sans-serif; | |
$pair[0] = true; | |
background-color: hsl(0, 0%, 100%); | |
color: hsl(0, 0%, 12.5%); | |
min-width: 240px; | |
max-width: 1056px; | |
display: block; | |
margin: 0 auto; | |
padding: 16px; | |
// First closing bracket bumps node/pair to false. | |
} | |
$node[1] = false; | |
$pair[1] = false; | |
// Next forward bracket bumps node back up. | |
@media (min-width:800px) { | |
$node[1] = true; | |
$pair[1] = false; | |
// Next forward bracket bumps node up. | |
html { | |
$node[2] = true; | |
$pair[2] = false; | |
// First pairing bumps level pair up one. | |
width: 1056px; | |
$pair[2] = true; | |
} | |
$node[2] = false; | |
$pair[2] = false; | |
} | |
$node[1] = false; | |
$pair[1] = false; | |
} | |
$node[0] = false; | |
$pair[0] = false; | |
Should be no more than three (3) nodes deep. | |
*/ | |
private function prcFile( $file, $item ) | |
{ | |
$item['php'] = null; | |
$skip = 0; | |
// | |
$node[0] = false; | |
$node[1] = false; | |
$node[2] = false; | |
$node[3] = false; | |
$left = ''; | |
$right = ''; | |
$level = null; | |
$max = 34; | |
// | |
if( ! isset( $item['text']['data'] ) ) | |
{ | |
return; | |
} | |
foreach( $item['text']['data'] as $cnt => $line ) | |
{ | |
// Reset $data on each loop. | |
$data = ''; | |
// Remove the line returns (essential). | |
$line = str_replace( "\n", '', $line ); | |
if( $this->opts['dev'] && $cnt == $max ) | |
{ | |
break; | |
} | |
// Comment start. | |
if( $this->iss( $line, '/*' ) || $skip ) | |
{ | |
$skip = 1; | |
} | |
// Comment end. | |
if( $this->iss( $line, '*/' ) && ! $skip ) | |
{ | |
$skip = 0; | |
} | |
// Skip single line comment. | |
if( $this->iss( $line, '/*' ) && $this->iss( $line, '*/' ) ) | |
{ | |
continue; | |
} | |
// Process only lines containing valid CSS. | |
if( ! $this->isCSS( $line ) ) | |
{ | |
continue; | |
} | |
// Skip empty lines. | |
if( empty( $line ) ) | |
{ | |
continue; | |
} | |
$this->opts['dev'] ? printf( '<pre>' . $cnt . ': ' . $line . '<br>' ) : ''; | |
//============================== NODE 0 ================================= | |
if( $this->iss( $line, '{' ) && ! $node[0] && ! $node[1] && ! $this->isMedia( $line ) ) | |
{ | |
$node[0] = true; | |
$level = ' '; // 0 (4) | |
$data .= $this->genNode( $line, $level ); | |
$this->opts['dev2'] ? $data .= ' /* End Node 0 */' . PHP_EOL : ''; | |
$node[0] = false; | |
} | |
//============================== NODE 1 ================================= | |
if( $this->iss( $line, '{' ) && ! $node[1] && ! $node[2] && ! $node[3] && $this->isMedia( $line ) ) | |
{ | |
$node[1] = true; | |
$level = ' '; // 0 (4) | |
$this->opts['dev2'] ? $data = ' /* Begin Node 1 */' . PHP_EOL : ''; | |
$data .= $this->genNode( $line, $level ); | |
} | |
//============================== NODE 2 =============================== | |
elseif( $this->iss( $line, '{' ) && $node[1] && ! $node[2] && ! $node[3] ) | |
{ | |
$node[2] = true; | |
$level = ' '; // 1 (6) | |
$this->opts['dev2'] ? $data = ' /* Begin Node 2 */' . PHP_EOL : ''; | |
$data .= $this->genNode( $line, $level ); | |
} | |
//============================== NODE 3 ============================= | |
elseif( $this->iss( $line, '{' ) && $node[1] && $node[2] && ! $node[3] ) | |
{ | |
$node[3] = true; | |
$level = ' '; // 2 (8) | |
$this->opts['dev2'] ? $data = ' /* Begin Node 3 */' . PHP_EOL : ''; | |
$data .= $this->genNode( $line, $level ); | |
} | |
elseif( $this->iss( $line, '{' ) && $this->iss( $line, '}' ) ) | |
{ | |
$data = $this->genNodeEmpty( $line, $level ); | |
} | |
else | |
{ | |
// Not captured | |
} | |
// ========================== SELECTOR ONLY ============================= | |
if( $this->iss( $line, ':' ) && $this->iss( $line, ';' ) ) | |
{ | |
$level0 = ' ' . $level; | |
$data = $this->genPair( $line, $level0 ); | |
} | |
//========================== CLOSE NODE 3 =============================== | |
if( $this->iss( $line, '}' ) && $node[1] && $node[2] && $node[3] ) | |
{ | |
$node[3] = false; | |
$data = ' ],' . PHP_EOL; | |
$this->opts['dev2'] ? $data .= ' /* Close Node 3 */' . PHP_EOL : ''; | |
} | |
//=========================== CLOSE NODE 2 ============================== | |
if( $this->iss( $line, '}' ) && $node[1] && $node[2] && ! $node[3] ) | |
{ | |
$node[2] = false; | |
$data = ' ],' . PHP_EOL; | |
$this->opts['dev2'] ? $data .= ' /* Close Node 2 */' . PHP_EOL : ''; | |
} | |
//=========================== CLOSE NODE 1 ============================== | |
// Node 1 is always a media query. | |
if( $this->iss( $line, '}' ) && $node[1] && ! $node[2] && ! $node[3] && $this->isMedia( $line ) ) | |
{ | |
$node[1] = false; | |
// Should be the end of the line, man. | |
$data = ' ],' . PHP_EOL; | |
$this->opts['dev2'] ? $data .= ' /* Close Node 1 */' . PHP_EOL : ''; | |
} | |
//=========================== CLOSE NODE 0 ============================== | |
// Node 0 is always a non-Media query | |
if( $node[0] && ! $node[1] && ! $node[2] && ! $node[3] && ! $this->isMedia( $line ) ) | |
{ | |
$node[0] = false; | |
// Should be the end of the line, man. | |
$data = ' ],' . PHP_EOL; | |
$this->opts['dev2'] ? $data .= ' /* Close Node 0 */' . PHP_EOL : ''; | |
} | |
//==================================================== | |
$item['php'] .= $data; | |
} // Loop | |
// Array is closed in the function body function. | |
return $item; | |
} | |
/** | |
* Generate Node | |
* | |
* @param $line | |
* | |
* @return string; | |
*/ | |
private function genNode( $line, $level ) | |
{ | |
$left = null; | |
$right = null; | |
$ex = explode( '{', $line ); | |
if( ! empty( $ex[0] ) ) | |
{ | |
$left = sprintf( "'%s'", trim( $ex[0] ) ); | |
} | |
if( isset( $ex[1] ) ) | |
{ | |
$ex[1] = str_replace( "\n", '', $ex[1] ); | |
$ex[1] = trim( $ex[1] ); | |
if( strlen( $ex[1] ) > 0 ) | |
{ | |
$right = sprintf( "'%s'", $ex[1] ); | |
} | |
} | |
$data = sprintf( '%s%s => [ %s%s', $level, $left, $right, PHP_EOL ); | |
$data .= $this->genPair( $line, $level ); | |
$data .= $level . '],' . PHP_EOL; | |
return $data; | |
} | |
/** | |
* Generate Pairing | |
* | |
* @param $line | |
*/ | |
private function genPair( $line, $level ) | |
{ | |
$left = null; | |
$right = null; | |
$line = rtrim( $line, ';' ); | |
$ex = explode( ':', $line ); | |
if( ! empty( $ex[0] ) ) | |
{ | |
$left = sprintf( "'%s'", trim( $ex[0] ) ); | |
} | |
if( ! empty( $ex[1] ) ) | |
{ | |
$right = sprintf( "'%s'", trim( $ex[1] ) ); | |
} | |
return sprintf( '%s%s => %s,%s', $level, $left, $right, PHP_EOL ); | |
} | |
/** | |
* Generate Node | |
* | |
* @param $line | |
* | |
* @return string; | |
*/ | |
private function genNodeEmpty( $line, $level ) | |
{ | |
$left = null; | |
$right = null; | |
$ex = explode( '{', $line ); | |
if( ! empty( $ex[0] ) ) | |
{ | |
$left = sprintf( "'%s'", trim( $ex[0] ) ); | |
} | |
$right = $level . '],' . PHP_EOL; | |
return sprintf( '%s%s => [ %s%s', $level, $left, $right, PHP_EOL ); | |
} | |
/** | |
* Check Line | |
* | |
* @param string $line | |
* | |
* @return bool | |
*/ | |
private function chkLine( $line ) | |
{ | |
// Skip empty lines. | |
if( ! empty( $line ) ) | |
{ | |
return true; | |
} | |
else | |
{ | |
return false; | |
} | |
} | |
/** | |
* Check Data | |
* | |
* @param string $data | |
* | |
* @return bool | |
*/ | |
private function chkData( $data ) | |
{ | |
// Not empty, good!!! | |
if( ! empty( $data ) && ! is_array( $data ) ) | |
{ | |
return true; | |
} | |
else | |
{ | |
pre_dump( 'Problem with the data, Houston' ); | |
return false; | |
} | |
} | |
/** | |
* Process Line | |
* | |
* Moved to Process File, but left here for comparison. | |
* | |
* @param array $item | |
* @param string $line | |
* @param int $cnt | |
* | |
* @return string|bool | |
*/ | |
private function prcLine( $item, $line, $cnt ) | |
{ | |
// Skip empty lines. | |
if( ! empty( $line ) ) | |
{ | |
// Change colons to arrows on selectors only. | |
if( $this->isSelector( $line ) && ! $this->isMedia( $line ) && ! $this->isPseudo( $line ) ) | |
{ | |
$line = str_replace( ':', '=>', $line ); | |
} | |
if( $this->iss( $line, '{' ) ) | |
{ | |
//$line = $line . $item['line']['sel']; | |
} | |
// Remove double line spacing for an array. | |
$line = str_replace( "\n\n", "\n", $line ); | |
// Change the brackets., one of these is media close. | |
$line = str_replace( '{', '[', $line ); | |
// Remove all semi-colons. | |
$line = str_replace( ';', '', $line ); | |
// Replace the right bracket. Add a comma. | |
$line = str_replace( '}', '],', $line ); | |
// Change '[' to '=> ['. | |
$line = str_replace( '[', '=> [', $line ); | |
// Add quotes around all selectors and attributes. | |
$line = $this->addQuotes( $line ); | |
return $line; | |
} | |
else | |
{ | |
return false; | |
} | |
} | |
/** | |
* Is a Media Query | |
* | |
* @param string $line | |
* | |
* @return bool | |
*/ | |
private function isMedia( $line ) | |
{ | |
if( $this->iss( $line, '@media' ) && $this->iss( $line, '{' ) ) | |
{ | |
return true; | |
} | |
else | |
{ | |
return false; | |
} | |
} | |
/** | |
* Is a Comment | |
* | |
* @param string $line | |
* | |
* @return bool | |
*/ | |
private function isComment( $line ) | |
{ | |
if( $this->iss( $line, '/*' ) | |
|| $this->iss( $line, '*/' ) | |
|| $this->iss( $line, '*' ) | |
|| $this->iss( $line, ':' ) ) | |
{ | |
return true; | |
} | |
else | |
{ | |
return false; | |
} | |
} | |
/** | |
* Is a Element. | |
* | |
* @param string $line | |
* | |
* @return bool | |
*/ | |
private function isElement( $line ) | |
{ | |
if( $this->iss( $line, '{' ) && ! $this->isMedia( $line ) && ! $this->isPseudo( $line ) ) | |
{ | |
return true; | |
} | |
else | |
{ | |
return false; | |
} | |
} | |
/** | |
* Is a Multi Line Selector | |
* | |
* @param string $line | |
* | |
* @return bool | |
*/ | |
private function isMultiSel( $line ) | |
{ | |
if( // Comma, but no semi-colon. | |
( $this->iss( $line, ',' ) && ! $this->iss( $line, ';' ) ) | |
// No colons. | |
&& ! $this->iss( $line, ':' ) | |
// No semi colons on their own. | |
&& ! $this->iss( $line, ';' ) | |
// Not a comment. | |
&& ! $this->isComment( $line ) ) | |
{ | |
return true; | |
} | |
else | |
{ | |
return false; | |
} | |
} | |
/** | |
* Is a Pseudo Element. | |
* | |
* @param string $line | |
* | |
* @return bool | |
*/ | |
private function isPseudo( $line ) | |
{ | |
if( $this->iss( $line, '{' ) && $this->iss( $line, ':' ) ) | |
{ | |
return true; | |
} | |
else | |
{ | |
return false; | |
} | |
} | |
/** | |
* Is a Selector Attribute Pairing | |
* | |
* MUST be called before colons are removed. | |
* | |
* @param string $line | |
* | |
* @return bool | |
*/ | |
private function isSelector( $line ) | |
{ | |
if( $this->iss( $line, ':' ) && $this->iss( $line, ';' ) ) | |
{ | |
return true; | |
} | |
else | |
{ | |
return false; | |
} | |
} | |
/** | |
* Add Quotes to the File | |
* | |
* Add single quotes around all CSS selectors and attributes. | |
* | |
* The simplest way to do this appears to break the file string | |
* into a line by line array (i.e. take apart on line breaks). | |
* Then, for each line, take it apart either on the '{' or on | |
* the ':', then trim the remaining on the left and the right, | |
* then put back together. | |
* | |
* The disadvantage to this approach is that well formed CSS | |
* has multiple selectors on separate lines. These need to be | |
* placed all on a single line (programmatically or manually), | |
* so that they will be dealt with in their entirety, instead | |
* of being left out on that line. | |
* | |
* @link https://www.php.net/manual/en/function.preg-split.php | |
* | |
* @example $keys = preg_split("/[\s,]+/", "hypertext language, programming"); | |
* | |
* @param array $file | |
* @param array $item | |
* | |
* @return array | |
*/ | |
private function addQuoFile( $file, $item ) | |
{ | |
$text = ''; | |
if( isset( $item['text']['input'] ) ) | |
{ | |
if( $this->opts['dev2'] ) | |
{ | |
pre_dump( $item['text']['input'], 1 ); | |
} | |
$lines = preg_split("/[\n]/", $item['text']['input'] ); | |
foreach( $lines as $line ) | |
{ | |
$left = ''; | |
$right = ''; | |
$spc[1] = ' '; // Four spaces (minimum). | |
$spc[2] = ' '; // Six spaces | |
if( $this->iss( $line, '{' ) && ! $this->iss( $line, '}' ) ) | |
{ | |
$parts = explode( '{', $line ); | |
if( isset( $parts[0] ) ) | |
{ | |
$left = trim( $parts[0] ); | |
$left = sprintf( "'%s'", $left ); | |
} | |
if( isset( $parts[1] ) ) | |
{ | |
$right = trim( $parts[1] ); | |
$right = sprintf( "'%s'", $right ); | |
} | |
// Add indentation ($spc#). | |
$line = sprintf( '%s%s {%s', $spc[1], $left, PHP_EOL ); | |
$text .= $line; | |
} | |
// empty brackets (must keep). | |
elseif( $this->iss( $line, '{' ) && $this->iss( $line, '}' ) ) | |
{ | |
$parts = explode( '{', $line ); | |
if( isset( $parts[0] ) ) | |
{ | |
$left = trim( $parts[0] ); | |
$left = sprintf( "'%s'", $left ); | |
} | |
if( isset( $parts[1] ) ) | |
{ | |
// No quotes. Should be just a bracket. | |
$right = trim( $parts[1] ); | |
} | |
// Add indentation ($spc#). | |
$line = sprintf( '%s%s {%s%s', $spc[1], $left, $right, PHP_EOL ); | |
$text .= $line; | |
} | |
elseif( $this->iss( $line, ':' ) && $this->iss( $line, ';' ) ) | |
{ | |
$parts = explode( ':', $line ); | |
if( isset( $parts[0] ) ) | |
{ | |
$left = trim( $parts[0] ); | |
$left = sprintf( "'%s'", $left ); | |
} | |
if( isset( $parts[1] ) ) | |
{ | |
$right = trim( $parts[1] ); | |
$right = trim( $right, ';' ); | |
$right = sprintf( "'%s'", $right ); | |
} | |
// Add indentation ($spc).and => | |
$line = sprintf( '%s%s => %s,%s', $spc[2], $left, $right, PHP_EOL ); | |
$text .= $line; | |
} | |
else | |
{ | |
$text .= $spc[1] . $line . PHP_EOL; | |
} | |
} | |
$item['text']['quot'] = $text; | |
} | |
if( $this->opts['dev2'] ) | |
{ | |
pre_dump( $item['text']['quot'], 0 ); | |
} | |
return $item; | |
} | |
/** | |
* Replace the Brackets on the File. | |
* | |
* Replaces the { and } with => [ and ], | |
* Do not replace the : in pseudo elements. | |
* | |
* @param string $str | |
* | |
* @return string | |
*/ | |
private function repBrkFile( $file, $item ) | |
{ | |
$text = ''; | |
if( isset( $item['text']['quot'] ) ) | |
{ | |
// Initialize | |
$text = $item['text']['quot']; | |
$text = str_replace( '{', '=> [', $text ); | |
$text = str_replace( '}', '],', $text ); | |
$text = str_replace( ';', '', $text ); | |
$item['text']['output'] = $text; | |
} | |
if( $this->opts['dev1'] ) | |
{ | |
pre_dump( $item['text']['output'], 1 ); | |
} | |
return $item; | |
} | |
/** | |
* Replace the Colons in the File | |
* | |
* Replace the : with =>, but not pseudo selectors. | |
* Break apart by line, and put together again to do this. | |
* | |
* @param array $file | |
* @param array $item | |
* | |
* @return array | |
*/ | |
private function repClnFile( $file, $item ) | |
{ | |
$text = ''; | |
if( isset( $item['text']['quot'] ) ) | |
{ | |
// Initialize | |
$text = $item['text']['quot']; | |
$text = str_replace( '{', '=> [', $text ); | |
$text = str_replace( '}', '],', $text ); | |
$text = str_replace( ';', '', $text ); | |
$item['text']['output'] = $text; | |
} | |
if( $this->opts['dev1'] ) | |
{ | |
pre_dump( $item['text']['output'], 1 ); | |
} | |
return $item; | |
} | |
/** | |
* Add Quotes | |
* | |
* Adds single quotes around CSS selectors and attributes. | |
* | |
* @param string $str | |
* | |
* @return string | |
*/ | |
private function addQuotes( $line ) | |
{ | |
if( $this->iss( $line, '=>' ) ) | |
{ | |
$ex = explode( '=>', $line ); | |
// Left side | |
if( isset( $ex[0] ) ) | |
{ | |
$left = trim( $ex[0] ); | |
if( $this->iss( $ex[0], '@media' ) ) | |
{ | |
$left = sprintf( " '%s'", $left ); | |
} | |
elseif( $this->iss( $ex[1], '[' ) ) | |
{ | |
$left = sprintf( " '%s'", $left ); | |
} | |
else | |
{ | |
$left = sprintf( " '%s'", $left ); | |
} | |
} | |
// Right side | |
if( isset( $ex[1] ) && ! empty( $ex[1] ) ) | |
{ | |
$right = trim( $ex[1] ); | |
if( ! $this->iss( $ex[1], '[' ) ) | |
{ | |
$right = sprintf( "'%s',", $right ); | |
} | |
} | |
} | |
// Concatenate | |
if( ! empty( $left ) || ! empty( $right ) ) | |
{ | |
$line = sprintf( '%s => %s', $left, $right ); | |
} | |
return $line; | |
} | |
/** | |
* Get the Function Name | |
* | |
* @param array $file | |
* @param array $item | |
* | |
* @return array | |
*/ | |
private function genFncName( $file, $item ) | |
{ | |
if( isset( $item['file']['base'] ) ) | |
{ | |
$item['function']['name'] = null; | |
$item['function']['title'] = null; | |
$item['function']['name'] = sprintf( 'get_%s_data', $item['file']['base'] ); | |
$item['function']['name'] = str_replace( '-', '_', $item['function']['name'] ); | |
$title = str_replace( '_', ' ', $item['function']['name'] ); | |
$item['function']['title'] = ucwords( $title ); | |
} | |
return $item; | |
} | |
/** | |
* Generates the Data (Assoc Array as a String) | |
* | |
* @param array $file | |
* @param array $item | |
* | |
* @return array | |
*/ | |
private function genDat( $file, $item ) | |
{ | |
$str = ''; | |
$str .= ' $items = [' . PHP_EOL; | |
// Generates a CSS string. | |
foreach( $entities as $cnt => $entity ) | |
{ | |
if( $entity['type'] == $type['name'] ) | |
{ | |
if( $entity['use'] ) | |
{ | |
$str .= sprintf( " '%s' => [%s", $entity['name'], PHP_EOL ); | |
foreach( $attributes as $attribute ) | |
{ | |
if( $attribute['use'] ) | |
{ | |
$str .= sprintf( " '%s' => '%s',%s", | |
$attribute['name'], $attribute['default'], PHP_EOL ); | |
} | |
} | |
if( $cnt < count( $entities ) ) | |
{ | |
$str .= ' ],'; | |
} | |
} | |
} | |
} // Loop | |
$str .= ' ];' . PHP_EOL; | |
$str .= PHP_EOL; | |
$str .= ' return $items;' . PHP_EOL; | |
$item['php'] = $str; | |
return $item; | |
} | |
/** | |
* Generates the File | |
* | |
* @param array $file | |
* @param array $item | |
* | |
* @return array | |
*/ | |
private function genFile( $file, $item ) | |
{ | |
if( is_array( $item ) ) | |
{ | |
$item = $this->getPageHeader( $file, $item ); | |
$item = $this->getFunctionBody( $file, $item ); | |
if( $this->opts['dev3'] ) | |
{ | |
pre_dump( $item['php'] ); | |
} | |
$item = $this->getFileSize( $file, $item ); | |
$item = $this->getFileFooter( $file, $item ); | |
} | |
return $item; | |
} | |
/** | |
* Page Header | |
* | |
* @param array $file | |
* @param array $item | |
* | |
* @return array | |
*/ | |
private function getPageHeader( $file, $item ) | |
{ | |
// Initialize | |
$item['text']['print'] = ''; | |
$str = ''; | |
if( isset( $item['file']['name'] ) ) | |
{ | |
$str .= '<?php' . PHP_EOL; | |
$str .= '/**' . PHP_EOL; | |
$str .= sprintf( ' * %s%s', $this->opts['page']['title'], PHP_EOL ); | |
$str .= ' *' . PHP_EOL; | |
$str .= sprintf( ' * File: %s%s', $item['file']['name'], PHP_EOL ); | |
$str .= $this->getTimeStamp(); | |
$str .= $this->getIDStamp(); | |
$str .= ' *' . PHP_EOL; | |
$str .= sprintf( ' * (By: %s)%s', $this->opts['this']['file'], PHP_EOL ); | |
$str .= ' */' . PHP_EOL; | |
$str .= 'namespace Earth3300\EC01;' . PHP_EOL; | |
$str .= PHP_EOL; | |
$str .= "if( ! defined( 'NDA' ) )" . PHP_EOL; | |
$str .= '{' . PHP_EOL; | |
$str .= " define( 'NDA', true );" . PHP_EOL; | |
$str .= '}' . PHP_EOL; | |
$str .= PHP_EOL; | |
$item['text']['print'] .= $str; | |
} | |
return $item; | |
} | |
/** | |
* Get Function Body | |
* | |
* @param array $file | |
* @param array $item | |
* | |
* @return array | |
*/ | |
private function getFunctionBody( $file, $item ) | |
{ | |
$str = ''; | |
if( isset( $item['function']['name'] ) ) | |
{ | |
$str .= '/**' . PHP_EOL; | |
$str .= sprintf( ' * %s%s', $item['function']['title'], PHP_EOL ); | |
$str .= ' *' . PHP_EOL; | |
$str .= ' * @return array' . PHP_EOL; | |
$str .= ' */' . PHP_EOL; | |
$str .= sprintf( 'function %s()%s', $item['function']['name'], PHP_EOL ); | |
$str .= '{' . PHP_EOL; | |
$str .= ' $item = [' . PHP_EOL; | |
$str .= $item['text']['output']; | |
$str .= ' ];' . PHP_EOL; | |
$str .= PHP_EOL; | |
$str .= ' return $item;' . PHP_EOL; | |
$str .= '}' . PHP_EOL; | |
$str .= PHP_EOL; | |
$item['text']['print'] .= $str; | |
} | |
return $item; | |
} | |
/** | |
* Time Stamp (Including Created Date) | |
* | |
* @return string | |
*/ | |
private function getTimeStamp() | |
{ | |
$str = ''; | |
$str .= sprintf( ' * Created: %s%s', $this->opts['this']['date']['created'], PHP_EOL ); | |
$str .= sprintf( ' * Updated: %s%s', date( 'Y-m-d' ), PHP_EOL ); | |
$str .= sprintf( ' * Time: %s%s', date( 'H:i:s T' ), PHP_EOL ); | |
return $str; | |
} | |
/** | |
* ID Stamp | |
* | |
* @return string | |
*/ | |
private function getIDStamp() | |
{ | |
$str = ''; | |
$str .= ' * ID: ENG-ON-001' . PHP_EOL; | |
return $str; | |
} | |
/** | |
* Is (In) String (Helper Function) | |
* | |
* @param string $a Haystack | |
* @param string $b Needle | |
* | |
* @return bool | |
*/ | |
function iss( $a, $b ) | |
{ | |
if( is_string( $a ) && is_string( $b ) | |
&& strpos( $a, $b ) !== false ) | |
{ | |
return true; | |
} | |
else | |
{ | |
return false; | |
} | |
} | |
/** | |
* Is CSS (Helper Function) | |
* | |
* @param string $line | |
* | |
* @return bool | |
*/ | |
function isCSS( $line ) | |
{ | |
// Opening or closing | |
if( $this->iss( $line, '{' ) || $this->iss( $line, '}' ) ) | |
{ | |
return true; | |
} | |
// Selector : Attribute | |
elseif( $this->iss( $line, ':' ) && $this->iss( $line, ';' ) ) | |
{ | |
return true; | |
} | |
elseif( $this->iss( $line, ',' ) && ! $this->isComment( $line ) ) | |
{ | |
return true; | |
} | |
else | |
{ | |
return false; | |
} | |
} | |
/** | |
* Get File Size | |
* | |
* @param array $file | |
* @param array $item | |
* | |
* @return array | |
*/ | |
private function getFileSize( $file, $item ) | |
{ | |
$item['size'] = null; | |
if( isset( $item['text']['output'] ) ) | |
{ | |
$item['size'] = strlen( $item['text']['output'] ); | |
} | |
return $item; | |
} | |
/** | |
* File Footer | |
* | |
* @param array $file | |
* @param array $item | |
* | |
* For use at the end of the file as needed. | |
*/ | |
private function getFileFooter( $file, $item ) | |
{ | |
// Initialize | |
$str = ''; | |
$str .= '/*'; | |
$str .= ' End of File ('; | |
$str .= $item['size'] . ' B).'; | |
$str .= ' */' . PHP_EOL; | |
$str .= PHP_EOL; | |
// Add this string to the end... | |
$item['text']['print'] .= $str; | |
return $item; | |
} | |
/** | |
* Print the File | |
* | |
* @param array $file | |
* @param array $item | |
* | |
* @return array | |
*/ | |
private function printFile( $file, $item ) | |
{ | |
$str = ''; | |
if ( isset( $_GET['print'] ) ) | |
{ | |
if ( isset( $_POST['safety'] ) ) | |
{ | |
$str = ''; | |
if( isset( $item['file']['output'] ) && isset( $item['php'] ) ) | |
{ | |
if( ! file_exists( $item['file']['output'] ) | |
|| $this->opts['file']['overwrite'] ) | |
{ | |
$resp = file_put_contents( $item['file']['output'], $item['text']['print'] ); | |
$str = sprintf( | |
'File: %s (%s B)<br>%s', $item['file']['output'], $resp, PHP_EOL ); | |
} | |
else | |
{ | |
$str = sprintf( | |
'File: %s (exists)<br>%s', $item['file']['output'], PHP_EOL ); | |
} | |
} | |
} | |
} | |
return $str; | |
} | |
/** | |
* Get Form | |
* | |
* @return string|bool | |
*/ | |
private function getForm() | |
{ | |
if( isset( $_GET['ctrls'] ) ) | |
{ | |
// Initialize | |
$str = ''; | |
$str .= '<form action="" method="post">' . PHP_EOL; | |
$str .= '<div>' . PHP_EOL; | |
$str .= '<input type="checkbox" name="safety" id="safety" required> ' . PHP_EOL; | |
$str .= '<input type="submit" class="btn btn-primary" value="Run">' . PHP_EOL; | |
$str .= '</div>' . PHP_EOL; | |
$str .= '</form>' . PHP_EOL; | |
return $str; | |
} | |
else | |
{ | |
return false; | |
} | |
} | |
/** | |
* Wrap the HTML in Page HTML `<!DOCTYPE html>`, etc. | |
* | |
* Use basic settings. Assume no SEO necessary. Bootstrap CSS only. | |
* | |
* @param array $file | |
* | |
* @return string | |
*/ | |
private function getPageHTML( $file ) | |
{ | |
$str = 'N/A'; | |
if( is_array( $file ) ) | |
{ | |
$str = ''; | |
$str = '<!DOCTYPE html>' . PHP_EOL; | |
$str .= '<html lang="en-CA" class="theme-dark">' . 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['this']['title'], PHP_EOL ); | |
$str .= '<meta name="robots" content="noindex,nofollow" />' . PHP_EOL; | |
$str .= '<link rel=stylesheet href="/style.min.css">' . PHP_EOL; | |
$str .= '</head>' . PHP_EOL; | |
$str .= '<body>' . PHP_EOL; | |
$str .= '<main>' . PHP_EOL; | |
$str .= sprintf( '<h1>%s</h1>%s', $this->opts['this']['title'], PHP_EOL ); | |
$str .= isset( $file['text']['desc'] ) ? $file['text']['desc'] : ''; | |
$str .= $this->getForm(); | |
$str .= isset( $file['text']['info'] ) ? $file['text']['info'] : ''; | |
$str .= isset( $file['text']['resp'] ) ? $file['text']['resp'] : ''; | |
if( isset( $_GET['display'] ) ) | |
{ | |
if( isset( $file['php'] ) ) | |
{ | |
$str .= '<pre>' . PHP_EOL; | |
$str .= $file['php']; | |
$str .= '</pre>' . PHP_EOL; | |
} | |
} | |
$str .= '</main>' . PHP_EOL; | |
$str .= '</html>' . PHP_EOL; | |
} | |
return $str; | |
} | |
} // End Class | |
if ( ! function_exists( 'pre_dump' ) ) { | |
/** Dumps a formatted string or array. */ | |
function pre_dump( $arr, $continue = 1 ) { | |
if ( isset( $_GET['debug'] ) ) { | |
if (is_string( $arr ) ) { | |
$arr = str_replace( ['<','>'], ['<','>'], $arr ); | |
} | |
echo "<pre>" . PHP_EOL; | |
var_dump( $arr ); | |
if ( isset( $_GET['exit'] ) || ! $continue ) { | |
exit( '<br/>' . 'Done.' ); | |
} | |
echo "</pre>" . PHP_EOL; | |
} | |
} | |
} | |
/** | |
* Global initialization function | |
*/ | |
function ec01_css_printer() | |
{ | |
$printer = new CssPrinter(); | |
return $printer->init(); | |
} | |
ec01_css_printer(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment