Version 4.5.0
This commit is contained in:
1 parent
1a0c7fd3c2
commit
f79dcf067a
3791 files changed
+248032
-76372
No files matched your search
+115
-50
@@ -11,7 +11,7 @@
|
||||
namespace IPS\Dispatcher;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
@@ -26,11 +26,12 @@ class _Front extends \IPS\Dispatcher\Standard
|
||||
* Controller Location
|
||||
*/
|
||||
public $controllerLocation = 'front';
|
||||
|
||||
|
||||
/**
|
||||
* Init
|
||||
*
|
||||
* @return void
|
||||
* @return void
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
@@ -45,6 +46,11 @@ class _Front extends \IPS\Dispatcher\Standard
|
||||
{
|
||||
$protocol = '1.1';
|
||||
}
|
||||
|
||||
/* Don't allow the setup in progress page to be cached, it will only be displayed for a very short period of time */
|
||||
header( "Cache-Control: no-cache, no-store, must-revalidate" );
|
||||
header( "Pragma: no-cache" );
|
||||
header( "Expires: 0" );
|
||||
|
||||
if ( \IPS\CIC and ! \IPS\Session\Front::loggedIn() and ! \IPS\Session\Front::i()->userAgent->spider )
|
||||
{
|
||||
@@ -114,14 +120,22 @@ class _Front extends \IPS\Dispatcher\Standard
|
||||
\IPS\Output::i()->error( $e->getMessage(), '2S100/' . $e->getCode(), $e->getCode() === 4 ? 403 : 404, '' );
|
||||
}
|
||||
}
|
||||
|
||||
/* Set a referral cookie */
|
||||
if( \IPS\Settings::i()->ref_on and isset( \IPS\Request::i()->_rid ) )
|
||||
{
|
||||
\IPS\Request::i()->setCookie( 'referred_by', \intval( \IPS\Request::i()->_rid ), \IPS\DateTime::create()->add( new \DateInterval( 'P1Y' ) ) );
|
||||
}
|
||||
|
||||
/* Enable sidebar by default (controllers can turn it off if needed) */
|
||||
\IPS\Output::i()->sidebar['enabled'] = ( \IPS\Request::i()->isAjax() ) ? FALSE : TRUE;
|
||||
|
||||
/* Add in RSS Feeds */
|
||||
foreach( \IPS\core\Rss::getAllFeeds() AS $feed_id => $feed )
|
||||
foreach( \IPS\core\Rss::getStore() AS $feed_id => $feed )
|
||||
{
|
||||
if ( $feed->groups == '*' OR \IPS\Member::loggedIn()->inGroup( $feed->groups ) )
|
||||
$feed = \IPS\core\Rss::constructFromData( $feed );
|
||||
|
||||
if ( $feed->_enabled AND ( $feed->groups == '*' OR \IPS\Member::loggedIn()->inGroup( $feed->groups ) ) )
|
||||
{
|
||||
\IPS\Output::i()->rssFeeds[ $feed->_title ] = $feed->url();
|
||||
}
|
||||
@@ -164,7 +178,7 @@ class _Front extends \IPS\Dispatcher\Standard
|
||||
{
|
||||
\IPS\Output::i()->sidebar = FALSE;
|
||||
\IPS\Output::i()->bodyClasses[] = 'ipsLayout_minimal';
|
||||
if( !in_array( $this->controller, array( 'contact', 'warnings' ) ) )
|
||||
if( !\in_array( $this->controller, array( 'contact', 'warnings', 'privacy', 'guidelines', 'metatags' ) ) )
|
||||
{
|
||||
\IPS\Output::i()->showBanned();
|
||||
}
|
||||
@@ -174,13 +188,13 @@ class _Front extends \IPS\Dispatcher\Standard
|
||||
/* Do we need more info from the member or do they need to validate? */
|
||||
|
||||
/* This controllers should always be accessible, no matter if the member is awaiting validation or needs to set up the email or name */
|
||||
$legalControllers = array( 'privacy', 'contact', 'terms' );
|
||||
$legalControllers = array( 'privacy', 'contact', 'terms', 'embed', 'metatags' );
|
||||
|
||||
/* Do we need more info from the member or do they need to validate? */
|
||||
if( \IPS\Member::loggedIn()->member_id and $this->controller !== 'language' and $this->controller !== 'theme' and $this->controller !== 'ajax' and !\in_array( $this->controller, $legalControllers ) )
|
||||
{
|
||||
/* Need their name or email... */
|
||||
if( ( \IPS\Member::loggedIn()->real_name === '' or !\IPS\Member::loggedIn()->email ) and $this->controller !== 'register' )
|
||||
if( ( \IPS\Member::loggedIn()->real_name === '' or !\IPS\Member::loggedIn()->email ) and $this->controller !== 'register' and $this->controller !== 'login' )
|
||||
{
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=system&controller=register&do=complete' )->setQueryString( 'ref', base64_encode( \IPS\Request::i()->url() ) ) );
|
||||
}
|
||||
@@ -195,18 +209,29 @@ class _Front extends \IPS\Dispatcher\Standard
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=system&controller=register&do=reconfirm', 'front', 'register' )->setQueryString( 'ref', base64_encode( \IPS\Request::i()->url() ) ) );
|
||||
}
|
||||
/* Have required profile actions that need completing */
|
||||
else if ( \IPS\Settings::i()->quick_register AND !\IPS\Member::loggedIn()->members_bitoptions['profile_completed'] AND !in_array( $this->controller, array( 'register', 'login', 'redirect', 'ajax', 'settings' ) ) AND $completion = \IPS\Member::loggedIn()->profileCompletion() AND count( $completion['required'] ) )
|
||||
else if ( \IPS\Settings::i()->quick_register AND !\IPS\Member::loggedIn()->members_bitoptions['profile_completed'] AND !\in_array( $this->controller, array( 'register', 'login', 'redirect', 'ajax', 'settings', 'checkout', 'pixabay', 'editor' ) ) AND $completion = \IPS\Member::loggedIn()->profileCompletion() AND \count( $completion['required'] ) )
|
||||
{
|
||||
foreach( $completion['required'] AS $id => $completed )
|
||||
{
|
||||
if ( $completed === FALSE )
|
||||
{
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=system&controller=register&do=finish", 'front', 'register' ) );
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=system&controller=register&do=finish&_new=1", 'front', 'register' )->setQueryString( 'ref', base64_encode( \IPS\Request::i()->url() ) ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Need to reset password */
|
||||
elseif ( $this->controller !== 'settings' AND ( !isset( \IPS\Request::i()->area ) OR \IPS\Request::i()->area !== 'password' ) )
|
||||
{
|
||||
foreach( \IPS\Login::methods() AS $method )
|
||||
{
|
||||
if ( $url = $method->forcePasswordResetUrl( \IPS\Member::loggedIn(), \IPS\Request::i()->url() ) )
|
||||
{
|
||||
\IPS\Output::i()->redirect( $url );
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Need to set up MFA... */
|
||||
elseif ( !in_array( $this->controller, array( 'register', 'login', 'redirect', 'ajax', 'settings' ) ) )
|
||||
elseif ( !\in_array( $this->controller, array( 'register', 'login', 'redirect', 'ajax', 'settings', 'embed' ) ) )
|
||||
{
|
||||
$haveAcceptableHandlers = FALSE;
|
||||
$haveConfiguredHandler = FALSE;
|
||||
@@ -237,17 +262,24 @@ class _Front extends \IPS\Dispatcher\Standard
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( 'app=core&module=system&controller=settings&do=initialMfa', 'front', 'settings' )->setQueryString( 'ref', base64_encode( \IPS\Request::i()->url() ) ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Permission Check */
|
||||
if ( !\IPS\Member::loggedIn()->canAccessModule( $this->module ) )
|
||||
try
|
||||
{
|
||||
if ( !\IPS\Member::loggedIn()->member_id and isset( \IPS\Request::i()->_mfaLogin ) )
|
||||
if ( !\IPS\Member::loggedIn()->canAccessModule( $this->module ) )
|
||||
{
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=system&controller=login", 'front', 'login' )->setQueryString( '_mfaLogin', 1 ) );
|
||||
if ( !\IPS\Member::loggedIn()->member_id and isset( \IPS\Request::i()->_mfaLogin ) )
|
||||
{
|
||||
\IPS\Output::i()->redirect( \IPS\Http\Url::internal( "app=core&module=system&controller=login", 'front', 'login' )->setQueryString( '_mfaLogin', 1 ) );
|
||||
}
|
||||
\IPS\Output::i()->error( ( \IPS\Member::loggedIn()->member_id ? 'no_module_permission' : 'no_module_permission_guest' ), '2S100/2', 403, 'no_module_permission_admin' );
|
||||
}
|
||||
\IPS\Output::i()->error( ( \IPS\Member::loggedIn()->member_id ? 'no_module_permission' : 'no_module_permission_guest' ), '2S100/2', 403, 'no_module_permission_admin' );
|
||||
}
|
||||
catch( \InvalidArgumentException $e ) # invalid module
|
||||
{
|
||||
\IPS\Output::i()->error( 'requested_route_404', '2S160/5', 404, '' );
|
||||
}
|
||||
|
||||
/* Stuff for output */
|
||||
@@ -276,7 +308,7 @@ class _Front extends \IPS\Dispatcher\Standard
|
||||
/* Figure out what the global search is */
|
||||
foreach ( $this->application->extensions( 'core', 'ContentRouter' ) as $object )
|
||||
{
|
||||
if ( count( $object->classes ) === 1 )
|
||||
if ( \count( $object->classes ) === 1 )
|
||||
{
|
||||
$classes = $object->classes;
|
||||
foreach ( $classes as $class )
|
||||
@@ -319,18 +351,28 @@ class _Front extends \IPS\Dispatcher\Standard
|
||||
/* If they are accessing "index.php/whatever", we want "index.php?/whatever */
|
||||
if ( !( $correctUrl instanceof \IPS\Http\Url ) and $url instanceof \IPS\Http\Url\Internal and mb_strpos( $url->data[ \IPS\Http\Url::COMPONENT_PATH ], '/index.php/' ) !== FALSE )
|
||||
{
|
||||
$pathFromBaseUrl = mb_substr( $url->data[ \IPS\Http\Url::COMPONENT_PATH ], mb_strlen( \IPS\Http\Url::internal('')->data[ \IPS\Http\Url::COMPONENT_PATH ] ) );
|
||||
if ( preg_match( '/index.php\//', $pathFromBaseUrl ) )
|
||||
$pathFromBaseUrl = ltrim( mb_substr( $url->data[ \IPS\Http\Url::COMPONENT_PATH ], mb_strlen( \IPS\Http\Url::internal('')->data[ \IPS\Http\Url::COMPONENT_PATH ] ) ), '/' );
|
||||
if ( mb_substr( $pathFromBaseUrl, 0, 10 ) === 'index.php/' )
|
||||
{
|
||||
$correctUrl = \IPS\Http\Url\Friendly::friendlyUrlFromComponent( 0, trim( mb_substr( $pathFromBaseUrl, 10 ), '/' ), $url->queryString );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Redirect to the correct URL if we got one */
|
||||
if ( $correctUrl instanceof \IPS\Http\Url )
|
||||
{
|
||||
if( $correctUrl->seoPagination and \in_array( 'page', array_keys( $url->hiddenQueryString ) ) )
|
||||
{
|
||||
$correctUrl = $correctUrl->setPage( 'page', $url->hiddenQueryString['page'] );
|
||||
}
|
||||
\IPS\Output::i()->redirect( $correctUrl, NULL, 301 );
|
||||
}
|
||||
|
||||
/* Check pagination */
|
||||
if ( $url instanceof \IPS\Http\Url\Friendly and $url->seoPagination and \in_array( 'page', array_keys( $url->queryString ) ) )
|
||||
{
|
||||
\IPS\Output::i()->redirect( $url->setPage( 'page', $url->queryString['page'] )->stripQueryString('page'), NULL, 301 );
|
||||
}
|
||||
}
|
||||
|
||||
/* If the accessed URL is friendly, set the "real" query string properties */
|
||||
@@ -346,7 +388,13 @@ class _Front extends \IPS\Dispatcher\Standard
|
||||
{
|
||||
$this->_controller = NULL;
|
||||
}
|
||||
|
||||
|
||||
/* If this is a POST request, and this key has already been populated, do not overwrite it as this allows form input to be ignored and the query string data used */
|
||||
if ( \IPS\Request::i()->requestMethod() == 'POST' and isset( \IPS\Request::i()->$k ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
\IPS\Request::i()->$k = $v;
|
||||
}
|
||||
}
|
||||
@@ -382,25 +430,6 @@ class _Front extends \IPS\Dispatcher\Standard
|
||||
*/
|
||||
protected function checkCached()
|
||||
{
|
||||
/* Store page view in Redis */
|
||||
if ( \IPS\CACHE_METHOD == 'Redis' and \IPS\CIC and !\IPS\Request::i()->isAjax() )
|
||||
{
|
||||
try
|
||||
{
|
||||
if( \IPS\Redis::i() === NULL )
|
||||
{
|
||||
throw new \RedisException( 'Redis instance is NULL', -1 );
|
||||
}
|
||||
|
||||
\IPS\Redis::i()->logPageHit();
|
||||
}
|
||||
catch( \RedisException $e )
|
||||
{
|
||||
/* Sometimes the connection can be reset - we don't want to let an uncaught exception bubble up in those cases */
|
||||
\IPS\Log::log( $e, 'redis' );
|
||||
}
|
||||
}
|
||||
|
||||
/* If this is a guest and there's a full cached page, we can serve that */
|
||||
if( mb_strtolower( $_SERVER['REQUEST_METHOD'] ) == 'get' and !isset( \IPS\Request::i()->csrfKey ) and !isset( \IPS\Request::i()->_mfaLogin ) and !\IPS\Session\Front::loggedIn() and !isset( \IPS\Request::i()->cookie['noCache'] ) and !\IPS\Request::i()->ipAddressIsBanned() and \IPS\CACHE_PAGE_TIMEOUT )
|
||||
{
|
||||
@@ -423,13 +452,25 @@ class _Front extends \IPS\Dispatcher\Standard
|
||||
/* Which theme? */
|
||||
$theme = isset( \IPS\Request::i()->cookie['theme'] ) ? \IPS\Request::i()->cookie['theme'] : '';
|
||||
|
||||
/* Make sure a session is initiated */
|
||||
\IPS\Session\Front::i();
|
||||
|
||||
/* Get cache */
|
||||
try
|
||||
{
|
||||
$cache = \IPS\Data\Cache::i()->getWithExpire( 'page_' . md5( (int) \IPS\Request::i()->isSecure() . ( !empty( $_SERVER['HTTP_HOST'] ) ? $_SERVER['HTTP_HOST'] : $_SERVER['SERVER_NAME'] ) . '/' . $_SERVER['REQUEST_URI'] ) . "_{$language}_{$theme}", TRUE );
|
||||
$cache = \IPS\Output\Cache::i()->get( 'page_' . md5( (string) \IPS\Request::i()->url() ) . "_{$language}_{$theme}", TRUE );
|
||||
$sessionId = isset( \IPS\Request::i()->cookie['IPSSessionFront'] ) ? \IPS\Request::i()->cookie['IPSSessionFront'] : \IPS\Session::i()->id;
|
||||
|
||||
\IPS\Output::i()->sendOutput( str_replace( '{{csrfKey}}', md5( '& 0&' . $sessionId ), $cache['output'] ), $cache['code'], $cache['contentType'], $cache['httpHeaders'], FALSE, TRUE );
|
||||
/* RSS feeds can be shown cached, all other pages contain a cache buster once logged in */
|
||||
$cache['meta']['httpHeaders'] += \IPS\Output::getCacheHeaders( $cache['meta']['lastUpdated'], \IPS\CACHE_PAGE_TIMEOUT );
|
||||
|
||||
if( isset( $_SERVER['HTTP_IF_MODIFIED_SINCE'] ) AND $_SERVER['HTTP_IF_MODIFIED_SINCE'] == $cache['meta']['httpHeaders']['Last-Modified'] )
|
||||
{
|
||||
\IPS\Output::i()->sendOutput( NULL, 304, $cache['meta']['contentType'], $cache['meta']['httpHeaders'], FALSE, TRUE, FALSE, FALSE );
|
||||
}
|
||||
|
||||
\IPS\Output::i()->sendOutput( str_replace( '{{csrfKey}}', md5( \IPS\SUITE_UNIQUE_KEY . '&& 0&' . $sessionId ), $cache['output'] ), $cache['meta']['code'], $cache['meta']['contentType'], $cache['meta']['httpHeaders'], FALSE, TRUE );
|
||||
|
||||
}
|
||||
catch ( \OutOfRangeException $e ) {}
|
||||
}
|
||||
@@ -466,11 +507,11 @@ class _Front extends \IPS\Dispatcher\Standard
|
||||
{
|
||||
$widgets = array();
|
||||
|
||||
if ( ! isset( \IPS\Output::i()->sidebar['widgets'] ) OR ! is_array( \IPS\Output::i()->sidebar['widgets'] ) )
|
||||
if ( ! isset( \IPS\Output::i()->sidebar['widgets'] ) OR ! \is_array( \IPS\Output::i()->sidebar['widgets'] ) )
|
||||
{
|
||||
\IPS\Output::i()->sidebar['widgets'] = array();
|
||||
}
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
$widgetConfig = \IPS\Db::i()->select( '*', 'core_widget_areas', array( 'app=? AND module=? AND controller=?', $this->application->directory, $this->module->key, $this->controller ) );
|
||||
@@ -497,7 +538,7 @@ class _Front extends \IPS\Dispatcher\Standard
|
||||
}
|
||||
}
|
||||
|
||||
if( count( $widgets ) )
|
||||
if( \count( $widgets ) )
|
||||
{
|
||||
if ( ( \IPS\Data\Cache::i() instanceof \IPS\Data\Cache\None ) and ! \IPS\Theme::isUsingTemplateDiskCache() )
|
||||
{
|
||||
@@ -514,7 +555,7 @@ class _Front extends \IPS\Dispatcher\Standard
|
||||
}
|
||||
}
|
||||
|
||||
if( count( $templateLoad ) )
|
||||
if( \count( $templateLoad ) )
|
||||
{
|
||||
\IPS\Data\Store::i()->loadIntoMemory( $templateLoad );
|
||||
}
|
||||
@@ -522,6 +563,7 @@ class _Front extends \IPS\Dispatcher\Standard
|
||||
|
||||
$widgetObjects = array();
|
||||
$storeLoad = array();
|
||||
$googleFonts = array();
|
||||
foreach ( $widgets as $areaKey => $area )
|
||||
{
|
||||
foreach ( $area as $widget )
|
||||
@@ -540,6 +582,23 @@ class _Front extends \IPS\Dispatcher\Standard
|
||||
{
|
||||
$storeLoad[] = $_widget->cacheKey;
|
||||
}
|
||||
|
||||
if ( \in_array( 'IPS\Widget\Builder', class_implements( $_widget ) ) )
|
||||
{
|
||||
if ( ! empty( $_widget->configuration['widget_adv__font'] ) and $_widget->configuration['widget_adv__font'] !== 'inherit' )
|
||||
{
|
||||
$font = $_widget->configuration['widget_adv__font'];
|
||||
|
||||
if ( \mb_substr( $font, -6 ) === ' black' )
|
||||
{
|
||||
$fontWeight = 900;
|
||||
$font = \mb_substr( $font, 0, -6 ) . ':400,900';
|
||||
}
|
||||
|
||||
$googleFonts[ $font ] = $font;
|
||||
}
|
||||
}
|
||||
|
||||
$widgetObjects[ $areaKey ][] = $_widget;
|
||||
}
|
||||
catch ( \Exception $e )
|
||||
@@ -549,7 +608,12 @@ class _Front extends \IPS\Dispatcher\Standard
|
||||
}
|
||||
}
|
||||
|
||||
if( ( \IPS\Data\Cache::i() instanceof \IPS\Data\Cache\None ) and count( $storeLoad ) )
|
||||
if ( \count( $googleFonts ) )
|
||||
{
|
||||
\IPS\Output::i()->linkTags['googlefonts'] = array('rel' => 'stylesheet', 'href' => "https://fonts.googleapis.com/css?family=" . implode( "|", array_values( $googleFonts ) ) . "&display=swap");
|
||||
}
|
||||
|
||||
if( ( \IPS\Data\Cache::i() instanceof \IPS\Data\Cache\None ) and \count( $storeLoad ) )
|
||||
{
|
||||
\IPS\Data\Store::i()->loadIntoMemory( $storeLoad );
|
||||
}
|
||||
@@ -563,10 +627,10 @@ class _Front extends \IPS\Dispatcher\Standard
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Meta tags */
|
||||
\IPS\Output::i()->buildMetaTags();
|
||||
|
||||
|
||||
/* Check MFA */
|
||||
$this->checkMfa();
|
||||
|
||||
@@ -617,6 +681,7 @@ class _Front extends \IPS\Dispatcher\Standard
|
||||
{
|
||||
\IPS\Output::i()->globalControllers[] = 'core.front.core.app';
|
||||
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'front.js' ) );
|
||||
\IPS\Output::i()->jsFiles = array_merge( \IPS\Output::i()->jsFiles, \IPS\Output::i()->js( 'front_core.js', 'core', 'front' ) );
|
||||
|
||||
if ( \IPS\Member::loggedIn()->members_bitoptions['bw_using_skin_gen'] AND ( isset( \IPS\Request::i()->cookie['vseThemeId'] ) AND \IPS\Request::i()->cookie['vseThemeId'] ) and \IPS\Member::loggedIn()->isAdmin() and \IPS\Member::loggedIn()->hasAcpRestriction( 'core', 'customization', 'theme_easy_editor' ) )
|
||||
{
|
||||
@@ -674,7 +739,7 @@ class _Front extends \IPS\Dispatcher\Standard
|
||||
{
|
||||
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'styles/query_log.css', 'core', 'front' ) );
|
||||
}
|
||||
if ( \IPS\CACHING_LOG )
|
||||
if ( \IPS\CACHING_LOG or \IPS\REDIS_LOG )
|
||||
{
|
||||
\IPS\Output::i()->cssFiles = array_merge( \IPS\Output::i()->cssFiles, \IPS\Theme::i()->css( 'styles/caching_log.css', 'core', 'front' ) );
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user