diff --git a/Dockerfile b/Dockerfile index 6eaa763448..84442c7198 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,6 +14,10 @@ RUN apt-get update \ && docker-php-ext-install -j$(nproc) opcache \ && docker-php-ext-configure pdo_mysql \ && docker-php-ext-install -j$(nproc) pdo_mysql \ + && pecl install brotli \ + && docker-php-ext-enable brotli \ + && pecl install zstd \ + && docker-php-ext-enable zstd \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* diff --git a/composer.json b/composer.json index 553cedaf86..cd669a3e00 100644 --- a/composer.json +++ b/composer.json @@ -28,6 +28,7 @@ "filp/whoops": "^2.14", "gabordemooij/redbean": "^5.7", "geoip2/geoip2": "^3.0.0", + "hostbybelle/compressionbuffer": "^1.0", "io-developer/php-whois": "^4.1", "lcharette/webpack-encore-twig": "^1.2.0", "league/commonmark": "^2.3", diff --git a/composer.lock b/composer.lock index 8ac614fcbc..8266cf382a 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "08b744c6a4c8e1a0f880570457a581cb", + "content-hash": "9b6fd56ed203486b5a99e3ed8887b12d", "packages": [ { "name": "antcms/antloader", @@ -53,6 +53,61 @@ }, "time": "2024-03-12T22:17:58+00:00" }, + { + "name": "asispts/http-accept", + "version": "v1.0.0", + "source": { + "type": "git", + "url": "https://github.com/asispts/http-accept.git", + "reference": "7beca5a724ef329bb5a0094b5aef7bfeab1193ae" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/asispts/http-accept/zipball/7beca5a724ef329bb5a0094b5aef7bfeab1193ae", + "reference": "7beca5a724ef329bb5a0094b5aef7bfeab1193ae", + "shasum": "" + }, + "require": { + "php": "^7.2|^8.0" + }, + "require-dev": { + "asispts/ptscs": "^1.0", + "phpstan/phpstan": "^1.4", + "phpstan/phpstan-phpunit": "^1.0", + "phpunit/phpunit": "^8.5|^9.5|^10.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "HttpAccept\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Asis Pattisahusiwa", + "email": "asispts@gmail.com" + } + ], + "description": "PHP Parser to deal with HTTP Accept, Accept-Language, Accept-Encoding, and Content-Type headers", + "homepage": "https://github.com/asispts/http-accept", + "keywords": [ + "accept", + "accept-encoding", + "accept-language", + "content-type", + "http-header-parser", + "http-headers" + ], + "support": { + "issues": "https://github.com/asispts/http-accept/issues", + "source": "https://github.com/asispts/http-accept/tree/v1.0.0" + }, + "time": "2023-04-28T02:59:23+00:00" + }, { "name": "brick/math", "version": "0.11.0", @@ -899,6 +954,56 @@ ], "time": "2023-12-03T20:05:35+00:00" }, + { + "name": "hostbybelle/compressionbuffer", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/HostByBelle/CompressionBuffer.git", + "reference": "a5ed8b63c9657a235f5551db1b2b7de37801f253" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/HostByBelle/CompressionBuffer/zipball/a5ed8b63c9657a235f5551db1b2b7de37801f253", + "reference": "a5ed8b63c9657a235f5551db1b2b7de37801f253", + "shasum": "" + }, + "require": { + "asispts/http-accept": "^1.0", + "php": ">=8.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.53", + "phpstan/phpstan": "^1.10" + }, + "suggest": { + "ext-brotli": "For brotli output compression", + "ext-zlib": "For gzip & deflate output compression", + "ext-zstd": "For zstd output compression" + }, + "type": "library", + "autoload": { + "psr-4": { + "HostByBelle\\": "src/HostByBelle" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Belle Aerni", + "email": "belleaerni@gmail.com" + } + ], + "description": "CompressionBuffer provides easy access to zstd, brotli, and gzip output buffering with PHP on any webserver.", + "support": { + "issues": "https://github.com/HostByBelle/CompressionBuffer/issues", + "source": "https://github.com/HostByBelle/CompressionBuffer/tree/1.0.0" + }, + "time": "2024-04-08T22:57:40+00:00" + }, { "name": "io-developer/php-whois", "version": "4.1.10", diff --git a/cspell.json b/cspell.json index bbdfe1d309..b0c063ed21 100644 --- a/cspell.json +++ b/cspell.json @@ -393,7 +393,8 @@ "intval", "thisfiledoesnotexist", "exchangerate", - "currencydata" + "currencydata", + "brotli" ], "ignorePaths": [ "tests-legacy/**", diff --git a/phpstan.neon b/phpstan.neon index 5233682888..f20f5da050 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -26,8 +26,6 @@ parameters: - '#^Function __trans not found\.$#' - '#^Function __pluralTrans not found\.$#' - '#^Inner named functions are not supported by PHPStan\. Consider refactoring to an anonymous function, class method, or a top\-level\-defined function\. See issue \#165 \(https\://github\.com/phpstan/phpstan/issues/165\) for more details\.$#' - - message: '#^Result of function header \(void\) is used\.$#' - path: src/modules/Custompages/Controller/Client.php - message: '#^Variable \$ext_id on left side of \?\?\= is never defined\.$#' path: src/modules/Extension/Service.php - '#^Access to an undefined property RedBeanPHP\\SimpleModel\:\:\$updated_at\.$#' diff --git a/src/config-sample.php b/src/config-sample.php index 7082b536de..1dd2f679ac 100644 --- a/src/config-sample.php +++ b/src/config-sample.php @@ -48,27 +48,45 @@ 'report_errors' => false, ], + 'system' => [ + /* + * Full URL where FOSSBilling is installed with trailing slash. + */ + 'url' => 'http://localhost/', + + /* + * The URL prefix to access the BB admin area. Ex: '/admin' for https://example.com/admin. + */ + 'admin_area_prefix' => '/admin', + + /* + * Configure the update branch for the automatic updater. + * Currently acceptable options are "release" or "preview". + */ + 'update_branch' => 'release', + + /* + * FOSSBilling will automatically execute cron when you login to the admin panel if it hasn't been executed in awhile. You can disable this fallback here. + */ + 'disable_auto_cron' => false, + + /* + * Set location to store sensitive data. + */ + 'path_data' => __DIR__ . '/data', + + /* + * FOSSBilling will automatically perform zstd, brotli, gzip, or deflate output compression depending on installed extensions and the client connecting. + * Disable this here if you want to not use output compression or control it outside of FOSSBilling itself (such as your webserver) + */ + 'do_output_compression' => true, + ], + 'info' => [ 'salt' => bin2hex(random_bytes(16)), 'instance_id' => 'XXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXXX', ], - /* - * Full URL where FOSSBilling is installed with trailing slash. - */ - 'url' => 'http://localhost/', - - /* - * The URL prefix to access the BB admin area. Ex: '/admin' for https://example.com/admin. - */ - 'admin_area_prefix' => '/admin', - - /* - * Configure the update branch for the automatic updater. - * Currently acceptable options are "release" or "preview". - */ - 'update_branch' => 'release', - 'maintenance_mode' => [ /* * Enable or disable the system maintenance mode. @@ -90,11 +108,6 @@ 'allowed_ips' => [], ], - /* - * FOSSBilling will automatically execute cron when you login to the admin panel if it hasn't been executed in awhile. You can disable this fallback here. - */ - 'disable_auto_cron' => false, - /* * These configuration options allow you to configure the default localisation. */ @@ -112,11 +125,6 @@ 'datetime_pattern' => '', ], - /* - * Set location to store sensitive data. - */ - 'path_data' => __DIR__ . '/data', - 'db' => [ /* * Database type. Don't change this if in doubt. @@ -168,7 +176,7 @@ // How many requests allowed per time span 'rate_limit' => 1000, - /** + /* * Note about rate-limiting login attempts: * When the limit is reached, a default delay of 2 seconds is added to the request. * This makes brute-forcing a password useless while not outright blocking legitimate traffic. @@ -184,13 +192,13 @@ 'rate_limit_login' => 20, /* - * This enables the usage of a token to protect the system from CSRF attacks. - * Disabling this is highly discouraged and opens your instance to a known vulnerability. - * This option is only here for backwards compatibility. - */ + * This enables the usage of a token to protect the system from CSRF attacks. + * Disabling this is highly discouraged and opens your instance to a known vulnerability. + * This option is only here for backwards compatibility. + */ 'CSRFPrevention' => true, - /** + /* * Any IP address within this list will not be put through the rate-limiter system. * This is useful if you have an application with a static IP address that needs to make frequent API requests to FOSSBilling. */ diff --git a/src/di.php b/src/di.php index e8a0343d0b..d6d9c43ec4 100644 --- a/src/di.php +++ b/src/di.php @@ -406,6 +406,7 @@ $di['set_return_uri']; header(sprintf('Location: %s', $di['url']->adminLink('staff/login'))); + ob_end_flush(); exit; } @@ -439,6 +440,7 @@ // Redirect to login page if browser request $login_url = $di['url']->link('login'); header("Location: $login_url"); + ob_end_flush(); exit; } } @@ -477,6 +479,7 @@ // Redirect to login page if browser request $login_url = $di['url']->adminLink('staff/login'); header("Location: $login_url"); + ob_end_flush(); exit; } } @@ -528,6 +531,7 @@ // If they aren't attempting to access their profile, redirect them to it. $login_url = $di['url']->link('client/profile'); header("Location: $login_url"); + ob_end_flush(); exit; } } @@ -834,6 +838,7 @@ $csv->output($outputName); // Prevent further output from being added to the end of the CSV + ob_end_flush(); exit; }); diff --git a/src/index.php b/src/index.php index 8fdb5fb828..9430995c78 100644 --- a/src/index.php +++ b/src/index.php @@ -1,4 +1,5 @@ applyCorePatches(); $di['tools']->emptyFolder(PATH_CACHE); - exit('Any missing config migrations or database patches have been applied and the cache has been cleared'); + echo 'Any missing config migrations or database patches have been applied and the cache has been cleared'; } catch (Exception $e) { - exit('An error occurred while attempting to apply patches:
' . $e->getMessage()); + echo 'An error occurred while attempting to apply patches:
' . $e->getMessage(); } + exit; } $debugBar['time']->startMeasure('session_start', 'Starting / restoring the session'); @@ -90,6 +92,9 @@ exit; } -// If no HTTP error passed, run the app. -echo $app->run(); +// Start output buffering & run the app +ob_start(CompressionBuffer::handler(...)); +header('X-Accel-Buffering: no'); +$app->run(); +ob_end_flush(); exit; diff --git a/src/library/Box/App.php b/src/library/Box/App.php index 664d9bf23e..93d95e59c5 100644 --- a/src/library/Box/App.php +++ b/src/library/Box/App.php @@ -112,7 +112,7 @@ public function delete(string $url, string $methodName, ?array $conditions = [], $this->event('delete', $url, $methodName, $conditions, $class); } - public function run(): string + public function run(): void { $this->debugBar['time']->startMeasure('registerModule', 'Registering module routes'); $this->registerModule(); @@ -126,7 +126,7 @@ public function run(): string $this->checkPermission(); $this->debugBar['time']->stopMeasure('checkperm'); - return $this->processRequest(); + echo $this->processRequest(); } /** @@ -136,6 +136,7 @@ public function redirect($path): never { $location = $this->di['url']->link($path); header("Location: $location"); + ob_end_flush(); exit; } diff --git a/src/library/Box/AppAdmin.php b/src/library/Box/AppAdmin.php index f7176b4465..9b44d9a22b 100644 --- a/src/library/Box/AppAdmin.php +++ b/src/library/Box/AppAdmin.php @@ -34,6 +34,7 @@ protected function checkPermission(): void http_response_code(403); $e = new FOSSBilling\InformationException('You do not have permission to access the :mod: module', [':mod:' => $this->mod], 403); echo $this->render('error', ['exception' => $e]); + ob_end_flush(); exit; } } @@ -49,6 +50,7 @@ public function redirect($path): never { $location = $this->di['url']->adminLink($path); header("Location: $location"); + ob_end_flush(); exit; } diff --git a/src/library/FOSSBilling/CentralAlerts.php b/src/library/FOSSBilling/CentralAlerts.php index 45919bdd5a..61651eb444 100644 --- a/src/library/FOSSBilling/CentralAlerts.php +++ b/src/library/FOSSBilling/CentralAlerts.php @@ -77,7 +77,7 @@ public function filterAlerts(array $type = [], string $version = Version::VERSIO } if ($version) { - if (Config::getProperty('update_branch', 'release') === 'preview') { + if (Config::getProperty('system.update_branch', 'release') === 'preview') { $alerts = array_filter($alerts, fn ($alert) => $alert['include_preview_branch']); } else { $alerts = array_filter($alerts, function ($alert) use ($version) { diff --git a/src/library/FOSSBilling/ErrorPage.php b/src/library/FOSSBilling/ErrorPage.php index 45057ebb85..35814cf27f 100644 --- a/src/library/FOSSBilling/ErrorPage.php +++ b/src/library/FOSSBilling/ErrorPage.php @@ -324,6 +324,7 @@ function toggle() { '; echo $page; + ob_end_flush(); exit; } } diff --git a/src/library/FOSSBilling/ExtensionManager.php b/src/library/FOSSBilling/ExtensionManager.php index fac75b69cf..a120bad1c9 100644 --- a/src/library/FOSSBilling/ExtensionManager.php +++ b/src/library/FOSSBilling/ExtensionManager.php @@ -136,7 +136,7 @@ public function isExtensionCompatible(string $extension): bool { $latest = $this->getLatestExtensionRelease($extension); - if (Config::getProperty('update_branch', 'release') === 'release') { + if (Config::getProperty('system.update_branch', 'release') === 'release') { if (version_compare(Version::VERSION, $latest['min_fossbilling_version'], '<')) { return false; } diff --git a/src/library/FOSSBilling/Requirements.php b/src/library/FOSSBilling/Requirements.php index 25537dbec6..6eb833f752 100644 --- a/src/library/FOSSBilling/Requirements.php +++ b/src/library/FOSSBilling/Requirements.php @@ -36,6 +36,8 @@ class Requirements 'bz2' => 'optional support for bzip2 archives', 'simplexml' => 'the Plesk integration', 'xml' => 'the Plesk integration', + 'brotli' => 'output compression using brotli', + 'zstd' => 'output compression using zstd', ], 'min_version' => '8.1', ]; diff --git a/src/library/FOSSBilling/Update.php b/src/library/FOSSBilling/Update.php index 1f9a786dd6..14ad0b958d 100644 --- a/src/library/FOSSBilling/Update.php +++ b/src/library/FOSSBilling/Update.php @@ -42,7 +42,7 @@ public function getDi(): ?\Pimple\Container */ public function getUpdateBranch(): string { - return Config::getProperty('update_branch', 'release'); + return Config::getProperty('system.update_branch', 'release'); } /** diff --git a/src/library/FOSSBilling/UpdatePatcher.php b/src/library/FOSSBilling/UpdatePatcher.php index 45c295be79..81ff0a01c5 100644 --- a/src/library/FOSSBilling/UpdatePatcher.php +++ b/src/library/FOSSBilling/UpdatePatcher.php @@ -52,38 +52,64 @@ public function applyConfigPatches(): void $newConfig = $currentConfig; $newConfig['security']['mode'] ??= 'strict'; $newConfig['security']['force_https'] ??= true; - $newConfig['security']['session_lifespan'] ??= $newConfig['security']['cookie_lifespan'] ?? 7200; + $newConfig['security']['session_lifespan'] ??= $currentConfig['security']['cookie_lifespan'] ?? 7200; $newConfig['security']['perform_session_fingerprinting'] ??= true; $newConfig['security']['debug_fingerprint'] ??= false; - $newConfig['update_branch'] ??= 'release'; - $newConfig['log_stacktrace'] ??= true; - $newConfig['stacktrace_length'] ??= 25; + + $newConfig['system']['url'] ??= $currentConfig['url']; + $newConfig['system']['admin_area_prefix'] ??= $currentConfig['admin_area_prefix'] ?? '/admin'; + $newConfig['system']['update_branch'] ??= $currentConfig['update_branch'] ?? 'release'; + $newConfig['system']['disable_auto_cron'] ??= $currentConfig['disable_auto_cron'] ?? false; + $newConfig['system']['path_data'] ??= $currentConfig['path_data']; + $newConfig['system']['do_output_compression'] ??= true; + $newConfig['maintenance_mode']['enabled'] ??= false; $newConfig['maintenance_mode']['allowed_urls'] ??= []; $newConfig['maintenance_mode']['allowed_ips'] ??= []; - $newConfig['disable_auto_cron'] ??= false; + $newConfig['i18n']['locale'] ??= $currentConfig['locale'] ?? 'en_US'; $newConfig['i18n']['timezone'] ??= $currentConfig['timezone'] ?? 'UTC'; $newConfig['i18n']['date_format'] ??= 'medium'; $newConfig['i18n']['time_format'] ??= 'short'; + $newConfig['db']['port'] ??= '3306'; + $newConfig['api']['throttle_delay'] ??= 2; $newConfig['api']['rate_span_login'] ??= 60; $newConfig['api']['rate_limit_login'] ??= 20; $newConfig['api']['CSRFPrevention'] ??= true; $newConfig['api']['rate_limit_whitelist'] ??= []; - $newConfig['debug_and_monitoring']['debug'] ??= $newConfig['debug'] ?? false; - $newConfig['debug_and_monitoring']['log_stacktrace'] ??= $newConfig['log_stacktrace'] ?? true; - $newConfig['debug_and_monitoring']['stacktrace_length'] ??= $newConfig['stacktrace_length'] ?? 25; + + $newConfig['debug_and_monitoring']['debug'] ??= $currentConfig['debug'] ?? false; + $newConfig['debug_and_monitoring']['log_stacktrace'] ??= $currentConfig['log_stacktrace'] ?? true; + $newConfig['debug_and_monitoring']['stacktrace_length'] ??= $currentConfig['stacktrace_length'] ?? 25; $newConfig['debug_and_monitoring']['report_errors'] ??= false; + if (!class_exists('Uuid')) { $this->registerFallbackAutoloader(); } $newConfig['info']['instance_id'] ??= Uuid::uuid4()->toString(); - $newConfig['info']['salt'] ??= $newConfig['salt']; + $newConfig['info']['salt'] ??= $currentConfig['salt']; // Remove depreciated config keys/subkeys. - $depreciatedConfigKeys = ['guzzle', 'locale', 'locale_date_format', 'locale_time_format', 'timezone', 'sef_urls', 'salt', 'path_logs', 'log_to_db']; + $depreciatedConfigKeys = [ + 'guzzle', + 'locale', + 'locale_date_format', + 'locale_time_format', + 'timezone', + 'sef_urls', + 'salt', + 'path_logs', + 'log_to_db', + 'update_branch', + 'log_stacktrace', + 'stacktrace_length', + 'disable_auto_cron', + 'path_data', + 'admin_area_prefix', + 'url' + ]; $depreciatedConfigSubkeys = [ 'security' => 'cookie_lifespan', ]; @@ -295,7 +321,7 @@ private function getPatches($patchLevel = 0): array 36 => function (): void { // Patch to complete merging the Kb and Support modules. // @see https://github.com/FOSSBilling/FOSSBilling/pull/1180 - + // Renames the "kb_article" and "kb_article_category" tables to "support_kb_article" and "support_kb_article_category", respectively. $q = 'RENAME TABLE kb_article TO support_kb_article, kb_article_category TO support_kb_article_category;'; $this->executeSql($q); @@ -327,7 +353,7 @@ private function getPatches($patchLevel = 0): array 37 => function (): void { // Patch to complete remove the outdated queue module. // @see https://github.com/FOSSBilling/FOSSBilling/pull/1777 - + try { $ext_service = $this->di['mod_service']('extension'); // If the queue extension exists, uninstall it. @@ -378,7 +404,7 @@ private function getPatches($patchLevel = 0): array $config = $ext_service->getConfig('mod_currency'); $config['ext'] = 'mod_currency'; // This should automatically be set, but some appear to be having cache issues that causes it to not be - + // Migrate the old currency exchange rate sync settings $key = $pairs['currencylayer'] ?? ''; if ($key) { @@ -399,7 +425,7 @@ private function getPatches($patchLevel = 0): array ]; ksort($patches, SORT_NATURAL); - return array_filter($patches, fn ($key) => $key > $patchLevel, ARRAY_FILTER_USE_KEY); + return array_filter($patches, fn($key) => $key > $patchLevel, ARRAY_FILTER_USE_KEY); } /** diff --git a/src/load.php b/src/load.php index 2902cb5239..573857959d 100644 --- a/src/load.php +++ b/src/load.php @@ -15,6 +15,7 @@ use Symfony\Component\Filesystem\Filesystem; use Whoops\Handler\PrettyPageHandler; use Whoops\Run; +use HostByBelle\CompressionBuffer; const PATH_ROOT = __DIR__; const PATH_VENDOR = PATH_ROOT . DIRECTORY_SEPARATOR . 'vendor'; @@ -245,12 +246,12 @@ function exceptionHandler(Exception|Error $e) // Set globals and relevant settings based on the config. date_default_timezone_set(Config::getProperty('i18n.timezone', 'UTC')); -define('ADMIN_PREFIX', Config::getProperty('admin_area_prefix')); +define('ADMIN_PREFIX', Config::getProperty('system.admin_area_prefix')); define('DEBUG', (bool) Config::getProperty('debug_and_monitoring.debug', false)); -define('PATH_DATA', Config::getProperty('path_data')); +define('PATH_DATA', Config::getProperty('system.path_data')); define('PATH_CACHE', PATH_DATA . DIRECTORY_SEPARATOR . 'cache'); define('PATH_LOG', PATH_DATA . DIRECTORY_SEPARATOR . 'log'); -define('SYSTEM_URL', Config::getProperty('url')); +define('SYSTEM_URL', Config::getProperty('system.url')); define('INSTANCE_ID', Config::getProperty('info.instance_id', 'Unknown')); // Initial setup and checks passed, now we setup our custom autoloader. @@ -285,3 +286,9 @@ function exceptionHandler(Exception|Error $e) ini_set('display_errors', '0'); ini_set('display_startup_errors', '0'); } + +// Setup output handling and then disable it if needed +CompressionBuffer::setUp(); +if (!Config::getProperty('system.do_output_compression', true)) { + CompressionBuffer::disable(); +} diff --git a/src/modules/Api/Controller/Client.php b/src/modules/Api/Controller/Client.php index 58718283c4..ac2bcaa998 100644 --- a/src/modules/Api/Controller/Client.php +++ b/src/modules/Api/Controller/Client.php @@ -290,6 +290,7 @@ public function renderJson($data = null, \Exception $e = null) $result = ['result' => $data, 'error' => null]; } echo json_encode($result); + ob_end_flush(); exit; } diff --git a/src/modules/Client/Controller/Admin.php b/src/modules/Client/Controller/Admin.php index dcc973fa2c..85a6a3f684 100644 --- a/src/modules/Client/Controller/Admin.php +++ b/src/modules/Client/Controller/Admin.php @@ -118,6 +118,7 @@ public function get_login(\Box_App $app, $id) header('HTTP/1.1 301 Moved Permanently'); header('Location: ' . $this->di['tools']->url($redirect_to)); + ob_end_flush(); exit; } } diff --git a/src/modules/Custompages/Controller/Client.php b/src/modules/Custompages/Controller/Client.php index 4202ae8202..102f44726b 100644 --- a/src/modules/Custompages/Controller/Client.php +++ b/src/modules/Custompages/Controller/Client.php @@ -49,7 +49,9 @@ public function get_page(\Box_App $app, $slug) if (isset($page['id'])) { return $app->render('mod_custompages_content', ['page' => $page]); } else { - exit(header('Location: ' . $this->di['url']->get(''))); + header('Location: ' . $this->di['url']->get('')); + ob_end_flush(); + exit; } } } diff --git a/src/modules/Custompages/Service.php b/src/modules/Custompages/Service.php index ac53a295af..fabcddb3d7 100644 --- a/src/modules/Custompages/Service.php +++ b/src/modules/Custompages/Service.php @@ -96,7 +96,9 @@ public function updatePage($id, $title, $description, $keywords, $content, $slug $ex = $this->di['pdo']->prepare('SELECT id from custom_pages WHERE slug = ? AND id <> ?'); $ex->execute([$slug, $id]); if ($ex->rowCount() > 0) { - exit(json_encode(['result' => null, 'error' => ['message' => 'You need to set unique slug.', 'code' => 9999]])); + echo json_encode(['result' => null, 'error' => ['message' => 'You need to set unique slug.', 'code' => 9999]]); + ob_end_flush(); + exit; } $this->di['pdo']->prepare('UPDATE custom_pages SET title = ?, description = ?, keywords = ?, content = ?, slug = ? WHERE id = ?')->execute([$title, $description, $keywords, $content, $slug, $id]); $this->di['logger']->info('Updated custom page #%s', $id); diff --git a/src/modules/Extension/Service.php b/src/modules/Extension/Service.php index 9555692996..89f518f8cd 100644 --- a/src/modules/Extension/Service.php +++ b/src/modules/Extension/Service.php @@ -745,6 +745,7 @@ public function hasManagePermission(string $module, \Box_App $app = null): void $e = new \FOSSBilling\InformationException('You do not have permission to access the :mod: module', [':mod:' => $module], 403); if (!is_null($app)) { echo $app->render('error', ['exception' => $e]); + ob_end_flush(); exit; } else { throw $e; @@ -759,6 +760,7 @@ public function hasManagePermission(string $module, \Box_App $app = null): void $e = new \FOSSBilling\InformationException('You do not have permission to perform this action', [], 403); if (!is_null($app)) { echo $app->render('error', ['exception' => $e]); + ob_end_flush(); exit; } else { throw $e; diff --git a/src/modules/Invoice/Service.php b/src/modules/Invoice/Service.php index 4a2df8297c..c91496d05c 100644 --- a/src/modules/Invoice/Service.php +++ b/src/modules/Invoice/Service.php @@ -1231,6 +1231,7 @@ public function generatePDF($hash, $identity) $pdf->loadHtml($html); $pdf->render(); $pdf->stream($invoice['serie_nr'], ['Attachment' => false]); + ob_end_flush(); exit(0); } diff --git a/src/modules/Redirect/Controller/Client.php b/src/modules/Redirect/Controller/Client.php index fb879408b9..a6d2ff60ca 100644 --- a/src/modules/Redirect/Controller/Client.php +++ b/src/modules/Redirect/Controller/Client.php @@ -51,6 +51,7 @@ public function do_redirect(\Box_App $app): never $target = $service->getRedirectByPath($app->uri); header('HTTP/1.1 301 Moved Permanently'); header('Location: ' . $target); + ob_end_flush(); exit; } } diff --git a/src/modules/System/Service.php b/src/modules/System/Service.php index a6262f31e6..4e6666e44b 100644 --- a/src/modules/System/Service.php +++ b/src/modules/System/Service.php @@ -277,7 +277,7 @@ public function getMessages($type) } $last_exec = $this->getParamValue('last_cron_exec'); - $disableAutoCron = Config::getProperty('disable_auto_cron', false); + $disableAutoCron = Config::getProperty('system.disable_auto_cron', false); /* * Here we check if cron has been run at all or within a recent timeframe.