Fixed Cookie Sessions to close before Response Body...in Kernel.

main
Robert 3 weeks ago
parent b7b18a924d
commit 9b2d9f9390
  1. 3
      src/Bootstrap.php
  2. 429
      src/Framework/Assets.php
  3. 4
      src/Framework/ErrorHandler.php
  4. 867
      src/Framework/HtmlDocument.php
  5. 3
      src/Framework/Http/Kernel.php
  6. 5
      src/Framework/Services/Sessions/CookieSessionHandler.php
  7. 8
      src/Framework/SessionManagement.php
  8. 49
      src/Framework/SiteHelper.php

@ -11,6 +11,7 @@ declare(strict_types=1);
use IOcornerstone\Psr4AutoloaderClass; use IOcornerstone\Psr4AutoloaderClass;
use IOcornerstone\Framework\{ use IOcornerstone\Framework\{
Registry as Reg, Registry as Reg,
SiteHelper,
Console, Console,
Configure, Configure,
CliDefaults, CliDefaults,
@ -46,6 +47,8 @@ $loader->addNamespace("Psr\Http\Server", [
PSR . 'http-server-handler' . DIRECTORY_SEPARATOR . 'src' PSR . 'http-server-handler' . DIRECTORY_SEPARATOR . 'src'
]); ]);
SiteHelper::setupHTTP();
function dd($var = 'nothing', endDump $end = endDump::EXIT_AND_STOP) function dd($var = 'nothing', endDump $end = endDump::EXIT_AND_STOP)
{ {
Common::dump($var, $end); Common::dump($var, $end);

@ -1,12 +1,13 @@
<?php <?php
declare(strict_types = 1); declare(strict_types=1);
/** /**
* @author Robert Strutts * @author Robert Strutts
* @copyright (c) 2026, Robert Strutts * @copyright (c) 2026, Robert Strutts
* @license MIT * @license MIT
*/ */
namespace IOcornerstone\Framework; namespace IOcornerstone\Framework;
use IOcornerstone\Framework\{ use IOcornerstone\Framework\{
@ -17,26 +18,34 @@ use IOcornerstone\Framework\{
class Assets class Assets
{ {
public static function getVer(string $filename): string { private static $files = [];
if (self::attemptsRootDir($filename)) {
return ""; public static function getAssetFiles(): array{
return self::$files;
} }
$safe_file = Security::filterUri($filename); public static function getVer(string $filename): string
if (! file_exists($safe_file)) { {
return "?ver=false"; if (self::attemptsRootDir($filename)) {
return "";
}
$safe_file = Security::filterUri($filename);
if (!file_exists($safe_file)) {
return "?ver=false";
}
return "?ver=" . date('Y.m.d_H.i.s', filemtime($safe_file));
} }
return "?ver=" . date('Y.m.d_H.i.s', filemtime($safe_file));
}
/** /**
* Check for / or absolute path not belonging to /var/www or PRJ:ROOT * Check for / or absolute path not belonging to /var/www or PRJ:ROOT
* @param string|null $path * @param string|null $path
* @return bool * @return bool
*/ */
private static function attemptsRootDir(?string $path): bool { private static function attemptsRootDir(?string $path): bool
{
// up from src and back up to public // up from src and back up to public
$open_base_dir_path = BaseDir. '/public/'; $open_base_dir_path = BaseDir . '/public/';
if ($path === null || $path === '') { if ($path === null || $path === '') {
return false; return false;
@ -50,219 +59,249 @@ class Assets
return false; return false;
} }
public static function getAjaxFiles(string $ajax_folder): string
{
if (self::attemptsRootDir($ajax_folder)) {
return "";
}
$safe_folder = Security::filterUri($ajax_folder);
public static function getAjaxFiles(string $ajax_folder): string { $ret = "var assets_files = [];" . PHP_EOL;
if (self::attemptsRootDir($ajax_folder)) { $js = glob($safe_folder . "*.{js,css}", GLOB_BRACE);
return ""; foreach ($js as $file) {
$ret .= 'assets_files.push({ filename: "' . basename($file) . '", ts: "' . self::getVer($file) . '" });' . PHP_EOL;
}
return $ret;
} }
$safe_folder = Security::filterUri($ajax_folder);
$ret = "var assets_files = [];" . PHP_EOL; public static function loadallCss(array $files, string $scope = 'project'): string
$js = glob($safe_folder . "*.{js,css}", GLOB_BRACE); {
foreach($js as $file) { $ret = '';
$ret .= 'assets_files.push({ filename: "' . basename($file) . '", ts: "' . self::getVer($file) . '" });' . PHP_EOL; foreach ($files as $file => $a_media) {
$ret .= self::wrapCss($file, $scope, $a_media);
}
return $ret;
} }
return $ret;
}
public static function loadallCss(array $files, string $scope='project'): string { public static function loadallJs(array $files, string $scope = 'project'): string
$ret = ''; {
foreach($files as $file=>$a_media) { $ret = '';
$ret .= self::wrapCss($file, $scope, $a_media); foreach ($files as $file => $a) {
$ret .= self::wrapJs($file, $scope, $a);
}
return $ret;
} }
return $ret;
}
public static function loadallJs(array $files, string $scope='project'): string { public static function image(string $file, string $scope = '', array $a = array()): string
$ret = ''; {
foreach($files as $file=>$a) { $more = '';
$ret .= self::wrapJs($file, $scope, $a); if (count($a)) {
foreach ($a as $k => $v) {
$more .= " {$k}=\"{$v}\"";
}
}
$file = self::wrapAsset($file, $scope);
if ($file === false) {
return '';
}
return "<img src=\"{$file}\" {$more}/>\r\n";
} }
return $ret;
}
public static function image(string $file, string $scope = '', array $a = array()): string { public static function alert($msg)
$more = ''; {
if (count($a)) { return self::inlineJs('alert("' . $msg . '");');
foreach ($a as $k => $v) {
$more .= " {$k}=\"{$v}\"";
}
}
$file = self::wrapAsset($file, $scope);
if ($file === false) {
return '';
} }
return "<img src=\"{$file}\" {$more}/>\r\n";
}
public static function alert($msg) { /**
return self::inlineJs('alert("'.$msg.'");'); * Wrapper for JS/CSS assets for the page.
} * @param string $file or CDN
* @param string $scope (project/framework/cdn)
* @retval boolean|string false is not found, else Asset REF
*/
public static function wrapAsset(string $file, string $scope = 'project')
{
$scope = StringFacade::strtolower($scope);
if ($scope === 'cdn') {
$proto = $_SERVER['SERVER_PROTOCOL'];
if ($proto === null) {
$protocol = '://';
} else {
$protocol = strtolower(substr($proto, 0, strpos($proto, '/'))) . '://';
}
return (str_contains($file, '://') === true) ? $file : $protocol . $file;
}
if ($scope === 'project' || $scope === 'app') {
$path = PROJECT_ASSETS_DIR;
$ism = self::isMinified($path, $file);
return ($ism !== false) ? PROJECT_ASSETS_BASE_REF . "/" . $ism : false;
}
if ($scope === 'assets') {
$path = ASSETS_DIR . "/";
$ism = self::isMinified($path, $file);
return ($ism !== false) ? ASSETS_BASE_REF . "/" . $ism : false;
}
return $file;
}
/** /**
* Wrapper for JS/CSS assets for the page. * Fetch Version of file if exists
* @param string $file or CDN * @param string $file
* @param string $scope (project/framework/cdn) * @param string $scope
* @retval boolean|string false is not found, else Asset REF * @return string|bool
*/ */
public static function wrapAsset(string $file, string $scope = 'project') { private static function projectPaths(string $file, string $scope = 'project'): string|bool
$scope = StringFacade::strtolower($scope); {
if ($scope === 'cdn') { $scope = stringFacade::strtolower($scope);
$proto = $_SERVER['SERVER_PROTOCOL']; if ($scope === 'cdn') {
if ($proto === null) { return "";
$protocol = '://'; } else if ($scope === 'project' || $scope === 'app') {
$path = PROJECT_ASSETS_DIR;
} else if ($scope === 'assets') {
$path = ASSETS_DIR . "/";
} else { } else {
$protocol = strtolower(substr($proto, 0, strpos($proto, '/'))) . '://'; return "";
}
$check = self::isMinified($path, $file);
$version = ($check !== false) ? self::getVer($path . $check) : false;
if ($version === false) {
return false;
} }
return (str_contains($file, '://') === true) ? $file : $protocol . $file;
}
if ($scope === 'project' || $scope === 'app') {
$path = PROJECT_ASSETS_DIR;
$ism = self::isMinified($path, $file);
return ($ism !== false) ? PROJECT_ASSETS_BASE_REF . "/" . $ism : false;
}
if ($scope === 'assets') {
$path = ASSETS_DIR . "/";
$ism = self::isMinified($path, $file);
return ($ism !== false) ? ASSETS_BASE_REF . "/" . $ism : false;
}
return $file;
}
/**
* Fetch Version of file if exists
* @param string $file
* @param string $scope
* @return string|bool
*/
private static function projectPaths(string $file, string $scope = 'project'): string | bool {
$scope = stringFacade::strtolower($scope);
if ($scope === 'cdn') {
return "";
} else if ($scope === 'project' || $scope === 'app') {
$path = PROJECT_ASSETS_DIR;
} else if ($scope === 'assets') {
$path = ASSETS_DIR . "/";
} else {
return "";
}
$check = self::isMinified($path, $file);
return ($check !==false) ? self::getVer($path . $check) : false;
}
/** if (self::hasFile($file)) {
* Wrapper to return the CSS href=file.. stylesheet code for use in page. return false;
* @param string $file - CSS file }
* @param string $media - default of all media return $version;
* @retval string
*/
public static function wrapCss(string $file, string $scope = 'project', array $a_media = array()): string {
$more = '';
if (count($a_media)) {
foreach ($a_media as $k => $v) {
$more .= " {$k}=\"{$v}\"";
}
} else {
$more .= " media=\"all\"";
} }
$ver = self::projectPaths($file, $scope); private static function hasFile(string $file): bool
$wrap_file = self::wrapAsset($file, $scope); {
if ($ver === false || $wrap_file === false) { if (in_array($file, static::$files)) {
return "<!-- CSS: {$file} not Found -->"; return true;
}
static::$files[] = $file;
return false;
} }
return "<link rel=\"stylesheet\" href=\"{$wrap_file}{$ver}\" type=\"text/css\"{$more}/>\r\n";
}
/** /**
* Wrapper to return the JavaScript src=file... code for use with page. * Wrapper to return the CSS href=file.. stylesheet code for use in page.
* @param type $file - external JS file. * @param string $file - CSS file
* @retval string of script src=file * @param string $media - default of all media
*/ * @retval string
public static function wrapJs(string $file, string $scope = 'project', array $a = array()): string { */
$more = ''; public static function wrapCss(string $file, string $scope = 'project', array $a_media = array()): string
if (count($a)) { {
foreach ($a as $k => $v) { $more = '';
$more .= (isset($k) && $k !=0 ) ? " {$k}=\"{$v}\"" : " {$v}"; if (count($a_media)) {
} foreach ($a_media as $k => $v) {
} $more .= " {$k}=\"{$v}\"";
}
} else {
$more .= " media=\"all\"";
}
$ver = self::projectPaths($file, $scope); $ver = self::projectPaths($file, $scope);
$wrap_file = self::wrapAsset($file, $scope); $wrap_file = self::wrapAsset($file, $scope);
if ($ver === false || $wrap_file === false) { if ($ver === false || $wrap_file === false) {
return "<!-- Script: {$file} not Found -->"; return "<!-- CSS: {$file} not Found -->";
}
return "<link rel=\"stylesheet\" href=\"{$wrap_file}{$ver}\" type=\"text/css\"{$more}/>\r\n";
} }
return "<script src=\"{$wrap_file}{$ver}\"{$more}></script>\r\n";
//return "<script type=\"text/javascript\">js_loader(\"{$file}\");</script>";
}
/**
* Purpose: To do inline JavaScript.
* @param type $code string of code to inline into page.
* @retval type
*/
public static function inlineJs(string $code): string {
return "<script type=\"text/javascript\">\r\n//<![CDATA[\r\n {$code}\r\n //]]> \r\n </script>\r\n";
}
/** /**
* Purpose: To execute this JavaScript code once JQuery is Ready(). * Wrapper to return the JavaScript src=file... code for use with page.
* @param string $code to do once JQuery is Ready * @param type $file - external JS file.
* @retval string wrapped in ready code... * @retval string of script src=file
*/ */
public static function jqueryLoad(string $code): string { public static function wrapJs(string $file, string $scope = 'project', array $a = array()): string
return "\r\n$(function() { \r\n \t {$code} \r\n }); \r\n"; {
} $more = '';
if (count($a)) {
foreach ($a as $k => $v) {
$more .= (isset($k) && $k != 0) ? " {$k}=\"{$v}\"" : " {$v}";
}
}
public static function isMinified(string $path, string $file) { $ver = self::projectPaths($file, $scope);
if (self::attemptsRootDir($path)) { $wrap_file = self::wrapAsset($file, $scope);
return false; if ($ver === false || $wrap_file === false) {
return "<!-- Script: {$file} not Found -->";
}
return "<script src=\"{$wrap_file}{$ver}\"{$more}></script>\r\n";
//return "<script type=\"text/javascript\">js_loader(\"{$file}\");</script>";
} }
$safe_path = Security::filterUri($path);
$safe_file = Security::filterUri($file);
if (str_contains($safe_file, '.auto.js')) { /**
$production = (isLive()); * Purpose: To do inline JavaScript.
$safe_file = str_replace('.auto.js', '', $safe_file); * @param type $code string of code to inline into page.
if ( $production && file_exists($safe_path . $safe_file . '.min.js') ) { * @retval type
return $safe_file . '.min.js'; */
} public static function inlineJs(string $code): string
return (file_exists($safe_path . $safe_file . '.js')) ? $safe_file . '.js' : false; {
return "<script type=\"text/javascript\">\r\n//<![CDATA[\r\n {$code}\r\n //]]> \r\n </script>\r\n";
} }
if (str_contains($safe_file, '.auto.css')) { /**
$production = (isLive()); * Purpose: To execute this JavaScript code once JQuery is Ready().
$safe_file = str_replace('.auto.css', '', $safe_file); * @param string $code to do once JQuery is Ready
if ( $production && file_exists($safe_path . $safe_file . '.min.css') ) { * @retval string wrapped in ready code...
return $safe_file . '.min.css'; */
} public static function jqueryLoad(string $code): string
return (file_exists($safe_path . $safe_file . '.css')) ? $safe_file . '.css' : false; {
return "\r\n$(function() { \r\n \t {$code} \r\n }); \r\n";
} }
return ( file_exists($safe_path . $safe_file) ) ? $safe_file : false;
}
/** public static function isMinified(string $path, string $file)
* meta redirect when headers are already sent... {
* @param string url - site to do redirect on if (self::attemptsRootDir($path)) {
* @reval none return false;
*/ }
public static function gotoUrl(string $url): void { $safe_path = Security::filterUri($path);
echo '<META http-equiv="refresh" content="0;URL=' . $url . '">'; $safe_file = Security::filterUri($file);
exit;
} if (str_contains($safe_file, '.auto.js')) {
$production = (isLive());
$safe_file = str_replace('.auto.js', '', $safe_file);
if ($production && file_exists($safe_path . $safe_file . '.min.js')) {
return $safe_file . '.min.js';
}
return (file_exists($safe_path . $safe_file . '.js')) ? $safe_file . '.js' : false;
}
if (str_contains($safe_file, '.auto.css')) {
$production = (isLive());
$safe_file = str_replace('.auto.css', '', $safe_file);
if ($production && file_exists($safe_path . $safe_file . '.min.css')) {
return $safe_file . '.min.css';
}
return (file_exists($safe_path . $safe_file . '.css')) ? $safe_file . '.css' : false;
}
return (file_exists($safe_path . $safe_file)) ? $safe_file : false;
}
/** /**
* Rediect to url and attempt to send via header. * meta redirect when headers are already sent...
* @param string $url - site to do redirect for * @param string url - site to do redirect on
* @retval none - exits once done * @reval none
*/ */
public static function redirectUrl(string $url): void { public static function gotoUrl(string $url): void
$url = str_replace(array('&amp;', "\n", "\r"), array('&', '', ''), $url); {
if (!headers_sent()) { echo '<META http-equiv="refresh" content="0;URL=' . $url . '">';
header('Location: ' . $url); exit;
} else {
self::goto_url($url);
} }
exit;
}
/**
* Rediect to url and attempt to send via header.
* @param string $url - site to do redirect for
* @retval none - exits once done
*/
public static function redirectUrl(string $url): void
{
$url = str_replace(array('&amp;', "\n", "\r"), array('&', '', ''), $url);
if (!headers_sent()) {
header('Location: ' . $url);
} else {
self::goto_url($url);
}
exit;
}
} }

@ -115,7 +115,9 @@ final class ErrorHandler
return true; return true;
} }
http_response_code(500); if (! headers_sent()) {
http_response_code(500);
}
if ($this->debug) { if ($this->debug) {
$this->renderDebug($e); $this->renderDebug($e);

@ -1,12 +1,13 @@
<?php <?php
declare(strict_types = 1); declare(strict_types=1);
/** /**
* @author Robert Strutts * @author Robert Strutts
* @copyright (c) 2026, Robert Strutts * @copyright (c) 2026, Robert Strutts
* @license MIT * @license MIT
*/ */
namespace IOcornerstone\Framework; namespace IOcornerstone\Framework;
use IOcornerstone\Framework\{ use IOcornerstone\Framework\{
@ -22,414 +23,474 @@ use IOcornerstone\Framework\{
*/ */
class HtmlDocument class HtmlDocument
{ {
private $title = '';
private $author = ''; private $title = '';
private $description = ''; private $author = '';
private $keywords = ''; private $description = '';
private $robots = ''; private $keywords = '';
private $head = ''; private $robots = '';
private $header = ''; private $head = '';
private $body = ''; private $header = '';
private $footer = ''; private $body = '';
private $jsOnReady = ''; private $footer = '';
private $styles = ''; private $jsOnReady = '';
private $scripts = ''; private $styles = '';
private $mainStyles = ''; private $scripts = '';
private $mainScripts = ''; private $mainStyles = '';
private $activeCrumb = ''; private $mainScripts = '';
private $breadcrumb = array(); private $activeCrumb = '';
private $breadcrumb = [];
public function __construct() {
$this->title = Configure::get('html', 'title') ?? ''; public function __construct()
$this->author = Configure::get('html', 'author') ?? ''; {
$this->footer = Configure::get('html', 'footer') ?? ''; $this->title = Configure::get('html', 'title') ?? '';
$this->keywords = Configure::get('html', 'keywords') ?? ''; $this->author = Configure::get('html', 'author') ?? '';
$this->description = Configure::get('html', 'description') ?? ''; $this->footer = Configure::get('html', 'footer') ?? '';
$this->robots = Configure::get('html', 'robots'); $this->keywords = Configure::get('html', 'keywords') ?? '';
$css = Configure::get('html', 'css'); $this->description = Configure::get('html', 'description') ?? '';
if (Common::getCount($css) > 0) { $this->robots = Configure::get('html', 'robots');
foreach($css as $file=>$path) { $css = Configure::get('html', 'css');
if (is_array($file)) continue; if (Common::getCount($css) > 0) {
if (is_array($path)) { foreach ($css as $file => $path) {
if (isset($path['path'])) { if (is_array($file))
$pathType = $path['path']; continue;
unset($path['path']); if (is_array($path)) {
} else { if (isset($path['path'])) {
$pathType = "project"; $pathType = $path['path'];
unset($path['path']);
} else {
$pathType = "project";
}
$this->addCss($file, $pathType, $path);
} else {
$this->addCss($file, $path);
}
} }
$this->addCss($file, $pathType, $path);
} else {
$this->addCss($file, $path);
} }
} $js = Configure::get('html', 'javascript');
} if (Common::getCount($js) > 0) {
$js = Configure::get('html', 'javascript'); foreach ($js as $file => $path) {
if (Common::getCount($js) >0) { if (is_array($file))
foreach($js as $file=>$path) { continue;
if (is_array($file)) continue; if (is_array($path)) {
if (is_array($path)) { if (isset($path['path'])) {
if (isset($path['path'])) { $pathType = $path['path'];
$pathType = $path['path']; unset($path['path']);
unset($path['path']); } else {
} else { $pathType = "project";
$pathType = "project"; }
$this->addJs($file, $pathType, $path);
} else {
$this->addJs($file, $path);
}
} }
$this->addJs($file, $pathType, $path);
} else {
$this->addJs($file, $path);
} }
}
} }
}
public function clearCss(): void
public function clearCss(): void { {
$this->styles = ''; $this->styles = '';
} }
public function clearJs(): void { public function clearJs(): void
$this->scripts = ''; {
} $this->scripts = '';
}
/**
* Set both Title and Header for HTML /**
* @param string $title * Set both Title and Header for HTML
*/ * @param string $title
public function setTitleAndHeader(string $title): void { */
$this->title = $title; public function setTitleAndHeader(string $title): void
$this->header = $title; {
} $this->title = $title;
$this->header = $title;
/** }
* Set Author for HTML
* @param string $title /**
*/ * Set Author for HTML
public function setAuthor(string $author): void { * @param string $title
$this->author = $author; */
} public function setAuthor(string $author): void
{
/** $this->author = $author;
* Set Title for HTML }
* @param string $title
*/ /**
public function setTitle(string $title): void { * Set Title for HTML
$this->title = $title; * @param string $title
} */
public function setTitle(string $title): void
/** {
* Set Header for HTML $this->title = $title;
* @param string $header }
*/
public function setHeader(string $header): void { /**
$this->header = $header; * Set Header for HTML
} * @param string $header
*/
public function setHead(string $head): void { public function setHeader(string $header): void
$this->head = $head; {
} $this->header = $header;
}
/**
* Set Footer for HTML public function setHead(string $head): void
* @param string $footer {
*/ $this->head = $head;
public function setFooter(string $footer): void { }
/**
* Set Footer for HTML
* @param string $footer
*/
public function setFooter(string $footer): void
{
// $this->add_css('footer.css', 'project'); // $this->add_css('footer.css', 'project');
$this->footer = $footer; $this->footer = $footer;
} }
/** /**
* Set Description for HTML * Set Description for HTML
* @param string $description * @param string $description
*/ */
public function setDescription(string $description): void { public function setDescription(string $description): void
$this->description = $description; {
} $this->description = $description;
}
/**
* Set Keywords for HTML /**
* @param string $keywords * Set Keywords for HTML
*/ * @param string $keywords
public function setKeywords(string $keywords): void { */
$this->keywords = $keywords; public function setKeywords(string $keywords): void
} {
$this->keywords = $keywords;
/** }
* Set Robots for HTML
* @param string $robot /**
*/ * Set Robots for HTML
public function setRobots(string $robot): void { * @param string $robot
$this->robots = $robot; */
} public function setRobots(string $robot): void
{
public function setBody(string $body): void { $this->robots = $robot;
$this->body = $body; }
}
public function setBody(string $body): void
/** {
* Set Active BreadCrumb in HTML $this->body = $body;
* @param string $active }
*/
public function setActiveCrumb(string $active): void { /**
$this->activeCrumb = $active; * Set Active BreadCrumb in HTML
} * @param string $active
*/
/** public function setActiveCrumb(string $active): void
* Set BreadCrumbs using array (HyperLink => Name of Crumb) {
* @param array $crumbs Array(href => name) $this->activeCrumb = $active;
*/ }
public function setBreadcrumbs(array $crumbs): void {
$this->breadcrumb = $crumbs; /**
} * Set BreadCrumbs using array (HyperLink => Name of Crumb)
* @param array $crumbs Array(href => name)
public function setAssetsFromArray(array $files, string $which, string $scope = 'project'): void { */
foreach($files as $file => $a) { public function setBreadcrumbs(array $crumbs): void
switch($which) { {
case 'main_css': $this->breadcrumb = $crumbs;
$this->addMainCss($file, $scope, $a); }
break;
case 'css': public function setAssetsFromArray(array $files, string $which, string $scope = 'project'): void
$this->addCss($file, $scope, $a); {
break; foreach ($files as $file => $a) {
case 'main_js': switch ($which) {
$this->addMainJs($file, $scope, $a); case 'main_css':
break; $this->addMainCss($file, $scope, $a);
case 'js': break;
$this->addJs($file, $scope, $a); case 'css':
break; $this->addCss($file, $scope, $a);
} break;
} case 'main_js':
} $this->addMainJs($file, $scope, $a);
break;
private function missingFile(string $file, string $scope, string $kind) { case 'js':
$failed = strtoupper($kind) . " filename of {$file} - {$scope} Asset Failed to Load!"; $this->addJs($file, $scope, $a);
$this->addToJavascript("console.log(\"%c {$failed}\", \"color: red\")"); break;
$comment = "<!-- {$failed} -->"; }
if ($kind === "css") { }
$this->styles .= $comment; }
} else if ($kind === "main_css") {
$this->mainStyles .= $comment; private function missingFile(string $file, string $scope, string $kind)
} else if ($kind === "js") { {
$this->scripts .= $comment; $failed = strtoupper($kind) . " filename of {$file} - {$scope} Asset Failed to Load!";
} else if ($kind === "main_js") { $this->addToJavascript("console.log(\"%c {$failed}\", \"color: red\")");
$this->mainScripts .= $comment; $comment = "<!-- {$failed} -->";
if ($kind === "css") {
$this->styles .= $comment;
} else if ($kind === "main_css") {
$this->mainStyles .= $comment;
} else if ($kind === "js") {
$this->scripts .= $comment;
} else if ($kind === "main_js") {
$this->mainScripts .= $comment;
}
}
/**
* Add CSS stylesheet to HTML under main CSS
* @param string $file
* @param string $scope (project, framework, cdn)
* @return bool was successful
*/
public function addCss(string $file, string $scope = 'project', array $a = array()): bool
{
$css = Assets::wrapAsset($file, $scope);
if ($css === false) {
$this->missingFile($file, $scope, "css");
return false;
}
$this->styles .= Assets::wrapCss($file, $scope, $a);
return true;
}
/**
* Add JS JavaScript to HTML under main JS
* @param string $file
* @param string $scope (project, framework, cdn)
* @return bool was successful
*/
public function addJs(string $file, string $scope = 'project', array $a = array()): bool
{
$js = Assets::wrapAsset($file, $scope);
if ($js === false) {
$this->jsLog($file . " - {$scope} Asset Failed to Load!");
return false;
}
$this->scripts .= Assets::wrapJs($file, $scope, $a);
return true;
}
/**
* Add CSS stylesheet to HTML towards top of HTML for CSS
* @param string $file
* @param string $scope (project, framework, cdn)
* @return bool was successful
*/
public function addMainCss(string $file, string $scope = 'project', array $a = array()): bool
{
$css = Assets::wrapAsset($file, $scope);
if ($css === false) {
$this->jsLog($file . " - {$scope} Asset Failed to Load!");
return false;
}
$this->mainStyles .= Assets::wrapCss($file, $scope, $a);
return true;
}
/**
* Add JavaScript to HTML towards top of HTML for JS
* @param string $file
* @param string $scope (project, framework, cdn)
* @return bool was successful
*/
public function addMainJs(string $file, string $scope = 'project', array $a = array()): bool
{
$js = Assets::wrapAsset($file, $scope);
if ($js === false) {
$this->jsLog($file . " - {$scope} Asset Failed to Load!");
return false;
}
$this->mainScripts .= Assets::wrapJs($file, $scope, $a);
return true;
}
/**
* Adds JavaScript code to called after JQuery is ready.
* @param string $code
*/
//public function add_js_onready(string $code): void {
// $this->js_onready .= \px_inline_js(\px_jquery_load($code));
//}
/**
* Log to JavaScript Console under Chrome Browser
* @param string $log
*/
public function jsLog(string $log): void
{
$this->addToJavascript("console.log('{$log}');");
}
/**
* Place JavaScript in HTML
* @param string $js
*/
public function addToJavascript(string $js): void
{
if (!empty($js)) {
$this->scripts .= Assets::inlineJs($js);
}
}
/**
* Use CSS/JS for Database SSP
public function datatables_code(): void {
$this->addCss('datatables/datatables.min.css', 'cl');
$this->addJs('datatables/datatables_no_jquery.min.js', 'cl');
} }
} *
*/
/**
* Add CSS stylesheet to HTML under main CSS /**
* @param string $file * Used by Template file to render HTML Author
* @param string $scope (project, framework, cdn) * @return string HTML Author
* @return bool was successful */
*/ public function getAuthor(): string
public function addCss(string $file, string $scope = 'project', array $a = array()): bool { {
$css = Assets::wrapAsset($file, $scope); return $this->author;
if ($css === false) { }
$this->missingFile($file, $scope, "css");
return false;
}
$this->styles .= Assets::wrapCss($file, $scope, $a);
return true;
}
/**
* Add JS JavaScript to HTML under main JS
* @param string $file
* @param string $scope (project, framework, cdn)
* @return bool was successful
*/
public function addJs(string $file, string $scope = 'project', array $a = array()): bool {
$js = Assets::wrapAsset($file, $scope);
if ($js === false) {
$this->js_log($file . " - {$scope} Asset Failed to Load!");
return false;
}
$this->scripts .= Assets::wrapJs($file, $scope, $a);
return true;
}
/**
* Add CSS stylesheet to HTML towards top of HTML for CSS
* @param string $file
* @param string $scope (project, framework, cdn)
* @return bool was successful
*/
public function addMainCss(string $file, string $scope = 'project', array $a = array()): bool {
$css = Assets::wrapAsset($file, $scope);
if ($css === false) {
$this->js_log($file . " - {$scope} Asset Failed to Load!");
return false;
}
$this->mainStyles .= Assets::wrapCss($file, $scope, $a);
return true;
}
/**
* Add JavaScript to HTML towards top of HTML for JS
* @param string $file
* @param string $scope (project, framework, cdn)
* @return bool was successful
*/
public function addMainJs(string $file, string $scope = 'project', array $a = array()): bool {
$js = Assets::wrapAsset($file, $scope);
if ($js === false) {
$this->js_log($file . " - {$scope} Asset Failed to Load!");
return false;
}
$this->mainScripts .= Assets::wrapJs($file, $scope, $a);
return true;
}
/**
* Adds JavaScript code to called after JQuery is ready.
* @param string $code
*/
//public function add_js_onready(string $code): void {
// $this->js_onready .= \px_inline_js(\px_jquery_load($code));
//}
/**
* Log to JavaScript Console under Chrome Browser
* @param string $log
*/
public function jsLog(string $log): void {
$this->addToJavascript("console.log('{$log}');");
}
/**
* Place JavaScript in HTML
* @param string $js
*/
public function addToJavascript(string $js): void {
if (! empty($js)) {
$this->scripts .= Assets::inlineJs($js);
}
}
/**
* Use CSS/JS for Database SSP
public function datatables_code(): void {
$this->addCss('datatables/datatables.min.css', 'cl');
$this->addJs('datatables/datatables_no_jquery.min.js', 'cl');
}
*
*/
/**
* Used by Template file to render HTML Author
* @return string HTML Author
*/
public function getAuthor(): string {
return $this->author;
}
/**
* Used by Template file to render HTML TITLE
* @return string HTML TITLE
*/
public function getTitle(): string {
return $this->title;
}
/**
* Used by Template file to render HTML Header
* @return string HTML Header
*/
public function getHeader(): string {
return $this->header;
}
public function getBody(): string {
return $this->body;
}
/**
* Used by Template file to render HTML Footer
* @return string HTML Footer
*/
public function getFooter(): string {
return $this->footer;
}
/**
* Used by Template file to render HTML Meta data for Description
* @return string HTML Meta Description
*/
public function getDescription(): string {
return $this->description;
}
/**
* Used by Template file to render HTML Meta data for Keywords
* @return string HTML Meta Keywords
*/
public function getKeywords(): string {
return $this->keywords;
}
/**
* Used by Template file to render HTML Meta data for Robots
* @return string HTML Meta Robots
*/
public function getRobots(): ?string {
return $this->robots;
}
/**
* Used by Template file to render HTML CSS
* @return string HTML CSS
*/
public function getStyles(): string {
return $this->styles;
}
/**
* Used by Template file to render HTML JavaScripts
* @return string HTML JS
*/
public function getScripts(): string {
return $this->scripts;
}
/**
* Used by Template file to render HTML main CSS @Top
* @return string HTML CSS
*/
public function getMainStyles(): string {
return $this->mainStyles;
}
/**
* Used by Template file to render HTML main JS @Top
* @return string HTML JavaScript
*/
public function getMainScripts(): string {
return $this->mainScripts;
}
/**
* Used by Template file to render HTML JS after main JS
* @return string HTML JS
*/
public function getJsOnReady(): string {
return $this->jsOnReady;
}
/** /**
* Used by Template file to render HTML Active BreadCrumb * Used by Template file to render HTML TITLE
* @return string HTML Active BreadCrumb * @return string HTML TITLE
*/ */
public function getActiveCrumb(): string { public function getTitle(): string
return $this->activeCrumb; {
} return $this->title;
}
/**
* Used by Template file to render HTML BreadCrumbs /**
* @return string HTML BreadCrumbs * Used by Template file to render HTML Header
*/ * @return string HTML Header
public function getBreadcrumbs(): array { */
return $this->breadcrumb; public function getHeader(): string
} {
return $this->header;
public function getHead(): string { }
return $this->head;
} public function getBody(): string
{
return $this->body;
}
/**
* Used by Template file to render HTML Footer
* @return string HTML Footer
*/
public function getFooter(): string
{
return $this->footer;
}
/**
* Used by Template file to render HTML Meta data for Description
* @return string HTML Meta Description
*/
public function getDescription(): string
{
return $this->description;
}
/**
* Used by Template file to render HTML Meta data for Keywords
* @return string HTML Meta Keywords
*/
public function getKeywords(): string
{
return $this->keywords;
}
/**
* Used by Template file to render HTML Meta data for Robots
* @return string HTML Meta Robots
*/
public function getRobots(): ?string
{
return $this->robots;
}
/**
* Used by Template file to render HTML CSS
* @return string HTML CSS
*/
public function getStyles(): string
{
return $this->styles;
}
/**
* Used by Template file to render HTML JavaScripts
* @return string HTML JS
*/
public function getScripts(): string
{
return $this->scripts;
}
/**
* Used by Template file to render HTML main CSS @Top
* @return string HTML CSS
*/
public function getMainStyles(): string
{
return $this->mainStyles;
}
/**
* Used by Template file to render HTML main JS @Top
* @return string HTML JavaScript
*/
public function getMainScripts(): string
{
return $this->mainScripts;
}
/**
* Used by Template file to render HTML JS after main JS
* @return string HTML JS
*/
public function getJsOnReady(): string
{
return $this->jsOnReady;
}
/**
* Used by Template file to render HTML Active BreadCrumb
* @return string HTML Active BreadCrumb
*/
public function getActiveCrumb(): string
{
return $this->activeCrumb;
}
/**
* Used by Template file to render HTML BreadCrumbs
* @return string HTML BreadCrumbs
*/
public function getBreadcrumbs(): array
{
return $this->breadcrumb;
}
public function getHead(): string
{
return $this->head;
}
public function getBreadcrumbsAuto(): string
{
if (! count($this->breadcrumb) && empty($this->activeCrumb)) {
return "";
}
$out = "<nav><ul class=\"breadcrumb\">" . PHP_EOL;
foreach($this->breadcrumb as $link => $crumb) {
$out .= "<li><a href=\"$link\">$crumb</a></li>" . PHP_EOL;
}
if (! empty($this->activeCrumb)) {
$out .= "<li>" . $this->activeCrumb . "</li>" . PHP_EOL;
}
$out .= "</ul></nav>" . PHP_EOL;
return $out;
}
} }

@ -130,6 +130,9 @@ class Kernel {
header("$name: $value", false); header("$name: $value", false);
} }
} }
if (function_exists('session_status') && session_status() == PHP_SESSION_ACTIVE) {
session_write_close();
}
echo $response->getBody(); echo $response->getBody();
} }

@ -39,10 +39,7 @@ class CookieSessionHandler implements \SessionHandlerInterface {
if (isset($options['cookie_secure'])) { if (isset($options['cookie_secure'])) {
self::$cookieSecure = $options['cookie_secure']; self::$cookieSecure = $options['cookie_secure'];
} else { } else {
/** $use_secure = (USE_SECURE);
* @todo Fix this...use_secure
*/
$use_secure = true;
if ($use_secure === false) { if ($use_secure === false) {
self::$cookieSecure = false; self::$cookieSecure = false;
} }

@ -45,7 +45,7 @@ final class SessionManagement
'files' => new FileSes($enc, $options), 'files' => new FileSes($enc, $options),
default => new CookieSes($enc, $options), default => new CookieSes($enc, $options),
}; };
session_set_save_handler($handler, true); session_set_save_handler($handler);
self::makeSessionStarted(); self::makeSessionStarted();
} }
@ -56,12 +56,8 @@ final class SessionManagement
session_name($name); session_name($name);
} }
/**
* @todo Fix ForceSecure....to detect mode
*/
if (! headers_sent()) { if (! headers_sent()) {
$use_secure = 1; // (site_helper::get_use_secure()) ? 1 : 0; $use_secure = (USE_SECURE) ? 1 : 0;
$use_secure = ($force_secure) ? 1 : $use_secure; $use_secure = ($force_secure) ? 1 : $use_secure;
session_start([ session_start([
'cookie_lifetime' => 0, // until browser is closed 'cookie_lifetime' => 0, // until browser is closed

@ -1,12 +1,13 @@
<?php <?php
declare(strict_types = 1); declare(strict_types=1);
/** /**
* @author Robert Strutts * @author Robert Strutts
* @copyright (c) 2026, Robert Strutts * @copyright (c) 2026, Robert Strutts
* @license MIT * @license MIT
*/ */
namespace IOcornerstone\Framework; namespace IOcornerstone\Framework;
use IOcornerstone\Framework\Security; use IOcornerstone\Framework\Security;
@ -19,13 +20,33 @@ use IOcornerstone\Framework\Security;
*/ */
final class SiteHelper final class SiteHelper
{ {
private static $local_site_domains = ['localhost']; private static $local_site_domains = ['localhost'];
private static $Private_IPs_allowed = ['127.0.0.1', '::1']; private static $Private_IPs_allowed = ['127.0.0.1', '::1'];
private static $Public_IPs_allowed = []; private static $Public_IPs_allowed = [];
public static function setLocalSiteDomains(string|array $domain_name): void { public static function setupHTTP(): void
{
define("PROJECT_ASSETS_DIR", BaseDir . DIRECTORY_SEPARATOR . "public" . DIRECTORY_SEPARATOR . "assets" . DIRECTORY_SEPARATOR);
$server_port = $_SERVER['SERVER_PORT'] ?? 80;
$secure_port_on = $_SERVER['HTTPS'] ?? "off";
$use_secure = ($server_port == "443" || $secure_port_on == "on");
$protocol = ($use_secure) ? "https://" : "http://";
$domain_name = $_SERVER['HTTP_HOST'] ?? "";
define("HTTP_PROT", $protocol);
define("USE_SECURE", $use_secure);
define("PROJECT_BASE_REF", $protocol . $domain_name);
define("PROJECT_ASSETS_BASE_REF", PROJECT_BASE_REF . "/assets");
define("ASSETS_DIR", PROJECT_ASSETS_DIR);
define('ASSETS_BASE_REF', PROJECT_ASSETS_BASE_REF);
}
public static function setLocalSiteDomains(string|array $domain_name): void
{
if (is_array($domain_name)) { if (is_array($domain_name)) {
foreach($domain_name as $domain) { foreach ($domain_name as $domain) {
self::$local_site_domains[] = $domain; self::$local_site_domains[] = $domain;
} }
} elseif (is_string($domain_name)) { } elseif (is_string($domain_name)) {
@ -33,9 +54,10 @@ final class SiteHelper
} }
} }
public static function setAllowedPrivateIPs(string|array $IP_addresses): void { public static function setAllowedPrivateIPs(string|array $IP_addresses): void
{
if (is_array($IP_addresses)) { if (is_array($IP_addresses)) {
foreach($IP_addresses as $IP) { foreach ($IP_addresses as $IP) {
$s_ip = Security::getValidIp($IP); $s_ip = Security::getValidIp($IP);
if ($s_ip === false) { if ($s_ip === false) {
continue; continue;
@ -51,9 +73,10 @@ final class SiteHelper
} }
} }
public static function setAllowedPublicIPs(string|array $IP_addresses): void { public static function setAllowedPublicIPs(string|array $IP_addresses): void
{
if (is_array($IP_addresses)) { if (is_array($IP_addresses)) {
foreach($IP_addresses as $IP) { foreach ($IP_addresses as $IP) {
$s_ip = Security::getValidPublicIp($IP); $s_ip = Security::getValidPublicIp($IP);
if ($s_ip === false) { if ($s_ip === false) {
continue; continue;
@ -69,16 +92,19 @@ final class SiteHelper
} }
} }
public static function isServerName_A_PrivateDomain(): bool { public static function isServerName_A_PrivateDomain(): bool
{
$white_list = array_merge(self::$local_site_domains, self::$Private_IPs_allowed); $white_list = array_merge(self::$local_site_domains, self::$Private_IPs_allowed);
return (Security::isServerNameOnDomainList($white_list)); return (Security::isServerNameOnDomainList($white_list));
} }
public static function remoteNotAllowedForceLive(): bool { public static function remoteNotAllowedForceLive(): bool
return (! self::is_allowed()); {
return (!self::is_allowed());
} }
public static function is_allowed(): bool { public static function is_allowed(): bool
{
$remote_ip = Security::getClientIpAddress(); $remote_ip = Security::getClientIpAddress();
if (in_array($remote_ip, self::$Public_IPs_allowed)) { if (in_array($remote_ip, self::$Public_IPs_allowed)) {
return true; return true;
@ -88,5 +114,4 @@ final class SiteHelper
} }
return false; return false;
} }
} }

Loading…
Cancel
Save