PHP Classes

File: compile.php

Recommend this page to a friend!
  Packages of Uku-Kaarel Jo~esaar   too-vark   compile.php   Download  
File: compile.php
Role: Auxiliary script
Content type: text/plain
Description: Auxiliary script
Class: too-vark
Manage people work schedule times and tasks
Author: By
Last change:
Date: 8 days ago
Size: 10,279 bytes
 

Contents

Class file image Download
<?php declare(strict_types=1); ?><!DOCTYPE html> <head><meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover"> <style> <?php include_once 'src/style.css'; ?> a{font-size:var(--fs-2xl);margin:var(--sp-12); padding:var(--sp-7);border:1pt solid var(--btn-silver-border); background:var(--btn-silver-bg);line-height:3rem;} a,a:active,a:visited{color:var(--btn-silver-text);} </style> <h3>Starting Single-File Compilation...</h3> <?php /* USAGE: * php compile.php (or localhost) * ? creates index_release.php in the same directory * * DEPLOYMENT: * Copy index_release.php( + app.sqlite + icon.png) to your web server. Rename to "index.php". * No src/ directory needed ? everything is in the single file. * * DEBUG BUILD: * Set define('APP_DEBUG',true) in index.php ? compile produces index_debug.php instead. * debug.js included, no minification. * * COMPRESSION (release only): * PHP: php_strip_whitespace() per file, then newlines at top-level boundaries (function/class ends). * CSS: comment + whitespace removal, split after } and ; * JS: as-is (safe choice ? gzip handles the rest). * Markers /* included from ? * / survive because compression runs BEFORE wrapping. */ $source_file = './index.php'; $output_file = './index_release.php'; $output_dbg_file = './index_debug.php'; $str_included_from = 'included from'; // ??? COMPRESSION FUNCTIONS /** * Compress PHP code using php_strip_whitespace (tokenizer-based, safe). * Then split the resulting giant line at safe breakpoints using token_get_all: * ? newline after } * ? newline after ; when NOT inside parentheses (protects for-loop semicolons) */ function php_compress(string $content): string { // php_strip_whitespace() needs a file path $tmp = tempnam(sys_get_temp_dir(), 'tvc_'); file_put_contents($tmp, "<?php\n" . $content); $stripped = php_strip_whitespace($tmp); unlink($tmp); // Remove the <?php we prepended $stripped = preg_replace('/^<\?php\s*/', '', $stripped); if (trim($stripped) === '') return ''; // Split at top-level boundaries only (function/class ends). // One function = one compact line. Avoids the single-giant-line problem // without over-splitting at every semicolon. $tokens = token_get_all('<?php ' . $stripped); $out = ''; $depth = 0; $first_tag = true; foreach ($tokens as $t) { if (is_array($t)) { // Skip only the < ? php we prepended, keep subsequent ones (views.php has ? >...< ? php) if ($t[0] === T_OPEN_TAG && $first_tag) { $first_tag = false; continue; } // Newline before top-level function/class definition if ($depth === 0 && in_array($t[0], [T_FUNCTION, T_CLASS], true)) $out .= "\n"; $out .= $t[1]; } else { $out .= $t; if ($t === '{') $depth++; elseif ($t === '}') { $depth--; if ($depth === 0) $out .= "\n"; } } } return trim($out); } /** * Compress CSS: strip comments, collapse whitespace, split at } and ; */ function css_compress(string $css): string { $css = preg_replace('!/\*.*?\*/!s', '', $css); $css = preg_replace('/\s+/', ' ', $css); $css = str_replace([' { ',' } ','; '], ['{','}',';'], $css); // Split into readable lines $css = str_replace('}', "}\n", $css); $css = str_replace(';', ";\n", $css); return trim($css); } // ??? TEMPLATE function include_tpl_hfa($file,$content){ global $str_included_from; return " /* {$str_included_from} $file [[[*/ $content /* EOF $file */ "; } // ??? MAIN LOOP $result_lines=array(); $source_code = file_get_contents($source_file); $source_lines = explode("\n", $source_code); $tag0=false; $APP_DEBUG=false; foreach ($source_lines as $line_num => $line){ // Detect debug mode from index.php define if(str_contains($line,"define('APP_DEBUG',true")){ $APP_DEBUG=true; $output_file=$output_dbg_file; } if( str_contains($line,'include_once ') ) { preg_match("/include_once\s+['\"]([^'\"]+)['\"]/", $line, $matches); $file = $matches[1] ?? ''; echo "$file"; if(file_exists($file)){ $content = file_get_contents($file); $orig_size = strlen($content); // CSS: compress in release, as-is in debug if (str_ends_with($file, '.css')) { if(!$APP_DEBUG) $content = css_compress($content); $result_lines[] = include_tpl_hfa($file,$content); } // JS: include or skip debug.js based on APP_DEBUG elseif (str_ends_with($file, '.js')) { if (str_ends_with($file, '/debug.js')) { if($APP_DEBUG) $result_lines[] = include_tpl_hfa($file,$content); // release build: skip debug.js entirely } else { $result_lines[] = include_tpl_hfa($file,$content); } } // PHP: strip tags, compress in release else { $content = preg_replace('/^<\?php\s*/i', '', $content); $content = preg_replace('/declare\s*\(\s*strict_types\s*=\s*1\s*\)\s*;\s*/i', '', $content); $content = preg_replace('/\?>\s*$/', '', $content); if(!$APP_DEBUG) $content = php_compress($content); $result_lines[] = include_tpl_hfa($file,$content); } $ratio = $orig_size > 0 ? round(strlen($content) / $orig_size * 100) : 0; echo " ({$ratio}%)"; }else { echo "<span style='color:var(--c-red)'>Warning: Could not find {$file}</span>"; $result_lines[]=$line; } echo "<br>"; } //line with include_once else { $line = preg_replace('/declare\s*\(\s*strict_types\s*=\s*1\s*\)\s*;\s*/i', '', $line); $result_lines[]=$line; if($tag0===false && str_contains($line,'<?php') ){$tag0=true; // Grab version from first ## heading in CHANGELOG.md $app_ver = 'dev'; if (file_exists('CHANGELOG.md')) { preg_match('/^## (v\S+)/m', file_get_contents('CHANGELOG.md', false, null, 0, 512), $vm); if (!empty($vm[1])) $app_ver = $vm[1]; } $result_lines[]="declare(strict_types=1);\ndefine('APP_VERSION', '$app_ver ? " . date('Y-m-d H:i') . "');"; } } }//lines // ??? EMBED PLUGIN FILES // The plugins.php loader uses glob() at runtime. For single-file deploy, // we inline plugin PHP/JS/CSS directly so no plugins/ directory is needed. $plugin_dir = './plugins/'; $plugin_ids = array(); if (is_dir($plugin_dir)) { echo "<br><b>Plugins:</b><br>"; // PHP plugins ? inline after plugins.php (which is already inlined above) // The glob() in plugins.php will find nothing in production, but // these inlined files define the same functions and return arrays. // We wrap each in a self-executing closure that feeds $plugin_routes etc. $plugin_php_block = "\n// ??? INLINED PLUGINS\n"; foreach (glob($plugin_dir . '*.php') as $pf) { $plugin_ids[]=pathinfo($pf,PATHINFO_FILENAME); $content = file_get_contents($pf); $orig_size = strlen($content); $content = preg_replace('/^<\?php\s*/i', '', $content); $content = preg_replace('/\?>\s*$/', '', $content); // Split: extract function definitions (keep global) and the return [...] (wrap in loader) // The return statement registers the plugin ? we need to feed it to the loader vars $content = preg_replace( '/^return\s+\[/m', '$_preg = [', $content ); $content .= "\n" . '$_pid = $_preg["id"] ?? "";' . "\n" . 'if ($_pid) { $plugins[$_pid] = $_preg;' . ' if (isset($_preg["routes"])) foreach ($_preg["routes"] as $_r => $_h) $plugin_routes[$_r] = $_h;' . ' if (isset($_preg["views"])) foreach ($_preg["views"] as $_vk => $_vfn) $plugin_views[$_vk] = $_vfn;' . ' if (isset($_preg["nav"])) $plugin_nav = array_merge($plugin_nav, $_preg["nav"]);' . ' if (isset($_preg["etag_routes"])) $plugin_etag_routes = array_merge($plugin_etag_routes, $_preg["etag_routes"]);' . ' if (isset($_preg["write_routes"])) $plugin_write_routes = array_merge($plugin_write_routes, $_preg["write_routes"]);' . ' }' . "\n"; if (!$APP_DEBUG) $content = php_compress($content); $plugin_php_block .= include_tpl_hfa($pf, $content); $ratio = $orig_size > 0 ? round(strlen($content) / $orig_size * 100) : 0; echo basename($pf) . " ({$ratio}%)<br>"; } // Insert PHP plugins right after the plugins.php EOF marker ; $compiled_str = implode("\n", $result_lines); // plugins not to reload $compiled_str=str_replace( '$plugins = [];', "\$plugins=array('".implode("'=>[], '", $plugin_ids)."'=>[]);", $compiled_str); $marker = '/* EOF src/plugins.php */'; $pos = strpos($compiled_str, $marker); if ($pos !== false) { $insert_at = $pos + strlen($marker); $compiled_str = substr($compiled_str, 0, $insert_at) . $plugin_php_block . substr($compiled_str, $insert_at); $result_lines = explode("\n", $compiled_str); } // JS plugins ? append after app.js foreach (glob($plugin_dir . '*.js') as $jf) { $content = file_get_contents($jf); $result_lines[] = include_tpl_hfa($jf, $content); echo basename($jf) . "<br>"; } // CSS plugins ? inject before </style> $css_block = ''; foreach (glob($plugin_dir . '*.css') as $cf) { $content = file_get_contents($cf); if (!$APP_DEBUG) $content = css_compress($content); $css_block .= include_tpl_hfa($cf, $content); echo basename($cf) . "<br>"; } if ($css_block) { $compiled_str = implode("\n", $result_lines); $compiled_str = str_replace('</style>', $css_block . "\n</style>", $compiled_str); $result_lines = explode("\n", $compiled_str); } } clearstatcache(false,$output_file); $output_fs0 = intval(filesize($output_file)); if (!file_exists($source_file)) { die("Error: index.php not found."); } $compiled_code = implode("\n", $result_lines); $bytes = file_put_contents($output_file, $compiled_code); echo " <h3 style='color:green'>Success!</h3>"; echo "<a href=\"./tests/run.php?verbose=1\" target=\"_blank\">Run PHP Tests</a> "; echo "<a href=\"./tests/run_js.html\" target=\"_blank\">Run JS Tests</a><br> "; echo "<a href=\"./tests/audit_plugin.html\" target=\"_blank\">audit JS Tests</a><br> "; echo "<a href=\"./Styleguide.html\" target=\"_blank\"><span class=\"status-2\">*</span>Styleguide<span class=\"status-0\">*</span></a> "; echo "<a href=\"tests/demo-db.php\" target=\"_blank\">GenDemoDB</a><br> "; echo "<a href=\"$source_file\" target=\"_blank\">Source: $source_file</a> <br>"; echo "<a href=\"$output_file\" target=\"_blank\">Output: $output_file</a> <br><br> "; echo "Created $app_ver <b>$output_file</b> (" . number_format($bytes / 1024, 2) . " KB) ". ($output_fs0 - $bytes).'b'; ?>