2019-08-15 20:52:42 +02:00
< ? php
2020-02-08 17:16:42 +01:00
/**
2023-01-01 15:36:24 +01:00
* @ copyright Copyright ( C ) 2010 - 2023 , the Friendica project
2020-02-08 17:16:42 +01:00
*
* @ license GNU AGPL version 3 or any later version
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation , either version 3 of the
* License , or ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU Affero General Public License for more details .
*
* You should have received a copy of the GNU Affero General Public License
* along with this program . If not , see < https :// www . gnu . org / licenses />.
*
*/
2019-08-15 20:52:42 +02:00
namespace Friendica\App ;
use ArrayAccess ;
use DOMDocument ;
use DOMXPath ;
use Friendica\App ;
use Friendica\Content\Nav ;
2021-10-26 21:44:29 +02:00
use Friendica\Core\Config\Capability\IManageConfigValues ;
2019-08-15 20:52:42 +02:00
use Friendica\Core\Hook ;
2020-01-18 20:59:39 +01:00
use Friendica\Core\L10n ;
2022-05-17 22:47:23 +02:00
use Friendica\Core\Logger ;
2023-01-08 07:17:06 +01:00
use Friendica\Core\PConfig\Capability\IManagePersonalConfigValues ;
2019-08-15 20:52:42 +02:00
use Friendica\Core\Renderer ;
2022-04-10 10:31:55 +02:00
use Friendica\Core\System ;
2019-08-15 20:52:42 +02:00
use Friendica\Core\Theme ;
2022-04-10 10:31:55 +02:00
use Friendica\Module\Response ;
2019-08-15 20:52:42 +02:00
use Friendica\Network\HTTPException ;
2020-02-01 01:41:20 +01:00
use Friendica\Util\Network ;
2020-12-09 23:10:27 +01:00
use Friendica\Util\Profiler ;
2023-01-08 07:17:06 +01:00
use Friendica\Util\Strings ;
2023-07-10 04:44:40 +02:00
use GuzzleHttp\Psr7\Utils ;
2021-11-21 23:37:17 +01:00
use Psr\Http\Message\ResponseInterface ;
2019-08-15 20:52:42 +02:00
/**
* Contains the page specific environment variables for the current Page
* - Contains all stylesheets
* - Contains all footer - scripts
* - Contains all page specific content ( header , footer , content , ... )
*
* The run () method is the single point where the page will get printed to the screen
*/
class Page implements ArrayAccess
{
/**
* @ var array Contains all stylesheets , which should get loaded during page
*/
2019-11-29 17:33:48 +01:00
private $stylesheets = [];
2019-08-15 20:52:42 +02:00
/**
* @ var array Contains all scripts , which are added to the footer at last
*/
2019-11-29 17:33:48 +01:00
private $footerScripts = [];
2019-08-15 20:52:42 +02:00
/**
* @ var array The page content , which are showed directly
*/
2019-11-29 17:33:48 +01:00
private $page = [
'aside' => '' ,
'bottom' => '' ,
'content' => '' ,
'footer' => '' ,
'htmlhead' => '' ,
'nav' => '' ,
'page_title' => '' ,
'right_aside' => '' ,
'template' => '' ,
'title' => '' ,
2023-01-11 23:09:40 +01:00
'section' => '' ,
'module' => '' ,
2019-11-29 17:33:48 +01:00
];
2019-08-15 20:52:42 +02:00
/**
* @ var string The basepath of the page
*/
private $basePath ;
2022-05-17 23:25:01 +02:00
private $timestamp = 0 ;
private $method = '' ;
2022-09-20 16:30:56 +02:00
private $module = '' ;
private $command = '' ;
2022-05-17 22:47:23 +02:00
2019-08-15 20:52:42 +02:00
/**
* @ param string $basepath The Page basepath
*/
public function __construct ( string $basepath )
{
2022-05-17 22:47:23 +02:00
$this -> timestamp = microtime ( true );
2019-08-15 20:52:42 +02:00
$this -> basePath = $basepath ;
}
2022-09-20 16:30:56 +02:00
public function setLogging ( string $method , string $module , string $command )
2022-05-17 22:47:23 +02:00
{
2022-05-17 23:25:01 +02:00
$this -> method = $method ;
2022-09-20 16:30:56 +02:00
$this -> module = $module ;
$this -> command = $command ;
2022-05-17 22:47:23 +02:00
}
2022-06-10 20:49:03 +02:00
public function logRuntime ( IManageConfigValues $config , string $origin = '' )
2022-05-17 22:47:23 +02:00
{
2022-09-20 16:30:56 +02:00
$ignore = $config -> get ( 'system' , 'runtime_ignore' );
if ( in_array ( $this -> module , $ignore ) || in_array ( $this -> command , $ignore )) {
2022-05-18 05:10:38 +02:00
return ;
}
2022-09-20 16:30:56 +02:00
$signature = ! empty ( $_SERVER [ 'HTTP_SIGNATURE' ]);
$load = number_format ( System :: currentLoad (), 2 );
$runtime = number_format ( microtime ( true ) - $this -> timestamp , 3 );
2022-05-18 05:10:38 +02:00
if ( $runtime > $config -> get ( 'system' , 'runtime_loglimit' )) {
2022-09-20 16:30:56 +02:00
Logger :: debug ( 'Runtime' , [ 'method' => $this -> method , 'module' => $this -> module , 'runtime' => $runtime , 'load' => $load , 'origin' => $origin , 'signature' => $signature , 'request' => $_SERVER [ 'REQUEST_URI' ] ? ? '' ]);
2022-05-18 05:10:38 +02:00
}
2022-05-17 22:47:23 +02:00
}
2022-11-20 01:30:48 +01:00
// ArrayAccess interface
2019-08-15 20:52:42 +02:00
/**
2022-11-20 01:30:48 +01:00
* @ inheritDoc
2019-08-15 20:52:42 +02:00
*/
2022-11-20 01:30:48 +01:00
#[\ReturnTypeWillChange]
2022-11-09 23:16:12 +01:00
public function offsetExists ( $offset ) : bool
2019-08-15 20:52:42 +02:00
{
return isset ( $this -> page [ $offset ]);
}
/**
2022-11-20 01:30:48 +01:00
* @ inheritDoc
2019-08-15 20:52:42 +02:00
*/
2022-11-20 01:30:48 +01:00
#[\ReturnTypeWillChange]
2019-08-15 20:52:42 +02:00
public function offsetGet ( $offset )
{
return $this -> page [ $offset ] ? ? null ;
}
/**
2022-11-20 01:30:48 +01:00
* @ inheritDoc
2019-08-15 20:52:42 +02:00
*/
2022-11-20 01:30:48 +01:00
#[\ReturnTypeWillChange]
public function offsetSet ( $offset , $value ) : void
2019-08-15 20:52:42 +02:00
{
$this -> page [ $offset ] = $value ;
}
/**
2022-11-20 01:30:48 +01:00
* @ inheritDoc
2019-08-15 20:52:42 +02:00
*/
2022-11-20 01:30:48 +01:00
#[\ReturnTypeWillChange]
public function offsetUnset ( $offset ) : void
2019-08-15 20:52:42 +02:00
{
if ( isset ( $this -> page [ $offset ])) {
unset ( $this -> page [ $offset ]);
}
}
/**
* Register a stylesheet file path to be included in the < head > tag of every page .
* Inclusion is done in App -> initHead () .
* The path can be absolute or relative to the Friendica installation base folder .
*
* @ param string $path
2020-08-16 00:56:17 +02:00
* @ param string $media
2019-08-15 20:52:42 +02:00
* @ see Page :: initHead ()
*/
2022-06-16 16:49:43 +02:00
public function registerStylesheet ( string $path , string $media = 'screen' )
2019-08-15 20:52:42 +02:00
{
2022-10-17 12:37:48 +02:00
$path = Network :: appendQueryParam ( $path , [ 'v' => App :: VERSION ]);
2020-02-01 01:41:20 +01:00
2019-08-15 20:52:42 +02:00
if ( mb_strpos ( $path , $this -> basePath . DIRECTORY_SEPARATOR ) === 0 ) {
$path = mb_substr ( $path , mb_strlen ( $this -> basePath . DIRECTORY_SEPARATOR ));
}
2020-08-16 00:56:17 +02:00
$this -> stylesheets [ trim ( $path , '/' )] = $media ;
2019-08-15 20:52:42 +02:00
}
/**
* Initializes Page -> page [ 'htmlhead' ] .
*
* Includes :
* - Page title
* - Favicons
* - Registered stylesheets ( through App -> registerStylesheet ())
* - Infinite scroll data
* - head . tpl template
*
2022-10-20 21:27:32 +02:00
* @ param App $app The Friendica App instance
* @ param Arguments $args The Friendica App Arguments
* @ param L10n $l10n The l10n language instance
* @ param IManageConfigValues $config The Friendica configuration
* @ param IManagePersonalConfigValues $pConfig The Friendica personal configuration ( for user )
* @ param int $localUID The local user id
2019-08-15 20:52:42 +02:00
*
* @ throws HTTPException\InternalServerErrorException
*/
2022-10-20 21:27:32 +02:00
private function initHead ( App $app , Arguments $args , L10n $l10n , IManageConfigValues $config , IManagePersonalConfigValues $pConfig , int $localUID )
2019-08-15 20:52:42 +02:00
{
2022-10-20 21:27:32 +02:00
$interval = ( $localUID ? $pConfig -> get ( $localUID , 'system' , 'update_interval' ) : 40000 );
2019-08-15 20:52:42 +02:00
// If the update is 'deactivated' set it to the highest integer number (~24 days)
if ( $interval < 0 ) {
$interval = 2147483647 ;
}
if ( $interval < 10000 ) {
$interval = 40000 ;
}
// Default title: current module called
2021-11-19 22:47:49 +01:00
if ( empty ( $this -> page [ 'title' ]) && $args -> getModuleName ()) {
$this -> page [ 'title' ] = ucfirst ( $args -> getModuleName ());
2019-08-15 20:52:42 +02:00
}
// Prepend the sitename to the page title
$this -> page [ 'title' ] = $config -> get ( 'config' , 'sitename' , '' ) . ( ! empty ( $this -> page [ 'title' ]) ? ' | ' . $this -> page [ 'title' ] : '' );
if ( ! empty ( Renderer :: $theme [ 'stylesheet' ])) {
$stylesheet = Renderer :: $theme [ 'stylesheet' ];
} else {
$stylesheet = $app -> getCurrentThemeStylesheetPath ();
}
$this -> registerStylesheet ( $stylesheet );
$shortcut_icon = $config -> get ( 'system' , 'shortcut_icon' );
if ( $shortcut_icon == '' ) {
2022-04-28 12:41:26 +02:00
$shortcut_icon = 'images/friendica.svg' ;
2019-08-15 20:52:42 +02:00
}
$touch_icon = $config -> get ( 'system' , 'touch_icon' );
if ( $touch_icon == '' ) {
2020-10-03 20:25:10 +02:00
$touch_icon = 'images/friendica-192.png' ;
2019-08-15 20:52:42 +02:00
}
Hook :: callAll ( 'head' , $this -> page [ 'htmlhead' ]);
$tpl = Renderer :: getMarkupTemplate ( 'head.tpl' );
/* put the head template at the beginning of page [ 'htmlhead' ]
* since the code added by the modules frequently depends on it
* being first
*/
$this -> page [ 'htmlhead' ] = Renderer :: replaceMacros ( $tpl , [
2023-04-09 14:15:20 +02:00
'$l10n' => [
2023-07-09 22:14:53 +02:00
'delitem' => $l10n -> t ( 'Delete this item?' ),
'blockAuthor' => $l10n -> t ( " Block this author? They won't be able to follow you nor see your public posts, and you won't be able to see their posts and their notifications. " ),
'ignoreAuthor' => $l10n -> t ( " Ignore this author? You won't be able to see their posts and their notifications. " ),
'collapseAuthor' => $l10n -> t ( " Collapse this author's posts? " ),
'ignoreServer' => $l10n -> t ( " Ignore this author's server? " ),
'ignoreServerDesc' => $l10n -> t ( " You won't see any content from this server including reshares in your Network page, the community pages and individual conversations. " ),
2023-04-09 14:15:20 +02:00
'likeError' => $l10n -> t ( 'Like not successful' ),
'dislikeError' => $l10n -> t ( 'Dislike not successful' ),
'announceError' => $l10n -> t ( 'Sharing not successful' ),
'attendError' => $l10n -> t ( 'Attendance unsuccessful' ),
'srvError' => $l10n -> t ( 'Backend error' ),
'netError' => $l10n -> t ( 'Network error' ),
// Dropzone
'dictDefaultMessage' => $l10n -> t ( 'Drop files here to upload' ),
'dictFallbackMessage' => $l10n -> t ( " Your browser does not support drag and drop file uploads. " ),
'dictFallbackText' => $l10n -> t ( 'Please use the fallback form below to upload your files like in the olden days.' ),
'dictFileTooBig' => $l10n -> t ( 'File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.' ),
'dictInvalidFileType' => $l10n -> t ( " You can't upload files of this type. " ),
'dictResponseError' => $l10n -> t ( 'Server responded with {{statusCode}} code.' ),
'dictCancelUpload' => $l10n -> t ( 'Cancel upload' ),
'dictUploadCanceled' => $l10n -> t ( 'Upload canceled.' ),
'dictCancelUploadConfirmation' => $l10n -> t ( 'Are you sure you want to cancel this upload?' ),
'dictRemoveFile' => $l10n -> t ( 'Remove file' ),
'dictMaxFilesExceeded' => $l10n -> t ( " You can't upload any more files. " ),
],
2022-10-20 21:27:32 +02:00
'$local_user' => $localUID ,
2022-10-17 12:37:48 +02:00
'$generator' => 'Friendica' . ' ' . App :: VERSION ,
2019-11-28 18:27:16 +01:00
'$update_interval' => $interval ,
'$shortcut_icon' => $shortcut_icon ,
'$touch_icon' => $touch_icon ,
'$block_public' => intval ( $config -> get ( 'system' , 'block_public' )),
2020-08-16 00:56:17 +02:00
'$stylesheets' => $this -> stylesheets ,
2023-04-09 14:15:20 +02:00
2023-03-15 21:48:17 +01:00
// Dropzone
'$max_imagesize' => round ( \Friendica\Util\Strings :: getBytesFromShorthand ( $config -> get ( 'system' , 'maximagesize' )) / 1000000 , 1 ),
2019-11-28 18:27:16 +01:00
]) . $this -> page [ 'htmlhead' ];
2019-08-15 20:52:42 +02:00
}
2021-11-04 21:29:59 +01:00
/**
* Returns the complete URL of the current page , e . g .: http ( s ) :// something . com / network
*
* Taken from http :// webcheatsheet . com / php / get_current_page_url . php
*/
2022-06-16 16:49:43 +02:00
private function curPageURL () : string
2021-11-04 21:29:59 +01:00
{
$pageURL = 'http' ;
if ( ! empty ( $_SERVER [ " HTTPS " ]) && ( $_SERVER [ " HTTPS " ] == " on " )) {
$pageURL .= " s " ;
}
2021-11-20 15:38:03 +01:00
2021-11-04 21:29:59 +01:00
$pageURL .= " :// " ;
2021-11-20 15:38:03 +01:00
2021-11-04 21:29:59 +01:00
if ( $_SERVER [ " SERVER_PORT " ] != " 80 " && $_SERVER [ " SERVER_PORT " ] != " 443 " ) {
$pageURL .= $_SERVER [ " SERVER_NAME " ] . " : " . $_SERVER [ " SERVER_PORT " ] . $_SERVER [ " REQUEST_URI " ];
} else {
$pageURL .= $_SERVER [ " SERVER_NAME " ] . $_SERVER [ " REQUEST_URI " ];
}
return $pageURL ;
}
2022-11-20 01:30:48 +01:00
2019-08-15 20:52:42 +02:00
/**
* Initializes Page -> page [ 'footer' ] .
*
* Includes :
2023-03-21 04:16:32 +01:00
* - JavaScript homebase
2019-08-15 20:52:42 +02:00
* - Mobile toggle link
* - Registered footer scripts ( through App -> registerFooterScript ())
* - footer . tpl template
*
* @ param App $app The Friendica App instance
2019-08-16 09:46:38 +02:00
* @ param Mode $mode The Friendica runtime mode
2019-08-15 20:52:42 +02:00
* @ param L10n $l10n The l10n instance
*
* @ throws HTTPException\InternalServerErrorException
*/
2019-08-16 09:46:38 +02:00
private function initFooter ( App $app , Mode $mode , L10n $l10n )
2019-08-15 20:52:42 +02:00
{
// If you're just visiting, let javascript take you home
if ( ! empty ( $_SESSION [ 'visitor_home' ])) {
$homebase = $_SESSION [ 'visitor_home' ];
2021-08-09 21:48:39 +02:00
} elseif ( ! empty ( $app -> getLoggedInUserNickname ())) {
$homebase = 'profile/' . $app -> getLoggedInUserNickname ();
2019-08-15 20:52:42 +02:00
}
if ( isset ( $homebase )) {
$this -> page [ 'footer' ] .= '<script>var homebase="' . $homebase . '";</script>' . " \n " ;
}
/*
* Add a " toggle mobile " link if we ' re using a mobile device
*/
2019-08-16 09:46:38 +02:00
if ( $mode -> isMobile () || $mode -> isTablet ()) {
2019-08-15 20:52:42 +02:00
if ( isset ( $_SESSION [ 'show-mobile' ]) && ! $_SESSION [ 'show-mobile' ]) {
2021-11-04 21:29:59 +01:00
$link = 'toggle_mobile?address=' . urlencode ( $this -> curPageURL ());
2019-08-15 20:52:42 +02:00
} else {
2021-11-04 21:29:59 +01:00
$link = 'toggle_mobile?off=1&address=' . urlencode ( $this -> curPageURL ());
2019-08-15 20:52:42 +02:00
}
$this -> page [ 'footer' ] .= Renderer :: replaceMacros ( Renderer :: getMarkupTemplate ( " toggle_mobile_footer.tpl " ), [
'$toggle_link' => $link ,
'$toggle_text' => $l10n -> t ( 'toggle mobile' )
]);
}
Hook :: callAll ( 'footer' , $this -> page [ 'footer' ]);
$tpl = Renderer :: getMarkupTemplate ( 'footer.tpl' );
$this -> page [ 'footer' ] = Renderer :: replaceMacros ( $tpl , [
2019-11-28 18:27:16 +01:00
'$footerScripts' => array_unique ( $this -> footerScripts ),
]) . $this -> page [ 'footer' ];
2019-08-15 20:52:42 +02:00
}
/**
* Initializes Page -> page [ 'content' ] .
*
* Includes :
* - module content
* - hooks for content
*
2021-11-21 23:37:17 +01:00
* @ param ResponseInterface $response The Module response class
2021-11-21 20:06:36 +01:00
* @ param Mode $mode The Friendica execution mode
2019-08-15 20:52:42 +02:00
*
* @ throws HTTPException\InternalServerErrorException
*/
2021-11-21 23:37:17 +01:00
private function initContent ( ResponseInterface $response , Mode $mode )
2019-08-15 20:52:42 +02:00
{
// initialise content region
if ( $mode -> isNormal ()) {
Hook :: callAll ( 'page_content_top' , $this -> page [ 'content' ]);
}
2021-11-21 23:37:17 +01:00
$this -> page [ 'content' ] .= ( string ) $response -> getBody ();
2019-08-15 20:52:42 +02:00
}
/**
* Register a javascript file path to be included in the < footer > tag of every page .
* Inclusion is done in App -> initFooter () .
* The path can be absolute or relative to the Friendica installation base folder .
*
* @ param string $path
*
* @ see Page :: initFooter ()
*
*/
public function registerFooterScript ( $path )
{
2022-10-17 12:37:48 +02:00
$path = Network :: appendQueryParam ( $path , [ 'v' => App :: VERSION ]);
2020-02-01 01:41:20 +01:00
2019-08-15 20:52:42 +02:00
$url = str_replace ( $this -> basePath . DIRECTORY_SEPARATOR , '' , $path );
$this -> footerScripts [] = trim ( $url , '/' );
}
/**
* Executes the creation of the current page and prints it to the screen
*
2021-11-21 20:06:36 +01:00
* @ param App $app The Friendica App
* @ param BaseURL $baseURL The Friendica Base URL
* @ param Arguments $args The Friendica App arguments
* @ param Mode $mode The current node mode
2021-11-21 23:37:17 +01:00
* @ param ResponseInterface $response The Response of the module class , including type , content & headers
2021-11-21 20:06:36 +01:00
* @ param L10n $l10n The l10n language class
2023-01-08 07:17:06 +01:00
* @ param Profiler $profiler
2021-11-21 20:06:36 +01:00
* @ param IManageConfigValues $config The Configuration of this node
* @ param IManagePersonalConfigValues $pconfig The personal / user configuration
2023-01-08 07:17:06 +01:00
* @ param Nav $nav
* @ param int $localUID
* @ throws HTTPException\MethodNotAllowedException
* @ throws HTTPException\InternalServerErrorException
* @ throws HTTPException\ServiceUnavailableException
2019-08-15 20:52:42 +02:00
*/
2023-01-08 07:17:06 +01:00
public function run ( App $app , BaseURL $baseURL , Arguments $args , Mode $mode , ResponseInterface $response , L10n $l10n , Profiler $profiler , IManageConfigValues $config , IManagePersonalConfigValues $pconfig , Nav $nav , int $localUID )
2019-08-15 20:52:42 +02:00
{
2021-11-19 22:47:49 +01:00
$moduleName = $args -> getModuleName ();
2019-08-15 20:52:42 +02:00
2022-05-17 23:25:01 +02:00
$this -> command = $moduleName ;
$this -> method = $args -> getMethod ();
2022-05-17 22:47:23 +02:00
2019-08-15 20:52:42 +02:00
/* Create the page content .
* Calls all hooks which are including content operations
*
* Sets the $Page -> page [ 'content' ] variable
*/
2020-12-09 23:10:27 +01:00
$timestamp = microtime ( true );
2021-11-21 20:06:36 +01:00
$this -> initContent ( $response , $mode );
2019-08-15 20:52:42 +02:00
2019-10-06 17:18:51 +02:00
// Load current theme info after module has been initialized as theme could have been set in module
$currentTheme = $app -> getCurrentTheme ();
$theme_info_file = 'view/theme/' . $currentTheme . '/theme.php' ;
if ( file_exists ( $theme_info_file )) {
require_once $theme_info_file ;
}
if ( function_exists ( str_replace ( '-' , '_' , $currentTheme ) . '_init' )) {
$func = str_replace ( '-' , '_' , $currentTheme ) . '_init' ;
$func ( $app );
}
2019-08-15 20:52:42 +02:00
/* Create the page head after setting the language
* and getting any auth credentials .
*
* Moved initHead () and initFooter () to after
* all the module functions have executed so that all
* theme choices made by the modules can take effect .
*/
2022-10-20 21:27:32 +02:00
$this -> initHead ( $app , $args , $l10n , $config , $pconfig , $localUID );
2019-08-15 20:52:42 +02:00
/* Build the page ending -- this is stuff that goes right before
* the closing </ body > tag
*/
2019-08-16 09:46:38 +02:00
$this -> initFooter ( $app , $mode , $l10n );
2019-08-15 20:52:42 +02:00
2021-12-09 14:04:51 +01:00
$profiler -> set ( microtime ( true ) - $timestamp , 'aftermath' );
2019-08-16 09:46:38 +02:00
if ( ! $mode -> isAjax ()) {
2019-08-15 20:52:42 +02:00
Hook :: callAll ( 'page_end' , $this -> page [ 'content' ]);
}
// Add the navigation (menu) template
if ( $moduleName != 'install' && $moduleName != 'maintenance' ) {
$this -> page [ 'htmlhead' ] .= Renderer :: replaceMacros ( Renderer :: getMarkupTemplate ( 'nav_head.tpl' ), []);
2023-01-08 07:17:06 +01:00
$this -> page [ 'nav' ] = $nav -> getHtml ();
2019-08-15 20:52:42 +02:00
}
// Build the page - now that we have all the components
if ( isset ( $_GET [ " mode " ]) && (( $_GET [ " mode " ] == " raw " ) || ( $_GET [ " mode " ] == " minimal " ))) {
$doc = new DOMDocument ();
$target = new DOMDocument ();
$target -> loadXML ( " <root></root> " );
$content = mb_convert_encoding ( $this -> page [ " content " ], 'HTML-ENTITIES' , " UTF-8 " );
2023-03-22 05:08:36 +01:00
/// @TODO one day, kill those error-suppressing @ stuff, or PHP should ban it
2019-08-15 20:52:42 +02:00
@ $doc -> loadHTML ( $content );
$xpath = new DOMXPath ( $doc );
$list = $xpath -> query ( " //*[contains(@id,'tread-wrapper-')] " ); /* */
foreach ( $list as $item ) {
$item = $target -> importNode ( $item , true );
// And then append it to the target
$target -> documentElement -> appendChild ( $item );
}
if ( $_GET [ " mode " ] == " raw " ) {
2023-09-21 18:35:55 +02:00
$response -> withBody ( Utils :: streamFor ( $target -> saveHTML ()));
System :: echoResponse ( $response );
System :: exit ();
2019-08-15 20:52:42 +02:00
}
}
$page = $this -> page ;
2023-01-11 23:09:40 +01:00
// add and escape some common but crucial content for direct "echo" in HTML (security)
$page [ 'title' ] = htmlspecialchars ( $page [ 'title' ] ? ? '' );
$page [ 'section' ] = htmlspecialchars ( $args -> get ( 0 ) ? ? 'generic' );
$page [ 'module' ] = htmlspecialchars ( $args -> getModuleName () ? ? '' );
2022-10-17 12:37:48 +02:00
header ( " X-Friendica-Version: " . App :: VERSION );
2019-08-15 20:52:42 +02:00
header ( " Content-type: text/html; charset=utf-8 " );
2023-02-18 20:57:30 +01:00
if ( $config -> get ( 'system' , 'hsts' ) && ( $baseURL -> getScheme () === 'https' )) {
2019-08-15 20:52:42 +02:00
header ( " Strict-Transport-Security: max-age=31536000 " );
}
// Some security stuff
header ( 'X-Content-Type-Options: nosniff' );
header ( 'X-XSS-Protection: 1; mode=block' );
header ( 'X-Permitted-Cross-Domain-Policies: none' );
header ( 'X-Frame-Options: sameorigin' );
// Things like embedded OSM maps don't work, when this is enabled
// header("Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; connect-src 'self'; style-src 'self' 'unsafe-inline'; font-src 'self'; img-src 'self' https: data:; media-src 'self' https:; child-src 'self' https:; object-src 'none'");
/* We use $_GET [ " mode " ] for special page templates . So we will check if we have
* to load another page template than the default one .
* The page templates are located in / view / php / or in the theme directory .
*/
2019-11-28 18:27:16 +01:00
if ( isset ( $_GET [ 'mode' ])) {
$template = Theme :: getPathForFile ( 'php/' . Strings :: sanitizeFilePathItem ( $_GET [ 'mode' ]) . '.php' );
2019-08-15 20:52:42 +02:00
}
// If there is no page template use the default page template
if ( empty ( $template )) {
2019-11-28 18:27:16 +01:00
$template = Theme :: getPathForFile ( 'php/default.php' );
2019-08-15 20:52:42 +02:00
}
// Theme templates expect $a as an App instance
2019-08-15 20:58:57 +02:00
$a = $app ;
2019-08-15 20:52:42 +02:00
// Used as is in view/php/default.php
$lang = $l10n -> getCurrentLang ();
2023-07-10 04:44:40 +02:00
ob_start ();
2019-08-15 20:52:42 +02:00
require_once $template ;
2023-07-10 04:44:40 +02:00
$body = ob_get_clean ();
return $response -> withBody ( Utils :: streamFor ( $body ));
2019-08-15 20:52:42 +02:00
}
}