Improved app booting

Bugfix SALT.php failed on initialization
Cleanup unused and obsolete constants and php settings
This commit is contained in:
djmaze 2021-12-23 16:04:40 +01:00
parent b80e62adfc
commit f92d453e8b
8 changed files with 279 additions and 319 deletions

View file

@ -3,12 +3,12 @@
if (!defined('APP_VERSION')) if (!defined('APP_VERSION'))
{ {
define('APP_VERSION', '0.0.0'); define('APP_VERSION', '0.0.0');
define('APP_INDEX_ROOT_PATH', strtr(__DIR__, DIRECTORY_SEPARATOR, '/') . '/'); define('APP_INDEX_ROOT_PATH', __DIR__ . DIRECTORY_SEPARATOR);
} }
if (file_exists(APP_INDEX_ROOT_PATH.'snappymail/v/'.APP_VERSION.'/include.php')) if (file_exists('snappymail/v/'.APP_VERSION.'/include.php'))
{ {
include APP_INDEX_ROOT_PATH.'snappymail/v/'.APP_VERSION.'/include.php'; include 'snappymail/v/'.APP_VERSION.'/include.php';
} }
else else
{ {

View file

@ -1,53 +0,0 @@
<?php
if (!\defined('RAINLOOP_APP_LIBRARIES_PATH'))
{
\define('RAINLOOP_APP_PATH', \rtrim(\realpath(__DIR__), '\\/').'/');
\define('RAINLOOP_APP_LIBRARIES_PATH', RAINLOOP_APP_PATH.'libraries/');
/**
* @param string $sClassName
*/
function rainLoopSplAutoloadRegisterFunction($sClassName) : void
{
/** case-sensitive autoload */
$file = \strtr($sClassName, '\\', DIRECTORY_SEPARATOR) . '.php';
// if ($file = \stream_resolve_include_path($file)) {
if (\is_file(RAINLOOP_APP_LIBRARIES_PATH . $file)) {
include_once RAINLOOP_APP_LIBRARIES_PATH . $file;
}
}
if (false === \set_include_path(RAINLOOP_APP_LIBRARIES_PATH . PATH_SEPARATOR . \get_include_path())) {
exit('set_include_path() failed. Probably due to Apache config using php_admin_value instead of php_value');
}
\spl_autoload_extensions('.php');
\spl_autoload_register();
\spl_autoload_register('rainLoopSplAutoloadRegisterFunction');
}
if (\class_exists('RainLoop\Api'))
{
if (!empty($_ENV['RAINLOOP_INCLUDE_AS_API']))
{
if (!\defined('APP_API_STARTED'))
{
\define('APP_API_STARTED', true);
\RainLoop\Api::Handle();
}
}
else if (!\defined('APP_STARTED'))
{
\define('APP_STARTED', true);
\RainLoop\Api::Handle();
\RainLoop\Service::Handle();
\RainLoop\Api::ExitOnEnd();
}
}
else if (\function_exists('rainLoopSplAutoloadRegisterFunction'))
{
\spl_autoload_unregister('rainLoopSplAutoloadRegisterFunction');
}

View file

@ -9,6 +9,8 @@ use RainLoop\KeyPathHelper;
use RainLoop\Notifications; use RainLoop\Notifications;
use RainLoop\Utils; use RainLoop\Utils;
//define('APP_DEV_VERSION', '0.0.0');
trait Admin trait Admin
{ {
private static $AUTH_ADMIN_TOKEN_KEY = 'smadmin'; private static $AUTH_ADMIN_TOKEN_KEY = 'smadmin';
@ -556,11 +558,11 @@ trait Admin
if ($oItem && isset($oItem->type, $oItem->id, $oItem->name, if ($oItem && isset($oItem->type, $oItem->id, $oItem->name,
$oItem->version, $oItem->release, $oItem->file, $oItem->description)) $oItem->version, $oItem->release, $oItem->file, $oItem->description))
{ {
if (!empty($oItem->required) && APP_DEV_VERSION !== APP_VERSION && version_compare(APP_VERSION, $oItem->required, '<')) { if (!empty($oItem->required) && '0.0.0' !== APP_VERSION && version_compare(APP_VERSION, $oItem->required, '<')) {
continue; continue;
} }
if (!empty($oItem->depricated) && APP_DEV_VERSION !== APP_VERSION && version_compare(APP_VERSION, $oItem->depricated, '>=')) { if (!empty($oItem->depricated) && '0.0.0' !== APP_VERSION && version_compare(APP_VERSION, $oItem->depricated, '>=')) {
continue; continue;
} }
@ -630,7 +632,7 @@ trait Admin
$bRainLoopUpdatable = \file_exists(APP_INDEX_ROOT_PATH.'index.php') $bRainLoopUpdatable = \file_exists(APP_INDEX_ROOT_PATH.'index.php')
&& \is_writable(APP_INDEX_ROOT_PATH.'index.php') && \is_writable(APP_INDEX_ROOT_PATH.'index.php')
&& \is_writable(APP_INDEX_ROOT_PATH.'snappymail/') && \is_writable(APP_INDEX_ROOT_PATH.'snappymail/')
&& APP_VERSION !== APP_DEV_VERSION; && APP_VERSION !== '0.0.0';
// \uksort($aList, function($a, $b){return \strcasecmp($a['name'], $b['name']);}); // \uksort($aList, function($a, $b){return \strcasecmp($a['name'], $b['name']);});

View file

@ -211,12 +211,4 @@ class Api
Utils::ClearCookie(Utils::SESSION_TOKEN); Utils::ClearCookie(Utils::SESSION_TOKEN);
return true; return true;
} }
public static function ExitOnEnd() : void
{
if (!\defined('SNAPPYMAIL_EXIT_ON_END'))
{
\define('SNAPPYMAIL_EXIT_ON_END', true);
}
}
} }

View file

@ -11,7 +11,7 @@ class Application extends \RainLoop\Config\AbstractConfig
parent::__construct('application.ini', parent::__construct('application.ini',
'; SnappyMail configuration file '; SnappyMail configuration file
; Please don\'t add custom parameters here, those will be overwritten', ; Please don\'t add custom parameters here, those will be overwritten',
defined('APP_ADDITIONAL_CONFIGURATION_NAME') ? APP_ADDITIONAL_CONFIGURATION_NAME : ''); APP_CONFIGURATION_NAME);
} }
public function Load() : bool public function Load() : bool

