mirror of
https://github.com/LBRYFoundation/lbry.com.git
synced 2025-08-23 17:47:26 +00:00
390 lines
11 KiB
PHP
390 lines
11 KiB
PHP
<?php
|
|
|
|
class Response
|
|
{
|
|
const HEADER_STATUS = 'Status';
|
|
const HEADER_LOCATION = 'Location';
|
|
|
|
const HEADER_CACHE_CONTROL = 'Cache-Control';
|
|
const HEADER_ETAG = 'Etag';
|
|
|
|
const HEADER_CONTENT_TYPE = 'Content-Type';
|
|
const HEADER_CONTENT_LENGTH = 'Content-Length';
|
|
const HEADER_CONTENT_DISPOSITION = 'Content-Disposition';
|
|
const HEADER_CONTENT_TYPE_OPTIONS = 'X-Content-Type-Options';
|
|
const HEADER_CONTENT_ENCODING = 'Content-Encoding';
|
|
const HEADER_CROSS_ORIGIN = 'Access-Control-Allow-Origin';
|
|
|
|
protected static $metaDescription = '';
|
|
protected static $metaTitle = '';
|
|
protected static $jsCalls = [];
|
|
protected static $assets = [
|
|
'js' => [
|
|
'/js/jquery-3.4.1.min.js',
|
|
'/js/global.js'
|
|
],
|
|
'css' => ['/css/all.css']
|
|
];
|
|
protected static $headers = [
|
|
'Cache-Control' => 'private, no-cache'
|
|
];
|
|
protected static $headersSent = false;
|
|
protected static $content = '';
|
|
protected static $contentSent = false;
|
|
protected static $gzipResponseContent = true;
|
|
protected static $metaImages = [];
|
|
protected static $facebookAnalyticsType = "PageView";
|
|
|
|
private static $PostRenderCallbacks = array();
|
|
|
|
public static function setMetaDescription($description)
|
|
{
|
|
static::$metaDescription = $description;
|
|
}
|
|
|
|
public static function addMetaImage($url)
|
|
{
|
|
static::$metaImages[] = $url;
|
|
}
|
|
|
|
public static function addMetaImages(array $urls)
|
|
{
|
|
foreach ($urls as $url) {
|
|
static::addMetaImage($url);
|
|
}
|
|
}
|
|
|
|
public static function getMetaDescription()
|
|
{
|
|
return static::$metaDescription ?: 'A Content Revolution';
|
|
}
|
|
|
|
public static function getMetaImages()
|
|
{
|
|
return static::$metaImages ?: [Request::getHostAndProto() . '/img/og-image.png?_cache=' . date('Y-m-d')];
|
|
}
|
|
|
|
public static function setMetaTitle($title)
|
|
{
|
|
static::$metaTitle = $title;
|
|
}
|
|
|
|
public static function getMetaTitle()
|
|
{
|
|
return trim(static::$metaTitle);
|
|
}
|
|
|
|
public static function guessMetaTitle($content)
|
|
{
|
|
$title = '';
|
|
preg_match_all('/<h(1|2)[^>]*>([^<]+)</', $content, $titleMatches);
|
|
foreach ($titleMatches[1] as $matchIndex => $headerValue) {
|
|
if ($headerValue == '1' || !$title) {
|
|
$title = $titleMatches[2][$matchIndex];
|
|
if ($headerValue == '1') {
|
|
return trim($title);
|
|
}
|
|
}
|
|
}
|
|
return trim($title);
|
|
}
|
|
|
|
public static function getJsCalls()
|
|
{
|
|
return static::$jsCalls;
|
|
}
|
|
|
|
public static function jsOutputCallback($js)
|
|
{
|
|
static::$jsCalls[] = $js;
|
|
return '';
|
|
}
|
|
|
|
public static function addJsAsset($src)
|
|
{
|
|
static::$assets['js'][$src] = $src;
|
|
}
|
|
|
|
public static function addCssAsset($src)
|
|
{
|
|
static::$assets['css'][$src] = $src;
|
|
}
|
|
|
|
public static function getJsAssets()
|
|
{
|
|
return static::$assets['js'];
|
|
}
|
|
|
|
public static function getCssAssets()
|
|
{
|
|
return static::$assets['css'];
|
|
}
|
|
|
|
public static function setCssAssets(array $assets = [])
|
|
{
|
|
static::$assets['css'] = $assets;
|
|
}
|
|
public static function setGzipResponseContent($gzip = true)
|
|
{
|
|
static::$gzipResponseContent = $gzip;
|
|
}
|
|
|
|
public static function gzipContentIfNotDisabled()
|
|
{
|
|
if (static::$gzipResponseContent) {
|
|
$content = static::getContent();
|
|
if (strlen($content) > 256) { // not worth it for really short content
|
|
$compressed = gzencode($content, 1);
|
|
static::setContent($compressed);
|
|
static::setHeader(static::HEADER_CONTENT_LENGTH, strlen($compressed));
|
|
static::setHeader(static::HEADER_CONTENT_ENCODING, 'gzip');
|
|
}
|
|
}
|
|
}
|
|
|
|
public static function send()
|
|
{
|
|
$status = static::getHeader(static::HEADER_STATUS);
|
|
$sendContent = true;
|
|
if ((!$status || $status === 200) &&
|
|
static::getHeader(static::HEADER_ETAG) &&
|
|
Request::getHttpHeader('If-None-Match', null) === static::getHeader(static::HEADER_ETAG)
|
|
) {
|
|
static::setHeader(static::HEADER_STATUS, 304);
|
|
$sendContent = false;
|
|
}
|
|
|
|
static::sendHeaders();
|
|
|
|
if ($sendContent) {
|
|
static::sendContent();
|
|
}
|
|
}
|
|
|
|
public static function setContent(string $content)
|
|
{
|
|
static::$content = $content;
|
|
}
|
|
|
|
public static function getContent(): string
|
|
{
|
|
return static::$content;
|
|
}
|
|
|
|
public static function sendContent()
|
|
{
|
|
if (static::$contentSent) {
|
|
throw new LogicException('Content has already been sent. It cannot be sent twice');
|
|
}
|
|
|
|
echo static::$content;
|
|
|
|
static::$contentSent = true;
|
|
}
|
|
|
|
public static function setDownloadHttpHeaders($name, $type = null, $size = null, $noSniff = true)
|
|
{
|
|
static::setBinaryHttpHeaders($type, $size, $noSniff);
|
|
static::setHeader('Content-Disposition', 'attachment;filename=' . $name);
|
|
}
|
|
|
|
public static function setBinaryHttpHeaders($type, $size = null, $noSniff = true)
|
|
{
|
|
static::setGzipResponseContent(false); // in case its already compressed
|
|
static::setHeaders(array_filter([
|
|
static::HEADER_CONTENT_TYPE => $type,
|
|
static::HEADER_CONTENT_LENGTH => $size ?: null,
|
|
static::HEADER_CONTENT_TYPE_OPTIONS => $noSniff ? 'nosniff' : null,
|
|
]));
|
|
}
|
|
|
|
//public immutable cache = hard-caching (no server checks) until time limit passes
|
|
public static function enablePublicImmutableCache(int $seconds = 300)
|
|
{
|
|
static::setHeader(static::HEADER_CACHE_CONTROL, 'public, max-age=' . $seconds);
|
|
}
|
|
|
|
//public mutable cache = soft-caching (requires at least one round trip for headers) as long as etag identifier matches
|
|
public static function enablePublicMutableCache(string $etag)
|
|
{
|
|
static::setHeader(static::HEADER_CACHE_CONTROL, 'public');
|
|
static::setHeader(static::HEADER_ETAG, $etag);
|
|
}
|
|
|
|
//always reload and re-execute this resource, disable any local or intermediary caching
|
|
public static function disableHttpCache()
|
|
{
|
|
static::setHeader(static::HEADER_CACHE_CONTROL, 'private, no-cache, no-store');
|
|
}
|
|
|
|
public static function setHeader($name, $value)
|
|
{
|
|
static::$headers[$name] = $value;
|
|
}
|
|
|
|
public static function setHeaders($headers, $overwrite = true)
|
|
{
|
|
foreach ($headers as $name => $value) {
|
|
if ($overwrite || !static::getHeader($name)) {
|
|
static::setHeader($name, $value);
|
|
}
|
|
}
|
|
}
|
|
|
|
public static function getHeader($name, $default = null)
|
|
{
|
|
return static::$headers[$name] ?? $default;
|
|
}
|
|
|
|
public static function getHeaders(): array
|
|
{
|
|
return static::$headers;
|
|
}
|
|
|
|
public static function setStatus($status)
|
|
{
|
|
static::setHeader(static::HEADER_STATUS, $status);
|
|
}
|
|
|
|
public static function setDefaultSecurityHeaders()
|
|
{
|
|
$defaultHeaders = [
|
|
//'Content-Security-Policy' => "frame-ancestors 'none'",
|
|
//'X-Frame-Options' => 'DENY',
|
|
'X-XSS-Protection' => '1',
|
|
];
|
|
|
|
if (IS_PRODUCTION) {
|
|
$defaultHeaders['Strict-Transport-Security'] = 'max-age=31536000';
|
|
}
|
|
|
|
static::setHeaders($defaultHeaders, false);
|
|
}
|
|
|
|
public static function sendHeaders()
|
|
{
|
|
if (static::$headersSent) {
|
|
throw new LogicException('Headers have already been sent. They cannot be sent twice');
|
|
}
|
|
|
|
if (!static::getHeader(static::HEADER_CONTENT_TYPE)) {
|
|
static::setHeader(static::HEADER_CONTENT_TYPE, 'text/html');
|
|
}
|
|
|
|
$headers = static::getHeaders();
|
|
|
|
if (isset($headers[static::HEADER_STATUS])) {
|
|
$status = 'HTTP/1.0 ' . $headers[static::HEADER_STATUS] . ' ' . static::getStatusTextForCode($headers[static::HEADER_STATUS]);
|
|
header($status);
|
|
|
|
if (substr(php_sapi_name(), 0, 3) == 'cgi') {
|
|
// fastcgi servers cannot send this status information because it was sent by them already due to the HTT/1.0 line
|
|
// so we can safely unset them. see ticket #3191
|
|
unset($headers[static::HEADER_STATUS]);
|
|
}
|
|
}
|
|
|
|
foreach ($headers as $name => $value) {
|
|
header($name . ': ' . $value);
|
|
}
|
|
|
|
static::$headersSent = true;
|
|
}
|
|
|
|
public static function getStatusTextForCode($code)
|
|
{
|
|
$statusTexts = [
|
|
'100' => 'Continue',
|
|
'101' => 'Switching Protocols',
|
|
'200' => 'OK',
|
|
'201' => 'Created',
|
|
'202' => 'Accepted',
|
|
'203' => 'Non-Authoritative Information',
|
|
'204' => 'No Content',
|
|
'205' => 'Reset Content',
|
|
'206' => 'Partial Content',
|
|
'300' => 'Multiple Choices',
|
|
'301' => 'Moved Permanently',
|
|
'302' => 'Found',
|
|
'303' => 'See Other',
|
|
'304' => 'Not Modified',
|
|
'305' => 'Use Proxy',
|
|
'306' => '(Unused)',
|
|
'307' => 'Temporary Redirect',
|
|
'400' => 'Bad Request',
|
|
'401' => 'Unauthorized',
|
|
'402' => 'Payment Required',
|
|
'403' => 'Forbidden',
|
|
'404' => 'Not Found',
|
|
'405' => 'Method Not Allowed',
|
|
'406' => 'Not Acceptable',
|
|
'407' => 'Proxy Authentication Required',
|
|
'408' => 'Request Timeout',
|
|
'409' => 'Conflict',
|
|
'410' => 'Gone',
|
|
'411' => 'Length Required',
|
|
'412' => 'Precondition Failed',
|
|
'413' => 'Request Entity Too Large',
|
|
'414' => 'Request-URI Too Long',
|
|
'415' => 'Unsupported Media Type',
|
|
'416' => 'Requested Range Not Satisfiable',
|
|
'417' => 'Expectation Failed',
|
|
'419' => 'Authentication Timeout',
|
|
'422' => 'Unprocessable Entity',
|
|
'426' => 'Upgrade Required',
|
|
'429' => 'Too Many Requests',
|
|
'500' => 'Internal Server Error',
|
|
'501' => 'Not Implemented',
|
|
'502' => 'Bad Gateway',
|
|
'503' => 'Service Unavailable',
|
|
'504' => 'Gateway Timeout',
|
|
'505' => 'HTTP Version Not Supported',
|
|
];
|
|
|
|
return $statusTexts[$code] ?? null;
|
|
}
|
|
|
|
public static function setFacebookPixelAnalyticsType($type)
|
|
{
|
|
static::$facebookAnalyticsType = $type;
|
|
}
|
|
|
|
public static function getFacebookPixelAnalyticsType()
|
|
{
|
|
return static::$facebookAnalyticsType;
|
|
}
|
|
|
|
protected static function normalizeHeaderName($name): string
|
|
{
|
|
return preg_replace_callback(
|
|
'/\-(.)/',
|
|
function ($matches) {
|
|
return '-' . strtoupper($matches[1]);
|
|
},
|
|
strtr(ucfirst(strtolower($name)), '_', '-')
|
|
);
|
|
}
|
|
|
|
public static function addPostRenderCallback($cb)
|
|
{
|
|
array_push(static::$PostRenderCallbacks, $cb);
|
|
}
|
|
|
|
public static function invokePostRenderCallbacks()
|
|
{
|
|
foreach (static::$PostRenderCallbacks as &$cb) {
|
|
$cb();
|
|
}
|
|
}
|
|
|
|
|
|
// public static function addBodyCssClass($classOrClasses)
|
|
// {
|
|
// static::$bodyCssClasses = array_unique(array_merge(static::$bodyCssClasses, (array)$classOrClasses));
|
|
// }
|
|
//
|
|
// public static function getBodyCssClasses()
|
|
// {
|
|
// return static::$bodyCssClasses;
|
|
// }
|
|
}
|