398 lines
16 KiB
PHP
Executable File
398 lines
16 KiB
PHP
Executable File
<?php
|
|
/**
|
|
* Simple compilescript for DBSR.
|
|
*
|
|
* Compared to the rest of DBSR this code is a mess,
|
|
* but since it's only used for compiling I never
|
|
* spend to much time on refactoring this. Feel free
|
|
* to do so. ;)
|
|
*/
|
|
|
|
// Directories
|
|
$input_directory = 'src';
|
|
$output_directory = 'compiled';
|
|
|
|
// Minimize output (optimalisations like whitespace removal and file combination, reducing total size and increasing speed)
|
|
$minimize_php = TRUE;
|
|
$minimize_html = TRUE;
|
|
$minimize_js = TRUE;
|
|
$minimize_css = TRUE;
|
|
$minimize_svg = TRUE;
|
|
|
|
// Compress entire PHP output file using a compression algorithm
|
|
// Valid options: none, gzip
|
|
// Note that gzip will void cross-platform compatibility!
|
|
$compress = 'none';
|
|
|
|
// Files to compile
|
|
$compile_sets = array(
|
|
'DBSearchReplace-GUI.php' => array(
|
|
'DBSR.php',
|
|
'DBSR_GUI_Resources',
|
|
'DBSR_GUI.php',
|
|
'Bootstrapper.php',
|
|
'DBSR_GUI_Bootstrapper.php'
|
|
),
|
|
'DBSearchReplace-CLI.php' => array(
|
|
'DBSR.php',
|
|
'DBSR_CLI.php',
|
|
'Bootstrapper.php',
|
|
'DBSR_CLI_Bootstrapper.php'
|
|
),
|
|
);
|
|
|
|
// Stop throwing irritating errors, we're simply compiling!
|
|
error_reporting(0);
|
|
|
|
// Uses UglifyJS... if you don't have it, get the latest version from GitHub <https://github.com/mishoo/UglifyJS2>
|
|
function jsCompiler($code) {
|
|
// Start uglifyjs
|
|
$process = proc_open('.' . DIRECTORY_SEPARATOR . 'node_modules' . DIRECTORY_SEPARATOR . '.bin' . DIRECTORY_SEPARATOR . 'uglifyjs -c unsafe=true -b beautify=false,ascii_only=true', array(
|
|
0 => array('pipe', 'r'),
|
|
1 => array('pipe', 'w'),
|
|
2 => array('pipe', 'w'),
|
|
), $pipes);
|
|
|
|
// Check if uglifyjs could be found / started
|
|
if(is_resource($process)) {
|
|
// Write the code to STDIN for uglifyjs
|
|
fwrite($pipes[0], $code, strlen($code));
|
|
|
|
// Close the pipe so uglifyjs knows it's time to start
|
|
fclose($pipes[0]);
|
|
|
|
// Read the compressed output from STDOUT
|
|
$code_compressed = trim(stream_get_contents($pipes[1]));
|
|
|
|
// Close STDOUT to prevent deadlocks
|
|
fclose($pipes[1]);
|
|
|
|
// Read any errors from STDERR
|
|
$errors = stream_get_contents($pipes[2]);
|
|
|
|
// Close STDERR to prevent deadlocks
|
|
fclose($pipes[2]);
|
|
|
|
// Close the process handle
|
|
$return_value = proc_close($process);
|
|
|
|
// Check if the code compression completed succesfully
|
|
if($return_value > 0) {
|
|
// Something went wrong, return the old code
|
|
echo 'Warning: UglifyJS returned a non-zero value!', PHP_EOL;
|
|
if(!empty($errors)) echo $errors, PHP_EOL;
|
|
return $code;
|
|
} else {
|
|
// Return the compressed code
|
|
return $code_compressed;
|
|
}
|
|
} else {
|
|
// No uglifyjs, so just return the raw code
|
|
echo 'Warning: failed to run UglifyJS!', PHP_EOL;
|
|
return $code;
|
|
}
|
|
}
|
|
|
|
// Process dir function
|
|
function add_resources($dir, $prefix, &$source) {
|
|
global $minimize_php, $minimize_html, $minimize_js, $minimize_css, $minimize_svg;
|
|
|
|
// Record any winnings by compression
|
|
$compression_winnings = 0;
|
|
|
|
// Load up all resources in this directory
|
|
$resources = glob($dir . DIRECTORY_SEPARATOR . '*');
|
|
|
|
// Special case: CSS/JS compression
|
|
if((preg_match('#/?js$#', $dir) && $minimize_js) || (preg_match('#/?css$#', $dir) && $minimize_css)) {
|
|
if(preg_match('#/?js$#', $dir)) {
|
|
// JS order
|
|
$order = array(
|
|
'jquery',
|
|
'jquery-ui',
|
|
'jquery-liteaccordion',
|
|
'jquery-blockui',
|
|
'script',
|
|
);
|
|
} else {
|
|
// CSS order
|
|
$order = array(
|
|
'SourceSansPro',
|
|
'SourceCodePro',
|
|
'reset',
|
|
'jquery-ui',
|
|
'jquery-liteaccordion',
|
|
'style',
|
|
);
|
|
}
|
|
|
|
// Webfonts CSS special case
|
|
if(preg_match('#/?css$#', $dir)) {
|
|
$resources = array_merge($resources, glob(str_replace('css', 'webfonts', $dir) . DIRECTORY_SEPARATOR . '*.css'));
|
|
}
|
|
|
|
// Collect resource content
|
|
$resource_content = '';
|
|
foreach($order as $o) {
|
|
foreach($resources as $key => $resource) {
|
|
if(strpos($resource, $o) !== FALSE) {
|
|
if($resource_file_content = file_get_contents($resource)) {
|
|
$resource_content .= "\n" . $resource_file_content;
|
|
} else {
|
|
exit('Unable to load file ' . basename($resource));
|
|
}
|
|
unset($resources[$key]);
|
|
}
|
|
}
|
|
}
|
|
foreach($resources as $key => $resource) {
|
|
if(!is_file($resource)) continue;
|
|
if(is_readable($resource) && ($resource_file_content = file_get_contents($resource))) {
|
|
$resource_content .= "\n" . $resource_file_content;
|
|
} else {
|
|
exit('Unable to load file ' . basename($resource));
|
|
}
|
|
unset($resources[$key]);
|
|
}
|
|
|
|
// Save length to calculate winnings
|
|
$resource_content_length = strlen($resource_content);
|
|
|
|
// Compile / minimize
|
|
if(preg_match('#/?js$#', $dir)) {
|
|
// JS using Closure Compiler
|
|
$resource_content = jsCompiler($resource_content);
|
|
} else {
|
|
// CSS using regexes
|
|
$resource_content = preg_replace('#/\*.*?\*/#s', '', $resource_content);
|
|
$resource_content = preg_replace('/[\r\n]+/', '', $resource_content);
|
|
$resource_content = preg_replace('/\s*([:,])\s*/', '$1', $resource_content);
|
|
$resource_content = preg_replace('/\s*{\s*/', '{', $resource_content);
|
|
$resource_content = preg_replace('/\s*;?\s*}\s*/', '}', $resource_content);
|
|
$resource_content = preg_replace('/\s+/', ' ', $resource_content);
|
|
$resource_content = trim($resource_content);
|
|
}
|
|
|
|
// Calculate improvement by compression / minimization
|
|
$compression_winnings += $resource_content_length - strlen($resource_content);
|
|
|
|
// Write to source
|
|
if(preg_match('/[^\w\s[:print:]]/', $resource_content, $matches)) {
|
|
$resource_content = 'base64:' . base64_encode($resource_content);
|
|
} else {
|
|
$resource_content = 'normal:' . $resource_content;
|
|
}
|
|
if(preg_match('#/?js$#', $dir)) {
|
|
$source .= 'public static $js_scriptjs = ' . var_export($resource_content, TRUE) . ';' . "\n";
|
|
} else {
|
|
$source .= 'public static $css_stylecss = ' . var_export($resource_content, TRUE) . ';' . "\n";
|
|
}
|
|
} elseif(preg_match('#/?webfonts$#', $dir) && $minimize_css) {
|
|
foreach($resources as $key => $resource) {
|
|
if(preg_match('#\.css$#', $resource)) {
|
|
unset($resources[$key]);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Loop through dir
|
|
foreach($resources as $resource) {
|
|
if(is_readable($resource) && is_file($resource)) {
|
|
if(!($resource_content = file_get_contents($resource))) {
|
|
exit('Unable to load file ' . basename($resource));
|
|
}
|
|
|
|
// Save length to calculate winnings
|
|
$resource_content_length = strlen($resource_content);
|
|
|
|
// Special case: template file
|
|
if(basename($resource) == 'template.html') {
|
|
// Remove all JS tags to account for compression
|
|
if($minimize_js) $resource_content = preg_replace('#(\s*<script[^>]+></script>)+(\s+<script[^>]+script.js[^>]+></script>)#', '$2', $resource_content);
|
|
|
|
// Remove all LINK tags to account for CSS compression
|
|
if($minimize_css) $resource_content = preg_replace('#(\s*<link[^>]*rel="stylesheet"[^>]*/>)+(\s+<link[^>]+style.css[^>]+/>)#', '$2', $resource_content);
|
|
|
|
// Remove useless HTML whitespace
|
|
if($minimize_html) {
|
|
$resource_content = preg_replace('/\s+/', ' ', $resource_content);
|
|
$resource_content = str_replace('> <', '><', $resource_content);
|
|
}
|
|
}
|
|
|
|
// Special case: SVG font files
|
|
if(substr(basename($resource), -4) == '.svg' && $minimize_svg) {
|
|
$resource_content = preg_replace('/\s+/', ' ', $resource_content);
|
|
$resource_content = str_replace('> <', '><', $resource_content);
|
|
}
|
|
|
|
// Calculate improvement by compression / minimization
|
|
$compression_winnings += $resource_content_length - strlen($resource_content);
|
|
|
|
if(preg_match('/[^\w\s[:print:]]/', $resource_content)) {
|
|
$resource_content = 'base64:' . base64_encode($resource_content);
|
|
} else {
|
|
$resource_content = 'normal:' . $resource_content;
|
|
}
|
|
$source .= 'public static $' . preg_replace('/[^\w]/', '', preg_replace('#[/\\\\]#', '_', ($prefix == '' ? '' : ($prefix . '/')) . basename($resource))) . ' = ' . var_export($resource_content, TRUE) . ';' . "\n";
|
|
} elseif(is_readable($resource) && is_dir($resource)) {
|
|
$compression_winnings += add_resources($resource, ($prefix == '' ? '' : ($prefix . '/')) . basename($resource), $source);
|
|
} else {
|
|
exit('Unable to load file ' . basename($resource));
|
|
}
|
|
}
|
|
return $compression_winnings;
|
|
}
|
|
|
|
function normalizeFileSize($size) {
|
|
$filesizename = array(' bytes', ' KiB', ' MiB', ' GiB', ' TiB', ' PiB', ' EiB', ' ZiB', ' YiB');
|
|
return $size ? round($size/pow(1024, ($i = floor(log($size, 1024)))), 2) . $filesizename[$i] : '0 bytes';
|
|
}
|
|
|
|
// Process each file set
|
|
foreach($compile_sets as $name => $files) {
|
|
$compression_winnings = 0;
|
|
$source = '<?php';
|
|
foreach($files as $key => $file) {
|
|
$file_path = $input_directory . DIRECTORY_SEPARATOR . $file;
|
|
if(is_readable($file_path) && is_dir($file_path)) {
|
|
$source .= ' class ' . $file . ' { ';
|
|
$compression_winnings += add_resources($file_path, '', $source);
|
|
$source .= '
|
|
/**
|
|
* Get the resource file content.
|
|
* @param string $resource The filename of the resource.
|
|
* @return mixed The content of the file as string, or FALSE if unsuccessful.
|
|
*/
|
|
public static function getResource($resource) {
|
|
// Clean the resource name
|
|
$resource = preg_replace(\'/[^\w]/\', \'\', preg_replace(\'#[/\\\\\\\\]#\', \'_\', $resource));
|
|
|
|
// Look it up and return it
|
|
if(isset(static::$$resource)) {
|
|
// Check for base64 encoding
|
|
switch(substr(static::$$resource, 0, 6)) {
|
|
case \'base64\':
|
|
return base64_decode(substr(static::$$resource, 7));
|
|
|
|
default:
|
|
case \'normal\':
|
|
return substr(static::$$resource, 7);
|
|
}
|
|
} else {
|
|
return FALSE;
|
|
}
|
|
}';
|
|
$source .= '}';
|
|
} elseif(is_readable($file_path) && is_file($file_path)) {
|
|
$source .= substr(file_get_contents($file_path), 5);
|
|
} else {
|
|
exit('Unable to load file ' . $file);
|
|
}
|
|
}
|
|
|
|
if($minimize_php) {
|
|
$compressed = '';
|
|
|
|
$tokens = token_get_all($source);
|
|
$previous_token_keyword = FALSE;
|
|
$previous_token_char = FALSE;
|
|
foreach($tokens as $token) {
|
|
if(is_array($token)) {
|
|
switch($token[0]) {
|
|
case T_DOC_COMMENT:
|
|
case T_COMMENT:
|
|
case T_WHITESPACE:
|
|
continue 2;
|
|
}
|
|
$current_token_keyword = FALSE;
|
|
switch($token[0]) {
|
|
case T_ABSTRACT:
|
|
case T_AS:
|
|
case T_BREAK:
|
|
case T_CALLABLE:
|
|
case T_CASE:
|
|
case T_CLASS:
|
|
case T_CLONE:
|
|
case T_CONST:
|
|
case T_CONTINUE:
|
|
case T_ECHO:
|
|
case T_ELSE:
|
|
case T_ELSEIF:
|
|
case T_EXTENDS:
|
|
case T_FINAL:
|
|
case T_FUNCTION:
|
|
case T_GLOBAL:
|
|
case T_GOTO:
|
|
case T_IMPLEMENTS:
|
|
case T_INCLUDE:
|
|
case T_INCLUDE_ONCE:
|
|
case T_INSTANCEOF:
|
|
case T_INSTEADOF:
|
|
case T_INTERFACE:
|
|
case T_LOGICAL_AND:
|
|
case T_LOGICAL_OR:
|
|
case T_LOGICAL_XOR:
|
|
case T_NAMESPACE:
|
|
case T_NEW:
|
|
case T_PRIVATE:
|
|
case T_PUBLIC:
|
|
case T_PROTECTED:
|
|
case T_REQUIRE:
|
|
case T_REQUIRE_ONCE:
|
|
case T_RETURN:
|
|
case T_STATIC:
|
|
case T_THROW:
|
|
case T_TRAIT:
|
|
case T_USE:
|
|
case T_VAR:
|
|
case T_RETURN:
|
|
$current_token_keyword = TRUE;
|
|
break;
|
|
}
|
|
$compressed .= (!$previous_token_char && ($previous_token_keyword || $current_token_keyword) ? ' ' : '') . $token[1];
|
|
|
|
$previous_token_keyword = $current_token_keyword;
|
|
$previous_token_char = FALSE;
|
|
} else {
|
|
$compressed .= $token;
|
|
$previous_token_keyword = FALSE;
|
|
$previous_token_char = TRUE;
|
|
}
|
|
}
|
|
|
|
$compressed = trim(substr($compressed, 5));
|
|
|
|
switch($compress) {
|
|
case 'gzip':
|
|
$compressed = 'eval(gzuncompress(base64_decode(\'' . base64_encode(gzcompress($compressed, 9)) . '\')));';
|
|
break;
|
|
}
|
|
|
|
// Re-insert the GPL into the compressed
|
|
$compressed = '<?php' . "\n" .
|
|
'/* This file is part of DBSR.' . "\n" .
|
|
' *' . "\n" .
|
|
' * DBSR is free software: you can redistribute it and/or modify' . "\n" .
|
|
' * it under the terms of the GNU General Public License as published by' . "\n" .
|
|
' * the Free Software Foundation, either version 3 of the License, or' . "\n" .
|
|
' * (at your option) any later version.' . "\n" .
|
|
' *' . "\n" .
|
|
' * DBSR is distributed in the hope that it will be useful,' . "\n" .
|
|
' * but WITHOUT ANY WARRANTY; without even the implied warranty of' . "\n" .
|
|
' * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the' . "\n" .
|
|
' * GNU General Public License for more details.' . "\n" .
|
|
' *' . "\n" .
|
|
' * You should have received a copy of the GNU General Public License' . "\n" .
|
|
' * along with DBSR. If not, see <http://www.gnu.org/licenses/>.' . "\n" .
|
|
' */' . "\n" .
|
|
$compressed;
|
|
|
|
file_put_contents($output_directory . DIRECTORY_SEPARATOR . $name, $compressed);
|
|
echo 'Compiled file ', $name, ', total size is ' . normalizeFileSize(strlen($compressed)) . ' (including ', round(100 * (1 - (strlen($compressed) / (strlen($source) + $compression_winnings))), 1), '% reduction by compression)' . (PHP_SAPI == 'cli' ? '' : '<br />') . PHP_EOL;
|
|
} else {
|
|
file_put_contents($output_directory . DIRECTORY_SEPARATOR . $name, $source);
|
|
echo 'Compiled file ', $name, ', total size is ' . normalizeFileSize(strlen($source)) . (PHP_SAPI == 'cli' ? '' : '<br />') . PHP_EOL;
|
|
}
|
|
}
|