View file

@ -222,7 +222,9 @@ class Service
private function setCSP(string $sScriptNonce = null) : void private function setCSP(string $sScriptNonce = null) : void
{ {
$sContentSecurityPolicy = \trim($this->oActions->Config()->Get('security', 'content_security_policy', '')) ?: APP_DEFAULT_CSP; // "img-src https:" is allowed due to remote images in e-mails
$sContentSecurityPolicy = \trim($this->oActions->Config()->Get('security', 'content_security_policy', ''))
?: "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; img-src 'self' data: https: http:; style-src 'self' 'unsafe-inline'";
if ($this->oActions->Config()->Get('security', 'use_local_proxy_for_external_images', '')) { if ($this->oActions->Config()->Get('security', 'use_local_proxy_for_external_images', '')) {
$sContentSecurityPolicy = \preg_replace('/(img-src[^;]+)\\shttps:(\\s|;|$)/D', '$1$2', $sContentSecurityPolicy); $sContentSecurityPolicy = \preg_replace('/(img-src[^;]+)\\shttps:(\\s|;|$)/D', '$1$2', $sContentSecurityPolicy);
$sContentSecurityPolicy = \preg_replace('/(img-src[^;]+)\\shttp:(\\s|;|$)/D', '$1$2', $sContentSecurityPolicy); $sContentSecurityPolicy = \preg_replace('/(img-src[^;]+)\\shttp:(\\s|;|$)/D', '$1$2', $sContentSecurityPolicy);

View file

@ -51,4 +51,54 @@
exit(302); exit(302);
} }
$sCheckName = 'delete_if_you_see_it_after_install';
$sCheckFolder = APP_DATA_FOLDER_PATH.$sCheckName;
$sCheckFilePath = APP_DATA_FOLDER_PATH.$sCheckName.'/'.$sCheckName.'.file';
is_file($sCheckFilePath) && unlink($sCheckFilePath);
is_dir($sCheckFolder) && rmdir($sCheckFolder);
if (!is_dir(APP_DATA_FOLDER_PATH))
{
mkdir(APP_DATA_FOLDER_PATH, 0700, true);
}
else
{
chmod(APP_DATA_FOLDER_PATH, 0700);
}
$sTest = '';
switch (true)
{
case !is_dir(APP_DATA_FOLDER_PATH):
$sTest = 'is_dir';
break;
case !is_readable(APP_DATA_FOLDER_PATH):
$sTest = 'is_readable';
break;
case !is_writable(APP_DATA_FOLDER_PATH):
$sTest = 'is_writable';
break;
case !mkdir($sCheckFolder, 0700):
$sTest = 'mkdir';
break;
case false === file_put_contents($sCheckFilePath, time()):
$sTest = 'file_put_contents';
break;
case !unlink($sCheckFilePath):
$sTest = 'unlink';
break;
case !rmdir($sCheckFolder):
$sTest = 'rmdir';
break;
}
if (!empty($sTest))
{
echo '[202] Data folder permissions error ['.$sTest.']';
exit(202);
}
unset($sCheckName, $sCheckFilePath, $sCheckFolder, $sTest);
} }

