Version 5.0.0 beta 4

This commit is contained in:
Neo committed 2025-12-19 16:57:00 -08:00
1 parent e86153356a
commit 2f24f9de48
276 files changed
+8614 -6044

No files matched your search

+145 -25
View File
@@ -291,6 +291,11 @@ class Output
* @brief Data which were loaded via the GraphQL framework, but which have to be immediately available, rather then via later AJAX requests
*/
public array $graphData = [];
/**
* @brief A custom cache DateTime object set to UTC
*/
protected static bool|null|DateTime $cacheDate = NULL;
/**
* Constructor
@@ -523,6 +528,17 @@ class Output
return $title;
}
/**
* Store any custom DateTime for cache headers
*
* @param DateTime|bool $date
* @return void
*/
public static function setCacheTime( DateTime|bool $date=false ): void
{
static::$cacheDate = $date;
}
/**
* Retrieve cache headers
*
@@ -532,10 +548,43 @@ class Output
*/
public static function getCacheHeaders( int $lastModified, int $cacheSeconds ): array
{
/* The default is null, so if it is to false from setCacheTime, we should not cache */
if ( static::$cacheDate === false )
{
return static::getNoCacheHeaders();
}
$expires = DateTime::ts( ( time() + $cacheSeconds ), TRUE );
if ( static::$cacheDate instanceof \DateTime )
{
$expires = static::$cacheDate;
$cacheSeconds = $expires->getTimestamp() - time();
}
else
{
/* Set the cache date to the expiration date in case anything intercepts the output process and checks the cacheDate */
static::$cacheDate = $expires;
}
if ( \IPS\CIC or \IPS\IN_DEV )
{
return array(
'Date' => DateTime::ts( time(), TRUE )->rfc1123(),
'Last-Modified' => DateTime::ts( $lastModified, TRUE )->rfc1123(),
'Expires' => $expires->rfc1123(),
'Cache-Control' => implode( ', ', [
'max-age=0', // No cache for the browser [https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#response_directives]
'public', // Public cache
's-maxage=' . $cacheSeconds, // Cache for the CDN [https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#response_directives]
'stale-if-error' // Allow the CDN to serve stale content if there is an error
] )
);
}
return array(
'Date' => DateTime::ts( time(), TRUE )->rfc1123(),
'Last-Modified' => DateTime::ts( $lastModified, TRUE )->rfc1123(),
'Expires' => DateTime::ts( ( time() + $cacheSeconds ), TRUE )->rfc1123(),
'Expires' => $expires->rfc1123(),
'Cache-Control' => 'no-cache="Set-Cookie", max-age=' . $cacheSeconds . ", public, s-maxage=" . $cacheSeconds . ", stale-while-revalidate, stale-if-error",
);
}
@@ -799,7 +848,7 @@ class Output
/* Log */
$level = intval( substr( $code, 0, 1 ) );
if( !Session::i()->userAgent->spider )
if( !Session::i()->userAgent->bot )
{
if( $code and Settings::i()->error_log_level and $level >= Settings::i()->error_log_level )
{
@@ -890,6 +939,79 @@ class Output
}
}
/**
* Can this output be cached by CDN?
*
* @param string $contentType
* @param bool $checkCachePageTimeout
* @return bool
*/
public function isCacheable( string $contentType='text/html', bool $checkCachePageTimeout = true ): bool
{
/* Have we got a value for the default cache timeout? */
if ( $checkCachePageTimeout and ! \IPS\CACHE_PAGE_TIMEOUT )
{
return false;
}
/* Have we set a per-page cache timeout of false, which means we don't want to cache? */
if ( static::$cacheDate === false )
{
return false;
}
else if ( static::$cacheDate instanceof DateTime )
{
/* Or have we set a specific cache date and it's in the past? */
$cacheSeconds = static::$cacheDate->getTimestamp() - time();
if ( $cacheSeconds <= 0 )
{
return false;
}
}
/* Are we logged in? */
if ( Member::loggedIn()->member_id )
{
return false;
}
/* Are we using the legacy pageCaching flag? */
if ( ! $this->pageCaching )
{
return false;
}
/* Do we have a noCache cookie set? */
if ( isset( Request::i()->cookie['noCache'] ) )
{
return false;
}
/* Do we have a CSRF key? */
if ( isset( Request::i()->csrfKey ) )
{
return false;
}
/* Check the request method */
if ( ! in_array( mb_strtolower( $_SERVER['REQUEST_METHOD'] ), [ 'get', 'head' ] ) )
{
return false;
}
if ( ! in_array( $contentType, ['text/html', 'text/xml', 'application/manifest+json' ] ) )
{
return false;
}
if ( Dispatcher::hasInstance() and class_exists( 'IPS\Dispatcher', FALSE ) and Dispatcher::i()->controllerLocation !== 'front' )
{
return false;
}
return true;
}
/**
* @brief Flag to bypass CSRF IN_DEV check
*/
@@ -945,36 +1067,18 @@ class Output
$this->parseFileObjectUrls( $output );
}
/* Combine some common checks for re-use */
$canCache = function( $contentType, $obj ) {
if( $obj->pageCaching and
( mb_strtolower( $_SERVER['REQUEST_METHOD'] ) == 'get' OR mb_strtolower( $_SERVER['REQUEST_METHOD'] ) == 'head' ) and // Is a HTTP GET/HEAD request (don't cache output for POSTs)
( $contentType == 'text/html' or $contentType == 'text/xml' or $contentType == 'application/manifest+json' ) and // Output is HTML, XML or [PWA] application manifest (don't cache JSON output, etc)
Dispatcher::hasInstance() and class_exists( 'IPS\Dispatcher', FALSE ) and Dispatcher::i()->controllerLocation === 'front' // Is a normal, front-end page (necessary to know if user is logged in)
)
{
return TRUE;
}
return FALSE;
};
if (
CACHE_PAGE_TIMEOUT and // Page caching is enabled
$cacheThisPage and // Some pages can specify not to be cached (for example, when displaying a cached page, you don't want it recached)
!isset( Request::i()->cookie['noCache'] ) and // A noCache cookie might get set to not cache a particular guest (for example, if they have added items to their cart in the store)
$canCache( $contentType, $this ) and // Common checks, see above
!isset( Request::i()->csrfKey ) and // CSRF key isn't present (which would be like a POST request)
!Member::loggedIn()->member_id // User is not logged in
) {
/* Can we cache this page to a CDN? */
if( $cacheThisPage and $this->isCacheable( $contentType ) )
{
/* Add caching headers */
if( !isset( $httpHeaders['Cache-Control'] ) )
{
$httpHeaders += Output::getCacheHeaders( time(), CACHE_PAGE_TIMEOUT);
}
}
/* Send no-cache headers if we got to this point without any cache-control headers being set, or page caching is forced off */
elseif( !isset( $httpHeaders['Cache-Control'] ) OR !$this->pageCaching )
elseif( !isset( $httpHeaders['Cache-Control'] ) )
{
/* Send no-cache headers if we got to this point without any cache-control headers being set, or page caching is forced off */
$httpHeaders += Output::getNoCacheHeaders();
}
@@ -1154,6 +1258,22 @@ class Output
exit;
}
/**
* Should we reduce the number of links in the HTML for SEO purposes?
*
* @return bool
*/
public function reduceLinks(): bool
{
if ( ! Member::loggedIn()->member_id and Settings::i()->seo_reduce_links )
{
return true;
}
return false;
}
/**
* Remove any comment tags that were inserted in the middle of an HTML tag
*