View file

@ -1,13 +1,9 @@
<?php <?php
if (defined('APP_VERSION_ROOT_PATH')) {
return;
}
if (defined('APP_VERSION')) if (function_exists('sys_getloadavg')) {
{
// revoke permissions
umask(0077);
if (!defined('APP_VERSION_ROOT_PATH'))
{
if (function_exists('sys_getloadavg')) {
$load = sys_getloadavg(); $load = sys_getloadavg();
if ($load[0] > 95) { if ($load[0] > 95) {
header('HTTP/1.1 503 Service Unavailable'); header('HTTP/1.1 503 Service Unavailable');
@ -15,147 +11,98 @@ if (defined('APP_VERSION'))
exit('Mailserver too busy. Please try again later.'); exit('Mailserver too busy. Please try again later.');
} }
unset($load); unset($load);
} }
// PHP 8 // PHP 8
if (!function_exists('str_contains')) { if (!function_exists('str_contains')) {
function str_contains(string $haystack, string $needle) : bool function str_contains(string $haystack, string $needle) : bool
{ {
return false !== strpos($haystack, $needle); return false !== strpos($haystack, $needle);
} }
} }
if (!function_exists('str_starts_with')) { if (!function_exists('str_starts_with')) {
function str_starts_with(string $haystack, string $needle) : bool function str_starts_with(string $haystack, string $needle) : bool
{ {
return 0 === strncmp($haystack, $needle, strlen($needle)); return 0 === strncmp($haystack, $needle, strlen($needle));
} }
} }
ini_set('register_globals', 0); if (!defined('APP_VERSION')) {
ini_set('zend.ze1_compatibility_mode', 0); define('APP_VERSION', basename(__DIR__));
}
define('APP_VERSION_ROOT_PATH', APP_INDEX_ROOT_PATH.'snappymail/v/'.APP_VERSION.'/'); if (!defined('APP_INDEX_ROOT_PATH')) {
define('APP_INDEX_ROOT_PATH', dirname(dirname(dirname(__DIR__))) . DIRECTORY_SEPARATOR);
}
// "img-src https:" is allowed due to remote images in e-mails // revoke permissions
define('APP_DEFAULT_CSP', "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; img-src 'self' data: https: http:; style-src 'self' 'unsafe-inline'"); umask(0077);
date_default_timezone_set('UTC'); ini_set('register_globals', 0);
$sSite = strtolower(trim(empty($_SERVER['HTTP_HOST']) ? (empty($_SERVER['SERVER_NAME']) ? '' : $_SERVER['SERVER_NAME']) : $_SERVER['HTTP_HOST'])); define('APP_VERSION_ROOT_PATH', __DIR__ . DIRECTORY_SEPARATOR);
$sSite = 'www.' === substr($sSite, 0, 4) ? substr($sSite, 4) : $sSite;
$sSite = trim(preg_replace('/^.+@/', '', preg_replace('/:[\d]+$/', '', $sSite)));
$sSite = in_array($sSite, array('', 'localhost', '127.0.0.1', '::1', '::1/128', '0:0:0:0:0:0:0:1')) ? 'localhost' : $sSite;
define('APP_SITE', $sSite); date_default_timezone_set('UTC');
unset($sSite);
$sPrivateDataFolderInternalName = defined('MULTIDOMAIN') ? APP_SITE : ''; $sSite = strtolower(trim(empty($_SERVER['HTTP_HOST']) ? (empty($_SERVER['SERVER_NAME']) ? '' : $_SERVER['SERVER_NAME']) : $_SERVER['HTTP_HOST']));
define('APP_PRIVATE_DATA_NAME', $sPrivateDataFolderInternalName ?: '_default_'); $sSite = 'www.' === substr($sSite, 0, 4) ? substr($sSite, 4) : $sSite;
$sSite = trim(preg_replace('/^.+@/', '', preg_replace('/:[\d]+$/', '', $sSite)));
$sSite = in_array($sSite, array('', 'localhost', '127.0.0.1', '::1', '::1/128', '0:0:0:0:0:0:0:1')) ? 'localhost' : $sSite;
define('APP_DUMMY', '********'); define('APP_SITE', $sSite);
define('APP_DEV_VERSION', '0.0.0'); unset($sSite);
$sCustomDataPath = ''; $sPrivateDataFolderInternalName = defined('MULTIDOMAIN') ? APP_SITE : '';
$sCustomConfiguration = ''; define('APP_PRIVATE_DATA_NAME', $sPrivateDataFolderInternalName ?: '_default_');
if (is_file(APP_INDEX_ROOT_PATH.'include.php')) define('APP_DUMMY', '********');
{
$sCustomDataPath = '';
$sCustomConfiguration = '';
if (is_file(APP_INDEX_ROOT_PATH.'include.php'))
{
include_once APP_INDEX_ROOT_PATH.'include.php'; include_once APP_INDEX_ROOT_PATH.'include.php';
} }
defined('APP_USE_APCU_CACHE') || define('APP_USE_APCU_CACHE', true); defined('APP_USE_APCU_CACHE') || define('APP_USE_APCU_CACHE', true);
$sCustomDataPath = function_exists('__get_custom_data_full_path') ? rtrim(trim(__get_custom_data_full_path()), '\\/') : $sCustomDataPath; $sCustomDataPath = function_exists('__get_custom_data_full_path') ? rtrim(trim(__get_custom_data_full_path()), '\\/') : $sCustomDataPath;
define('APP_DATA_FOLDER_PATH', 0 === strlen($sCustomDataPath) ? APP_INDEX_ROOT_PATH.'data/' : $sCustomDataPath.'/'); define('APP_DATA_FOLDER_PATH', strlen($sCustomDataPath) ? $sCustomDataPath.'/' : APP_INDEX_ROOT_PATH.'data/');
unset($sCustomDataPath); unset($sCustomDataPath);
$sCustomConfiguration = function_exists('__get_additional_configuration_name') ? trim(__get_additional_configuration_name()) : $sCustomConfiguration; define('APP_CONFIGURATION_NAME', function_exists('__get_additional_configuration_name')
define('APP_ADDITIONAL_CONFIGURATION_NAME', $sCustomConfiguration); ? trim(__get_additional_configuration_name()) : $sCustomConfiguration);
unset($sCustomConfiguration); unset($sCustomConfiguration);
define('APP_DATA_FOLDER_PATH_UNIX', str_replace('\\', '/', APP_DATA_FOLDER_PATH)); // installation checking data folder
$sInstalled = is_file(APP_DATA_FOLDER_PATH.'INSTALLED') ? file_get_contents(APP_DATA_FOLDER_PATH.'INSTALLED') : '';
$sSalt = is_file(APP_DATA_FOLDER_PATH.'SALT.php') ? trim(file_get_contents(APP_DATA_FOLDER_PATH.'SALT.php')) : ''; if (APP_VERSION !== $sInstalled)
$sData = is_file(APP_DATA_FOLDER_PATH.'DATA.php') ? file_get_contents(APP_DATA_FOLDER_PATH.'DATA.php') : ''; {
$sInstalled = is_file(APP_DATA_FOLDER_PATH.'INSTALLED') ? file_get_contents(APP_DATA_FOLDER_PATH.'INSTALLED') : '';
// installation checking data folder
if (APP_VERSION !== $sInstalled)
{
include APP_VERSION_ROOT_PATH.'check.php'; include APP_VERSION_ROOT_PATH.'check.php';
}
$sCheckName = 'delete_if_you_see_it_after_install'; $sSalt = is_file(APP_DATA_FOLDER_PATH.'SALT.php') ? trim(file_get_contents(APP_DATA_FOLDER_PATH.'SALT.php')) : '';
$sCheckFolder = APP_DATA_FOLDER_PATH.$sCheckName; if (!$sSalt)
$sCheckFilePath = APP_DATA_FOLDER_PATH.$sCheckName.'/'.$sCheckName.'.file'; {
is_file($sCheckFilePath) && unlink($sCheckFilePath);
is_dir($sCheckFolder) && rmdir($sCheckFolder);
if (!is_dir(APP_DATA_FOLDER_PATH))
{
mkdir(APP_DATA_FOLDER_PATH, 0700, true);
}
else
{
chmod(APP_DATA_FOLDER_PATH, 0700);
}
$sTest = '';
switch (true)
{
case !is_dir(APP_DATA_FOLDER_PATH):
$sTest = 'is_dir';
break;
case !is_readable(APP_DATA_FOLDER_PATH):
$sTest = 'is_readable';
break;
case !is_writable(APP_DATA_FOLDER_PATH):
$sTest = 'is_writable';
break;
case !mkdir($sCheckFolder, 0700):
$sTest = 'mkdir';
break;
case false === file_put_contents($sCheckFilePath, time()):
$sTest = 'file_put_contents';
break;
case !unlink($sCheckFilePath):
$sTest = 'unlink';
break;
case !rmdir($sCheckFolder):
$sTest = 'rmdir';
break;
}
if (!empty($sTest))
{
echo '[202] Data folder permissions error ['.$sTest.']';
exit(202);
}
unset($sCheckName, $sCheckFilePath, $sCheckFolder, $sTest);
}
if (false === $sSalt)
{
// random salt // random salt
file_put_contents(APP_DATA_FOLDER_PATH.'SALT.php', '<'.'?php //'.bin2hex(random_bytes(48))); $sSalt = '<'.'?php //'.bin2hex(random_bytes(48));
} file_put_contents(APP_DATA_FOLDER_PATH.'SALT.php', $sSalt);
}
define('APP_SALT', md5($sSalt.APP_PRIVATE_DATA_NAME.$sSalt));
define('APP_SALT', md5($sSalt.APP_PRIVATE_DATA_NAME.$sSalt)); $sData = is_file(APP_DATA_FOLDER_PATH.'DATA.php') ? file_get_contents(APP_DATA_FOLDER_PATH.'DATA.php') : '';
define('APP_PRIVATE_DATA', APP_DATA_FOLDER_PATH.'_data_'.($sData ? md5($sData) : '').'/'.APP_PRIVATE_DATA_NAME.'/'); define('APP_PRIVATE_DATA', APP_DATA_FOLDER_PATH.'_data_'.($sData ? md5($sData) : '').'/'.APP_PRIVATE_DATA_NAME.'/');
define('APP_PLUGINS_PATH', APP_PRIVATE_DATA.'plugins/'); define('APP_PLUGINS_PATH', APP_PRIVATE_DATA.'plugins/');
ini_set('default_charset', 'UTF-8'); ini_set('default_charset', 'UTF-8');
ini_set('internal_encoding', 'UTF-8'); ini_set('internal_encoding', 'UTF-8');
mb_internal_encoding('UTF-8'); mb_internal_encoding('UTF-8');
mb_language('uni'); mb_language('uni');
if (APP_VERSION !== $sInstalled || (!is_dir(APP_PRIVATE_DATA) && strlen($sPrivateDataFolderInternalName) && '_default_' !== APP_PRIVATE_DATA_NAME))
{
define('APP_INSTALLED_START', true);
define('APP_INSTALLED_VERSION', $sInstalled);
if (APP_VERSION !== $sInstalled || (!is_dir(APP_PRIVATE_DATA) && strlen($sPrivateDataFolderInternalName) && '_default_' !== APP_PRIVATE_DATA_NAME))
{
file_put_contents(APP_DATA_FOLDER_PATH.'INSTALLED', APP_VERSION); file_put_contents(APP_DATA_FOLDER_PATH.'INSTALLED', APP_VERSION);
file_put_contents(APP_DATA_FOLDER_PATH.'VERSION', APP_VERSION); file_put_contents(APP_DATA_FOLDER_PATH.'VERSION', APP_VERSION);
file_put_contents(APP_DATA_FOLDER_PATH.'index.html', 'Forbidden'); file_put_contents(APP_DATA_FOLDER_PATH.'index.html', 'Forbidden');
@ -195,7 +142,7 @@ if (defined('APP_VERSION'))
$sFile = $sNewFile = $sNewFileName = ''; $sFile = $sNewFile = $sNewFileName = '';
$aFiles = glob(APP_VERSION_ROOT_PATH.'app/domains/*'); $aFiles = glob(APP_VERSION_ROOT_PATH.'app/domains/*');
if (is_array($aFiles) && 0 < \count($aFiles)) if (is_array($aFiles) && 0 < count($aFiles))
{ {
foreach ($aFiles as $sFile) foreach ($aFiles as $sFile)
{ {
@ -234,27 +181,26 @@ if (defined('APP_VERSION'))
unset($aFiles, $sFile, $sNewFileName, $sNewFile); unset($aFiles, $sFile, $sNewFileName, $sNewFile);
} }
} }
unset($sSalt, $sData, $sInstalled, $sPrivateDataFolderInternalName); unset($sSalt, $sData, $sInstalled, $sPrivateDataFolderInternalName);
}
if (!isset($_SERVER['HTTP_USER_AGENT'])) { if (!isset($_SERVER['HTTP_USER_AGENT'])) {
$_SERVER['HTTP_USER_AGENT'] = ''; $_SERVER['HTTP_USER_AGENT'] = '';
} }
if (empty($_SERVER['HTTPS']) || 'off' === $_SERVER['HTTPS']) { if (empty($_SERVER['HTTPS']) || 'off' === $_SERVER['HTTPS']) {
unset($_SERVER['HTTPS']); unset($_SERVER['HTTPS']);
} }
if (isset($_SERVER['REQUEST_SCHEME']) && 'https' === $_SERVER['REQUEST_SCHEME']) { if (isset($_SERVER['REQUEST_SCHEME']) && 'https' === $_SERVER['REQUEST_SCHEME']) {
$_SERVER['HTTPS'] = 'on'; $_SERVER['HTTPS'] = 'on';
} }
if (isset($_SERVER['HTTPS'])) { if (isset($_SERVER['HTTPS'])) {
header('Strict-Transport-Security: max-age=31536000'); header('Strict-Transport-Security: max-age=31536000');
} }
// See https://github.com/kjdev/php-ext-brotli // See https://github.com/kjdev/php-ext-brotli
if (!ini_get('zlib.output_compression') && !ini_get('brotli.output_compression')) { if (!ini_get('zlib.output_compression') && !ini_get('brotli.output_compression')) {
if (defined('USE_BROTLI') && is_callable('brotli_compress_add') && false !== stripos($_SERVER['HTTP_ACCEPT_ENCODING'], 'br')) { if (defined('USE_BROTLI') && is_callable('brotli_compress_add') && false !== stripos($_SERVER['HTTP_ACCEPT_ENCODING'], 'br')) {
ob_start(function(string $buffer, int $phase){ ob_start(function(string $buffer, int $phase){
static $resource; static $resource;
@ -267,12 +213,33 @@ if (defined('APP_VERSION'))
} else if (defined('USE_GZIP')) { } else if (defined('USE_GZIP')) {
ob_start('ob_gzhandler'); ob_start('ob_gzhandler');
} }
}
if (!defined('RAINLOOP_APP_LIBRARIES_PATH')) {
define('RAINLOOP_APP_LIBRARIES_PATH', rtrim(realpath(__DIR__), '\\/').'/app/libraries/');
if (false === set_include_path(RAINLOOP_APP_LIBRARIES_PATH . PATH_SEPARATOR . get_include_path())) {
exit('set_include_path() failed. Probably due to Apache config using php_admin_value instead of php_value');
} }
include APP_VERSION_ROOT_PATH.'app/handle.php'; spl_autoload_extensions('.php');
/** lowercase autoloader */
spl_autoload_register();
/** case-sensitive autoloader */
spl_autoload_register(function($sClassName){
$file = RAINLOOP_APP_LIBRARIES_PATH . strtr($sClassName, '\\', DIRECTORY_SEPARATOR) . '.php';
// if ($file = stream_resolve_include_path(strtr($sClassName, '\\', DIRECTORY_SEPARATOR) . '.php')) {
if (is_file($file)) {
include_once $file;
}
});
}
if (defined('SNAPPYMAIL_EXIT_ON_END') && SNAPPYMAIL_EXIT_ON_END) if (class_exists('RainLoop\\Api')) {
{ RainLoop\Api::Handle();
// NextCloud/OwnCloud?
if (empty($_ENV['RAINLOOP_INCLUDE_AS_API'])) {
RainLoop\Service::Handle();
exit(0); exit(0);
} }
} }